Load subcells and default subcell index from mod.yaml
This commit is contained in:
@@ -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: -512 ... 512, 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,35 @@ 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);
|
||||||
|
|
||||||
|
// Read subcell information
|
||||||
|
// sub-cell index 0 is the full cell
|
||||||
|
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);
|
||||||
|
|
||||||
|
foreach (var i in SubCellOffsets)
|
||||||
|
if (i.X < -512 || i.X > 512 || i.Y < -512 || i.Y > 512 || i.Z < 0)
|
||||||
|
throw new InvalidDataException("Subcell offsets must be in bounds (X & Y: -512 ... 512, Z > 0)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read default subcell index used when creating actors that share cells without SubCellInit
|
||||||
|
if (subcells.ContainsKey("DefaultIndex"))
|
||||||
|
SubCellDefaultIndex = FieldLoader.GetValue<int>("DefaultIndex", subcells ["DefaultIndex"].Value);
|
||||||
|
|
||||||
|
// Otherwise set the default subcell index to the middle subcell entry
|
||||||
|
else
|
||||||
|
SubCellDefaultIndex = SubCellOffsets.Length / 2; // default is the middle subcell entry
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|||||||
@@ -78,16 +78,8 @@ namespace OpenRA
|
|||||||
|
|
||||||
public readonly TileShape TileShape;
|
public readonly TileShape TileShape;
|
||||||
[FieldLoader.Ignore]
|
[FieldLoader.Ignore]
|
||||||
public readonly WVec[] SubCellOffsets =
|
public readonly WVec[] SubCellOffsets;
|
||||||
{
|
public readonly int SubCellDefaultIndex;
|
||||||
new WVec(0, 0, 0),
|
|
||||||
new WVec(-299, -256, 0),
|
|
||||||
new WVec(256, -256, 0),
|
|
||||||
new WVec(0, 0, 0),
|
|
||||||
new WVec(-299, 256, 0),
|
|
||||||
new WVec(256, 256, 0),
|
|
||||||
};
|
|
||||||
public readonly int SubCellsDefaultIndex = 3;
|
|
||||||
|
|
||||||
[FieldLoader.LoadUsing("LoadOptions")]
|
[FieldLoader.LoadUsing("LoadOptions")]
|
||||||
public MapOptions Options;
|
public MapOptions Options;
|
||||||
@@ -257,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.
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ namespace OpenRA.Traits
|
|||||||
public Actor Actor;
|
public Actor Actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly int[] SubCells = { 1, 2, 3, 4, 5 };
|
|
||||||
|
|
||||||
readonly ActorMapInfo info;
|
readonly ActorMapInfo info;
|
||||||
readonly Map map;
|
readonly Map map;
|
||||||
readonly CellLayer<InfluenceNode> influence;
|
readonly CellLayer<InfluenceNode> influence;
|
||||||
@@ -87,18 +85,18 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
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 int? 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)
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
this.self = init.self;
|
this.self = init.self;
|
||||||
this.Info = info;
|
this.Info = info;
|
||||||
|
|
||||||
toSubCell = fromSubCell = info.SharesCell ? init.world.Map.SubCellsDefaultIndex : 0;
|
toSubCell = fromSubCell = info.SharesCell ? init.world.Map.SubCellDefaultIndex : 0;
|
||||||
if (init.Contains<SubCellInit>())
|
if (init.Contains<SubCellInit>())
|
||||||
{
|
{
|
||||||
this.fromSubCell = this.toSubCell = init.Get<SubCellInit, int>();
|
this.fromSubCell = this.toSubCell = init.Get<SubCellInit, int>();
|
||||||
@@ -417,27 +417,36 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
public int GetDesiredSubcell(CPos a, Actor ignoreActor)
|
||||||
{
|
{
|
||||||
if (!Info.SharesCell)
|
if (!Info.SharesCell)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Prioritise the current subcell
|
// Prioritise the current subcell
|
||||||
return new[]{ fromSubCell, 1, 2, 3, 4, 5}.First(b =>
|
if (IsDesiredSubcellNotBlocked(a, fromSubCell, ignoreActor))
|
||||||
{
|
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)
|
||||||
|
|||||||
@@ -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 : 0;
|
var subCell = mi.SharesCell ? w.ActorMap.FreeSubCell(cell) : 0;
|
||||||
|
|
||||||
w.CreateActor(s.ToLowerInvariant(), new TypeDictionary
|
w.CreateActor(s.ToLowerInvariant(), new TypeDictionary
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -126,6 +126,10 @@ TileSets:
|
|||||||
mods/cnc/tilesets/temperat.yaml
|
mods/cnc/tilesets/temperat.yaml
|
||||||
mods/cnc/tilesets/jungle.yaml
|
mods/cnc/tilesets/jungle.yaml
|
||||||
|
|
||||||
|
SubCells:
|
||||||
|
Offsets: 0,0,0, -299,-256,0, 256,-256,0, 0,0,0, -299,256,0, 256,256,0
|
||||||
|
DefaultIndex: 3
|
||||||
|
|
||||||
LoadScreen: CncLoadScreen
|
LoadScreen: CncLoadScreen
|
||||||
Image: mods/cnc/uibits/chrome.png
|
Image: mods/cnc/uibits/chrome.png
|
||||||
Text: Loading
|
Text: Loading
|
||||||
|
|||||||
@@ -100,6 +100,10 @@ Notifications:
|
|||||||
TileSets:
|
TileSets:
|
||||||
mods/d2k/tilesets/arrakis.yaml
|
mods/d2k/tilesets/arrakis.yaml
|
||||||
|
|
||||||
|
SubCells:
|
||||||
|
Offsets: 0,0,0, -299,-256,0, 256,-256,0, 0,0,0, -299,256,0, 256,256,0
|
||||||
|
DefaultIndex: 3
|
||||||
|
|
||||||
TileSize: 32,32
|
TileSize: 32,32
|
||||||
|
|
||||||
Music:
|
Music:
|
||||||
|
|||||||
@@ -117,6 +117,10 @@ TileSets:
|
|||||||
mods/ra/tilesets/temperat.yaml
|
mods/ra/tilesets/temperat.yaml
|
||||||
mods/ra/tilesets/desert.yaml
|
mods/ra/tilesets/desert.yaml
|
||||||
|
|
||||||
|
SubCells:
|
||||||
|
Offsets: 0,0,0, -299,-256,0, 256,-256,0, 0,0,0, -299,256,0, 256,256,0
|
||||||
|
DefaultIndex: 3
|
||||||
|
|
||||||
Music:
|
Music:
|
||||||
mods/ra/music.yaml
|
mods/ra/music.yaml
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user