Merge pull request #6100 from atlimit8/Implement6086

Closes #6086
This commit is contained in:
Matthias Mailänder
2014-08-05 06:36:11 +02:00
17 changed files with 110 additions and 79 deletions

View File

@@ -37,6 +37,20 @@ namespace OpenRA
public readonly Size TileSize = new Size(24, 24); public readonly Size TileSize = new Size(24, 24);
public readonly TileShape TileShape = TileShape.Rectangle; public readonly TileShape TileShape = TileShape.Rectangle;
[Desc("(x,y,z) offset of the full cell and each sub-cell", "X & Y should be between -512 ... 512 and Z >= 0")]
public readonly WVec[] SubCellOffsets =
{
new WVec(0, 0, 0), // full cell - index 0
new WVec(-299, -256, 0), // top left - index 1
new WVec(256, -256, 0), // top right - index 2
new WVec(0, 0, 0), // center - index 3
new WVec(-299, 256, 0), // bottom left - index 4
new WVec(256, 256, 0), // bottom right - index 5
};
[Desc("Default subcell index used if SubCellInit is absent", "0 - full cell, 1 - first sub-cell")]
public readonly int SubCellDefaultIndex = 3;
public Manifest(string mod) public Manifest(string mod)
{ {
var path = new[] { "mods", mod, "mod.yaml" }.Aggregate(Path.Combine); var path = new[] { "mods", mod, "mod.yaml" }.Aggregate(Path.Combine);
@@ -87,6 +101,24 @@ namespace OpenRA
if (yaml.ContainsKey("TileShape")) if (yaml.ContainsKey("TileShape"))
TileShape = FieldLoader.GetValue<TileShape>("TileShape", yaml["TileShape"].Value); TileShape = FieldLoader.GetValue<TileShape>("TileShape", yaml["TileShape"].Value);
if (yaml.ContainsKey("SubCells"))
{
var subcells = yaml["SubCells"].ToDictionary();
// Read (x,y,z) offset (relative to cell center) pairs for positioning subcells
if (subcells.ContainsKey("Offsets"))
SubCellOffsets = FieldLoader.GetValue<WVec[]>("Offsets", subcells["Offsets"].Value);
if (subcells.ContainsKey("DefaultIndex"))
SubCellDefaultIndex = FieldLoader.GetValue<int>("DefaultIndex", subcells["DefaultIndex"].Value);
else // Otherwise set the default subcell index to the middle subcell entry
SubCellDefaultIndex = SubCellOffsets.Length / 2;
}
// Validate default index - 0 for no subcells, otherwise > 1 & <= subcell count (offset triples count - 1)
if (SubCellDefaultIndex < (SubCellOffsets.Length > 1 ? 1 : 0) || SubCellDefaultIndex >= SubCellOffsets.Length)
throw new InvalidDataException("Subcell default index must be a valid index into the offset triples and must be greater than 0 for mods with subcells");
// Allow inherited mods to import parent maps. // Allow inherited mods to import parent maps.
var compat = new List<string>(); var compat = new List<string>();
compat.Add(mod); compat.Add(mod);

View File

@@ -63,13 +63,12 @@ namespace OpenRA
public CPos Value(World world) { return value; } public CPos Value(World world) { return value; }
} }
public class SubCellInit : IActorInit<SubCell> public class SubCellInit : IActorInit<int>
{ {
[FieldFromYamlKey] public readonly int value = 0; [FieldFromYamlKey] public readonly int value = 0;
public SubCellInit() { } public SubCellInit() { }
public SubCellInit(int init) { value = init; } public SubCellInit(int init) { value = init; }
public SubCellInit(SubCell init) { value = (int)init; } public int Value(World world) { return value; }
public SubCell Value(World world) { return (SubCell)value; }
} }
public class CenterPositionInit : IActorInit<WPos> public class CenterPositionInit : IActorInit<WPos>

View File

@@ -77,6 +77,9 @@ namespace OpenRA
public Bitmap CustomPreview; public Bitmap CustomPreview;
public readonly TileShape TileShape; public readonly TileShape TileShape;
[FieldLoader.Ignore]
public readonly WVec[] SubCellOffsets;
public readonly int SubCellDefaultIndex;
[FieldLoader.LoadUsing("LoadOptions")] [FieldLoader.LoadUsing("LoadOptions")]
public MapOptions Options; public MapOptions Options;
@@ -246,6 +249,8 @@ namespace OpenRA
MapTiles = Exts.Lazy(() => LoadMapTiles()); MapTiles = Exts.Lazy(() => LoadMapTiles());
MapResources = Exts.Lazy(() => LoadResourceTiles()); MapResources = Exts.Lazy(() => LoadResourceTiles());
TileShape = Game.modData.Manifest.TileShape; TileShape = Game.modData.Manifest.TileShape;
SubCellOffsets = Game.modData.Manifest.SubCellOffsets;
SubCellDefaultIndex = Game.modData.Manifest.SubCellDefaultIndex;
// The Uid is calculated from the data on-disk, so // The Uid is calculated from the data on-disk, so
// format changes must be flushed to disk. // format changes must be flushed to disk.

View File

@@ -126,7 +126,7 @@ namespace OpenRA.Traits
{ {
WPos CenterPosition { get; } WPos CenterPosition { get; }
CPos TopLeft { get; } CPos TopLeft { get; }
IEnumerable<Pair<CPos, SubCell>> OccupiedCells(); IEnumerable<Pair<CPos, int>> OccupiedCells();
} }
public static class IOccupySpaceExts public static class IOccupySpaceExts

View File

@@ -29,16 +29,10 @@ namespace OpenRA.Traits
class InfluenceNode class InfluenceNode
{ {
public InfluenceNode Next; public InfluenceNode Next;
public SubCell SubCell; public int SubCell;
public Actor Actor; public Actor Actor;
} }
static readonly SubCell[] SubCells =
{
SubCell.TopLeft, SubCell.TopRight, SubCell.Center,
SubCell.BottomLeft, SubCell.BottomRight
};
readonly ActorMapInfo info; readonly ActorMapInfo info;
readonly Map map; readonly Map map;
readonly CellLayer<InfluenceNode> influence; readonly CellLayer<InfluenceNode> influence;
@@ -79,30 +73,30 @@ namespace OpenRA.Traits
yield return i.Actor; yield return i.Actor;
} }
public IEnumerable<Actor> GetUnitsAt(CPos a, SubCell sub) public IEnumerable<Actor> GetUnitsAt(CPos a, int sub)
{ {
if (!map.Contains(a)) if (!map.Contains(a))
yield break; yield break;
for (var i = influence[a]; i != null; i = i.Next) for (var i = influence[a]; i != null; i = i.Next)
if (!i.Actor.Destroyed && (i.SubCell == sub || i.SubCell == SubCell.FullCell)) if (!i.Actor.Destroyed && (i.SubCell == sub || i.SubCell == 0))
yield return i.Actor; yield return i.Actor;
} }
public bool HasFreeSubCell(CPos a) public bool HasFreeSubCell(CPos a)
{ {
if (!AnyUnitsAt(a)) return FreeSubCell(a) >= 0;
return true;
return SubCells.Any(b => !AnyUnitsAt(a, b));
} }
public SubCell? FreeSubCell(CPos a) public int FreeSubCell(CPos a)
{ {
if (!HasFreeSubCell(a)) if (!AnyUnitsAt(a))
return null; return map.SubCellDefaultIndex;
return SubCells.First(b => !AnyUnitsAt(a, b)); for (var i = 1; i < map.SubCellOffsets.Length; i++)
if (!AnyUnitsAt(a, i))
return i;
return -1;
} }
public bool AnyUnitsAt(CPos a) public bool AnyUnitsAt(CPos a)
@@ -110,10 +104,10 @@ namespace OpenRA.Traits
return influence[a] != null; return influence[a] != null;
} }
public bool AnyUnitsAt(CPos a, SubCell sub) public bool AnyUnitsAt(CPos a, int sub)
{ {
for (var i = influence[a]; i != null; i = i.Next) for (var i = influence[a]; i != null; i = i.Next)
if (i.SubCell == sub || i.SubCell == SubCell.FullCell) if (i.SubCell == sub || i.SubCell == 0)
return true; return true;
return false; return false;

View File

@@ -41,7 +41,7 @@ namespace OpenRA.Mods.RA.Activities
mobile.IsMoving = true; mobile.IsMoving = true;
from = self.CenterPosition; from = self.CenterPosition;
to = self.World.Map.CenterOfCell(targetMobile.fromCell) + MobileInfo.SubCellOffsets[targetMobile.fromSubCell]; to = self.World.Map.CenterOfCell(targetMobile.fromCell) + self.World.Map.SubCellOffsets[targetMobile.fromSubCell];
length = Math.Max((to - from).Length / speed.Range, 1); length = Math.Max((to - from).Length / speed.Range, 1);
self.Trait<RenderInfantry>().Attacking(self, Target.FromActor(target)); self.Trait<RenderInfantry>().Attacking(self, Target.FromActor(target));

View File

@@ -63,7 +63,7 @@ namespace OpenRA.Mods.RA.Activities
var exitCell = ChooseExitCell(actor); var exitCell = ChooseExitCell(actor);
if (exitCell == null) if (exitCell == null)
{ {
foreach (var blocker in BlockedExitCells(actor).SelectMany(self.World.ActorMap.GetUnitsAt)) foreach (var blocker in BlockedExitCells(actor).SelectMany(p => self.World.ActorMap.GetUnitsAt(p)))
{ {
foreach (var nbm in blocker.TraitsImplementing<INotifyBlockingMove>()) foreach (var nbm in blocker.TraitsImplementing<INotifyBlockingMove>())
nbm.OnNotifyBlockingMove(blocker, self); nbm.OnNotifyBlockingMove(blocker, self);

View File

@@ -46,7 +46,7 @@ namespace OpenRA.Mods.RA.Air
public class Aircraft : IFacing, IPositionable, ISync, INotifyKilled, IIssueOrder, IOrderVoice, INotifyAddedToWorld, INotifyRemovedFromWorld public class Aircraft : IFacing, IPositionable, ISync, INotifyKilled, IIssueOrder, IOrderVoice, INotifyAddedToWorld, INotifyRemovedFromWorld
{ {
static readonly Pair<CPos, SubCell>[] NoCells = { }; static readonly Pair<CPos, int>[] NoCells = { };
readonly AircraftInfo info; readonly AircraftInfo info;
readonly Actor self; readonly Actor self;
@@ -210,7 +210,7 @@ namespace OpenRA.Mods.RA.Air
} }
} }
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { return NoCells; } public IEnumerable<Pair<CPos, int>> OccupiedCells() { return NoCells; }
public WVec FlyStep(int facing) public WVec FlyStep(int facing)
{ {

View File

@@ -133,14 +133,14 @@ namespace OpenRA.Mods.RA.Buildings
this.Info = info; this.Info = info;
occupiedCells = FootprintUtils.UnpathableTiles( self.Info.Name, Info, TopLeft ) occupiedCells = FootprintUtils.UnpathableTiles( self.Info.Name, Info, TopLeft )
.Select(c => Pair.New(c, SubCell.FullCell)).ToArray(); .Select(c => Pair.New(c, 0)).ToArray();
CenterPosition = init.world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(init.world, Info); CenterPosition = init.world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(init.world, Info);
SkipMakeAnimation = init.Contains<SkipMakeAnimsInit>(); SkipMakeAnimation = init.Contains<SkipMakeAnimsInit>();
} }
Pair<CPos, SubCell>[] occupiedCells; Pair<CPos, int>[] occupiedCells;
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { return occupiedCells; } public IEnumerable<Pair<CPos, int>> OccupiedCells() { return occupiedCells; }
public void Created(Actor self) public void Created(Actor self)
{ {

View File

@@ -89,7 +89,7 @@ namespace OpenRA.Mods.RA
} }
public CPos TopLeft { get { return Location; } } public CPos TopLeft { get { return Location; } }
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield return Pair.New(Location, SubCell.FullCell); } public IEnumerable<Pair<CPos, int>> OccupiedCells() { yield return Pair.New(Location, 0); }
public WPos CenterPosition { get; private set; } public WPos CenterPosition { get; private set; }
public void SetPosition(Actor self, WPos pos) { SetPosition(self, self.World.Map.CellContaining(pos)); } public void SetPosition(Actor self, WPos pos) { SetPosition(self, self.World.Map.CellContaining(pos)); }

View File

@@ -52,7 +52,7 @@ namespace OpenRA.Mods.RA
self.QueueActivity(new Drag(CenterPosition, finalPos, distance / speed)); self.QueueActivity(new Drag(CenterPosition, finalPos, distance / speed));
} }
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); } public IEnumerable<Pair<CPos, int>> OccupiedCells() { yield return Pair.New(TopLeft, 0); }
public bool CanEnterCell(CPos cell, Actor ignoreActor, bool checkTransientActors) public bool CanEnterCell(CPos cell, Actor ignoreActor, bool checkTransientActors)
{ {
if (!self.World.Map.Contains(cell)) if (!self.World.Map.Contains(cell))

View File

@@ -24,7 +24,7 @@ namespace OpenRA.Mods.RA
{ {
[Sync] readonly CPos location; [Sync] readonly CPos location;
[Sync] readonly WPos position; [Sync] readonly WPos position;
readonly IEnumerable<Pair<CPos, SubCell>> occupied; readonly IEnumerable<Pair<CPos, int>> occupied;
public Immobile(ActorInitializer init, ImmobileInfo info) public Immobile(ActorInitializer init, ImmobileInfo info)
{ {
@@ -32,14 +32,14 @@ namespace OpenRA.Mods.RA
position = init.world.Map.CenterOfCell(location); position = init.world.Map.CenterOfCell(location);
if (info.OccupiesSpace) if (info.OccupiesSpace)
occupied = new [] { Pair.New(TopLeft, SubCell.FullCell) }; occupied = new [] { Pair.New(TopLeft, 0) };
else else
occupied = new Pair<CPos, SubCell>[0]; occupied = new Pair<CPos, int>[0];
} }
public CPos TopLeft { get { return location; } } public CPos TopLeft { get { return location; } }
public WPos CenterPosition { get { return position; } } public WPos CenterPosition { get { return position; } }
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { return occupied; } public IEnumerable<Pair<CPos, int>> OccupiedCells() { return occupied; }
public void AddedToWorld(Actor self) public void AddedToWorld(Actor self)
{ {

View File

@@ -133,16 +133,6 @@ namespace OpenRA.Mods.RA.Move
return TilesetMovementClass[tileset]; return TilesetMovementClass[tileset];
} }
public static readonly Dictionary<SubCell, WVec> SubCellOffsets = new Dictionary<SubCell, WVec>()
{
{SubCell.TopLeft, new WVec(-299, -256, 0)},
{SubCell.TopRight, new WVec(256, -256, 0)},
{SubCell.Center, new WVec(0, 0, 0)},
{SubCell.BottomLeft, new WVec(-299, 256, 0)},
{SubCell.BottomRight, new WVec(256, 256, 0)},
{SubCell.FullCell, new WVec(0, 0, 0)},
};
static bool IsMovingInMyDirection(Actor self, Actor other) static bool IsMovingInMyDirection(Actor self, Actor other)
{ {
if (!other.IsMoving()) return false; if (!other.IsMoving()) return false;
@@ -208,7 +198,7 @@ namespace OpenRA.Mods.RA.Move
int __facing; int __facing;
CPos __fromCell, __toCell; CPos __fromCell, __toCell;
public SubCell fromSubCell, toSubCell; public int fromSubCell, toSubCell;
//int __altitude; //int __altitude;
@@ -226,7 +216,7 @@ namespace OpenRA.Mods.RA.Move
[Sync] public int PathHash; // written by Move.EvalPath, to temporarily debug this crap. [Sync] public int PathHash; // written by Move.EvalPath, to temporarily debug this crap.
public void SetLocation(CPos from, SubCell fromSub, CPos to, SubCell toSub) public void SetLocation(CPos from, int fromSub, CPos to, int toSub)
{ {
if (fromCell == from && toCell == to && fromSubCell == fromSub && toSubCell == toSub) if (fromCell == from && toCell == to && fromSubCell == fromSub && toSubCell == toSub)
return; return;
@@ -248,16 +238,16 @@ namespace OpenRA.Mods.RA.Move
this.self = init.self; this.self = init.self;
this.Info = info; this.Info = info;
toSubCell = fromSubCell = info.SharesCell ? SubCell.Center : SubCell.FullCell; toSubCell = fromSubCell = info.SharesCell ? init.world.Map.SubCellDefaultIndex : 0;
if (init.Contains<SubCellInit>()) if (init.Contains<SubCellInit>())
{ {
this.fromSubCell = this.toSubCell = init.Get<SubCellInit, SubCell>(); this.fromSubCell = this.toSubCell = init.Get<SubCellInit, int>();
} }
if (init.Contains<LocationInit>()) if (init.Contains<LocationInit>())
{ {
this.__fromCell = this.__toCell = init.Get<LocationInit, CPos>(); this.__fromCell = this.__toCell = init.Get<LocationInit, CPos>();
SetVisualPosition(self, init.world.Map.CenterOfCell(fromCell) + MobileInfo.SubCellOffsets[fromSubCell]); SetVisualPosition(self, init.world.Map.CenterOfCell(fromCell) + self.World.Map.SubCellOffsets[fromSubCell]);
} }
this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing; this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
@@ -271,7 +261,7 @@ namespace OpenRA.Mods.RA.Move
public void SetPosition(Actor self, CPos cell) public void SetPosition(Actor self, CPos cell)
{ {
SetLocation(cell, fromSubCell, cell, fromSubCell); SetLocation(cell, fromSubCell, cell, fromSubCell);
SetVisualPosition(self, self.World.Map.CenterOfCell(fromCell) + MobileInfo.SubCellOffsets[fromSubCell]); SetVisualPosition(self, self.World.Map.CenterOfCell(fromCell) + self.World.Map.SubCellOffsets[fromSubCell]);
FinishedMoving(self); FinishedMoving(self);
} }
@@ -414,7 +404,7 @@ namespace OpenRA.Mods.RA.Move
public CPos TopLeft { get { return toCell; } } public CPos TopLeft { get { return toCell; } }
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() public IEnumerable<Pair<CPos, int>> OccupiedCells()
{ {
if (fromCell == toCell) if (fromCell == toCell)
yield return Pair.New(fromCell, fromSubCell); yield return Pair.New(fromCell, fromSubCell);
@@ -427,28 +417,36 @@ namespace OpenRA.Mods.RA.Move
} }
} }
public SubCell GetDesiredSubcell(CPos a, Actor ignoreActor) bool IsDesiredSubcellNotBlocked(CPos a, int b, Actor ignoreActor)
{
var blockingActors = self.World.ActorMap.GetUnitsAt(a, b).Where(c => c != ignoreActor);
if (blockingActors.Any())
{
// Non-sharable unit can enter a cell with shareable units only if it can crush all of them
if (Info.Crushes == null)
return false;
if (blockingActors.Any(c => !(c.HasTrait<ICrushable>() &&
c.TraitsImplementing<ICrushable>().Any(d => d.CrushableBy(Info.Crushes, self.Owner)))))
return false;
}
return true;
}
public int GetDesiredSubcell(CPos a, Actor ignoreActor)
{ {
if (!Info.SharesCell) if (!Info.SharesCell)
return SubCell.FullCell; return 0;
// Prioritise the current subcell // Prioritise the current subcell
return new[]{ fromSubCell, SubCell.TopLeft, SubCell.TopRight, SubCell.Center, if (IsDesiredSubcellNotBlocked(a, fromSubCell, ignoreActor))
SubCell.BottomLeft, SubCell.BottomRight}.First(b => return fromSubCell;
{
var blockingActors = self.World.ActorMap.GetUnitsAt(a, b).Where(c => c != ignoreActor);
if (blockingActors.Any())
{
// Non-sharable unit can enter a cell with shareable units only if it can crush all of them
if (Info.Crushes == null)
return false;
if (blockingActors.Any(c => !(c.HasTrait<ICrushable>() && for (var i = 1; i < self.World.Map.SubCellOffsets.Length; i++)
c.TraitsImplementing<ICrushable>().Any(d => d.CrushableBy(Info.Crushes, self.Owner))))) if (IsDesiredSubcellNotBlocked(a, i, ignoreActor))
return false; return i;
}
return true; return -1;
});
} }
public bool CanEnterCell(CPos p) public bool CanEnterCell(CPos p)

View File

@@ -150,8 +150,8 @@ namespace OpenRA.Mods.RA.Move
mobile.SetLocation(mobile.fromCell, mobile.fromSubCell, nextCell.Value.First, nextCell.Value.Second); mobile.SetLocation(mobile.fromCell, mobile.fromSubCell, nextCell.Value.First, nextCell.Value.Second);
var move = new MoveFirstHalf( var move = new MoveFirstHalf(
this, this,
self.World.Map.CenterOfCell(mobile.fromCell) + MobileInfo.SubCellOffsets[mobile.fromSubCell], self.World.Map.CenterOfCell(mobile.fromCell) + self.World.Map.SubCellOffsets[mobile.fromSubCell],
Util.BetweenCells(self.World, mobile.fromCell, mobile.toCell) + (MobileInfo.SubCellOffsets[mobile.fromSubCell] + MobileInfo.SubCellOffsets[mobile.toSubCell]) / 2, Util.BetweenCells(self.World, mobile.fromCell, mobile.toCell) + (self.World.Map.SubCellOffsets[mobile.fromSubCell] + self.World.Map.SubCellOffsets[mobile.toSubCell]) / 2,
mobile.Facing, mobile.Facing,
mobile.Facing, mobile.Facing,
0); 0);
@@ -180,7 +180,7 @@ namespace OpenRA.Mods.RA.Move
} }
} }
Pair<CPos, SubCell>? PopPath(Actor self, Mobile mobile) Pair<CPos, int>? PopPath(Actor self, Mobile mobile)
{ {
if (path.Count == 0) if (path.Count == 0)
return null; return null;
@@ -347,15 +347,15 @@ namespace OpenRA.Mods.RA.Move
protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent) protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent)
{ {
var fromSubcellOffset = MobileInfo.SubCellOffsets[mobile.fromSubCell]; var fromSubcellOffset = self.World.Map.SubCellOffsets[mobile.fromSubCell];
var toSubcellOffset = MobileInfo.SubCellOffsets[mobile.toSubCell]; var toSubcellOffset = self.World.Map.SubCellOffsets[mobile.toSubCell];
var nextCell = parent.PopPath(self, mobile); var nextCell = parent.PopPath(self, mobile);
if (nextCell != null) if (nextCell != null)
{ {
if (IsTurn(mobile, nextCell.Value.First)) if (IsTurn(mobile, nextCell.Value.First))
{ {
var nextSubcellOffset = MobileInfo.SubCellOffsets[nextCell.Value.Second]; var nextSubcellOffset = self.World.Map.SubCellOffsets[nextCell.Value.Second];
var ret = new MoveFirstHalf( var ret = new MoveFirstHalf(
move, move,
Util.BetweenCells(self.World, mobile.fromCell, mobile.toCell) + (fromSubcellOffset + toSubcellOffset) / 2, Util.BetweenCells(self.World, mobile.fromCell, mobile.toCell) + (fromSubcellOffset + toSubcellOffset) / 2,

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Mods.RA.Move
} }
} }
public List<CPos> FindUnitPathToRange(CPos src, SubCell srcSub, WPos target, WRange range, Actor self) public List<CPos> FindUnitPathToRange(CPos src, int srcSub, WPos target, WRange range, Actor self)
{ {
using (new PerfSample("Pathfinder")) using (new PerfSample("Pathfinder"))
{ {
@@ -89,7 +89,7 @@ namespace OpenRA.Mods.RA.Move
var rangeSquared = range.Range*range.Range; var rangeSquared = range.Range*range.Range;
// Correct for SubCell offset // Correct for SubCell offset
target -= MobileInfo.SubCellOffsets[srcSub]; target -= self.World.Map.SubCellOffsets[srcSub];
// Select only the tiles that are within range from the requested SubCell // Select only the tiles that are within range from the requested SubCell
// This assumes that the SubCell does not change during the path traversal // This assumes that the SubCell does not change during the path traversal

View File

@@ -61,7 +61,7 @@ namespace OpenRA.Mods.RA
throw new InvalidOperationException("No cells available to spawn starting unit {0}".F(s)); throw new InvalidOperationException("No cells available to spawn starting unit {0}".F(s));
var cell = validCells.Random(w.SharedRandom); var cell = validCells.Random(w.SharedRandom);
var subCell = mi.SharesCell ? w.ActorMap.FreeSubCell(cell).Value : SubCell.FullCell; var subCell = mi.SharesCell ? w.ActorMap.FreeSubCell(cell) : 0;
w.CreateActor(s.ToLowerInvariant(), new TypeDictionary w.CreateActor(s.ToLowerInvariant(), new TypeDictionary
{ {

View File

@@ -145,6 +145,9 @@ TileSets:
TileSize: 48,24 TileSize: 48,24
TileShape: Diamond TileShape: Diamond
SubCells:
Offsets: 0,0,0, -256,128,0, 0,-128,0, 256,128,0
DefaultIndex: 2
Music: Music:
mods/ts/music.yaml mods/ts/music.yaml