Merge pull request #6208 from atlimit8/FixUnloadCargo

Fixed UnloadCargo stacking using new subcell API exposure
This commit is contained in:
Matthias Mailänder
2014-08-30 14:38:17 +02:00
22 changed files with 287 additions and 153 deletions

View File

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

View File

@@ -79,7 +79,10 @@ namespace OpenRA
public readonly TileShape TileShape;
[FieldLoader.Ignore]
public readonly WVec[] SubCellOffsets;
public readonly int SubCellDefaultIndex;
public readonly SubCell DefaultSubCell;
public readonly SubCell LastSubCell;
public WVec OffsetOfSubCell(SubCell subCell) { return SubCellOffsets[(int)subCell]; }
[FieldLoader.LoadUsing("LoadOptions")]
public MapOptions Options;
@@ -250,7 +253,8 @@ namespace OpenRA
MapResources = Exts.Lazy(() => LoadResourceTiles());
TileShape = Game.modData.Manifest.TileShape;
SubCellOffsets = Game.modData.Manifest.SubCellOffsets;
SubCellDefaultIndex = Game.modData.Manifest.SubCellDefaultIndex;
LastSubCell = (SubCell)(SubCellOffsets.Length - 1);
DefaultSubCell = (SubCell)Game.modData.Manifest.SubCellDefaultIndex;
// The Uid is calculated from the data on-disk, so
// format changes must be flushed to disk.
@@ -494,6 +498,14 @@ namespace OpenRA
return new WPos(512 * (cell.X - cell.Y + 1), 512 * (cell.X + cell.Y + 1), 0);
}
public WPos CenterOfSubCell(CPos cell, SubCell subCell)
{
var index = (int)subCell;
if (index >= 0 && index <= SubCellOffsets.Length)
return CenterOfCell(cell) + SubCellOffsets[index];
return CenterOfCell(cell);
}
public CPos CellContaining(WPos pos)
{
if (TileShape == TileShape.Rectangle)

View File

@@ -28,7 +28,11 @@ namespace OpenRA.Traits
int generation;
public static Target FromPos(WPos p) { return new Target { pos = p, type = TargetType.Terrain }; }
public static Target FromCell(World w, CPos c) { return new Target { pos = w.Map.CenterOfCell(c), type = TargetType.Terrain }; }
public static Target FromCell(World w, CPos c, SubCell subCell = SubCell.FullCell)
{
return new Target { pos = w.Map.CenterOfSubCell(c, subCell), type = TargetType.Terrain };
}
public static Target FromOrder(World w, Order o)
{
return o.TargetActor != null

View File

@@ -151,7 +151,7 @@ namespace OpenRA.Traits
{
WPos CenterPosition { get; }
CPos TopLeft { get; }
IEnumerable<Pair<CPos, int>> OccupiedCells();
IEnumerable<Pair<CPos, SubCell>> OccupiedCells();
}
public static class IOccupySpaceExts
@@ -187,9 +187,11 @@ namespace OpenRA.Traits
public interface IPositionable : IOccupySpace
{
bool CanEnterCell(CPos location);
bool CanEnterCell(CPos location, Actor ignoreActor, bool checkTransientActors);
void SetPosition(Actor self, CPos cell);
bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any);
bool CanEnterCell(CPos location, Actor ignoreActor = null, bool checkTransientActors = true);
SubCell GetValidSubCell(SubCell preferred = SubCell.Any);
SubCell GetAvailableSubCell(CPos location, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, bool checkTransientActors = true);
void SetPosition(Actor self, CPos cell, SubCell subCell = SubCell.Any);
void SetPosition(Actor self, WPos pos);
void SetVisualPosition(Actor self, WPos pos);
}
@@ -202,7 +204,7 @@ namespace OpenRA.Traits
Activity MoveWithinRange(Target target, WRange range);
Activity MoveWithinRange(Target target, WRange minRange, WRange maxRange);
Activity MoveFollow(Actor self, Target target, WRange minRange, WRange maxRange);
Activity MoveIntoWorld(Actor self, CPos cell);
Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any);
Activity VisualMove(Actor self, WPos fromPos, WPos toPos);
CPos NearestMoveableCell(CPos target);
bool IsMoving { get; set; }

View File

@@ -14,7 +14,7 @@ using System.Linq;
namespace OpenRA.Traits
{
public enum SubCell { FullCell, TopLeft, TopRight, Center, BottomLeft, BottomRight }
public enum SubCell { Invalid = int.MinValue, Any = int.MinValue / 2, FullCell = 0, First = 1 }
public class ActorMapInfo : ITraitInfo
{
@@ -29,7 +29,7 @@ namespace OpenRA.Traits
class InfluenceNode
{
public InfluenceNode Next;
public int SubCell;
public SubCell SubCell;
public Actor Actor;
}
@@ -73,42 +73,80 @@ namespace OpenRA.Traits
yield return i.Actor;
}
public IEnumerable<Actor> GetUnitsAt(CPos a, int sub)
public IEnumerable<Actor> GetUnitsAt(CPos a, SubCell sub)
{
if (!map.Contains(a))
yield break;
for (var i = influence[a]; i != null; i = i.Next)
if (!i.Actor.Destroyed && (i.SubCell == sub || i.SubCell == 0))
if (!i.Actor.Destroyed && (i.SubCell == sub || i.SubCell == SubCell.FullCell))
yield return i.Actor;
}
public bool HasFreeSubCell(CPos a)
public bool HasFreeSubCell(CPos a, bool checkTransient = true)
{
return FreeSubCell(a) >= 0;
return FreeSubCell(a, SubCell.Any, checkTransient) != SubCell.Invalid;
}
public int FreeSubCell(CPos a)
public SubCell FreeSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, bool checkTransient = true)
{
if (preferredSubCell > SubCell.Any && !AnyUnitsAt(a, preferredSubCell, checkTransient))
return preferredSubCell;
if (!AnyUnitsAt(a))
return map.SubCellDefaultIndex;
return map.DefaultSubCell;
for (var i = 1; i < map.SubCellOffsets.Length; i++)
if (!AnyUnitsAt(a, i))
return i;
return -1;
for (var i = (int)SubCell.First; i < map.SubCellOffsets.Length; i++)
if (i != (int)preferredSubCell && !AnyUnitsAt(a, (SubCell)i, checkTransient))
return (SubCell)i;
return SubCell.Invalid;
}
public SubCell FreeSubCell(CPos a, SubCell preferredSubCell, Func<Actor, bool> checkIfBlocker)
{
if (preferredSubCell > SubCell.Any && !AnyUnitsAt(a, preferredSubCell, checkIfBlocker))
return preferredSubCell;
if (!AnyUnitsAt(a))
return map.DefaultSubCell;
for (var i = (int)SubCell.First; i < map.SubCellOffsets.Length; i++)
if (i != (int)preferredSubCell && !AnyUnitsAt(a, (SubCell)i, checkIfBlocker))
return (SubCell)i;
return SubCell.Invalid;
}
// NOTE: always includes transients with influence
public bool AnyUnitsAt(CPos a)
{
return influence[a] != null;
}
public bool AnyUnitsAt(CPos a, int sub)
// NOTE: can not check aircraft
public bool AnyUnitsAt(CPos a, SubCell sub, bool checkTransient = true)
{
bool always = sub == SubCell.FullCell || sub == SubCell.Any;
for (var i = influence[a]; i != null; i = i.Next)
if (i.SubCell == sub || i.SubCell == 0)
return true;
if (always || i.SubCell == sub || i.SubCell == SubCell.FullCell)
{
if (checkTransient)
return true;
var pos = i.Actor.TraitOrDefault<IPositionable>();
if (pos == null || !pos.IsLeavingCell(a, i.SubCell))
return true;
}
return false;
}
// NOTE: can not check aircraft
public bool AnyUnitsAt(CPos a, SubCell sub, Func<Actor, bool> withCondition)
{
bool always = sub == SubCell.FullCell || sub == SubCell.Any;
for (var i = influence[a]; i != null; i = i.Next)
if (always || i.SubCell == sub || i.SubCell == SubCell.FullCell)
if (withCondition(i.Actor))
return true;
return false;
}