Merge pull request #12577 from pchote/movement-layers
Implement tunnels, elevated bridges, jumpjet and subterranean units.
This commit is contained in:
@@ -19,26 +19,25 @@ namespace OpenRA
|
||||
public struct CPos : IScriptBindable, ILuaAdditionBinding, ILuaSubtractionBinding, ILuaEqualityBinding, ILuaTableBinding, IEquatable<CPos>
|
||||
{
|
||||
public readonly int X, Y;
|
||||
public readonly byte Layer;
|
||||
|
||||
public CPos(int x, int y) { X = x; Y = y; }
|
||||
public static readonly CPos Zero = new CPos(0, 0);
|
||||
public CPos(int x, int y) { X = x; Y = y; Layer = 0; }
|
||||
public CPos(int x, int y, byte layer) { X = x; Y = y; Layer = layer; }
|
||||
public static readonly CPos Zero = new CPos(0, 0, 0);
|
||||
|
||||
public static explicit operator CPos(int2 a) { return new CPos(a.X, a.Y); }
|
||||
|
||||
public static CPos operator +(CVec a, CPos b) { return new CPos(a.X + b.X, a.Y + b.Y); }
|
||||
public static CPos operator +(CPos a, CVec b) { return new CPos(a.X + b.X, a.Y + b.Y); }
|
||||
public static CPos operator -(CPos a, CVec b) { return new CPos(a.X - b.X, a.Y - b.Y); }
|
||||
public static CPos operator +(CVec a, CPos b) { return new CPos(a.X + b.X, a.Y + b.Y, b.Layer); }
|
||||
public static CPos operator +(CPos a, CVec b) { return new CPos(a.X + b.X, a.Y + b.Y, a.Layer); }
|
||||
public static CPos operator -(CPos a, CVec b) { return new CPos(a.X - b.X, a.Y - b.Y, a.Layer); }
|
||||
public static CVec operator -(CPos a, CPos b) { return new CVec(a.X - b.X, a.Y - b.Y); }
|
||||
|
||||
public static bool operator ==(CPos me, CPos other) { return me.X == other.X && me.Y == other.Y; }
|
||||
public static bool operator ==(CPos me, CPos other) { return me.X == other.X && me.Y == other.Y && me.Layer == other.Layer; }
|
||||
public static bool operator !=(CPos me, CPos other) { return !(me == other); }
|
||||
|
||||
public static CPos Max(CPos a, CPos b) { return new CPos(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
|
||||
public static CPos Min(CPos a, CPos b) { return new CPos(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode() ^ Layer.GetHashCode(); }
|
||||
|
||||
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
|
||||
|
||||
public bool Equals(CPos other) { return X == other.X && Y == other.Y; }
|
||||
public bool Equals(CPos other) { return X == other.X && Y == other.Y && Layer == other.Layer; }
|
||||
public override bool Equals(object obj) { return obj is CPos && Equals((CPos)obj); }
|
||||
|
||||
public override string ToString() { return X + "," + Y; }
|
||||
@@ -120,6 +119,7 @@ namespace OpenRA
|
||||
{
|
||||
case "X": return X;
|
||||
case "Y": return Y;
|
||||
case "Layer": return Layer;
|
||||
default: throw new LuaException("CPos does not define a member '{0}'".F(key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,6 @@
|
||||
<Compile Include="Traits\Player\PlayerColorPalette.cs" />
|
||||
<Compile Include="Traits\Player\PlayerHighlightPalette.cs" />
|
||||
<Compile Include="Traits\World\ScreenMap.cs" />
|
||||
<Compile Include="Traits\World\ActorMap.cs" />
|
||||
<Compile Include="Scripting\ScriptContext.cs" />
|
||||
<Compile Include="Scripting\ScriptActorInterface.cs" />
|
||||
<Compile Include="Scripting\ScriptObjectWrapper.cs" />
|
||||
|
||||
@@ -232,6 +232,30 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public enum SubCell { Invalid = int.MinValue, Any = int.MinValue / 2, FullCell = 0, First = 1 }
|
||||
public interface IActorMap
|
||||
{
|
||||
IEnumerable<Actor> GetActorsAt(CPos a);
|
||||
IEnumerable<Actor> GetActorsAt(CPos a, SubCell sub);
|
||||
bool HasFreeSubCell(CPos cell, bool checkTransient = true);
|
||||
SubCell FreeSubCell(CPos cell, SubCell preferredSubCell = SubCell.Any, bool checkTransient = true);
|
||||
SubCell FreeSubCell(CPos cell, SubCell preferredSubCell, Func<Actor, bool> checkIfBlocker);
|
||||
bool AnyActorsAt(CPos a);
|
||||
bool AnyActorsAt(CPos a, SubCell sub, bool checkTransient = true);
|
||||
bool AnyActorsAt(CPos a, SubCell sub, Func<Actor, bool> withCondition);
|
||||
void AddInfluence(Actor self, IOccupySpace ios);
|
||||
void RemoveInfluence(Actor self, IOccupySpace ios);
|
||||
int AddCellTrigger(CPos[] cells, Action<Actor> onEntry, Action<Actor> onExit);
|
||||
void RemoveCellTrigger(int id);
|
||||
int AddProximityTrigger(WPos pos, WDist range, WDist vRange, Action<Actor> onEntry, Action<Actor> onExit);
|
||||
void RemoveProximityTrigger(int id);
|
||||
void UpdateProximityTrigger(int id, WPos newPos, WDist newRange, WDist newVRange);
|
||||
void AddPosition(Actor a, IOccupySpace ios);
|
||||
void RemovePosition(Actor a, IOccupySpace ios);
|
||||
void UpdatePosition(Actor a, IOccupySpace ios);
|
||||
IEnumerable<Actor> ActorsInBox(WPos a, WPos b);
|
||||
}
|
||||
|
||||
public interface IRenderModifier { IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r); }
|
||||
public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); }
|
||||
public interface ILoadsPlayerPalettes { void LoadPlayerPalettes(WorldRenderer wr, string playerName, HSLColor playerColor, bool replaceExisting); }
|
||||
|
||||
@@ -14,7 +14,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Orders;
|
||||
@@ -107,7 +106,7 @@ namespace OpenRA
|
||||
|
||||
public readonly Map Map;
|
||||
|
||||
public readonly ActorMap ActorMap;
|
||||
public readonly IActorMap ActorMap;
|
||||
public readonly ScreenMap ScreenMap;
|
||||
public readonly WorldType Type;
|
||||
|
||||
@@ -159,7 +158,7 @@ namespace OpenRA
|
||||
|
||||
var worldActorType = type == WorldType.Editor ? "EditorWorld" : "World";
|
||||
WorldActor = CreateActor(worldActorType, new TypeDictionary());
|
||||
ActorMap = WorldActor.Trait<ActorMap>();
|
||||
ActorMap = WorldActor.Trait<IActorMap>();
|
||||
ScreenMap = WorldActor.Trait<ScreenMap>();
|
||||
|
||||
// Add players
|
||||
|
||||
@@ -771,7 +771,7 @@ namespace OpenRA.Mods.Common.AI
|
||||
|
||||
var path = pathfinder.FindPath(
|
||||
PathSearch.Search(World, mobileInfo, harvester, true,
|
||||
loc => domainIndex.IsPassable(harvester.Location, loc, passable) && harvester.CanHarvestAt(loc, resLayer, harvInfo, territory))
|
||||
loc => domainIndex.IsPassable(harvester.Location, loc, mobileInfo, passable) && harvester.CanHarvestAt(loc, resLayer, harvInfo, territory))
|
||||
.WithCustomCost(loc => World.FindActorsInCircle(World.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius)
|
||||
.Where(u => !u.IsDead && harvester.Owner.Stances[u.Owner] == Stance.Enemy)
|
||||
.Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (World.Map.CenterOfCell(loc) - u.CenterPosition).Length)))
|
||||
|
||||
@@ -100,7 +100,9 @@ namespace OpenRA.Mods.Common.Activities
|
||||
minRange = armaments.Max(a => a.Weapon.MinRange);
|
||||
maxRange = armaments.Min(a => a.MaxRange());
|
||||
|
||||
if (!Target.IsInRange(self.CenterPosition, maxRange) || Target.IsInRange(self.CenterPosition, minRange))
|
||||
var mobile = move as Mobile;
|
||||
if (!Target.IsInRange(self.CenterPosition, maxRange) || Target.IsInRange(self.CenterPosition, minRange)
|
||||
|| (mobile != null && !mobile.CanInteractWithGroundLayer(self)))
|
||||
{
|
||||
// Try to move within range, drop the target otherwise
|
||||
if (move == null)
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
var passable = (uint)mobileInfo.GetMovementClass(self.World.Map.Rules.TileSet);
|
||||
List<CPos> path;
|
||||
using (var search = PathSearch.Search(self.World, mobileInfo, self, true,
|
||||
loc => domainIndex.IsPassable(self.Location, loc, passable) && self.CanHarvestAt(loc, resLayer, harvInfo, territory))
|
||||
loc => domainIndex.IsPassable(self.Location, loc, mobileInfo, passable) && self.CanHarvestAt(loc, resLayer, harvInfo, territory))
|
||||
.WithCustomCost(loc =>
|
||||
{
|
||||
if ((avoidCell.HasValue && loc == avoidCell.Value) ||
|
||||
|
||||
@@ -184,10 +184,15 @@ namespace OpenRA.Mods.Common.Activities
|
||||
else
|
||||
{
|
||||
mobile.SetLocation(mobile.FromCell, mobile.FromSubCell, nextCell.Value.First, nextCell.Value.Second);
|
||||
var from = self.World.Map.CenterOfSubCell(mobile.FromCell, mobile.FromSubCell);
|
||||
|
||||
var map = self.World.Map;
|
||||
var from = (mobile.FromCell.Layer == 0 ? map.CenterOfCell(mobile.FromCell) :
|
||||
self.World.GetCustomMovementLayers()[mobile.FromCell.Layer].CenterOfCell(mobile.FromCell)) +
|
||||
map.Grid.OffsetOfSubCell(mobile.FromSubCell);
|
||||
|
||||
var to = Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) +
|
||||
(self.World.Map.Grid.OffsetOfSubCell(mobile.FromSubCell) +
|
||||
self.World.Map.Grid.OffsetOfSubCell(mobile.ToSubCell)) / 2;
|
||||
(map.Grid.OffsetOfSubCell(mobile.FromSubCell) + map.Grid.OffsetOfSubCell(mobile.ToSubCell)) / 2;
|
||||
|
||||
var move = new MoveFirstHalf(
|
||||
this,
|
||||
from,
|
||||
@@ -292,6 +297,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
protected readonly Move Move;
|
||||
protected readonly WPos From, To;
|
||||
protected readonly int FromFacing, ToFacing;
|
||||
protected readonly bool EnableArc;
|
||||
protected readonly WPos ArcCenter;
|
||||
protected readonly int ArcFromLength;
|
||||
protected readonly WAngle ArcFromAngle;
|
||||
@@ -328,6 +334,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
ArcFromAngle = (ArcCenter - from).Yaw;
|
||||
ArcToLength = (ArcCenter - to).HorizontalLength;
|
||||
ArcToAngle = (ArcCenter - to).Yaw;
|
||||
EnableArc = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +380,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
if (MoveFractionTotal != 0)
|
||||
{
|
||||
WPos pos;
|
||||
if (FromFacing != ToFacing)
|
||||
if (EnableArc)
|
||||
{
|
||||
var angle = WAngle.Lerp(ArcFromAngle, ArcToAngle, moveFraction, MoveFractionTotal);
|
||||
var length = int2.Lerp(ArcFromLength, ArcToLength, moveFraction, MoveFractionTotal);
|
||||
@@ -415,21 +422,22 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent)
|
||||
{
|
||||
var fromSubcellOffset = self.World.Map.Grid.OffsetOfSubCell(mobile.FromSubCell);
|
||||
var toSubcellOffset = self.World.Map.Grid.OffsetOfSubCell(mobile.ToSubCell);
|
||||
var map = self.World.Map;
|
||||
var fromSubcellOffset = map.Grid.OffsetOfSubCell(mobile.FromSubCell);
|
||||
var toSubcellOffset = map.Grid.OffsetOfSubCell(mobile.ToSubCell);
|
||||
|
||||
var nextCell = parent.PopPath(self);
|
||||
if (nextCell != null)
|
||||
{
|
||||
if (IsTurn(mobile, nextCell.Value.First))
|
||||
{
|
||||
var nextSubcellOffset = self.World.Map.Grid.OffsetOfSubCell(nextCell.Value.Second);
|
||||
var nextSubcellOffset = map.Grid.OffsetOfSubCell(nextCell.Value.Second);
|
||||
var ret = new MoveFirstHalf(
|
||||
Move,
|
||||
Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) + (fromSubcellOffset + toSubcellOffset) / 2,
|
||||
Util.BetweenCells(self.World, mobile.ToCell, nextCell.Value.First) + (toSubcellOffset + nextSubcellOffset) / 2,
|
||||
mobile.Facing,
|
||||
Util.GetNearestFacing(mobile.Facing, self.World.Map.FacingBetween(mobile.ToCell, nextCell.Value.First, mobile.Facing)),
|
||||
Util.GetNearestFacing(mobile.Facing, map.FacingBetween(mobile.ToCell, nextCell.Value.First, mobile.Facing)),
|
||||
moveFraction - MoveFractionTotal);
|
||||
|
||||
mobile.FinishedMoving(self);
|
||||
@@ -440,10 +448,13 @@ namespace OpenRA.Mods.Common.Activities
|
||||
parent.path.Add(nextCell.Value.First);
|
||||
}
|
||||
|
||||
var toPos = mobile.ToCell.Layer == 0 ? map.CenterOfCell(mobile.ToCell) :
|
||||
self.World.GetCustomMovementLayers()[mobile.ToCell.Layer].CenterOfCell(mobile.ToCell);
|
||||
|
||||
var ret2 = new MoveSecondHalf(
|
||||
Move,
|
||||
Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) + (fromSubcellOffset + toSubcellOffset) / 2,
|
||||
self.World.Map.CenterOfCell(mobile.ToCell) + toSubcellOffset,
|
||||
toPos + toSubcellOffset,
|
||||
mobile.Facing,
|
||||
mobile.Facing,
|
||||
moveFraction - MoveFractionTotal);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
static readonly List<CPos> NoPath = new List<CPos>();
|
||||
|
||||
readonly Mobile mobile;
|
||||
protected readonly Mobile Mobile;
|
||||
readonly IPathFinder pathFinder;
|
||||
readonly DomainIndex domainIndex;
|
||||
readonly uint movementClass;
|
||||
@@ -53,10 +53,10 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
Target = target;
|
||||
|
||||
mobile = self.Trait<Mobile>();
|
||||
Mobile = self.Trait<Mobile>();
|
||||
pathFinder = self.World.WorldActor.Trait<IPathFinder>();
|
||||
domainIndex = self.World.WorldActor.Trait<DomainIndex>();
|
||||
movementClass = (uint)mobile.Info.GetMovementClass(self.World.Map.Rules.TileSet);
|
||||
movementClass = (uint)Mobile.Info.GetMovementClass(self.World.Map.Rules.TileSet);
|
||||
|
||||
if (target.IsValidFor(self))
|
||||
targetPosition = self.World.Map.CellContaining(target.CenterPosition);
|
||||
@@ -91,7 +91,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
inner.Cancel(self);
|
||||
|
||||
self.SetTargetLine(Target.FromCell(self.World, targetPosition), Color.Green);
|
||||
return ActivityUtils.RunActivity(self, new AttackMoveActivity(self, mobile.MoveTo(targetPosition, 0)));
|
||||
return ActivityUtils.RunActivity(self, new AttackMoveActivity(self, Mobile.MoveTo(targetPosition, 0)));
|
||||
}
|
||||
|
||||
// Inner move order has completed.
|
||||
@@ -103,7 +103,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return NextActivity;
|
||||
|
||||
// Target has moved, and MoveAdjacentTo is still valid.
|
||||
inner = mobile.MoveTo(() => CalculatePathToTarget(self));
|
||||
inner = Mobile.MoveTo(() => CalculatePathToTarget(self));
|
||||
repath = false;
|
||||
}
|
||||
|
||||
@@ -142,14 +142,14 @@ namespace OpenRA.Mods.Common.Activities
|
||||
var loc = self.Location;
|
||||
|
||||
foreach (var cell in targetCells)
|
||||
if (domainIndex.IsPassable(loc, cell, movementClass) && mobile.CanEnterCell(cell))
|
||||
if (domainIndex.IsPassable(loc, cell, Mobile.Info, movementClass) && Mobile.CanEnterCell(cell))
|
||||
searchCells.Add(cell);
|
||||
|
||||
if (!searchCells.Any())
|
||||
return NoPath;
|
||||
|
||||
using (var fromSrc = PathSearch.FromPoints(self.World, mobile.Info, self, searchCells, loc, true))
|
||||
using (var fromDest = PathSearch.FromPoint(self.World, mobile.Info, self, loc, targetPosition, true).Reverse())
|
||||
using (var fromSrc = PathSearch.FromPoints(self.World, Mobile.Info, self, searchCells, loc, true))
|
||||
using (var fromDest = PathSearch.FromPoint(self.World, Mobile.Info, self, loc, targetPosition, true).Reverse())
|
||||
return pathFinder.FindBidiPath(fromSrc, fromDest);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Activities
|
||||
@@ -31,12 +32,13 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
// We are now in range. Don't move any further!
|
||||
// HACK: This works around the pathfinder not returning the shortest path
|
||||
return AtCorrectRange(self.CenterPosition);
|
||||
return AtCorrectRange(self.CenterPosition) && Mobile.CanInteractWithGroundLayer(self);
|
||||
}
|
||||
|
||||
protected override bool ShouldRepath(Actor self, CPos oldTargetPosition)
|
||||
{
|
||||
return targetPosition != oldTargetPosition && !AtCorrectRange(self.CenterPosition);
|
||||
return targetPosition != oldTargetPosition && (!AtCorrectRange(self.CenterPosition)
|
||||
|| !Mobile.CanInteractWithGroundLayer(self));
|
||||
}
|
||||
|
||||
protected override IEnumerable<CPos> CandidateMovementCells(Actor self)
|
||||
|
||||
@@ -30,8 +30,9 @@ namespace OpenRA.Mods.Common.Lint
|
||||
|
||||
var deathAnimationDeathtypes = animations.SelectMany(x => x.DeathTypes.Select(y => y.Key)).ToList();
|
||||
var spawnActorDeathtypes = actorInfo.Value.TraitInfos<SpawnActorOnDeathInfo>().Where(s => !string.IsNullOrEmpty(s.DeathType)).Select(a => a.DeathType);
|
||||
var spawnActorOnAnyDeathType = actorInfo.Value.TraitInfos<SpawnActorOnDeathInfo>().Any(s => s.DeathType == null);
|
||||
var deathTypes = deathAnimationDeathtypes.Concat(spawnActorDeathtypes).Distinct();
|
||||
if (!deathTypes.Any())
|
||||
if (!deathTypes.Any() || spawnActorOnAnyDeathType)
|
||||
continue;
|
||||
|
||||
var targetable = actorInfo.Value.TraitInfos<ITargetableInfo>().SelectMany(x => x.GetTargetTypes()).ToList();
|
||||
|
||||
@@ -793,6 +793,13 @@
|
||||
<Compile Include="UtilityCommands\OutputResolvedWeaponsCommand.cs" />
|
||||
<Compile Include="Traits\RevealOnFire.cs" />
|
||||
<Compile Include="Traits\Conditions\GrantConditionOnDisabled.cs" />
|
||||
<Compile Include="Traits\World\ActorMap.cs" />
|
||||
<Compile Include="Traits\World\TerrainTunnelLayer.cs" />
|
||||
<Compile Include="Traits\World\TerrainTunnel.cs" />
|
||||
<Compile Include="Traits\World\SubterraneanActorLayer.cs" />
|
||||
<Compile Include="Traits\World\JumpjetActorLayer.cs" />
|
||||
<Compile Include="Traits\World\ElevatedBridgeLayer.cs" />
|
||||
<Compile Include="Traits\World\ElevatedBridgePlaceholder.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="AfterBuild">
|
||||
|
||||
@@ -57,21 +57,28 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
|
||||
public class PooledCellInfoLayer : IDisposable
|
||||
{
|
||||
public CellLayer<CellInfo> Layer { get; private set; }
|
||||
CellInfoLayerPool layerPool;
|
||||
List<CellLayer<CellInfo>> layers = new List<CellLayer<CellInfo>>();
|
||||
|
||||
public PooledCellInfoLayer(CellInfoLayerPool layerPool)
|
||||
{
|
||||
this.layerPool = layerPool;
|
||||
Layer = layerPool.GetLayer();
|
||||
}
|
||||
|
||||
public CellLayer<CellInfo> GetLayer()
|
||||
{
|
||||
var layer = layerPool.GetLayer();
|
||||
layers.Add(layer);
|
||||
return layer;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Layer == null)
|
||||
return;
|
||||
layerPool.ReturnLayer(Layer);
|
||||
Layer = null;
|
||||
if (layerPool != null)
|
||||
foreach (var layer in layers)
|
||||
layerPool.ReturnLayer(layer);
|
||||
|
||||
layers = null;
|
||||
layerPool = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Pathfinder
|
||||
{
|
||||
@@ -84,18 +87,29 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
readonly MobileInfo mobileInfo;
|
||||
readonly MobileInfo.WorldMovementInfo worldMovementInfo;
|
||||
readonly CellInfoLayerPool.PooledCellInfoLayer pooledLayer;
|
||||
CellLayer<CellInfo> cellInfo;
|
||||
readonly bool checkTerrainHeight;
|
||||
CellLayer<CellInfo> groundInfo;
|
||||
|
||||
readonly Dictionary<byte, Pair<ICustomMovementLayer, CellLayer<CellInfo>>> customLayerInfo =
|
||||
new Dictionary<byte, Pair<ICustomMovementLayer, CellLayer<CellInfo>>>();
|
||||
|
||||
public PathGraph(CellInfoLayerPool layerPool, MobileInfo mobileInfo, Actor actor, World world, bool checkForBlocked)
|
||||
{
|
||||
pooledLayer = layerPool.Get();
|
||||
cellInfo = pooledLayer.Layer;
|
||||
groundInfo = pooledLayer.GetLayer();
|
||||
var layers = world.GetCustomMovementLayers().Values
|
||||
.Where(cml => cml.EnabledForActor(actor.Info, mobileInfo));
|
||||
|
||||
foreach (var cml in layers)
|
||||
customLayerInfo[cml.Index] = Pair.New(cml, pooledLayer.GetLayer());
|
||||
|
||||
World = world;
|
||||
this.mobileInfo = mobileInfo;
|
||||
worldMovementInfo = mobileInfo.GetWorldMovementInfo(world);
|
||||
Actor = actor;
|
||||
LaneBias = 1;
|
||||
checkConditions = checkForBlocked ? CellConditions.TransientActors : CellConditions.None;
|
||||
checkTerrainHeight = world.Map.Grid.MaximumTerrainHeight > 0;
|
||||
}
|
||||
|
||||
// Sets of neighbors for each incoming direction. These exclude the neighbors which are guaranteed
|
||||
@@ -117,7 +131,8 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
|
||||
public List<GraphConnection> GetConnections(CPos position)
|
||||
{
|
||||
var previousPos = cellInfo[position].PreviousPos;
|
||||
var info = position.Layer == 0 ? groundInfo : customLayerInfo[position.Layer].Second;
|
||||
var previousPos = info[position].PreviousPos;
|
||||
|
||||
var dx = position.X - previousPos.X;
|
||||
var dy = position.Y - previousPos.Y;
|
||||
@@ -133,6 +148,24 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
validNeighbors.Add(new GraphConnection(neighbor, movementCost));
|
||||
}
|
||||
|
||||
if (position.Layer == 0)
|
||||
{
|
||||
foreach (var cli in customLayerInfo.Values)
|
||||
{
|
||||
var layerPosition = new CPos(position.X, position.Y, cli.First.Index);
|
||||
var entryCost = cli.First.EntryMovementCost(Actor.Info, mobileInfo, layerPosition);
|
||||
if (entryCost != Constants.InvalidNode)
|
||||
validNeighbors.Add(new GraphConnection(layerPosition, entryCost));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var layerPosition = new CPos(position.X, position.Y, 0);
|
||||
var exitCost = customLayerInfo[position.Layer].First.ExitMovementCost(Actor.Info, mobileInfo, layerPosition);
|
||||
if (exitCost != Constants.InvalidNode)
|
||||
validNeighbors.Add(new GraphConnection(layerPosition, exitCost));
|
||||
}
|
||||
|
||||
return validNeighbors;
|
||||
}
|
||||
|
||||
@@ -161,7 +194,15 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
cellCost += customCost;
|
||||
}
|
||||
|
||||
// directional bonuses for smoother flow!
|
||||
// Prevent units from jumping over height discontinuities
|
||||
if (checkTerrainHeight && neighborCPos.Layer == 0)
|
||||
{
|
||||
var from = neighborCPos - direction;
|
||||
if (Math.Abs(World.Map.Height[neighborCPos] - World.Map.Height[from]) > 1)
|
||||
return Constants.InvalidNode;
|
||||
}
|
||||
|
||||
// Directional bonuses for smoother flow!
|
||||
if (LaneBias != 0)
|
||||
{
|
||||
var ux = neighborCPos.X + (InReverse ? 1 : 0) & 1;
|
||||
@@ -179,14 +220,15 @@ namespace OpenRA.Mods.Common.Pathfinder
|
||||
|
||||
public CellInfo this[CPos pos]
|
||||
{
|
||||
get { return cellInfo[pos]; }
|
||||
set { cellInfo[pos] = value; }
|
||||
get { return (pos.Layer == 0 ? groundInfo : customLayerInfo[pos.Layer].Second)[pos]; }
|
||||
set { (pos.Layer == 0 ? groundInfo : customLayerInfo[pos.Layer].Second)[pos] = value; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
groundInfo = null;
|
||||
customLayerInfo.Clear();
|
||||
pooledLayer.Dispose();
|
||||
cellInfo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Activities;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Effects;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -38,6 +39,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomMovementLayerType
|
||||
{
|
||||
public const byte Tunnel = 1;
|
||||
public const byte Subterranean = 2;
|
||||
public const byte Jumpjet = 3;
|
||||
public const byte ElevatedBridge = 4;
|
||||
}
|
||||
|
||||
[Desc("Unit is able to move.")]
|
||||
public class MobileInfo : ConditionalTraitInfo, IMoveInfo, IPositionableInfo, IOccupySpaceInfo, IFacingInfo,
|
||||
UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>
|
||||
@@ -73,6 +82,57 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
[VoiceReference] public readonly string Voice = "Action";
|
||||
|
||||
[GrantedConditionReference]
|
||||
[Desc("The condition to grant to self while inside a tunnel.")]
|
||||
public readonly string TunnelCondition = null;
|
||||
|
||||
[Desc("Can this unit move underground?")]
|
||||
public readonly bool Subterranean = false;
|
||||
|
||||
[GrantedConditionReference]
|
||||
[Desc("The condition to grant to self while underground.")]
|
||||
public readonly string SubterraneanCondition = null;
|
||||
|
||||
[Desc("Pathfinding cost for submerging or reemerging.")]
|
||||
public readonly int SubterraneanTransitionCost = 0;
|
||||
|
||||
[Desc("The terrain types that this actor can transition on. Leave empty to allow any.")]
|
||||
public readonly HashSet<string> SubterraneanTransitionTerrainTypes = new HashSet<string>();
|
||||
|
||||
[Desc("Can this actor transition on slopes?")]
|
||||
public readonly bool SubterraneanTransitionOnRamps = false;
|
||||
|
||||
[Desc("Depth at which the subterranian condition is applied.")]
|
||||
public readonly WDist SubterraneanTransitionDepth = new WDist(-1024);
|
||||
|
||||
[Desc("Dig animation image to play when transitioning.")]
|
||||
public readonly string SubterraneanTransitionImage = null;
|
||||
|
||||
[SequenceReference("SubterraneanTransitionImage")]
|
||||
[Desc("Dig animation image to play when transitioning.")]
|
||||
public readonly string SubterraneanTransitionSequence = null;
|
||||
|
||||
[PaletteReference]
|
||||
public readonly string SubterraneanTransitionPalette = "effect";
|
||||
|
||||
public readonly string SubterraneanTransitionSound = null;
|
||||
|
||||
[Desc("Can this unit fly over obsticals?")]
|
||||
public readonly bool Jumpjet = false;
|
||||
|
||||
[GrantedConditionReference]
|
||||
[Desc("The condition to grant to self while flying.")]
|
||||
public readonly string JumpjetCondition = null;
|
||||
|
||||
[Desc("Pathfinding cost for taking off or landing.")]
|
||||
public readonly int JumpjetTransitionCost = 0;
|
||||
|
||||
[Desc("The terrain types that this actor can transition on. Leave empty to allow any.")]
|
||||
public readonly HashSet<string> JumpjetTransitionTerrainTypes = new HashSet<string>();
|
||||
|
||||
[Desc("Can this actor transition on slopes?")]
|
||||
public readonly bool JumpjetTransitionOnRamps = true;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new Mobile(init, this); }
|
||||
|
||||
static object LoadSpeeds(MiniYaml y)
|
||||
@@ -151,15 +211,17 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public int MovementCostForCell(World world, CPos cell)
|
||||
{
|
||||
return MovementCostForCell(world.Map, TilesetTerrainInfo[world.Map.Rules.TileSet], cell);
|
||||
return MovementCostForCell(world, TilesetTerrainInfo[world.Map.Rules.TileSet], cell);
|
||||
}
|
||||
|
||||
int MovementCostForCell(Map map, TerrainInfo[] terrainInfos, CPos cell)
|
||||
int MovementCostForCell(World world, TerrainInfo[] terrainInfos, CPos cell)
|
||||
{
|
||||
if (!map.Contains(cell))
|
||||
if (!world.Map.Contains(cell))
|
||||
return int.MaxValue;
|
||||
|
||||
var index = map.GetTerrainIndex(cell);
|
||||
var index = cell.Layer == 0 ? world.Map.GetTerrainIndex(cell) :
|
||||
world.GetCustomMovementLayers()[cell.Layer].GetTerrainIndex(cell);
|
||||
|
||||
if (index == byte.MaxValue)
|
||||
return int.MaxValue;
|
||||
|
||||
@@ -279,7 +341,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public int MovementCostToEnterCell(WorldMovementInfo worldMovementInfo, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All)
|
||||
{
|
||||
var cost = MovementCostForCell(worldMovementInfo.World.Map, worldMovementInfo.TerrainInfos, cell);
|
||||
var cost = MovementCostForCell(worldMovementInfo.World, worldMovementInfo.TerrainInfos, cell);
|
||||
if (cost == int.MaxValue || !CanMoveFreelyInto(worldMovementInfo.World, self, cell, ignoreActor, check))
|
||||
return int.MaxValue;
|
||||
return cost;
|
||||
@@ -317,8 +379,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
bool IOccupySpaceInfo.SharesCell { get { return SharesCell; } }
|
||||
}
|
||||
|
||||
public class Mobile : ConditionalTrait<MobileInfo>, IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove, IFacing, ISync,
|
||||
IDeathActorInitModifier, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyBlockingMove, IActorPreviewInitModifier
|
||||
public class Mobile : ConditionalTrait<MobileInfo>, INotifyCreated, IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove,
|
||||
IFacing, ISync, IDeathActorInitModifier, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyBlockingMove, IActorPreviewInitModifier
|
||||
{
|
||||
const int AverageTicksBeforePathing = 5;
|
||||
const int SpreadTicksBeforePathing = 5;
|
||||
@@ -332,6 +394,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
int facing;
|
||||
CPos fromCell, toCell;
|
||||
public SubCell FromSubCell, ToSubCell;
|
||||
int tunnelToken = ConditionManager.InvalidConditionToken;
|
||||
int subterraneanToken = ConditionManager.InvalidConditionToken;
|
||||
int jumpjetToken = ConditionManager.InvalidConditionToken;
|
||||
ConditionManager conditionManager;
|
||||
|
||||
[Sync] public int Facing
|
||||
{
|
||||
@@ -359,6 +425,30 @@ namespace OpenRA.Mods.Common.Traits
|
||||
FromSubCell = fromSub;
|
||||
ToSubCell = toSub;
|
||||
AddInfluence();
|
||||
|
||||
// Tunnel condition is added/removed when starting the transition between layers
|
||||
if (toCell.Layer == CustomMovementLayerType.Tunnel && conditionManager != null &&
|
||||
!string.IsNullOrEmpty(Info.TunnelCondition) && tunnelToken == ConditionManager.InvalidConditionToken)
|
||||
tunnelToken = conditionManager.GrantCondition(self, Info.TunnelCondition);
|
||||
else if (toCell.Layer != CustomMovementLayerType.Tunnel && tunnelToken != ConditionManager.InvalidConditionToken)
|
||||
tunnelToken = conditionManager.RevokeCondition(self, tunnelToken);
|
||||
|
||||
// Play submerging animation as soon as it starts to submerge (before applying the condition)
|
||||
if (toCell.Layer == CustomMovementLayerType.Subterranean && fromCell.Layer != CustomMovementLayerType.Subterranean)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Info.SubterraneanTransitionSequence))
|
||||
self.World.AddFrameEndTask(w => w.Add(new SpriteEffect(self.World.Map.CenterOfCell(fromCell), self.World, Info.SubterraneanTransitionImage,
|
||||
Info.SubterraneanTransitionSequence, Info.SubterraneanTransitionPalette)));
|
||||
|
||||
if (!string.IsNullOrEmpty(Info.SubterraneanTransitionSound))
|
||||
Game.Sound.Play(SoundType.World, Info.SubterraneanTransitionSound);
|
||||
}
|
||||
|
||||
// Grant the jumpjet condition as soon as the actor starts leaving the ground layer
|
||||
// The condition is revoked from FinishedMoving
|
||||
if (toCell.Layer == CustomMovementLayerType.Jumpjet && conditionManager != null &&
|
||||
!string.IsNullOrEmpty(Info.JumpjetCondition) && jumpjetToken == ConditionManager.InvalidConditionToken)
|
||||
jumpjetToken = conditionManager.GrantCondition(self, Info.JumpjetCondition);
|
||||
}
|
||||
|
||||
public Mobile(ActorInitializer init, MobileInfo info)
|
||||
@@ -386,6 +476,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
SetVisualPosition(self, init.Get<CenterPositionInit, WPos>());
|
||||
}
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
conditionManager = self.TraitOrDefault<ConditionManager>();
|
||||
}
|
||||
|
||||
// Returns a valid sub-cell
|
||||
public SubCell GetValidSubCell(SubCell preferred = SubCell.Any)
|
||||
{
|
||||
@@ -413,7 +508,12 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
subCell = GetValidSubCell(subCell);
|
||||
SetLocation(cell, subCell, cell, subCell);
|
||||
SetVisualPosition(self, self.World.Map.CenterOfSubCell(cell, subCell));
|
||||
|
||||
var position = cell.Layer == 0 ? self.World.Map.CenterOfCell(cell) :
|
||||
self.World.GetCustomMovementLayers()[cell.Layer].CenterOfCell(cell);
|
||||
|
||||
var subcellOffset = self.World.Map.Grid.OffsetOfSubCell(subCell);
|
||||
SetVisualPosition(self, position + subcellOffset);
|
||||
FinishedMoving(self);
|
||||
}
|
||||
|
||||
@@ -431,6 +531,32 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
CenterPosition = pos;
|
||||
self.World.UpdateMaps(self, this);
|
||||
|
||||
// HACK: The submerging conditions must be applied part way through a move, and this is the only method that gets called
|
||||
// at the right times to detect this
|
||||
if (toCell.Layer == CustomMovementLayerType.Subterranean)
|
||||
{
|
||||
var depth = self.World.Map.DistanceAboveTerrain(self.CenterPosition);
|
||||
if (subterraneanToken == ConditionManager.InvalidConditionToken && depth < Info.SubterraneanTransitionDepth && conditionManager != null
|
||||
&& !string.IsNullOrEmpty(Info.SubterraneanCondition))
|
||||
subterraneanToken = conditionManager.GrantCondition(self, Info.SubterraneanCondition);
|
||||
}
|
||||
else if (subterraneanToken != ConditionManager.InvalidConditionToken)
|
||||
{
|
||||
var depth = self.World.Map.DistanceAboveTerrain(self.CenterPosition);
|
||||
if (depth > Info.SubterraneanTransitionDepth)
|
||||
{
|
||||
subterraneanToken = conditionManager.RevokeCondition(self, subterraneanToken);
|
||||
|
||||
// HACK: the submerging animation and sound won't play if a condition isn't defined
|
||||
if (!string.IsNullOrEmpty(Info.SubterraneanTransitionSound))
|
||||
Game.Sound.Play(SoundType.World, Info.SubterraneanTransitionSound);
|
||||
|
||||
if (!string.IsNullOrEmpty(Info.SubterraneanTransitionSequence))
|
||||
self.World.AddFrameEndTask(w => w.Add(new SpriteEffect(self.World.Map.CenterOfCell(fromCell), self.World, Info.SubterraneanTransitionImage,
|
||||
Info.SubterraneanTransitionSequence, Info.SubterraneanTransitionPalette)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddedToWorld(Actor self)
|
||||
@@ -598,6 +724,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void FinishedMoving(Actor self)
|
||||
{
|
||||
// Need to check both fromCell and toCell because FinishedMoving is called multiple times during the move
|
||||
// and that condition guarantees that this only runs when the unit has finished landing.
|
||||
if (fromCell.Layer != CustomMovementLayerType.Jumpjet && toCell.Layer != CustomMovementLayerType.Jumpjet && jumpjetToken != ConditionManager.InvalidConditionToken)
|
||||
jumpjetToken = conditionManager.RevokeCondition(self, jumpjetToken);
|
||||
|
||||
// Only make actor crush if it is on the ground
|
||||
if (!self.IsAtGroundLevel())
|
||||
return;
|
||||
@@ -626,7 +757,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public int MovementSpeedForCell(Actor self, CPos cell)
|
||||
{
|
||||
var index = self.World.Map.GetTerrainIndex(cell);
|
||||
var index = cell.Layer == 0 ? self.World.Map.GetTerrainIndex(cell) :
|
||||
self.World.GetCustomMovementLayers()[cell.Layer].GetTerrainIndex(cell);
|
||||
|
||||
if (index == byte.MaxValue)
|
||||
return 0;
|
||||
|
||||
@@ -716,6 +849,21 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanInteractWithGroundLayer(Actor self)
|
||||
{
|
||||
// TODO: Think about extending this to support arbitrary layer-layer checks
|
||||
// in a way that is compatible with the other IMove types.
|
||||
// This would then allow us to e.g. have units attack other units inside tunnels.
|
||||
if (ToCell.Layer == 0)
|
||||
return true;
|
||||
|
||||
ICustomMovementLayer layer;
|
||||
if (self.World.GetCustomMovementLayers().TryGetValue(ToCell.Layer, out layer))
|
||||
return layer.InteractsWithDefaultLayer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits)
|
||||
{
|
||||
if (!inits.Contains<DynamicFacingInit>() && !inits.Contains<FacingInit>())
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
if (mobileInfo != null)
|
||||
location = self.World.Map.ChooseClosestMatchingEdgeCell(self.Location,
|
||||
c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destination, passable));
|
||||
c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destination, mobileInfo, passable));
|
||||
}
|
||||
|
||||
// No suitable spawn location could be found, so production has failed.
|
||||
|
||||
@@ -18,7 +18,7 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.Common.Traits.Render
|
||||
{
|
||||
[Desc("This actor has a death animation.")]
|
||||
public class WithDeathAnimationInfo : ITraitInfo, Requires<RenderSpritesInfo>
|
||||
public class WithDeathAnimationInfo : ConditionalTraitInfo, Requires<RenderSpritesInfo>
|
||||
{
|
||||
[Desc("Sequence prefix to play when this actor is killed by a warhead.")]
|
||||
[SequenceReference(null, true)] public readonly string DeathSequence = "die";
|
||||
@@ -58,25 +58,24 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
: new Dictionary<string, string[]>();
|
||||
}
|
||||
|
||||
public object Create(ActorInitializer init) { return new WithDeathAnimation(init.Self, this); }
|
||||
public override object Create(ActorInitializer init) { return new WithDeathAnimation(init.Self, this); }
|
||||
}
|
||||
|
||||
public class WithDeathAnimation : INotifyKilled, INotifyCrushed
|
||||
public class WithDeathAnimation : ConditionalTrait<WithDeathAnimationInfo>, INotifyKilled, INotifyCrushed
|
||||
{
|
||||
public readonly WithDeathAnimationInfo Info;
|
||||
readonly RenderSprites rs;
|
||||
bool crushed;
|
||||
|
||||
public WithDeathAnimation(Actor self, WithDeathAnimationInfo info)
|
||||
: base(info)
|
||||
{
|
||||
Info = info;
|
||||
rs = self.Trait<RenderSprites>();
|
||||
}
|
||||
|
||||
public void Killed(Actor self, AttackInfo e)
|
||||
{
|
||||
// Actors with Crushable trait will spawn CrushedSequence.
|
||||
if (crushed)
|
||||
if (crushed || IsTraitDisabled)
|
||||
return;
|
||||
|
||||
var palette = Info.DeathSequencePalette;
|
||||
|
||||
@@ -16,7 +16,7 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.Common.Traits.Sound
|
||||
{
|
||||
[Desc("Sounds to play when killed.")]
|
||||
public class DeathSoundsInfo : ITraitInfo
|
||||
public class DeathSoundsInfo : ConditionalTraitInfo
|
||||
{
|
||||
[Desc("Death notification voice.")]
|
||||
[VoiceReference] public readonly string Voice = "Die";
|
||||
@@ -28,19 +28,21 @@ namespace OpenRA.Mods.Common.Traits.Sound
|
||||
"If empty, this will be used as the default sound for all death types.")]
|
||||
public readonly HashSet<string> DeathTypes = new HashSet<string>();
|
||||
|
||||
public object Create(ActorInitializer init) { return new DeathSounds(this); }
|
||||
public override object Create(ActorInitializer init) { return new DeathSounds(this); }
|
||||
}
|
||||
|
||||
public class DeathSounds : INotifyKilled
|
||||
public class DeathSounds : ConditionalTrait<DeathSoundsInfo>, INotifyKilled
|
||||
{
|
||||
readonly DeathSoundsInfo info;
|
||||
|
||||
public DeathSounds(DeathSoundsInfo info) { this.info = info; }
|
||||
public DeathSounds(DeathSoundsInfo info)
|
||||
: base(info) { }
|
||||
|
||||
public void Killed(Actor self, AttackInfo e)
|
||||
{
|
||||
if (info.DeathTypes.Count == 0 || e.Damage.DamageTypes.Overlaps(info.DeathTypes))
|
||||
self.PlayVoiceLocal(info.Voice, info.VolumeMultiplier);
|
||||
if (IsTraitDisabled)
|
||||
return;
|
||||
|
||||
if (Info.DeathTypes.Count == 0 || e.Damage.DamageTypes.Overlaps(Info.DeathTypes))
|
||||
self.PlayVoiceLocal(Info.Voice, Info.VolumeMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,10 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public enum SubCell { Invalid = int.MinValue, Any = int.MinValue / 2, FullCell = 0, First = 1 }
|
||||
|
||||
public class ActorMapInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Size of partition bins (cells)")]
|
||||
@@ -27,7 +26,7 @@ namespace OpenRA.Traits
|
||||
public object Create(ActorInitializer init) { return new ActorMap(init.World, this); }
|
||||
}
|
||||
|
||||
public class ActorMap : ITick
|
||||
public class ActorMap : IActorMap, ITick, INotifyCreated
|
||||
{
|
||||
class InfluenceNode
|
||||
{
|
||||
@@ -166,6 +165,8 @@ namespace OpenRA.Traits
|
||||
int nextTriggerId;
|
||||
|
||||
readonly CellLayer<InfluenceNode> influence;
|
||||
readonly Dictionary<int, CellLayer<InfluenceNode>> customInfluence = new Dictionary<int, CellLayer<InfluenceNode>>();
|
||||
public readonly Dictionary<int, ICustomMovementLayer> CustomMovementLayers = new Dictionary<int, ICustomMovementLayer>();
|
||||
|
||||
readonly Bin[] bins;
|
||||
readonly int rows, cols;
|
||||
@@ -193,6 +194,15 @@ namespace OpenRA.Traits
|
||||
actorShouldBeRemoved = removeActorPosition.Contains;
|
||||
}
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
foreach (var cml in self.TraitsImplementing<ICustomMovementLayer>())
|
||||
{
|
||||
CustomMovementLayers[cml.Index] = cml;
|
||||
customInfluence.Add(cml.Index, new CellLayer<InfluenceNode>(self.World.Map));
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ActorsAtEnumerator : IEnumerator<Actor>
|
||||
{
|
||||
InfluenceNode node;
|
||||
@@ -229,7 +239,9 @@ namespace OpenRA.Traits
|
||||
var uv = a.ToMPos(map);
|
||||
if (!influence.Contains(uv))
|
||||
return Enumerable.Empty<Actor>();
|
||||
return new ActorsAtEnumerable(influence[uv]);
|
||||
|
||||
var layer = a.Layer == 0 ? influence : customInfluence[a.Layer];
|
||||
return new ActorsAtEnumerable(layer[uv]);
|
||||
}
|
||||
|
||||
public IEnumerable<Actor> GetActorsAt(CPos a, SubCell sub)
|
||||
@@ -238,7 +250,8 @@ namespace OpenRA.Traits
|
||||
if (!influence.Contains(uv))
|
||||
yield break;
|
||||
|
||||
for (var i = influence[uv]; i != null; i = i.Next)
|
||||
var layer = a.Layer == 0 ? influence : customInfluence[a.Layer];
|
||||
for (var i = layer[uv]; i != null; i = i.Next)
|
||||
if (!i.Actor.Disposed && (i.SubCell == sub || i.SubCell == SubCell.FullCell))
|
||||
yield return i.Actor;
|
||||
}
|
||||
@@ -284,7 +297,8 @@ namespace OpenRA.Traits
|
||||
if (!influence.Contains(uv))
|
||||
return false;
|
||||
|
||||
return influence[uv] != null;
|
||||
var layer = a.Layer == 0 ? influence : customInfluence[a.Layer];
|
||||
return layer[uv] != null;
|
||||
}
|
||||
|
||||
// NOTE: can not check aircraft
|
||||
@@ -295,7 +309,8 @@ namespace OpenRA.Traits
|
||||
return false;
|
||||
|
||||
var always = sub == SubCell.FullCell || sub == SubCell.Any;
|
||||
for (var i = influence[uv]; i != null; i = i.Next)
|
||||
var layer = a.Layer == 0 ? influence : customInfluence[a.Layer];
|
||||
for (var i = layer[uv]; i != null; i = i.Next)
|
||||
{
|
||||
if (always || i.SubCell == sub || i.SubCell == SubCell.FullCell)
|
||||
{
|
||||
@@ -319,7 +334,8 @@ namespace OpenRA.Traits
|
||||
return false;
|
||||
|
||||
var always = sub == SubCell.FullCell || sub == SubCell.Any;
|
||||
for (var i = influence[uv]; i != null; i = i.Next)
|
||||
var layer = a.Layer == 0 ? influence : customInfluence[a.Layer];
|
||||
for (var i = layer[uv]; i != null; i = i.Next)
|
||||
if ((always || i.SubCell == sub || i.SubCell == SubCell.FullCell) && !i.Actor.Disposed && withCondition(i.Actor))
|
||||
return true;
|
||||
|
||||
@@ -334,7 +350,8 @@ namespace OpenRA.Traits
|
||||
if (!influence.Contains(uv))
|
||||
continue;
|
||||
|
||||
influence[uv] = new InfluenceNode { Next = influence[uv], SubCell = c.Second, Actor = self };
|
||||
var layer = c.First.Layer == 0 ? influence : customInfluence[c.First.Layer];
|
||||
layer[uv] = new InfluenceNode { Next = layer[uv], SubCell = c.Second, Actor = self };
|
||||
|
||||
List<CellTrigger> triggers;
|
||||
if (cellTriggerInfluence.TryGetValue(c.First, out triggers))
|
||||
@@ -351,9 +368,10 @@ namespace OpenRA.Traits
|
||||
if (!influence.Contains(uv))
|
||||
continue;
|
||||
|
||||
var temp = influence[uv];
|
||||
var layer = c.First.Layer == 0 ? influence : customInfluence[c.First.Layer];
|
||||
var temp = layer[uv];
|
||||
RemoveInfluenceInner(ref temp, self);
|
||||
influence[uv] = temp;
|
||||
layer[uv] = temp;
|
||||
|
||||
List<CellTrigger> triggers;
|
||||
if (cellTriggerInfluence.TryGetValue(c.First, out triggers))
|
||||
@@ -568,4 +586,12 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ActorMapWorldExts
|
||||
{
|
||||
public static Dictionary<int, ICustomMovementLayer> GetCustomMovementLayers(this World world)
|
||||
{
|
||||
return ((ActorMap)world.ActorMap).CustomMovementLayers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
@@ -21,14 +22,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public readonly string TerrainType = "Impassable";
|
||||
|
||||
public object Create(ActorInitializer init) { return new CliffBackBlockingLayer(this); }
|
||||
public object Create(ActorInitializer init) { return new CliffBackImpassabilityLayer(this); }
|
||||
}
|
||||
|
||||
class CliffBackBlockingLayer : IWorldLoaded
|
||||
class CliffBackImpassabilityLayer : IWorldLoaded
|
||||
{
|
||||
readonly CliffBackImpassabilityLayerInfo info;
|
||||
|
||||
public CliffBackBlockingLayer(CliffBackImpassabilityLayerInfo info)
|
||||
public CliffBackImpassabilityLayer(CliffBackImpassabilityLayerInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
@@ -36,8 +37,17 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public void WorldLoaded(World w, WorldRenderer wr)
|
||||
{
|
||||
var tileType = w.Map.Rules.TileSet.GetTerrainIndex(info.TerrainType);
|
||||
|
||||
// Units are allowed behind cliffs *only* if they are part of a tunnel portal
|
||||
var tunnelPortals = w.WorldActor.Info.TraitInfos<TerrainTunnelInfo>()
|
||||
.SelectMany(mti => mti.PortalCells())
|
||||
.ToHashSet();
|
||||
|
||||
foreach (var uv in w.Map.AllCells.MapCoords)
|
||||
{
|
||||
if (tunnelPortals.Contains(uv.ToCPos(w.Map)))
|
||||
continue;
|
||||
|
||||
// All the map cells that visually overlap the current cell
|
||||
var testCells = w.Map.ProjectedCellsCovering(uv)
|
||||
.SelectMany(puv => w.Map.Unproject(puv));
|
||||
|
||||
@@ -37,8 +37,17 @@ namespace OpenRA.Mods.Common.Traits
|
||||
domainIndexes[mc] = new MovementClassDomainIndex(world, mc);
|
||||
}
|
||||
|
||||
public bool IsPassable(CPos p1, CPos p2, uint movementClass)
|
||||
public bool IsPassable(CPos p1, CPos p2, MobileInfo mi, uint movementClass)
|
||||
{
|
||||
// HACK: Work around units in other movement layers from being blocked
|
||||
// when the point in the main layer is not pathable
|
||||
if (p1.Layer != 0 || p2.Layer != 0)
|
||||
return true;
|
||||
|
||||
// HACK: Workaround until we can generalize movement classes
|
||||
if (mi.Subterranean || mi.Jumpjet)
|
||||
return true;
|
||||
|
||||
return domainIndexes[movementClass].IsPassable(p1, p2);
|
||||
}
|
||||
|
||||
@@ -49,6 +58,12 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var index in domainIndexes)
|
||||
index.Value.UpdateCells(world, dirty);
|
||||
}
|
||||
|
||||
public void AddFixedConnection(IEnumerable<CPos> cells)
|
||||
{
|
||||
foreach (var index in domainIndexes)
|
||||
index.Value.AddFixedConnection(cells);
|
||||
}
|
||||
}
|
||||
|
||||
class MovementClassDomainIndex
|
||||
@@ -119,6 +134,19 @@ namespace OpenRA.Mods.Common.Traits
|
||||
CreateConnection(c1, c2);
|
||||
}
|
||||
|
||||
public void AddFixedConnection(IEnumerable<CPos> cells)
|
||||
{
|
||||
// HACK: this is a temporary workaround to add a permanent connection between the domains of the listed cells.
|
||||
// This is sufficient for fixed point-to-point tunnels, but not for dynamically updating custom layers
|
||||
// such as destroyable elevated bridges.
|
||||
// To support those the domain index will need to learn about custom movement layers, but that then requires
|
||||
// a complete refactor of the domain code to deal with MobileInfo or better a shared pathfinder class type.
|
||||
var cellDomains = cells.Select(c => domains[c]).ToHashSet();
|
||||
foreach (var c1 in cellDomains)
|
||||
foreach (var c2 in cellDomains.Where(c => c != c1))
|
||||
CreateConnection(c1, c2);
|
||||
}
|
||||
|
||||
bool HasConnection(int d1, int d2)
|
||||
{
|
||||
// Search our connections graph for a possible route
|
||||
|
||||
95
OpenRA.Mods.Common/Traits/World/ElevatedBridgeLayer.cs
Normal file
95
OpenRA.Mods.Common/Traits/World/ElevatedBridgeLayer.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you 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. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class ElevatedBridgeLayerInfo : ITraitInfo, Requires<DomainIndexInfo>, ILobbyCustomRulesIgnore
|
||||
{
|
||||
[Desc("Terrain type used by cells outside any elevated bridge footprint.")]
|
||||
public readonly string ImpassableTerrainType = "Impassable";
|
||||
|
||||
public object Create(ActorInitializer init) { return new ElevatedBridgeLayer(init.Self, this); }
|
||||
}
|
||||
|
||||
// For now this is mostly copies TerrainTunnelLayer. This will change once bridge destruction is implemented
|
||||
public class ElevatedBridgeLayer : ICustomMovementLayer, IWorldLoaded
|
||||
{
|
||||
readonly Map map;
|
||||
readonly CellLayer<WPos> cellCenters;
|
||||
readonly CellLayer<byte> terrainIndices;
|
||||
readonly HashSet<CPos> ends = new HashSet<CPos>();
|
||||
bool enabled;
|
||||
|
||||
public ElevatedBridgeLayer(Actor self, ElevatedBridgeLayerInfo info)
|
||||
{
|
||||
map = self.World.Map;
|
||||
cellCenters = new CellLayer<WPos>(map);
|
||||
terrainIndices = new CellLayer<byte>(map);
|
||||
terrainIndices.Clear(map.Rules.TileSet.GetTerrainIndex(info.ImpassableTerrainType));
|
||||
}
|
||||
|
||||
public void WorldLoaded(World world, WorldRenderer wr)
|
||||
{
|
||||
var domainIndex = world.WorldActor.Trait<DomainIndex>();
|
||||
foreach (var tti in world.WorldActor.Info.TraitInfos<ElevatedBridgePlaceholderInfo>())
|
||||
{
|
||||
enabled = true;
|
||||
|
||||
var terrain = map.Rules.TileSet.GetTerrainIndex(tti.TerrainType);
|
||||
foreach (var c in tti.BridgeCells())
|
||||
{
|
||||
var uv = c.ToMPos(map);
|
||||
terrainIndices[uv] = terrain;
|
||||
|
||||
var pos = map.CenterOfCell(c);
|
||||
cellCenters[uv] = pos - new WVec(0, 0, pos.Z - 512 * tti.Height);
|
||||
}
|
||||
|
||||
var end = tti.EndCells();
|
||||
domainIndex.AddFixedConnection(end);
|
||||
foreach (var c in end)
|
||||
{
|
||||
// Need to explicitly set both default and tunnel layers, otherwise the .Contains check will fail
|
||||
ends.Add(new CPos(c.X, c.Y, 0));
|
||||
ends.Add(new CPos(c.X, c.Y, CustomMovementLayerType.ElevatedBridge));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ICustomMovementLayer.EnabledForActor(ActorInfo a, MobileInfo mi) { return enabled; }
|
||||
byte ICustomMovementLayer.Index { get { return CustomMovementLayerType.ElevatedBridge; } }
|
||||
bool ICustomMovementLayer.InteractsWithDefaultLayer { get { return true; } }
|
||||
|
||||
WPos ICustomMovementLayer.CenterOfCell(CPos cell)
|
||||
{
|
||||
return cellCenters[cell];
|
||||
}
|
||||
|
||||
int ICustomMovementLayer.EntryMovementCost(ActorInfo a, MobileInfo mi, CPos cell)
|
||||
{
|
||||
return ends.Contains(cell) ? 0 : int.MaxValue;
|
||||
}
|
||||
|
||||
int ICustomMovementLayer.ExitMovementCost(ActorInfo a, MobileInfo mi, CPos cell)
|
||||
{
|
||||
return ends.Contains(cell) ? 0 : int.MaxValue;
|
||||
}
|
||||
|
||||
byte ICustomMovementLayer.GetTerrainIndex(CPos cell)
|
||||
{
|
||||
return terrainIndices[cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
75
OpenRA.Mods.Common/Traits/World/ElevatedBridgePlaceholder.cs
Normal file
75
OpenRA.Mods.Common/Traits/World/ElevatedBridgePlaceholder.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you 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. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public enum ElevatedBridgePlaceholderOrientation { X, Y }
|
||||
|
||||
[Desc("Placeholder to make static elevated bridges work.",
|
||||
"Define individual trait instances for each elevated bridge footprint in the map.")]
|
||||
public class ElevatedBridgePlaceholderInfo : TraitInfo<ElevatedBridgePlaceholder>, Requires<ElevatedBridgeLayerInfo>, ILobbyCustomRulesIgnore
|
||||
{
|
||||
[FieldLoader.Require]
|
||||
[Desc("Location of the bridge")]
|
||||
public readonly CPos Location = CPos.Zero;
|
||||
|
||||
[FieldLoader.Require]
|
||||
[Desc("Orientation of the bridge.")]
|
||||
public readonly ElevatedBridgePlaceholderOrientation Orientation;
|
||||
|
||||
[FieldLoader.Require]
|
||||
[Desc("Length of the bridge")]
|
||||
public readonly int Length = 0;
|
||||
|
||||
[FieldLoader.Require]
|
||||
[Desc("Height of the bridge in map height steps.")]
|
||||
public readonly byte Height = 0;
|
||||
|
||||
[Desc("Terrain type of the bridge.")]
|
||||
public readonly string TerrainType = "Road";
|
||||
|
||||
public IEnumerable<CPos> BridgeCells()
|
||||
{
|
||||
var dimensions = Orientation == ElevatedBridgePlaceholderOrientation.X ?
|
||||
new CVec(Length + 1, 3) : new CVec(3, Length + 1);
|
||||
|
||||
for (var y = 0; y < dimensions.Y; y++)
|
||||
for (var x = 0; x < dimensions.X; x++)
|
||||
yield return Location + new CVec(x, y);
|
||||
}
|
||||
|
||||
public IEnumerable<CPos> EndCells()
|
||||
{
|
||||
if (Orientation == ElevatedBridgePlaceholderOrientation.X)
|
||||
{
|
||||
for (var y = 0; y < 3; y++)
|
||||
{
|
||||
yield return Location + new CVec(0, y);
|
||||
yield return Location + new CVec(Length, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var x = 0; x < 3; x++)
|
||||
{
|
||||
yield return Location + new CVec(x, 0);
|
||||
yield return Location + new CVec(x, Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ElevatedBridgePlaceholder { }
|
||||
}
|
||||
103
OpenRA.Mods.Common/Traits/World/JumpjetActorLayer.cs
Normal file
103
OpenRA.Mods.Common/Traits/World/JumpjetActorLayer.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you 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. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class JumpjetActorLayerInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Terrain type of the airborne layer.")]
|
||||
public readonly string TerrainType = "Jumpjet";
|
||||
|
||||
[Desc("Height offset relative to the smoothed terrain for movement.")]
|
||||
public readonly WDist HeightOffset = new WDist(2304);
|
||||
|
||||
[Desc("Cell radius for smoothing adjacent cell heights.")]
|
||||
public readonly int SmoothingRadius = 2;
|
||||
|
||||
public object Create(ActorInitializer init) { return new JumpjetActorLayer(init.Self, this); }
|
||||
}
|
||||
|
||||
public class JumpjetActorLayer : ICustomMovementLayer
|
||||
{
|
||||
readonly Map map;
|
||||
|
||||
readonly byte terrainIndex;
|
||||
readonly CellLayer<int> height;
|
||||
|
||||
public JumpjetActorLayer(Actor self, JumpjetActorLayerInfo info)
|
||||
{
|
||||
map = self.World.Map;
|
||||
terrainIndex = self.World.Map.Rules.TileSet.GetTerrainIndex(info.TerrainType);
|
||||
height = new CellLayer<int>(map);
|
||||
foreach (var c in map.AllCells)
|
||||
{
|
||||
var neighbourCount = 0;
|
||||
var neighbourHeight = 0;
|
||||
for (var dy = -info.SmoothingRadius; dy <= info.SmoothingRadius; dy++)
|
||||
{
|
||||
for (var dx = -info.SmoothingRadius; dx <= info.SmoothingRadius; dx++)
|
||||
{
|
||||
var neighbour = c + new CVec(dx, dy);
|
||||
if (!map.AllCells.Contains(neighbour))
|
||||
continue;
|
||||
|
||||
neighbourCount++;
|
||||
neighbourHeight += map.Height[neighbour];
|
||||
}
|
||||
}
|
||||
|
||||
height[c] = info.HeightOffset.Length + neighbourHeight * 512 / neighbourCount;
|
||||
}
|
||||
}
|
||||
|
||||
bool ICustomMovementLayer.EnabledForActor(ActorInfo a, MobileInfo mi) { return mi.Jumpjet; }
|
||||
byte ICustomMovementLayer.Index { get { return CustomMovementLayerType.Jumpjet; } }
|
||||
bool ICustomMovementLayer.InteractsWithDefaultLayer { get { return true; } }
|
||||
|
||||
WPos ICustomMovementLayer.CenterOfCell(CPos cell)
|
||||
{
|
||||
var pos = map.CenterOfCell(cell);
|
||||
return pos + new WVec(0, 0, height[cell] - pos.Z);
|
||||
}
|
||||
|
||||
bool ValidTransitionCell(CPos cell, MobileInfo mi)
|
||||
{
|
||||
var terrainType = map.GetTerrainInfo(cell).Type;
|
||||
if (!mi.JumpjetTransitionTerrainTypes.Contains(terrainType) && mi.JumpjetTransitionTerrainTypes.Any())
|
||||
return false;
|
||||
|
||||
if (mi.JumpjetTransitionOnRamps)
|
||||
return true;
|
||||
|
||||
var tile = map.Tiles[cell];
|
||||
var ti = map.Rules.TileSet.GetTileInfo(tile);
|
||||
return ti == null || ti.RampType == 0;
|
||||
}
|
||||
|
||||
int ICustomMovementLayer.EntryMovementCost(ActorInfo a, MobileInfo mi, CPos cell)
|
||||
{
|
||||
return ValidTransitionCell(cell, mi) ? mi.JumpjetTransitionCost : int.MaxValue;
|
||||
}
|
||||
|
||||
int ICustomMovementLayer.ExitMovementCost(ActorInfo a, MobileInfo mi, CPos cell)
|
||||
{
|
||||
return ValidTransitionCell(cell, mi) ? mi.JumpjetTransitionCost : int.MaxValue;
|
||||
}
|
||||
|
||||
byte ICustomMovementLayer.GetTerrainIndex(CPos cell)
|
||||
{
|
||||
return terrainIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (domainIndex != null)
|
||||
{
|
||||
var passable = mi.GetMovementClass(world.Map.Rules.TileSet);
|
||||
if (!domainIndex.IsPassable(source, target, (uint)passable))
|
||||
if (!domainIndex.IsPassable(source, target, mi, (uint)passable))
|
||||
return EmptyPath;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (domainIndex != null)
|
||||
{
|
||||
var passable = mi.GetMovementClass(world.Map.Rules.TileSet);
|
||||
tilesInRange = new List<CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, (uint)passable)));
|
||||
tilesInRange = new List<CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, mi, (uint)passable)));
|
||||
if (!tilesInRange.Any())
|
||||
return EmptyPath;
|
||||
}
|
||||
|
||||
103
OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs
Normal file
103
OpenRA.Mods.Common/Traits/World/SubterraneanActorLayer.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you 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. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class SubterraneanActorLayerInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Terrain type of the underground layer.")]
|
||||
public readonly string TerrainType = "Subterranean";
|
||||
|
||||
[Desc("Height offset relative to the smoothed terrain for movement.")]
|
||||
public readonly WDist HeightOffset = -new WDist(2048);
|
||||
|
||||
[Desc("Cell radius for smoothing adjacent cell heights.")]
|
||||
public readonly int SmoothingRadius = 2;
|
||||
|
||||
public object Create(ActorInitializer init) { return new SubterraneanActorLayer(init.Self, this); }
|
||||
}
|
||||
|
||||
public class SubterraneanActorLayer : ICustomMovementLayer
|
||||
{
|
||||
readonly Map map;
|
||||
|
||||
readonly byte terrainIndex;
|
||||
readonly CellLayer<int> height;
|
||||
|
||||
public SubterraneanActorLayer(Actor self, SubterraneanActorLayerInfo info)
|
||||
{
|
||||
map = self.World.Map;
|
||||
terrainIndex = self.World.Map.Rules.TileSet.GetTerrainIndex(info.TerrainType);
|
||||
height = new CellLayer<int>(map);
|
||||
foreach (var c in map.AllCells)
|
||||
{
|
||||
var neighbourCount = 0;
|
||||
var neighbourHeight = 0;
|
||||
for (var dy = -info.SmoothingRadius; dy <= info.SmoothingRadius; dy++)
|
||||
{
|
||||
for (var dx = -info.SmoothingRadius; dx <= info.SmoothingRadius; dx++)
|
||||
{
|
||||
var neighbour = c + new CVec(dx, dy);
|
||||
if (!map.AllCells.Contains(neighbour))
|
||||
continue;
|
||||
|
||||
neighbourCount++;
|
||||
neighbourHeight += map.Height[neighbour];
|
||||
}
|
||||
}
|
||||
|
||||
height[c] = info.HeightOffset.Length + neighbourHeight * 512 / neighbourCount;
|
||||
}
|
||||
}
|
||||
|
||||
bool ICustomMovementLayer.EnabledForActor(ActorInfo a, MobileInfo mi) { return mi.Subterranean; }
|
||||
byte ICustomMovementLayer.Index { get { return CustomMovementLayerType.Subterranean; } }
|
||||
bool ICustomMovementLayer.InteractsWithDefaultLayer { get { return false; } }
|
||||
|
||||
WPos ICustomMovementLayer.CenterOfCell(CPos cell)
|
||||
{
|
||||
var pos = map.CenterOfCell(cell);
|
||||
return pos + new WVec(0, 0, height[cell] - pos.Z);
|
||||
}
|
||||
|
||||
bool ValidTransitionCell(CPos cell, MobileInfo mi)
|
||||
{
|
||||
var terrainType = map.GetTerrainInfo(cell).Type;
|
||||
if (!mi.SubterraneanTransitionTerrainTypes.Contains(terrainType) && mi.SubterraneanTransitionTerrainTypes.Any())
|
||||
return false;
|
||||
|
||||
if (mi.SubterraneanTransitionOnRamps)
|
||||
return true;
|
||||
|
||||
var tile = map.Tiles[cell];
|
||||
var ti = map.Rules.TileSet.GetTileInfo(tile);
|
||||
return ti == null || ti.RampType == 0;
|
||||
}
|
||||
|
||||
int ICustomMovementLayer.EntryMovementCost(ActorInfo a, MobileInfo mi, CPos cell)
|
||||
{
|
||||
return ValidTransitionCell(cell, mi) ? mi.SubterraneanTransitionCost : int.MaxValue;
|
||||
}
|
||||
|
||||
int ICustomMovementLayer.ExitMovementCost(ActorInfo a, MobileInfo mi, CPos cell)
|
||||
{
|
||||
return ValidTransitionCell(cell, mi) ? mi.SubterraneanTransitionCost : int.MaxValue;
|
||||
}
|
||||
|
||||
byte ICustomMovementLayer.GetTerrainIndex(CPos cell)
|
||||
{
|
||||
return terrainIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
OpenRA.Mods.Common/Traits/World/TerrainTunnel.cs
Normal file
62
OpenRA.Mods.Common/Traits/World/TerrainTunnel.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you 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. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class TerrainTunnelInfo : TraitInfo<TerrainTunnel>, Requires<TerrainTunnelLayerInfo>, ILobbyCustomRulesIgnore
|
||||
{
|
||||
[FieldLoader.Require]
|
||||
[Desc("Location of the tunnel")]
|
||||
public readonly CPos Location = CPos.Zero;
|
||||
|
||||
[FieldLoader.Require]
|
||||
[Desc("Height of the tunnel floor in map height steps.")]
|
||||
public readonly byte Height = 0;
|
||||
|
||||
[FieldLoader.Require]
|
||||
[Desc("Size of the tunnel footprint")]
|
||||
public readonly CVec Dimensions = CVec.Zero;
|
||||
|
||||
[FieldLoader.Require]
|
||||
[Desc("Tunnel footprint.", "_ is passable, x is blocked, and o are tunnel portals.")]
|
||||
public readonly string Footprint = string.Empty;
|
||||
|
||||
[FieldLoader.Require]
|
||||
[Desc("Terrain type of the tunnel floor.")]
|
||||
public readonly string TerrainType = null;
|
||||
|
||||
public IEnumerable<CPos> TunnelCells()
|
||||
{
|
||||
return CellsMatching('_').Concat(CellsMatching('o'));
|
||||
}
|
||||
|
||||
public IEnumerable<CPos> PortalCells()
|
||||
{
|
||||
return CellsMatching('o');
|
||||
}
|
||||
|
||||
IEnumerable<CPos> CellsMatching(char c)
|
||||
{
|
||||
var index = 0;
|
||||
var footprint = Footprint.Where(x => !char.IsWhiteSpace(x)).ToArray();
|
||||
for (var y = 0; y < Dimensions.Y; y++)
|
||||
for (var x = 0; x < Dimensions.X; x++)
|
||||
if (footprint[index++] == c)
|
||||
yield return Location + new CVec(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public class TerrainTunnel { }
|
||||
}
|
||||
94
OpenRA.Mods.Common/Traits/World/TerrainTunnelLayer.cs
Normal file
94
OpenRA.Mods.Common/Traits/World/TerrainTunnelLayer.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you 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. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public class TerrainTunnelLayerInfo : ITraitInfo, Requires<DomainIndexInfo>, ILobbyCustomRulesIgnore
|
||||
{
|
||||
[Desc("Terrain type used by cells outside any tunnel footprint.")]
|
||||
public readonly string ImpassableTerrainType = "Impassable";
|
||||
|
||||
public object Create(ActorInitializer init) { return new TerrainTunnelLayer(init.Self, this); }
|
||||
}
|
||||
|
||||
public class TerrainTunnelLayer : ICustomMovementLayer, IWorldLoaded
|
||||
{
|
||||
readonly Map map;
|
||||
readonly CellLayer<WPos> cellCenters;
|
||||
readonly CellLayer<byte> terrainIndices;
|
||||
readonly HashSet<CPos> portals = new HashSet<CPos>();
|
||||
bool enabled;
|
||||
|
||||
public TerrainTunnelLayer(Actor self, TerrainTunnelLayerInfo info)
|
||||
{
|
||||
map = self.World.Map;
|
||||
cellCenters = new CellLayer<WPos>(map);
|
||||
terrainIndices = new CellLayer<byte>(map);
|
||||
terrainIndices.Clear(map.Rules.TileSet.GetTerrainIndex(info.ImpassableTerrainType));
|
||||
}
|
||||
|
||||
public void WorldLoaded(World world, WorldRenderer wr)
|
||||
{
|
||||
var domainIndex = world.WorldActor.Trait<DomainIndex>();
|
||||
foreach (var tti in world.WorldActor.Info.TraitInfos<TerrainTunnelInfo>())
|
||||
{
|
||||
enabled = true;
|
||||
|
||||
var terrain = map.Rules.TileSet.GetTerrainIndex(tti.TerrainType);
|
||||
foreach (var c in tti.TunnelCells())
|
||||
{
|
||||
var uv = c.ToMPos(map);
|
||||
terrainIndices[uv] = terrain;
|
||||
|
||||
var pos = map.CenterOfCell(c);
|
||||
cellCenters[uv] = pos - new WVec(0, 0, pos.Z - 512 * tti.Height);
|
||||
}
|
||||
|
||||
var portal = tti.PortalCells();
|
||||
domainIndex.AddFixedConnection(portal);
|
||||
foreach (var c in portal)
|
||||
{
|
||||
// Need to explicitly set both default and tunnel layers, otherwise the .Contains check will fail
|
||||
portals.Add(new CPos(c.X, c.Y, 0));
|
||||
portals.Add(new CPos(c.X, c.Y, CustomMovementLayerType.Tunnel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ICustomMovementLayer.EnabledForActor(ActorInfo a, MobileInfo mi) { return enabled; }
|
||||
byte ICustomMovementLayer.Index { get { return CustomMovementLayerType.Tunnel; } }
|
||||
bool ICustomMovementLayer.InteractsWithDefaultLayer { get { return false; } }
|
||||
|
||||
WPos ICustomMovementLayer.CenterOfCell(CPos cell)
|
||||
{
|
||||
return cellCenters[cell];
|
||||
}
|
||||
|
||||
int ICustomMovementLayer.EntryMovementCost(ActorInfo a, MobileInfo mi, CPos cell)
|
||||
{
|
||||
return portals.Contains(cell) ? 0 : int.MaxValue;
|
||||
}
|
||||
|
||||
int ICustomMovementLayer.ExitMovementCost(ActorInfo a, MobileInfo mi, CPos cell)
|
||||
{
|
||||
return portals.Contains(cell) ? 0 : int.MaxValue;
|
||||
}
|
||||
|
||||
byte ICustomMovementLayer.GetTerrainIndex(CPos cell)
|
||||
{
|
||||
return terrainIndices[cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,4 +233,18 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
[RequireExplicitImplementation]
|
||||
public interface IGainsExperienceModifier { int GetGainsExperienceModifier(); }
|
||||
|
||||
[RequireExplicitImplementation]
|
||||
public interface ICustomMovementLayer
|
||||
{
|
||||
byte Index { get; }
|
||||
bool InteractsWithDefaultLayer { get; }
|
||||
|
||||
bool EnabledForActor(ActorInfo a, MobileInfo mi);
|
||||
int EntryMovementCost(ActorInfo a, MobileInfo mi, CPos cell);
|
||||
int ExitMovementCost(ActorInfo a, MobileInfo mi, CPos cell);
|
||||
|
||||
byte GetTerrainIndex(CPos cell);
|
||||
WPos CenterOfCell(CPos cell);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -85,7 +86,13 @@ namespace OpenRA.Mods.Common
|
||||
|
||||
public static WPos BetweenCells(World w, CPos from, CPos to)
|
||||
{
|
||||
return WPos.Lerp(w.Map.CenterOfCell(from), w.Map.CenterOfCell(to), 1, 2);
|
||||
var fromPos = from.Layer == 0 ? w.Map.CenterOfCell(from) :
|
||||
w.GetCustomMovementLayers()[from.Layer].CenterOfCell(from);
|
||||
|
||||
var toPos = to.Layer == 0 ? w.Map.CenterOfCell(to) :
|
||||
w.GetCustomMovementLayers()[to.Layer].CenterOfCell(to);
|
||||
|
||||
return WPos.Lerp(fromPos, toPos, 1, 2);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> ts, MersenneTwister random)
|
||||
|
||||
@@ -86,7 +86,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
var coordinateLabel = widget.GetOrNull<LabelWidget>("COORDINATE_LABEL");
|
||||
if (coordinateLabel != null)
|
||||
coordinateLabel.GetText = () => worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos).ToString();
|
||||
{
|
||||
coordinateLabel.GetText = () =>
|
||||
{
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
|
||||
var map = worldRenderer.World.Map;
|
||||
var height = map.Height.Contains(cell) ? map.Height[cell] : 0;
|
||||
return "{0},{1}".F(cell, height);
|
||||
};
|
||||
}
|
||||
|
||||
var cashLabel = widget.GetOrNull<LabelWidget>("CASH_LABEL");
|
||||
if (cashLabel != null)
|
||||
|
||||
@@ -100,8 +100,8 @@ namespace OpenRA.Mods.RA.Traits
|
||||
|
||||
static IEnumerable<CPos> GetMinefieldCells(CPos start, CPos end, WDist depth)
|
||||
{
|
||||
var mins = CPos.Min(start, end);
|
||||
var maxs = CPos.Max(start, end);
|
||||
var mins = new CPos(Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
|
||||
var maxs = new CPos(Math.Max(start.X, end.X), Math.Max(start.Y, end.Y));
|
||||
|
||||
/* TODO: proper endcaps, if anyone cares (which won't happen unless depth is large) */
|
||||
|
||||
|
||||
@@ -31,10 +31,8 @@ namespace OpenRA.Mods.TS.UtilityCommands
|
||||
{
|
||||
{ 0x01, "gasand" },
|
||||
{ 0x03, "gawall" },
|
||||
/*
|
||||
{ 0x18, "bridge1" },
|
||||
{ 0x19, "bridge2" },
|
||||
*/
|
||||
{ 0x1A, "nawall" },
|
||||
{ 0x27, "tracks01" },
|
||||
{ 0x28, "tracks02" },
|
||||
@@ -56,10 +54,8 @@ namespace OpenRA.Mods.TS.UtilityCommands
|
||||
{ 0x38, "tracktunnel02" },
|
||||
{ 0x39, "tracktunnel03" },
|
||||
{ 0x3A, "tracktunnel04" },
|
||||
/*
|
||||
{ 0x3B, "railbrdg1" },
|
||||
{ 0x3C, "railbrdg2" },
|
||||
*/
|
||||
{ 0x3D, "crat01" },
|
||||
{ 0x3E, "crat02" },
|
||||
{ 0x3F, "crat03" },
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 47 KiB |
@@ -119,26 +119,6 @@ Actors:
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor12: cabhut
|
||||
Location: 174,2
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor13: cabhut
|
||||
Location: 183,6
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor14: cabhut
|
||||
Location: 239,2
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor15: cabhut
|
||||
Location: 229,-2
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor16: tibtre01
|
||||
Location: 133,-102
|
||||
Owner: Neutral
|
||||
@@ -1582,8 +1562,59 @@ Actors:
|
||||
Actor623: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 115,-15
|
||||
Actor494: bridge1
|
||||
Owner: Neutral
|
||||
Location: 232,0
|
||||
Actor495: bridge1
|
||||
Owner: Neutral
|
||||
Location: 233,0
|
||||
Actor496: bridge1
|
||||
Owner: Neutral
|
||||
Location: 234,0
|
||||
Actor497: bridge1
|
||||
Owner: Neutral
|
||||
Location: 235,0
|
||||
Actor500: bridge1
|
||||
Owner: Neutral
|
||||
Location: 236,0
|
||||
Actor501: bridge1
|
||||
Owner: Neutral
|
||||
Location: 177,4
|
||||
Actor502: bridge1
|
||||
Owner: Neutral
|
||||
Location: 178,4
|
||||
Actor503: bridge1
|
||||
Owner: Neutral
|
||||
Location: 179,4
|
||||
Actor505: bridge1
|
||||
Owner: Neutral
|
||||
Location: 180,4
|
||||
|
||||
Rules:
|
||||
World:
|
||||
GlobalLightingPaletteEffect:
|
||||
Ambient: 0.72
|
||||
ElevatedBridgeLayer:
|
||||
TerrainTunnelLayer:
|
||||
ElevatedBridgePlaceholder@a:
|
||||
Location: 176, 3
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 5
|
||||
ElevatedBridgePlaceholder@b:
|
||||
Location: 231, -1
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 6
|
||||
TerrainTunnel@a:
|
||||
Location: 117, -15
|
||||
Dimensions: 3, 25
|
||||
Footprint: ooo ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ooo
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
TerrainTunnel@b:
|
||||
Location: 146, -19
|
||||
Dimensions: 3, 25
|
||||
Footprint: ooo ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ooo
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
@@ -14,7 +14,7 @@ Bounds: 2,4,141,226
|
||||
|
||||
Visibility: Lobby
|
||||
|
||||
Categories: Conquest
|
||||
Categories: Conquest, Playable, Original FS Map
|
||||
|
||||
Players:
|
||||
PlayerReference@Neutral:
|
||||
@@ -69,56 +69,6 @@ Players:
|
||||
Enemies: Creeps
|
||||
|
||||
Actors:
|
||||
Actor0: cabhut
|
||||
Location: 126,-52
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor1: cabhut
|
||||
Location: 109,-56
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor2: cabhut
|
||||
Location: 155,-83
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor3: cabhut
|
||||
Location: 159,-106
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor4: cabhut
|
||||
Location: 101,75
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor5: cabhut
|
||||
Location: 115,79
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor6: cabhut
|
||||
Location: 154,32
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor7: cabhut
|
||||
Location: 158,18
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor8: cabhut
|
||||
Location: 221,-41
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor9: cabhut
|
||||
Location: 225,-55
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor10: city15
|
||||
Location: 58,43
|
||||
Owner: Neutral
|
||||
@@ -214,16 +164,6 @@ Actors:
|
||||
Owner: Neutral
|
||||
Health: 50
|
||||
Facing: 96
|
||||
Actor29: cabhut
|
||||
Location: 53,29
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor30: cabhut
|
||||
Location: 49,5
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor31: car
|
||||
Location: 94,42
|
||||
Owner: Neutral
|
||||
@@ -837,8 +777,268 @@ Actors:
|
||||
Actor233: waypoint
|
||||
Location: 105,21
|
||||
Owner: Neutral
|
||||
Actor234: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,8
|
||||
Actor235: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,9
|
||||
Actor236: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,10
|
||||
Actor237: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,11
|
||||
Actor238: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,12
|
||||
Actor240: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,13
|
||||
Actor239: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,26
|
||||
Actor241: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,25
|
||||
Actor242: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,24
|
||||
Actor243: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,23
|
||||
Actor244: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,22
|
||||
Actor245: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,21
|
||||
Actor246: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,20
|
||||
Actor247: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,19
|
||||
Actor248: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,18
|
||||
Actor249: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,17
|
||||
Actor250: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,16
|
||||
Actor252: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,15
|
||||
Actor253: bridge2
|
||||
Owner: Neutral
|
||||
Location: 51,14
|
||||
Actor251: bridge1
|
||||
Owner: Neutral
|
||||
Location: 104,77
|
||||
Actor254: bridge1
|
||||
Owner: Neutral
|
||||
Location: 105,77
|
||||
Actor255: bridge1
|
||||
Owner: Neutral
|
||||
Location: 106,77
|
||||
Actor256: bridge1
|
||||
Owner: Neutral
|
||||
Location: 107,77
|
||||
Actor257: bridge1
|
||||
Owner: Neutral
|
||||
Location: 108,77
|
||||
Actor258: bridge1
|
||||
Owner: Neutral
|
||||
Location: 109,77
|
||||
Actor259: bridge1
|
||||
Owner: Neutral
|
||||
Location: 110,77
|
||||
Actor261: bridge1
|
||||
Owner: Neutral
|
||||
Location: 111,77
|
||||
Actor262: bridge1
|
||||
Owner: Neutral
|
||||
Location: 112,77
|
||||
Actor263: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,21
|
||||
Actor264: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,22
|
||||
Actor265: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,23
|
||||
Actor266: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,24
|
||||
Actor267: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,25
|
||||
Actor268: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,26
|
||||
Actor269: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,27
|
||||
Actor270: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,28
|
||||
Actor271: bridge2
|
||||
Owner: Neutral
|
||||
Location: 156,29
|
||||
Actor272: bridge1
|
||||
Owner: Neutral
|
||||
Location: 112,-54
|
||||
Actor273: bridge1
|
||||
Owner: Neutral
|
||||
Location: 113,-54
|
||||
Actor274: bridge1
|
||||
Owner: Neutral
|
||||
Location: 114,-54
|
||||
Actor275: bridge1
|
||||
Owner: Neutral
|
||||
Location: 115,-54
|
||||
Actor276: bridge1
|
||||
Owner: Neutral
|
||||
Location: 116,-54
|
||||
Actor277: bridge1
|
||||
Owner: Neutral
|
||||
Location: 117,-54
|
||||
Actor279: bridge1
|
||||
Owner: Neutral
|
||||
Location: 123,-54
|
||||
Actor280: bridge1
|
||||
Owner: Neutral
|
||||
Location: 122,-54
|
||||
Actor281: bridge1
|
||||
Owner: Neutral
|
||||
Location: 121,-54
|
||||
Actor283: bridge1
|
||||
Owner: Neutral
|
||||
Location: 120,-54
|
||||
Actor282: bridge1
|
||||
Owner: Neutral
|
||||
Location: 119,-54
|
||||
Actor284: bridge1
|
||||
Owner: Neutral
|
||||
Location: 118,-54
|
||||
Actor278: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-103
|
||||
Actor285: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-102
|
||||
Actor287: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-101
|
||||
Actor286: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-100
|
||||
Actor289: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-99
|
||||
Actor288: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-98
|
||||
Actor290: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-97
|
||||
Actor291: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-96
|
||||
Actor292: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-95
|
||||
Actor293: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-94
|
||||
Actor294: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-93
|
||||
Actor295: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-92
|
||||
Actor296: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-91
|
||||
Actor297: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-90
|
||||
Actor298: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-89
|
||||
Actor299: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-88
|
||||
Actor300: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-87
|
||||
Actor301: bridge2
|
||||
Owner: Neutral
|
||||
Location: 157,-86
|
||||
Actor302: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-52
|
||||
Actor303: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-51
|
||||
Actor304: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-50
|
||||
Actor305: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-49
|
||||
Actor306: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-48
|
||||
Actor307: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-47
|
||||
Actor309: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-46
|
||||
Actor308: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-45
|
||||
Actor310: bridge2
|
||||
Owner: Neutral
|
||||
Location: 223,-44
|
||||
|
||||
Rules:
|
||||
World:
|
||||
GlobalLightingPaletteEffect:
|
||||
Ambient: 0.93
|
||||
TerrainTunnelLayer:
|
||||
ElevatedBridgeLayer:
|
||||
ElevatedBridgePlaceholder@a:
|
||||
Location: 50, 7
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 20
|
||||
ElevatedBridgePlaceholder@b:
|
||||
Location: 103, 76
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 10
|
||||
ElevatedBridgePlaceholder@c:
|
||||
Location: 111, -55
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 13
|
||||
ElevatedBridgePlaceholder@d:
|
||||
Location: 155, 20
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 10
|
||||
ElevatedBridgePlaceholder@e:
|
||||
Location: 156, -104
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 19
|
||||
ElevatedBridgePlaceholder@f:
|
||||
Location: 222, -53
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 10
|
||||
@@ -14,7 +14,7 @@ Bounds: 2,8,77,126
|
||||
|
||||
Visibility: Lobby
|
||||
|
||||
Categories: Conquest, Original TS Map
|
||||
Categories: Conquest, Original FS Map, Playable
|
||||
|
||||
Players:
|
||||
PlayerReference@Neutral:
|
||||
@@ -816,44 +816,93 @@ Actors:
|
||||
Actor222: tuntop03
|
||||
Owner: Neutral
|
||||
Location: 109,4
|
||||
Actor223: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 106,-16
|
||||
Actor224: tuntop04
|
||||
Owner: Neutral
|
||||
Location: 87,28
|
||||
Actor225: tuntop03
|
||||
Owner: Neutral
|
||||
Location: 73,34
|
||||
Actor226: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 86,13
|
||||
Actor227: tuntop01
|
||||
Owner: Neutral
|
||||
Location: 60,34
|
||||
Actor228: tuntop04
|
||||
Owner: Neutral
|
||||
Location: 42,13
|
||||
Actor229: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 40,-2
|
||||
Actor230: tuntop01
|
||||
Owner: Neutral
|
||||
Location: 51,-6
|
||||
Actor231: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 72,-28
|
||||
Actor232: tuntop01
|
||||
Owner: Neutral
|
||||
Location: 77,-38
|
||||
Actor233: tuntop03
|
||||
Owner: Neutral
|
||||
Location: 93,-37
|
||||
Actor234: tuntop01
|
||||
Actor237: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 95,3
|
||||
Location: 107,-16
|
||||
Actor238: tuntop01
|
||||
Owner: Neutral
|
||||
Location: 77,-37
|
||||
Actor239: tuntop01
|
||||
Owner: Neutral
|
||||
Location: 95,4
|
||||
Actor240: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 73,-28
|
||||
Actor234: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 42,-2
|
||||
Actor236: tuntop01
|
||||
Owner: Neutral
|
||||
Location: 51,-5
|
||||
Actor235: tuntop02
|
||||
Owner: Neutral
|
||||
Location: 88,13
|
||||
|
||||
Rules:
|
||||
World:
|
||||
GlobalLightingPaletteEffect:
|
||||
Ambient: 0.62
|
||||
TerrainTunnelLayer:
|
||||
TerrainTunnel@a:
|
||||
Location: 60, 35
|
||||
Dimensions: 14, 3
|
||||
Footprint: o____________o o____________o o____________o
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
TerrainTunnel@b:
|
||||
Location: 43, -2
|
||||
Dimensions: 3, 16
|
||||
Footprint: ooo ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ooo
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
TerrainTunnel@c:
|
||||
Location: 88, 13
|
||||
Dimensions: 4, 16
|
||||
Footprint: xooo x___ x___ x___ x___ x___ x___ x___ x___ x___ x___ x___ x___ x___ x___ ooox
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
TerrainTunnel@d:
|
||||
Location: 51, -4
|
||||
Dimensions: 18, 3
|
||||
Footprint: o________________o o________________o o________________o
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
TerrainTunnel@e:
|
||||
Location: 95, 5
|
||||
Dimensions: 15, 3
|
||||
Footprint: o_____________o o_____________o o_____________o
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
TerrainTunnel@f:
|
||||
Location: 74, -28
|
||||
Dimensions: 3, 17
|
||||
Footprint: ooo ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ooo
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
TerrainTunnel@g:
|
||||
Location: 108, -16
|
||||
Dimensions: 3, 10
|
||||
Footprint: ooo ___ ___ ___ ___ ___ ___ ___ ___ ooo
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
TerrainTunnel@h:
|
||||
Location: 77, -36
|
||||
Dimensions: 17, 3
|
||||
Footprint: o_______________o o_______________o o_______________o
|
||||
Height: 2
|
||||
TerrainType: Clear
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 51 KiB |
@@ -14,7 +14,7 @@ Bounds: 2,4,161,224
|
||||
|
||||
Visibility: Lobby
|
||||
|
||||
Categories: Conquest, Original TS Map
|
||||
Categories: Conquest, Original TS Map, Playable
|
||||
|
||||
Players:
|
||||
PlayerReference@Neutral:
|
||||
@@ -184,76 +184,11 @@ Actors:
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor23: cabhut
|
||||
Location: 112,15
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor24: cabhut
|
||||
Location: 116,-9
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor25: cabhut
|
||||
Location: 96,34
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor26: cabhut
|
||||
Location: 121,44
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor27: cabhut
|
||||
Location: 126,30
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor28: cabhut
|
||||
Location: 85,11
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor29: cabhut
|
||||
Location: 130,-13
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor30: cabhut
|
||||
Location: 146,-9
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor31: cabhut
|
||||
Location: 151,-25
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor32: cabhut
|
||||
Location: 155,-42
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor33: cabhut
|
||||
Location: 145,-66
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor34: cabhut
|
||||
Location: 159,-69
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor35: cabhut
|
||||
Location: 173,-66
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor36: cabhut
|
||||
Location: 181,-34
|
||||
Owner: Neutral
|
||||
Health: 100
|
||||
Facing: 96
|
||||
Actor37: cabhut
|
||||
Location: 163,-137
|
||||
Owner: Neutral
|
||||
@@ -1209,41 +1144,633 @@ Actors:
|
||||
Actor341: lobrdg_r_ne
|
||||
Location: 160,-137
|
||||
Owner: Neutral
|
||||
Actor345: lobrdg_a
|
||||
Actor342: lobrdg_a
|
||||
Location: 160,-136
|
||||
Owner: Neutral
|
||||
Actor346: lobrdg_a
|
||||
Actor343: lobrdg_a
|
||||
Location: 160,-135
|
||||
Owner: Neutral
|
||||
Actor351: lobrdg_a
|
||||
Actor344: lobrdg_a
|
||||
Location: 160,-134
|
||||
Owner: Neutral
|
||||
Actor352: lobrdg_a
|
||||
Actor345: lobrdg_a
|
||||
Location: 160,-133
|
||||
Owner: Neutral
|
||||
Actor357: lobrdg_a
|
||||
Actor346: lobrdg_a
|
||||
Location: 160,-132
|
||||
Owner: Neutral
|
||||
Actor358: lobrdg_a
|
||||
Actor347: lobrdg_a
|
||||
Location: 160,-131
|
||||
Owner: Neutral
|
||||
Actor363: lobrdg_a
|
||||
Actor348: lobrdg_a
|
||||
Location: 160,-130
|
||||
Owner: Neutral
|
||||
Actor364: lobrdg_a
|
||||
Actor349: lobrdg_a
|
||||
Location: 160,-129
|
||||
Owner: Neutral
|
||||
Actor369: lobrdg_r_sw
|
||||
Actor350: lobrdg_r_sw
|
||||
Location: 160,-128
|
||||
Owner: Neutral
|
||||
Actor351: bridge1
|
||||
Location: 129,-64
|
||||
Owner: Neutral
|
||||
Actor352: bridge1
|
||||
Location: 130,-64
|
||||
Owner: Neutral
|
||||
Actor353: bridge1
|
||||
Location: 131,-64
|
||||
Owner: Neutral
|
||||
Actor354: bridge1
|
||||
Location: 132,-64
|
||||
Owner: Neutral
|
||||
Actor355: bridge2
|
||||
Location: 161,-90
|
||||
Owner: Neutral
|
||||
Actor356: bridge2
|
||||
Location: 161,-89
|
||||
Owner: Neutral
|
||||
Actor357: bridge2
|
||||
Location: 161,-88
|
||||
Owner: Neutral
|
||||
Actor358: bridge2
|
||||
Location: 161,-87
|
||||
Owner: Neutral
|
||||
Actor359: bridge2
|
||||
Location: 161,-86
|
||||
Owner: Neutral
|
||||
Actor360: bridge1
|
||||
Location: 63,13
|
||||
Owner: Neutral
|
||||
Actor361: bridge1
|
||||
Location: 140,-64
|
||||
Owner: Neutral
|
||||
Actor362: bridge1
|
||||
Location: 141,-64
|
||||
Owner: Neutral
|
||||
Actor363: bridge1
|
||||
Location: 142,-64
|
||||
Owner: Neutral
|
||||
Actor364: bridge2
|
||||
Location: 161,-75
|
||||
Owner: Neutral
|
||||
Actor365: bridge2
|
||||
Location: 161,-74
|
||||
Owner: Neutral
|
||||
Actor366: bridge2
|
||||
Location: 161,-73
|
||||
Owner: Neutral
|
||||
Actor367: bridge2
|
||||
Location: 161,-72
|
||||
Owner: Neutral
|
||||
Actor368: bridge1
|
||||
Location: 80,13
|
||||
Owner: Neutral
|
||||
Actor369: bridge1
|
||||
Location: 81,13
|
||||
Owner: Neutral
|
||||
Actor370: bridge1
|
||||
Location: 82,13
|
||||
Owner: Neutral
|
||||
Actor371: crat03
|
||||
Location: 158,-61
|
||||
Owner: Neutral
|
||||
Actor372: crat01
|
||||
Actor372: bridge2
|
||||
Location: 114,-6
|
||||
Owner: Neutral
|
||||
Actor373: bridge1
|
||||
Location: 176,-68
|
||||
Owner: Neutral
|
||||
Actor374: bridge2
|
||||
Location: 114,-5
|
||||
Owner: Neutral
|
||||
Actor375: bridge1
|
||||
Location: 177,-68
|
||||
Owner: Neutral
|
||||
Actor376: bridge2
|
||||
Location: 114,-4
|
||||
Owner: Neutral
|
||||
Actor377: bridge1
|
||||
Location: 178,-68
|
||||
Owner: Neutral
|
||||
Actor378: bridge2
|
||||
Location: 114,-3
|
||||
Owner: Neutral
|
||||
Actor379: bridge2
|
||||
Location: 114,-2
|
||||
Owner: Neutral
|
||||
Actor380: bridge2
|
||||
Location: 114,-1
|
||||
Owner: Neutral
|
||||
Actor381: bridge2
|
||||
Location: 114,0
|
||||
Owner: Neutral
|
||||
Actor382: bridge2
|
||||
Location: 153,-39
|
||||
Owner: Neutral
|
||||
Actor383: bridge2
|
||||
Location: 114,1
|
||||
Owner: Neutral
|
||||
Actor384: bridge2
|
||||
Location: 153,-38
|
||||
Owner: Neutral
|
||||
Actor385: bridge1
|
||||
Location: 183,-68
|
||||
Owner: Neutral
|
||||
Actor386: bridge2
|
||||
Location: 114,2
|
||||
Owner: Neutral
|
||||
Actor387: bridge2
|
||||
Location: 153,-37
|
||||
Owner: Neutral
|
||||
Actor388: bridge1
|
||||
Location: 184,-68
|
||||
Owner: Neutral
|
||||
Actor389: bridge2
|
||||
Location: 153,-36
|
||||
Owner: Neutral
|
||||
Actor390: bridge2
|
||||
Location: 114,4
|
||||
Owner: Neutral
|
||||
Actor391: bridge2
|
||||
Location: 153,-35
|
||||
Owner: Neutral
|
||||
Actor392: bridge2
|
||||
Location: 114,5
|
||||
Owner: Neutral
|
||||
Actor393: bridge2
|
||||
Location: 153,-34
|
||||
Owner: Neutral
|
||||
Actor394: bridge2
|
||||
Location: 114,6
|
||||
Owner: Neutral
|
||||
Actor395: bridge2
|
||||
Location: 153,-33
|
||||
Owner: Neutral
|
||||
Actor396: bridge2
|
||||
Location: 114,7
|
||||
Owner: Neutral
|
||||
Actor397: bridge2
|
||||
Location: 153,-32
|
||||
Owner: Neutral
|
||||
Actor398: bridge2
|
||||
Location: 114,8
|
||||
Owner: Neutral
|
||||
Actor399: bridge1
|
||||
Location: 133,-11
|
||||
Owner: Neutral
|
||||
Actor400: bridge2
|
||||
Location: 153,-31
|
||||
Owner: Neutral
|
||||
Actor401: bridge2
|
||||
Location: 114,9
|
||||
Owner: Neutral
|
||||
Actor402: bridge1
|
||||
Location: 134,-11
|
||||
Owner: Neutral
|
||||
Actor403: bridge2
|
||||
Location: 153,-30
|
||||
Owner: Neutral
|
||||
Actor404: bridge2
|
||||
Location: 114,10
|
||||
Owner: Neutral
|
||||
Actor405: bridge1
|
||||
Location: 135,-11
|
||||
Owner: Neutral
|
||||
Actor406: bridge2
|
||||
Location: 153,-29
|
||||
Owner: Neutral
|
||||
Actor407: bridge2
|
||||
Location: 114,11
|
||||
Owner: Neutral
|
||||
Actor408: bridge1
|
||||
Location: 136,-11
|
||||
Owner: Neutral
|
||||
Actor409: bridge2
|
||||
Location: 153,-28
|
||||
Owner: Neutral
|
||||
Actor410: bridge2
|
||||
Location: 114,12
|
||||
Owner: Neutral
|
||||
Actor411: bridge1
|
||||
Location: 137,-11
|
||||
Owner: Neutral
|
||||
Actor412: bridge1
|
||||
Location: 138,-11
|
||||
Owner: Neutral
|
||||
Actor413: bridge1
|
||||
Location: 139,-11
|
||||
Owner: Neutral
|
||||
Actor414: bridge1
|
||||
Location: 140,-11
|
||||
Owner: Neutral
|
||||
Actor415: bridge1
|
||||
Location: 141,-11
|
||||
Owner: Neutral
|
||||
Actor416: bridge2
|
||||
Location: 94,37
|
||||
Owner: Neutral
|
||||
Actor417: bridge1
|
||||
Location: 142,-11
|
||||
Owner: Neutral
|
||||
Actor418: bridge2
|
||||
Location: 94,38
|
||||
Owner: Neutral
|
||||
Actor419: bridge1
|
||||
Location: 143,-11
|
||||
Owner: Neutral
|
||||
Actor420: bridge2
|
||||
Location: 94,39
|
||||
Owner: Neutral
|
||||
Actor421: bridge2
|
||||
Location: 94,40
|
||||
Owner: Neutral
|
||||
Actor422: bridge2
|
||||
Location: 94,41
|
||||
Owner: Neutral
|
||||
Actor423: bridge2
|
||||
Location: 94,42
|
||||
Owner: Neutral
|
||||
Actor424: crat01
|
||||
Location: 123,20
|
||||
Owner: Neutral
|
||||
Actor425: bridge2
|
||||
Location: 94,54
|
||||
Owner: Neutral
|
||||
Actor426: bridge2
|
||||
Location: 94,55
|
||||
Owner: Neutral
|
||||
Actor427: bridge2
|
||||
Location: 94,56
|
||||
Owner: Neutral
|
||||
Actor428: bridge2
|
||||
Location: 94,57
|
||||
Owner: Neutral
|
||||
Actor429: bridge1
|
||||
Location: 184,-32
|
||||
Owner: Neutral
|
||||
Actor430: bridge1
|
||||
Location: 185,-32
|
||||
Owner: Neutral
|
||||
Actor431: bridge1
|
||||
Location: 186,-32
|
||||
Owner: Neutral
|
||||
Actor432: bridge1
|
||||
Location: 187,-32
|
||||
Owner: Neutral
|
||||
Actor433: bridge1
|
||||
Location: 129,28
|
||||
Owner: Neutral
|
||||
Actor434: bridge1
|
||||
Location: 130,28
|
||||
Owner: Neutral
|
||||
Actor435: bridge1
|
||||
Location: 131,28
|
||||
Owner: Neutral
|
||||
Actor436: bridge1
|
||||
Location: 132,28
|
||||
Owner: Neutral
|
||||
Actor437: bridge1
|
||||
Location: 133,28
|
||||
Owner: Neutral
|
||||
Actor438: bridge1
|
||||
Location: 193,-32
|
||||
Owner: Neutral
|
||||
Actor439: bridge1
|
||||
Location: 134,28
|
||||
Owner: Neutral
|
||||
Actor440: bridge1
|
||||
Location: 194,-32
|
||||
Owner: Neutral
|
||||
Actor441: bridge1
|
||||
Location: 135,28
|
||||
Owner: Neutral
|
||||
Actor442: bridge1
|
||||
Location: 195,-32
|
||||
Owner: Neutral
|
||||
Actor443: bridge1
|
||||
Location: 196,-32
|
||||
Owner: Neutral
|
||||
Actor444: bridge1
|
||||
Location: 197,-32
|
||||
Owner: Neutral
|
||||
Actor445: bridge2
|
||||
Location: 123,47
|
||||
Owner: Neutral
|
||||
Actor446: bridge2
|
||||
Location: 123,48
|
||||
Owner: Neutral
|
||||
Actor447: bridge2
|
||||
Location: 123,49
|
||||
Owner: Neutral
|
||||
Actor448: bridge2
|
||||
Location: 123,50
|
||||
Owner: Neutral
|
||||
Actor449: bridge1
|
||||
Location: 145,28
|
||||
Owner: Neutral
|
||||
Actor450: bridge2
|
||||
Location: 123,51
|
||||
Owner: Neutral
|
||||
Actor451: bridge1
|
||||
Location: 146,28
|
||||
Owner: Neutral
|
||||
Actor452: bridge1
|
||||
Location: 147,28
|
||||
Owner: Neutral
|
||||
Actor453: bridge1
|
||||
Location: 148,28
|
||||
Owner: Neutral
|
||||
Actor454: bridge2
|
||||
Location: 123,61
|
||||
Owner: Neutral
|
||||
Actor455: bridge2
|
||||
Location: 123,62
|
||||
Owner: Neutral
|
||||
Actor456: bridge2
|
||||
Location: 123,63
|
||||
Owner: Neutral
|
||||
Actor457: bridge2
|
||||
Location: 123,64
|
||||
Owner: Neutral
|
||||
Actor458: bridge2
|
||||
Location: 123,65
|
||||
Owner: Neutral
|
||||
Actor459: bridge2
|
||||
Location: 123,66
|
||||
Owner: Neutral
|
||||
Actor460: bridge2
|
||||
Location: 123,67
|
||||
Owner: Neutral
|
||||
Actor461: bridge1
|
||||
Owner: Neutral
|
||||
Location: 74,13
|
||||
Actor462: bridge1
|
||||
Owner: Neutral
|
||||
Location: 75,13
|
||||
Actor463: bridge1
|
||||
Owner: Neutral
|
||||
Location: 76,13
|
||||
Actor464: bridge1
|
||||
Owner: Neutral
|
||||
Location: 77,13
|
||||
Actor465: bridge1
|
||||
Owner: Neutral
|
||||
Location: 78,13
|
||||
Actor466: bridge1
|
||||
Owner: Neutral
|
||||
Location: 79,13
|
||||
Actor467: bridge1
|
||||
Owner: Neutral
|
||||
Location: 64,13
|
||||
Actor468: bridge1
|
||||
Owner: Neutral
|
||||
Location: 65,13
|
||||
Actor469: bridge1
|
||||
Owner: Neutral
|
||||
Location: 66,13
|
||||
Actor470: bridge1
|
||||
Owner: Neutral
|
||||
Location: 67,13
|
||||
Actor471: bridge1
|
||||
Owner: Neutral
|
||||
Location: 68,13
|
||||
Actor472: bridge1
|
||||
Owner: Neutral
|
||||
Location: 69,13
|
||||
Actor473: bridge1
|
||||
Owner: Neutral
|
||||
Location: 70,13
|
||||
Actor474: bridge1
|
||||
Owner: Neutral
|
||||
Location: 71,13
|
||||
Actor475: bridge1
|
||||
Owner: Neutral
|
||||
Location: 72,13
|
||||
Actor476: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,43
|
||||
Actor477: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,44
|
||||
Actor478: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,45
|
||||
Actor479: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,46
|
||||
Actor480: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,48
|
||||
Actor481: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,49
|
||||
Actor482: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,50
|
||||
Actor483: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,51
|
||||
Actor484: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,52
|
||||
Actor485: bridge2
|
||||
Owner: Neutral
|
||||
Location: 94,53
|
||||
Actor486: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,52
|
||||
Actor487: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,53
|
||||
Actor488: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,54
|
||||
Actor489: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,55
|
||||
Actor490: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,56
|
||||
Actor491: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,57
|
||||
Actor492: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,58
|
||||
Actor493: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,59
|
||||
Actor494: bridge2
|
||||
Owner: Neutral
|
||||
Location: 123,60
|
||||
Actor495: bridge1
|
||||
Owner: Neutral
|
||||
Location: 136,28
|
||||
Actor496: bridge1
|
||||
Owner: Neutral
|
||||
Location: 137,28
|
||||
Actor497: bridge1
|
||||
Owner: Neutral
|
||||
Location: 139,28
|
||||
Actor498: bridge1
|
||||
Owner: Neutral
|
||||
Location: 140,28
|
||||
Actor499: bridge1
|
||||
Owner: Neutral
|
||||
Location: 141,28
|
||||
Actor500: bridge1
|
||||
Owner: Neutral
|
||||
Location: 142,28
|
||||
Actor501: bridge1
|
||||
Owner: Neutral
|
||||
Location: 143,28
|
||||
Actor502: bridge1
|
||||
Owner: Neutral
|
||||
Location: 144,28
|
||||
Actor503: bridge1
|
||||
Owner: Neutral
|
||||
Location: 188,-32
|
||||
Actor504: bridge1
|
||||
Owner: Neutral
|
||||
Location: 189,-32
|
||||
Actor505: bridge1
|
||||
Owner: Neutral
|
||||
Location: 190,-32
|
||||
Actor506: bridge1
|
||||
Owner: Neutral
|
||||
Location: 191,-32
|
||||
Actor507: bridge1
|
||||
Owner: Neutral
|
||||
Location: 192,-32
|
||||
Actor508: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-85
|
||||
Actor509: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-84
|
||||
Actor510: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-83
|
||||
Actor511: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-82
|
||||
Actor512: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-81
|
||||
Actor513: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-80
|
||||
Actor514: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-79
|
||||
Actor515: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-78
|
||||
Actor516: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-77
|
||||
Actor517: bridge2
|
||||
Owner: Neutral
|
||||
Location: 161,-76
|
||||
Actor518: bridge1
|
||||
Owner: Neutral
|
||||
Location: 133,-64
|
||||
Actor519: bridge1
|
||||
Owner: Neutral
|
||||
Location: 134,-64
|
||||
Actor520: bridge1
|
||||
Owner: Neutral
|
||||
Location: 135,-64
|
||||
Actor521: bridge1
|
||||
Owner: Neutral
|
||||
Location: 136,-64
|
||||
Actor522: bridge1
|
||||
Owner: Neutral
|
||||
Location: 137,-64
|
||||
Actor523: bridge1
|
||||
Owner: Neutral
|
||||
Location: 137,-64
|
||||
Actor524: bridge1
|
||||
Owner: Neutral
|
||||
Location: 138,-64
|
||||
Actor525: bridge1
|
||||
Owner: Neutral
|
||||
Location: 139,-64
|
||||
Actor526: bridge1
|
||||
Owner: Neutral
|
||||
Location: 179,-68
|
||||
Actor527: bridge1
|
||||
Owner: Neutral
|
||||
Location: 180,-68
|
||||
Actor528: bridge1
|
||||
Owner: Neutral
|
||||
Location: 181,-68
|
||||
Actor529: bridge1
|
||||
Owner: Neutral
|
||||
Location: 182,-68
|
||||
|
||||
Rules:
|
||||
World:
|
||||
GlobalLightingPaletteEffect:
|
||||
Ambient: 0.75
|
||||
ElevatedBridgeLayer:
|
||||
ElevatedBridgePlaceholder@a:
|
||||
Location: 62, 12
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 23
|
||||
ElevatedBridgePlaceholder@b:
|
||||
Location: 93, 36
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 24
|
||||
ElevatedBridgePlaceholder@c:
|
||||
Location: 122, 46
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 23
|
||||
ElevatedBridgePlaceholder@d:
|
||||
Location: 128, 27
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 21
|
||||
ElevatedBridgePlaceholder@e:
|
||||
Location: 113, -7
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 20
|
||||
ElevatedBridgePlaceholder@f:
|
||||
Location: 132, -12
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 12
|
||||
ElevatedBridgePlaceholder@g:
|
||||
Location: 152, -40
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 13
|
||||
ElevatedBridgePlaceholder@h:
|
||||
Location: 142, -40
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 13
|
||||
ElevatedBridgePlaceholder@i:
|
||||
Location: 128, -63
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 15
|
||||
ElevatedBridgePlaceholder@j:
|
||||
Location: 160, -91
|
||||
Height: 6
|
||||
Orientation: Y
|
||||
Length: 21
|
||||
ElevatedBridgePlaceholder@k:
|
||||
Location: 175, -69
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 10
|
||||
ElevatedBridgePlaceholder@l:
|
||||
Location: 183, -33
|
||||
Height: 6
|
||||
Orientation: X
|
||||
Length: 15
|
||||
@@ -152,3 +152,34 @@ LOBRDG_R_SW:
|
||||
NeighbourOffsets: 1,-1
|
||||
EditorOnlyTooltip:
|
||||
Name: Bridge Ramp
|
||||
|
||||
^ElevatedBridgePlaceholder:
|
||||
AlwaysVisible:
|
||||
RenderSprites:
|
||||
Palette: terraindecoration
|
||||
WithSpriteBody:
|
||||
AutoSelectionSize:
|
||||
AppearsOnRadar:
|
||||
RadarColorFromTerrain:
|
||||
Terrain: Bridge
|
||||
BodyOrientation:
|
||||
UseClassicPerspectiveFudge: false
|
||||
QuantizedFacings: 1
|
||||
Tooltip:
|
||||
Name: Bridge
|
||||
Immobile:
|
||||
OccupiesSpace: false
|
||||
CustomSelectionSize:
|
||||
CustomBounds: 96, 144
|
||||
|
||||
BRIDGE1:
|
||||
Inherits: ^ElevatedBridgePlaceholder
|
||||
|
||||
BRIDGE2:
|
||||
Inherits: ^ElevatedBridgePlaceholder
|
||||
|
||||
RAILBRDG1:
|
||||
Inherits: ^ElevatedBridgePlaceholder
|
||||
|
||||
RAILBRDG2:
|
||||
Inherits: ^ElevatedBridgePlaceholder
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
RevealsShroud:
|
||||
Range: 6c0
|
||||
MaxHeightDelta: 3
|
||||
RequiresCondition: !inside-tunnel
|
||||
Turreted:
|
||||
TurnSpeed: 3
|
||||
Armament@PRIMARY:
|
||||
@@ -50,6 +51,7 @@
|
||||
Mobile:
|
||||
Speed: 56
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
|
||||
@@ -73,6 +75,7 @@ ICBM:
|
||||
Speed: 85
|
||||
TurnSpeed: 5
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 7c0
|
||||
MaxHeightDelta: 3
|
||||
Transforms:
|
||||
@@ -98,6 +101,7 @@ BUS:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Cargo:
|
||||
@@ -123,6 +127,7 @@ PICK:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Cargo:
|
||||
@@ -148,6 +153,7 @@ CAR:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Cargo:
|
||||
@@ -173,6 +179,7 @@ WINI:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Cargo:
|
||||
|
||||
@@ -279,6 +279,7 @@
|
||||
Valued:
|
||||
Cost: 10
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 2c0
|
||||
MaxHeightDelta: 3
|
||||
Mobile:
|
||||
@@ -298,6 +299,7 @@
|
||||
BlueTiberium: 90
|
||||
PathingCost: 90
|
||||
Veins: 50
|
||||
TunnelCondition: inside-tunnel
|
||||
WithTextControlGroupDecoration:
|
||||
SelectionDecorations:
|
||||
Palette: pips
|
||||
@@ -306,6 +308,7 @@
|
||||
Voiced:
|
||||
VoiceSet: Infantry
|
||||
Targetable:
|
||||
RequiresCondition: !inside-tunnel
|
||||
TargetTypes: Ground, Infantry
|
||||
QuantizeFacingsFromSequence:
|
||||
Sequence: stand
|
||||
@@ -471,6 +474,7 @@
|
||||
TurnSpeed: 5
|
||||
Voice: Move
|
||||
RequiresCondition: !empdisable
|
||||
TunnelCondition: inside-tunnel
|
||||
Selectable:
|
||||
Bounds: 40,24
|
||||
WithTextControlGroupDecoration:
|
||||
@@ -479,6 +483,7 @@
|
||||
Voiced:
|
||||
VoiceSet: Vehicle
|
||||
Targetable:
|
||||
RequiresCondition: !inside-tunnel
|
||||
TargetTypes: Ground, Vehicle, Repair
|
||||
Repairable:
|
||||
RepairBuildings: gadept
|
||||
@@ -521,6 +526,7 @@
|
||||
RequiresCondition: criticalspeed
|
||||
Modifier: 60
|
||||
Carryable:
|
||||
RequiresCondition: !inside-tunnel
|
||||
RevealOnFire:
|
||||
|
||||
^Tank:
|
||||
@@ -770,6 +776,7 @@
|
||||
Voice: Move
|
||||
Speed: 113
|
||||
RequiresCondition: !empdisable
|
||||
TunnelCondition: inside-tunnel
|
||||
Cargo:
|
||||
Types: Infantry
|
||||
UnloadVoice: Unload
|
||||
@@ -780,6 +787,7 @@
|
||||
RevealsShroud:
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
RequiresCondition: !inside-tunnel
|
||||
Selectable:
|
||||
Bounds: 40,24
|
||||
WithTextControlGroupDecoration:
|
||||
|
||||
@@ -77,6 +77,11 @@ JUMPJET:
|
||||
VoiceSet: JumpJet
|
||||
Mobile:
|
||||
Speed: 56
|
||||
Jumpjet: True
|
||||
JumpjetTransitionCost: 100
|
||||
JumpjetCondition: airborne
|
||||
TerrainSpeeds:
|
||||
Jumpjet: 110
|
||||
Health:
|
||||
HP: 120
|
||||
Armor:
|
||||
@@ -91,10 +96,71 @@ JUMPJET:
|
||||
AttackFrontal:
|
||||
Voice: Attack
|
||||
WithInfantryBody:
|
||||
RequiresCondition: !airborne
|
||||
DefaultAttackSequence: attack
|
||||
WithInfantryBody@flying:
|
||||
RequiresCondition: airborne
|
||||
DefaultAttackSequence: flying-attack
|
||||
StandSequences: flying
|
||||
MoveSequence: flying
|
||||
-TakeCover:
|
||||
Hovers:
|
||||
RequiresCondition: airborne
|
||||
ProducibleWithLevel:
|
||||
Prerequisites: barracks.upgraded
|
||||
Targetable:
|
||||
RequiresCondition: !airborne && !inside-tunnel
|
||||
Targetable@AIRBORNE:
|
||||
TargetTypes: Air
|
||||
RequiresCondition: airborne
|
||||
SpawnActorOnDeath@airborne:
|
||||
Actor: JUMPJET.Husk
|
||||
RequiresCondition: airborne
|
||||
DeathSounds@airborne:
|
||||
RequiresCondition: airborne
|
||||
WithDeathAnimation@normal:
|
||||
RequiresCondition: !airborne
|
||||
WithDeathAnimation@explosion:
|
||||
RequiresCondition: !airborne
|
||||
WithDeathAnimation@energy:
|
||||
RequiresCondition: !airborne
|
||||
WithDeathAnimation:
|
||||
RequiresCondition: !airborne
|
||||
DeathSounds@NORMAL:
|
||||
RequiresCondition: !airborne
|
||||
DeathSounds@EXPLOSION:
|
||||
RequiresCondition: !airborne
|
||||
DeathSounds@BURNED:
|
||||
RequiresCondition: !airborne
|
||||
DeathSounds@ZAPPED:
|
||||
RequiresCondition: !airborne
|
||||
SpawnActorOnDeath:
|
||||
RequiresCondition: !airborne
|
||||
SpawnActorOnDeath@FLAMEGUY:
|
||||
RequiresCondition: !airborne
|
||||
|
||||
JUMPJET.Husk:
|
||||
RenderSprites:
|
||||
BodyOrientation:
|
||||
QuantizedFacings: 1
|
||||
Aircraft:
|
||||
HiddenUnderFog:
|
||||
Type: GroundPosition
|
||||
AutoTargetIgnore:
|
||||
ScriptTriggers:
|
||||
Tooltip:
|
||||
Name: Jumpjet Infantry
|
||||
FallsToEarth:
|
||||
Velocity: 86
|
||||
Explosion:
|
||||
Aircraft:
|
||||
Speed: 186
|
||||
CanHover: True
|
||||
RenderSprites:
|
||||
Image: jumpjet
|
||||
AutoSelectionSize:
|
||||
WithSpriteBody:
|
||||
Sequence: die-falling
|
||||
|
||||
GHOST:
|
||||
Inherits: ^Soldier
|
||||
|
||||
@@ -21,6 +21,7 @@ APC:
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Turreted:
|
||||
@@ -41,6 +42,7 @@ APC:
|
||||
Sequence: water
|
||||
RequiresCondition: inwater
|
||||
LeavesTrails:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Image: wake
|
||||
Palette: effect
|
||||
TerrainTypes: Water
|
||||
@@ -78,6 +80,7 @@ HVR:
|
||||
Armor:
|
||||
Type: Wood
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 7c0
|
||||
MaxHeightDelta: 3
|
||||
Armament:
|
||||
@@ -92,6 +95,7 @@ HVR:
|
||||
WithVoxelTurret:
|
||||
Hovers:
|
||||
LeavesTrails:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Image: wake
|
||||
Palette: effect
|
||||
TerrainTypes: Water
|
||||
@@ -121,6 +125,7 @@ SMECH:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 6c0
|
||||
MaxHeightDelta: 3
|
||||
AttackFrontal:
|
||||
@@ -164,6 +169,7 @@ MMCH:
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 8c0
|
||||
MaxHeightDelta: 3
|
||||
BodyOrientation:
|
||||
@@ -216,6 +222,7 @@ HMEC:
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 8c0
|
||||
MaxHeightDelta: 3
|
||||
AttackFrontal:
|
||||
@@ -259,6 +266,7 @@ SONIC:
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 7c0
|
||||
MaxHeightDelta: 3
|
||||
Armament:
|
||||
|
||||
@@ -19,6 +19,7 @@ BGGY:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 6c0
|
||||
MaxHeightDelta: 3
|
||||
Armament:
|
||||
@@ -54,6 +55,7 @@ BIKE:
|
||||
Armor:
|
||||
Type: Wood
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Armament@PRIMARY:
|
||||
@@ -107,6 +109,7 @@ TTNK:
|
||||
MuzzleSequence: muzzle
|
||||
WithMuzzleOverlay:
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
RenderSprites:
|
||||
@@ -188,6 +191,7 @@ ART2:
|
||||
Speed: 71
|
||||
TurnSpeed: 2
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 9c0
|
||||
MaxHeightDelta: 3
|
||||
RenderVoxels:
|
||||
@@ -217,6 +221,7 @@ REPAIR:
|
||||
Speed: 85
|
||||
TurnSpeed: 5
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Armament:
|
||||
@@ -262,6 +267,7 @@ WEED:
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 4c0
|
||||
MaxHeightDelta: 3
|
||||
-WithVoxelBody:
|
||||
@@ -285,11 +291,21 @@ SAPC:
|
||||
TurnSpeed: 5
|
||||
Speed: 71
|
||||
RequiresCondition: !empdisable && !loading
|
||||
Subterranean: true
|
||||
SubterraneanCondition: submerged
|
||||
SubterraneanTransitionTerrainTypes: Clear, Rough
|
||||
SubterraneanTransitionCost: 120
|
||||
SubterraneanTransitionSound: subdril1.aud
|
||||
SubterraneanTransitionImage: dig
|
||||
SubterraneanTransitionSequence: idle
|
||||
TerrainSpeeds:
|
||||
Subterranean: 120
|
||||
Health:
|
||||
HP: 175
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel && !submerged
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Cargo:
|
||||
@@ -299,6 +315,10 @@ SAPC:
|
||||
UnloadVoice: Unload
|
||||
LoadingCondition: loading
|
||||
EjectOnDeath: true
|
||||
WithVoxelBody:
|
||||
RequiresCondition: !submerged
|
||||
Targetable:
|
||||
RequiresCondition: !inside-tunnel && !submerged
|
||||
|
||||
SUBTANK:
|
||||
Inherits: ^Tank
|
||||
@@ -317,11 +337,21 @@ SUBTANK:
|
||||
TurnSpeed: 6
|
||||
Speed: 71
|
||||
Crushes: wall, crate, infantry
|
||||
Subterranean: true
|
||||
SubterraneanCondition: submerged
|
||||
SubterraneanTransitionTerrainTypes: Clear, Rough
|
||||
SubterraneanTransitionCost: 120
|
||||
SubterraneanTransitionSound: subdril1.aud
|
||||
SubterraneanTransitionImage: dig
|
||||
SubterraneanTransitionSequence: idle
|
||||
TerrainSpeeds:
|
||||
Subterranean: 120
|
||||
Health:
|
||||
HP: 300
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel && !submerged
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Armament:
|
||||
@@ -329,6 +359,10 @@ SUBTANK:
|
||||
AttackFrontal:
|
||||
Voice: Attack
|
||||
AutoTarget:
|
||||
WithVoxelBody:
|
||||
RequiresCondition: !submerged
|
||||
Targetable:
|
||||
RequiresCondition: !inside-tunnel && !submerged
|
||||
|
||||
STNK:
|
||||
Inherits: ^Tank
|
||||
@@ -352,6 +386,7 @@ STNK:
|
||||
Armor:
|
||||
Type: Light
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 5c0
|
||||
MaxHeightDelta: 3
|
||||
Cloak:
|
||||
|
||||
@@ -19,6 +19,7 @@ MCV:
|
||||
Mobile:
|
||||
Speed: 85
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 4c0
|
||||
MaxHeightDelta: 3
|
||||
MustBeDestroyed:
|
||||
@@ -84,6 +85,7 @@ HARV:
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 4c0
|
||||
MaxHeightDelta: 3
|
||||
-WithVoxelBody:
|
||||
@@ -129,6 +131,7 @@ LPST:
|
||||
TurnSpeed: 5
|
||||
RequiresCondition: !empdisable && undeployed
|
||||
RevealsShroud:
|
||||
RequiresCondition: !inside-tunnel
|
||||
Range: 7c0
|
||||
MaxHeightDelta: 3
|
||||
GrantCondition@PREVIEWWORKAROUND:
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
TerrainGeometryOverlay:
|
||||
ExitsDebugOverlayManager:
|
||||
CliffBackImpassabilityLayer:
|
||||
SubterraneanActorLayer:
|
||||
JumpjetActorLayer:
|
||||
|
||||
World:
|
||||
Inherits: ^BaseWorld
|
||||
|
||||
@@ -62,3 +62,36 @@ lobrdg_r_sw:
|
||||
idle: lobrdg25
|
||||
damaged-idle: lobrdg26
|
||||
|
||||
bridge1:
|
||||
idle: bridge
|
||||
# Disabled to avoid glitches until shadow rendering is fixed
|
||||
# ShadowStart: 18
|
||||
UseTilesetExtension: true
|
||||
ZRamp: 1
|
||||
Offset: 0, -13, 3.5
|
||||
|
||||
bridge2:
|
||||
idle: bridge
|
||||
Start: 9
|
||||
# Disabled to avoid glitches until shadow rendering is fixed
|
||||
# ShadowStart: 27
|
||||
UseTilesetExtension: true
|
||||
ZRamp: 1
|
||||
Offset: 0, -25, 3.5
|
||||
|
||||
railbrdg1:
|
||||
idle: railbrdg
|
||||
# Disabled to avoid glitches until shadow rendering is fixed
|
||||
# ShadowStart: 18
|
||||
UseTilesetExtension: true
|
||||
ZRamp: 1
|
||||
Offset: 0, -13, 3.5
|
||||
|
||||
railbrdg2:
|
||||
idle: railbrdg
|
||||
Start: 9
|
||||
# Disabled to avoid glitches until shadow rendering is fixed
|
||||
# ShadowStart: 27
|
||||
UseTilesetExtension: true
|
||||
ZRamp: 1
|
||||
Offset: 0, -25, 3.5
|
||||
|
||||
@@ -359,10 +359,18 @@ jumpjet:
|
||||
prone-stand:
|
||||
Facings: 8
|
||||
ShadowStart: 451
|
||||
flying:
|
||||
Facings: 8
|
||||
Length: 6
|
||||
Start: 292
|
||||
ShadowStart: 743
|
||||
die-twirling: # TODO: animation for falling from sky starts at 436
|
||||
Start: 445
|
||||
Length: 6
|
||||
ShadowStart: 896
|
||||
die-falling:
|
||||
Start: 436
|
||||
Length: 9
|
||||
die-flying: # TODO: animation for falling from sky starts at 436
|
||||
Start: 445
|
||||
Length: 6
|
||||
@@ -379,6 +387,11 @@ jumpjet:
|
||||
Length: 6
|
||||
Facings: 8
|
||||
ShadowStart: 615
|
||||
flying-attack:
|
||||
Start: 388
|
||||
Facings: 8
|
||||
Length: 6
|
||||
ShadowStart: 839
|
||||
prone-attack:
|
||||
Start: 212
|
||||
Length: 6
|
||||
|
||||
@@ -616,7 +616,9 @@ tracks16:
|
||||
Offset: 0, -13, 42
|
||||
ZRamp: 1
|
||||
UseTilesetExtension: true
|
||||
ShadowStart: 1
|
||||
# Disabled to avoid glitches until shadow rendering is fixed
|
||||
# Appears to be unused in the original game too
|
||||
# ShadowStart: 1
|
||||
|
||||
tuntop01:
|
||||
Inherits: ^tuntop
|
||||
@@ -629,3 +631,9 @@ tuntop03:
|
||||
|
||||
tuntop04:
|
||||
Inherits: ^tuntop
|
||||
|
||||
dig:
|
||||
idle:
|
||||
Length: *
|
||||
ZOffset: 511
|
||||
Offset: 0, 0, 24
|
||||
@@ -72,6 +72,12 @@ Terrain:
|
||||
Type: Rock
|
||||
TargetTypes: Ground
|
||||
Color: 44443C
|
||||
TerrainType@Subterranean:
|
||||
Type: Subterranean
|
||||
Color: C7C9FA
|
||||
TerrainType@Jumpjet:
|
||||
Type: Jumpjet
|
||||
Color: C7C9FA
|
||||
|
||||
# Automatically generated. DO NOT EDIT!
|
||||
Templates:
|
||||
@@ -7580,7 +7586,7 @@ Templates:
|
||||
Template@296:
|
||||
Category: Bridges
|
||||
Id: 296
|
||||
Images: ovrps01.sno, ovrps01a.sno
|
||||
Images: ovrps01.sno
|
||||
Size: 3, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -7669,7 +7675,7 @@ Templates:
|
||||
Template@297:
|
||||
Category: Bridges
|
||||
Id: 297
|
||||
Images: ovrps02.sno, ovrps02a.sno
|
||||
Images: ovrps02.sno
|
||||
Size: 3, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -7758,7 +7764,7 @@ Templates:
|
||||
Template@298:
|
||||
Category: Bridges
|
||||
Id: 298
|
||||
Images: ovrps03.sno, ovrps03a.sno
|
||||
Images: ovrps03.sno
|
||||
Size: 2, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -7822,7 +7828,7 @@ Templates:
|
||||
Template@299:
|
||||
Category: Bridges
|
||||
Id: 299
|
||||
Images: ovrps04.sno, ovrps04a.sno
|
||||
Images: ovrps04.sno
|
||||
Size: 5, 3
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -7911,7 +7917,7 @@ Templates:
|
||||
Template@300:
|
||||
Category: Bridges
|
||||
Id: 300
|
||||
Images: ovrps05.sno, ovrps05a.sno
|
||||
Images: ovrps05.sno
|
||||
Size: 5, 3
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -8000,7 +8006,7 @@ Templates:
|
||||
Template@301:
|
||||
Category: Bridges
|
||||
Id: 301
|
||||
Images: ovrps06.sno, ovrps06a.sno
|
||||
Images: ovrps06.sno
|
||||
Size: 5, 2
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -14328,7 +14334,7 @@ Templates:
|
||||
Template@695:
|
||||
Category: TrainBridges
|
||||
Id: 695
|
||||
Images: tovrps01.sno, tovrps01a.sno
|
||||
Images: tovrps01.sno
|
||||
Size: 3, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -14417,7 +14423,7 @@ Templates:
|
||||
Template@696:
|
||||
Category: TrainBridges
|
||||
Id: 696
|
||||
Images: tovrps02.sno, tovrps02a.sno
|
||||
Images: tovrps02.sno
|
||||
Size: 3, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -14506,7 +14512,7 @@ Templates:
|
||||
Template@697:
|
||||
Category: TrainBridges
|
||||
Id: 697
|
||||
Images: tovrps03.sno, tovrps03a.sno
|
||||
Images: tovrps03.sno
|
||||
Size: 2, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -14570,7 +14576,7 @@ Templates:
|
||||
Template@698:
|
||||
Category: TrainBridges
|
||||
Id: 698
|
||||
Images: tovrps04.sno, tovrps04a.sno
|
||||
Images: tovrps04.sno
|
||||
Size: 5, 3
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -14659,7 +14665,7 @@ Templates:
|
||||
Template@699:
|
||||
Category: TrainBridges
|
||||
Id: 699
|
||||
Images: tovrps05.sno, tovrps05a.sno
|
||||
Images: tovrps05.sno
|
||||
Size: 5, 3
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -14748,7 +14754,7 @@ Templates:
|
||||
Template@700:
|
||||
Category: TrainBridges
|
||||
Id: 700
|
||||
Images: tovrps06.sno, tovrps06a.sno
|
||||
Images: tovrps06.sno
|
||||
Size: 5, 2
|
||||
Tiles:
|
||||
0: Cliff
|
||||
|
||||
@@ -72,6 +72,12 @@ Terrain:
|
||||
Type: Rock
|
||||
TargetTypes: Ground
|
||||
Color: 44443C
|
||||
TerrainType@Subterranean:
|
||||
Type: Subterranean
|
||||
Color: 745537
|
||||
TerrainType@Jumpjet:
|
||||
Type: Jumpjet
|
||||
Color: 745537
|
||||
|
||||
# Automatically generated. DO NOT EDIT!
|
||||
Templates:
|
||||
@@ -7580,7 +7586,7 @@ Templates:
|
||||
Template@296:
|
||||
Category: Bridges
|
||||
Id: 296
|
||||
Images: ovrps01.tem, ovrps01a.tem
|
||||
Images: ovrps01.tem
|
||||
Size: 3, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -7669,7 +7675,7 @@ Templates:
|
||||
Template@297:
|
||||
Category: Bridges
|
||||
Id: 297
|
||||
Images: ovrps02.tem, ovrps02a.tem
|
||||
Images: ovrps02.tem
|
||||
Size: 3, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -7758,7 +7764,7 @@ Templates:
|
||||
Template@298:
|
||||
Category: Bridges
|
||||
Id: 298
|
||||
Images: ovrps03.tem, ovrps03a.tem
|
||||
Images: ovrps03.tem
|
||||
Size: 2, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -7822,7 +7828,7 @@ Templates:
|
||||
Template@299:
|
||||
Category: Bridges
|
||||
Id: 299
|
||||
Images: ovrps04.tem, ovrps04a.tem
|
||||
Images: ovrps04.tem
|
||||
Size: 5, 3
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -7911,7 +7917,7 @@ Templates:
|
||||
Template@300:
|
||||
Category: Bridges
|
||||
Id: 300
|
||||
Images: ovrps05.tem, ovrps05a.tem
|
||||
Images: ovrps05.tem
|
||||
Size: 5, 3
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -8000,7 +8006,7 @@ Templates:
|
||||
Template@301:
|
||||
Category: Bridges
|
||||
Id: 301
|
||||
Images: ovrps06.tem, ovrps06a.tem
|
||||
Images: ovrps06.tem
|
||||
Size: 5, 2
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -13365,7 +13371,7 @@ Templates:
|
||||
Template@566:
|
||||
Category: TrainBridges
|
||||
Id: 566
|
||||
Images: tovrps01.tem, tovrps01a.tem
|
||||
Images: tovrps01.tem
|
||||
Size: 3, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -13454,7 +13460,7 @@ Templates:
|
||||
Template@567:
|
||||
Category: TrainBridges
|
||||
Id: 567
|
||||
Images: tovrps02.tem, tovrps02a.tem
|
||||
Images: tovrps02.tem
|
||||
Size: 3, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -13543,7 +13549,7 @@ Templates:
|
||||
Template@568:
|
||||
Category: TrainBridges
|
||||
Id: 568
|
||||
Images: tovrps03.tem, tovrps03a.tem
|
||||
Images: tovrps03.tem
|
||||
Size: 2, 5
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -13607,7 +13613,7 @@ Templates:
|
||||
Template@569:
|
||||
Category: TrainBridges
|
||||
Id: 569
|
||||
Images: tovrps04.tem, tovrps04a.tem
|
||||
Images: tovrps04.tem
|
||||
Size: 5, 3
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -13696,7 +13702,7 @@ Templates:
|
||||
Template@570:
|
||||
Category: TrainBridges
|
||||
Id: 570
|
||||
Images: tovrps05.tem, tovrps05a.tem
|
||||
Images: tovrps05.tem
|
||||
Size: 5, 3
|
||||
Tiles:
|
||||
0: Cliff
|
||||
@@ -13785,7 +13791,7 @@ Templates:
|
||||
Template@571:
|
||||
Category: TrainBridges
|
||||
Id: 571
|
||||
Images: tovrps06.tem, tovrps06a.tem
|
||||
Images: tovrps06.tem
|
||||
Size: 5, 2
|
||||
Tiles:
|
||||
0: Cliff
|
||||
|
||||
Reference in New Issue
Block a user