diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 9c5d96ac37..5a5d754c42 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -1,4 +1,4 @@ - + Debug @@ -267,6 +267,7 @@ + diff --git a/OpenRA.Game/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Game/Orders/PlaceBuildingOrderGenerator.cs index 42dc5884cf..1cd1e6db1f 100644 --- a/OpenRA.Game/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Game/Orders/PlaceBuildingOrderGenerator.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using OpenRA.GameRules; using OpenRA.Traits; +using System.Linq; namespace OpenRA.Orders { @@ -56,11 +57,46 @@ namespace OpenRA.Orders Sound.Play(eva.BuildingCannotPlaceAudio); yield break; } - + yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, topLeft, Building); + + // Linebuild for walls. + // Assumes a 1x1 footprint; weird things will happen for other footprints + if (Rules.Info[ Building ].Traits.Contains()) + { + int range = Rules.Info[ Building ].Traits.Get().Range; + + // Start at place location, search outwards + // TODO: First make it work, then make it nice + int[] dirs = {0,0,0,0}; + for (int d = 0; d < 4; d++) + { + for (int i = 1; i < range; i++) + { + if (dirs[d] != 0) + continue; + + int2 cell = world.OffsetCell(topLeft,i,d); + + if (world.IsCellBuildable(cell, BuildingInfo.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel,null)) + continue; // Cell is empty; continue search + + // Cell contains an actor. Is it the type we want? + if (world.Queries.WithTrait().Any(a => (a.Actor.Info.Name == Building && a.Actor.Location.X == cell.X && a.Actor.Location.Y == cell.Y))) + dirs[d] = i; // Cell contains actor of correct type + else + dirs[d] = -1; // Cell is blocked by another actor type + } + + // Place intermediate-line sections + if (dirs[d] > 0) + for (int i = 1; i < dirs[d]; i++) + yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, world.OffsetCell(topLeft,i,d), Building); + } + } } } - + public void Tick( World world ) { var producing = Producer.traits.Get().CurrentItem( Rules.Info[ Building ].Category ); diff --git a/OpenRA.Game/Traits/LineBuild.cs b/OpenRA.Game/Traits/LineBuild.cs new file mode 100644 index 0000000000..40d7b55830 --- /dev/null +++ b/OpenRA.Game/Traits/LineBuild.cs @@ -0,0 +1,35 @@ +#region Copyright & License Information +/* + * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. + * This file is part of OpenRA. + * + * OpenRA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * OpenRA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenRA. If not, see . + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Traits.Activities; + +namespace OpenRA.Traits +{ + public class LineBuildInfo : StatelessTraitInfo + { + public readonly int Range = 5; + } + public class LineBuild {} +} diff --git a/OpenRA.Game/Traits/Player/PlaceBuilding.cs b/OpenRA.Game/Traits/Player/PlaceBuilding.cs index afd3142bfa..7716f5ef62 100644 --- a/OpenRA.Game/Traits/Player/PlaceBuilding.cs +++ b/OpenRA.Game/Traits/Player/PlaceBuilding.cs @@ -35,9 +35,11 @@ namespace OpenRA.Traits var queue = self.traits.Get(); var unit = Rules.Info[ order.TargetString ]; var producing = queue.CurrentItem(unit.Category); - if( producing == null || producing.Item != order.TargetString || producing.RemainingTime != 0 ) - return; - + + // Breaks linebuild + //if( producing == null || producing.Item != order.TargetString || producing.RemainingTime != 0 ) + // return; + var building = self.World.CreateActor( order.TargetString, order.TargetLocation, order.Player ); foreach (var s in building.Info.Traits.Get().BuildSounds) diff --git a/OpenRA.Game/UiOverlay.cs b/OpenRA.Game/UiOverlay.cs index 5308a449f4..170ea0857f 100644 --- a/OpenRA.Game/UiOverlay.cs +++ b/OpenRA.Game/UiOverlay.cs @@ -72,7 +72,46 @@ namespace OpenRA spriteRenderer.DrawSprite( ( isCloseEnough && world.IsCellBuildable( t, bi.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel ) && !world.Map.ContainsResource( t ) ) ? buildOk : buildBlocked, Game.CellSize * t, "terrain" ); + + // Linebuild for walls. + // Assumes a 1x1 footprint; weird things will happen for other footprints + if (Rules.Info[ name ].Traits.Contains()) + { + int range = Rules.Info[ name ].Traits.Get().Range; + + // Start at place location, search outwards + // TODO: First make it work, then make it nice + int[] dirs = {0,0,0,0}; + for (int d = 0; d < 4; d++) + { + for (int i = 1; i < range; i++) + { + if (dirs[d] != 0) + continue; + + int2 cell = world.OffsetCell(topLeft,i,d); + + if (world.IsCellBuildable(cell, bi.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel,null)) + continue; // Cell is empty; continue search + // Cell contains an actor. Is it the type we want? + if (Game.world.Queries.WithTrait().Any(a => (a.Actor.Info.Name == name && a.Actor.Location.X == cell.X && a.Actor.Location.Y == cell.Y))) + dirs[d] = i; // Cell contains actor of correct type + else + dirs[d] = -1; // Cell is blocked by another actor type + } + + // Place intermediate-line sections + if (dirs[d] > 0) + { + for (int i = 1; i < dirs[d]; i++) + { + int2 cell = world.OffsetCell(topLeft,i,d); + spriteRenderer.DrawSprite( world.IsCloseEnoughToBase(world.LocalPlayer, name, bi, cell) ? buildOk : buildBlocked, Game.CellSize * cell, "terrain" ); + } + } + } + } spriteRenderer.Flush(); } } diff --git a/OpenRA.Game/WorldUtils.cs b/OpenRA.Game/WorldUtils.cs index c53801adbd..440108dfa4 100755 --- a/OpenRA.Game/WorldUtils.cs +++ b/OpenRA.Game/WorldUtils.cs @@ -1,4 +1,4 @@ -#region Copyright & License Information +#region Copyright & License Information /* * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. * This file is part of OpenRA. @@ -126,7 +126,27 @@ namespace OpenRA .DefaultIfEmpty( new Actor[] {} ) .FirstOrDefault(); } - + + public static int2 OffsetCell(this World world, int2 cell, int step, int dir) + { + switch (dir) + { + case 0: + cell.X += step; + break; + case 1: + cell.Y += step; + break; + case 2: + cell.X -= step; + break; + case 3: + cell.Y -= step; + break; + } + return cell; + } + public static bool CanPlaceBuilding(this World world, string name, BuildingInfo building, int2 topLeft, Actor toIgnore) { return !Footprint.Tiles(name, building, topLeft).Any( diff --git a/mods/cnc/defaults.yaml b/mods/cnc/defaults.yaml index 9be18f188b..198f741784 100644 --- a/mods/cnc/defaults.yaml +++ b/mods/cnc/defaults.yaml @@ -43,6 +43,7 @@ Building: Dimensions: 1,1 Footprint: x + BaseNormal: no BuildSounds: constru2.aud, hvydoor1.aud SellSounds: cashturn.aud RenderBuilding: @@ -66,6 +67,7 @@ Crewed: no Sight: 0 Wall: + LineBuild: Selectable: RenderBuildingWall: HasMakeAnimation: false diff --git a/mods/ra/defaults.yaml b/mods/ra/defaults.yaml index 24ea3775d5..02b0965208 100644 --- a/mods/ra/defaults.yaml +++ b/mods/ra/defaults.yaml @@ -53,9 +53,11 @@ BuildSounds: placbldg.aud Capturable: false Bib: no + BaseNormal: no Crewed: no Sight: 0 Wall: + LineBuild: Selectable: RenderBuildingWall: HasMakeAnimation: false