static void Emit(Actor self) { var info = self.Info.Traits.Get <EmitInfantryOnSellInfo>(); var csv = self.Info.Traits.GetOrDefault <CustomSellValueInfo>(); var valued = self.Info.Traits.GetOrDefault <ValuedInfo>(); var cost = csv != null ? csv.Value : (valued != null ? valued.Cost : 0); var health = self.TraitOrDefault <Health>(); var dudesValue = info.ValuePercent * cost; if (health != null) { dudesValue = dudesValue * health.HP / health.MaxHP; } dudesValue /= 100; var eligibleLocations = FootprintUtils.Tiles(self).ToList(); var actorTypes = info.ActorTypes.Select(a => new { Name = a, Cost = self.World.Map.Rules.Actors[a].Traits.Get <ValuedInfo>().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, new TypeDictionary { new LocationInit(loc), new OwnerInit(self.Owner), })); } }
IEnumerable <Order> ClearBlockersOrders(World world, CPos topLeft) { var allTiles = FootprintUtils.Tiles(world.Map.Rules, building, buildingInfo, topLeft).ToArray(); var neightborTiles = Util.ExpandFootprint(allTiles, true).Except(allTiles) .Where(world.Map.Contains).ToList(); var blockers = allTiles.SelectMany(world.ActorMap.GetActorsAt) .Where(a => a.Owner == queue.Actor.Owner && a.IsIdle) .Select(a => new TraitPair <Mobile>(a, a.TraitOrDefault <Mobile>())); foreach (var blocker in blockers.Where(x => x.Trait != null)) { var availableCells = neightborTiles.Where(t => blocker.Trait.CanEnterCell(t)).ToList(); if (availableCells.Count == 0) { continue; } yield return(new Order("Move", blocker.Actor, false) { TargetLocation = blocker.Actor.ClosestCell(availableCells), SuppressVisualFeedback = true }); } }
public D2ConcreteOwners(World world) { map = world.Map; owners = new CellLayer <Player>(map); world.ActorAdded += a => { var c = a.Info.TraitInfoOrDefault <D2ConcreteInfo>(); if (c == null) { return; } var b = a.Info.TraitInfoOrDefault <BuildingInfo>(); if (b == null) { return; } foreach (var u in FootprintUtils.Tiles(map.Rules, a.Info.Name, b, a.Location)) { if (owners.Contains(u) && owners[u] == null) { owners[u] = a.Owner; } } }; }
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); } }
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"); } }
public FrozenUnderFog(ActorInitializer init, FrozenUnderFogInfo info) { // Spawned actors (e.g. building husks) shouldn't be revealed startsRevealed = info.StartsRevealed && !init.Contains <ParentActorInit>(); footprint = FootprintUtils.Tiles(init.self); tooltip = Lazy.New(() => init.self.TraitsImplementing <IToolTip>().FirstOrDefault()); tooltip = Lazy.New(() => init.self.TraitsImplementing <IToolTip>().FirstOrDefault()); health = Lazy.New(() => init.self.TraitOrDefault <Health>()); frozen = new Dictionary <Player, FrozenActor>(); visible = init.world.Players.ToDictionary(p => p, p => false); }
void UpdateNeighbours(Actor self) { var footprint = FootprintUtils.Tiles(self).ToArray(); var adjacent = Util.ExpandFootprint(footprint, true).Except(footprint) .Where(self.World.Map.Contains).ToList(); var adjacentActorTraits = adjacent.SelectMany(self.World.ActorMap.GetActorsAt) .SelectMany(a => a.TraitsImplementing <IWallConnector>()); foreach (var rb in adjacentActorTraits) { rb.SetDirty(); } }
public void AddedToWorld(Actor self) { var map = self.World.Map; if (template.PickAny) { // Fill the footprint with random variants foreach (var c in FootprintUtils.Tiles(self)) { // Only place on allowed terrain types if (!info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) { continue; } // Don't place under other buildings or custom terrain if (bi.GetBuildingAt(c) != self || map.CustomTerrain[c] != byte.MaxValue) { continue; } var index = Game.CosmeticRandom.Next(template.TilesCount); layer.AddTile(c, new TerrainTile(template.Id, (byte)index)); } return; } var origin = self.Location + info.Offset; for (var i = 0; i < template.TilesCount; i++) { var c = origin + new CVec(i % template.Size.X, i / template.Size.X); // Only place on allowed terrain types if (!info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) { continue; } // Don't place under other buildings or custom terrain if (bi.GetBuildingAt(c) != self || map.CustomTerrain[c] != byte.MaxValue) { continue; } layer.AddTile(c, new TerrainTile(template.Id, (byte)i)); } }
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 CPos?ChooseBuildLocation(string actorType) { var bi = Rules.Info[actorType].Traits.Get <BuildingInfo>(); foreach (var t in world.FindTilesInCircle(baseCenter, MaxBaseDistance)) { if (world.CanPlaceBuilding(actorType, bi, t, null)) { if (bi.IsCloseEnoughToBase(world, p, actorType, t)) { if (NoBuildingsUnder(Util.ExpandFootprint( FootprintUtils.Tiles(actorType, bi, t), false))) { return(t); } } } } return(null); // i don't know where to put it. }
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 CPos?ChooseBuildLocation(string actorType, bool distanceToBaseIsImportant, int maxBaseDistance, BuildingType type) { var bi = Rules.Info[actorType].Traits.GetOrDefault <BuildingInfo>(); if (bi == null) { return(null); } Func <WPos, CPos, CPos?> findPos = (pos, center) => { for (var k = MaxBaseDistance; k >= 0; k--) { var tlist = world.FindTilesInCircle(center, k) .OrderBy(a => (a.CenterPosition - pos).LengthSquared); foreach (var t in tlist) { if (world.CanPlaceBuilding(actorType, bi, t, null)) { if (bi.IsCloseEnoughToBase(world, p, actorType, t)) { if (NoBuildingsUnder(Util.ExpandFootprint(FootprintUtils.Tiles(actorType, bi, t), false))) { return(t); } } } } } return(null); }; switch (type) { case BuildingType.Defense: Actor enemyBase = FindEnemyBuildingClosestToPos(baseCenter.CenterPosition); return(enemyBase != null?findPos(enemyBase.CenterPosition, defenseCenter) : null); case BuildingType.Refinery: var tilesPos = world.FindTilesInCircle(baseCenter, MaxBaseDistance) .Where(a => resourceTypes.Contains(world.GetTerrainType(new CPos(a.X, a.Y)))) .OrderBy(a => (a.CenterPosition - baseCenter.CenterPosition).LengthSquared); return(tilesPos.Any() ? findPos(tilesPos.First().CenterPosition, baseCenter) : null); case BuildingType.Building: for (var k = 0; k < maxBaseDistance; k++) { foreach (var t in world.FindTilesInCircle(baseCenter, k)) { if (world.CanPlaceBuilding(actorType, bi, t, null)) { if (distanceToBaseIsImportant && !bi.IsCloseEnoughToBase(world, p, actorType, t)) { continue; } if (NoBuildingsUnder(Util.ExpandFootprint(FootprintUtils.Tiles(actorType, bi, t), false))) { return(t); } } } } break; } // Can't find a build location return(null); }
public override bool IsCloseEnoughToBase(World world, Player p, string buildingName, CPos topLeft) { if (base.IsCloseEnoughToBase(world, p, buildingName, topLeft)) { return(true); } var shroud = p.Shroud; var hasVisibleCells = false; var hasExploredCells = false; for (var y = topLeft.Y; y < topLeft.Y + Dimensions.Y; y++) { for (var x = topLeft.X; x < topLeft.X + Dimensions.X; x++) { var pos = new CPos(x, y); if (!shroud.IsExplored(pos)) { if (AllCellsShouldBeExplored) { return(false); } } else { hasExploredCells = true; } if (!shroud.IsVisible(pos)) { if (AllCellsShouldBeVisible) { return(false); } } else { hasVisibleCells = true; } } } if (AnyCellShouldBeExplored && !hasExploredCells) { return(false); } if (AnyCellShouldBeVisible && !hasVisibleCells) { return(false); } var scanStart = world.Map.Clamp(topLeft - new CVec(Adjacent, Adjacent)); var scanEnd = world.Map.Clamp(topLeft + Dimensions + new CVec(Adjacent, Adjacent)); var nearnessCandidates = new List <CPos>(); var co = world.WorldActor.Trait <D2ConcreteOwners>(); var allyBuildEnabled = world.WorldActor.Trait <MapBuildRadius>().AllyBuildRadiusEnabled; for (var y = scanStart.Y; y < scanEnd.Y; y++) { for (var x = scanStart.X; x < scanEnd.X; x++) { var pos = new CPos(x, y); if (shroud.IsExplored(pos) && shroud.IsVisible(pos)) { var ownerAtPos = co.GetOwnerAt(pos); if (ownerAtPos != null && (ownerAtPos == p || (allyBuildEnabled && ownerAtPos.Stances[p] == Stance.Ally))) { nearnessCandidates.Add(pos); } } } } var buildingTiles = FootprintUtils.Tiles(world.Map.Rules, buildingName, this, topLeft).ToList(); return(nearnessCandidates .Any(a => buildingTiles .Any(b => Math.Abs(a.X - b.X) <= Adjacent && Math.Abs(a.Y - b.Y) <= Adjacent))); }
public IEnumerable <IRenderable> RenderAboveShroud(WorldRenderer wr, World world) { // Draw chrono range yield return(new RangeCircleRenderable( self.CenterPosition, WDist.FromCells(self.Trait <StructureChrono>().Info.MaxDistance), 0, Color.FromArgb(128, Color.LawnGreen), Color.FromArgb(96, Color.Black))); 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 = self.Info; // rules.Actors[building]; foreach (var dec in actorInfo.TraitInfos <IPlaceBuildingDecorationInfo>()) { foreach (var r in dec.Render(wr, world, actorInfo, offset)) { yield return(r); } } // Cells, we are about to construct and occupy. var cells = new Dictionary <CPos, bool>(); if (!initialized) { var td = new TypeDictionary() { //new OpenRA.Mods.Common.FactionInit(faction), new OpenRA.Mods.Common.FactionInit(""), new OwnerInit(self.Owner), new HideBibPreviewInit() }; var init = new ActorPreviewInitializer(actorInfo, wr, td); preview = actorInfo.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 selfPos = self.Trait <IOccupySpace>().TopLeft; var isCloseEnough = ((topLeft - selfPos).Length) <= info.MaxDistance; foreach (var t in FootprintUtils.Tiles(rules, building, buildingInfo, topLeft)) { cells.Add(t, isCloseEnough && world.IsCellBuildable(t, buildingInfo) && res.GetResource(t) == null); } var placeBuildingInfo = self.Owner.PlayerActor.Info.TraitInfo <PlaceBuildingInfo>(); var pal = wr.Palette(placeBuildingInfo.Palette); var topLeftPos = world.Map.CenterOfCell(topLeft); // draw red or white buildable cell indicator. 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 override void AddedToWorld(Actor self) { base.AddedToWorld(self); blockedPositions = FootprintUtils.Tiles(self); }