New crush code, now with less bs
This commit is contained in:
@@ -35,7 +35,6 @@ namespace OpenRA
|
||||
public PathFinder( World world )
|
||||
{
|
||||
this.world = world;
|
||||
var map = world.Map;
|
||||
}
|
||||
|
||||
class CachedPath
|
||||
|
||||
@@ -306,6 +306,7 @@ namespace OpenRA.Traits.Activities
|
||||
{
|
||||
self.CenterLocation = Util.CenterOfCell( mobile.toCell );
|
||||
mobile.fromCell = mobile.toCell;
|
||||
mobile.FinishedMoving(self);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
public readonly TerrainType[] TerrainTypes;
|
||||
public readonly float[] TerrainSpeeds;
|
||||
public readonly string[] Crushes;
|
||||
public readonly int WaitAverage = 60;
|
||||
public readonly int WaitSpread = 20;
|
||||
|
||||
@@ -39,6 +40,7 @@ namespace OpenRA.Traits
|
||||
public class Mobile : IIssueOrder, IResolveOrder, IOccupySpace, IMove
|
||||
{
|
||||
public readonly Actor self;
|
||||
public readonly MobileInfo Info;
|
||||
public readonly Dictionary<TerrainType,float> TerrainCost;
|
||||
public readonly Dictionary<TerrainType,float> TerrainSpeed;
|
||||
|
||||
@@ -67,6 +69,7 @@ namespace OpenRA.Traits
|
||||
public Mobile(ActorInitializer init, MobileInfo info)
|
||||
{
|
||||
this.self = init.self;
|
||||
this.Info = info;
|
||||
this.__fromCell = this.__toCell = init.location;
|
||||
AddInfluence();
|
||||
|
||||
@@ -137,9 +140,19 @@ namespace OpenRA.Traits
|
||||
|
||||
public virtual bool CanEnterCell(int2 cell, Actor ignoreActor, bool checkTransientActors)
|
||||
{
|
||||
if (!self.World.WorldActor.traits.Get<BuildingInfluence>().CanMoveHere(cell, ignoreActor))
|
||||
// Check for buildings
|
||||
var building = self.World.WorldActor.traits.Get<BuildingInfluence>().GetBuildingBlocking(cell);
|
||||
if (building != null && building != ignoreActor)
|
||||
{
|
||||
var crushable = building.traits.WithInterface<ICrushable>();
|
||||
if (crushable.Count() == 0)
|
||||
return false;
|
||||
|
||||
if (!crushable.Any(b => b.CrushClasses.Intersect(Info.Crushes).Any()))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check mobile actors
|
||||
if (checkTransientActors)
|
||||
{
|
||||
var canShare = self.traits.Contains<SharesCell>();
|
||||
@@ -152,14 +165,25 @@ namespace OpenRA.Traits
|
||||
return false;
|
||||
|
||||
// We can enter a cell with nonshareable units if we can crush all of them
|
||||
if (nonshareable.Any(
|
||||
a => !self.World.IsActorCrushableByActor(a, self)))
|
||||
if (nonshareable.Any(a => !(a.traits.Contains<ICrushable>() &&
|
||||
a.traits.WithInterface<ICrushable>().Any(b => b.CrushClasses.Intersect(Info.Crushes).Any()))))
|
||||
return false;
|
||||
}
|
||||
|
||||
return MovementCostForCell(self, cell) < float.PositiveInfinity;
|
||||
}
|
||||
|
||||
public virtual void FinishedMoving(Actor self)
|
||||
{
|
||||
var crushable = self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(self.Location).Where(a => a != self && a.traits.Contains<ICrushable>());
|
||||
foreach (var a in crushable)
|
||||
{
|
||||
var crushActions = a.traits.WithInterface<ICrushable>().Where(b => b.CrushClasses.Intersect(Info.Crushes).Any());
|
||||
foreach (var b in crushActions)
|
||||
b.OnCrush(self);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual float MovementCostForCell(Actor self, int2 cell)
|
||||
{
|
||||
if (!self.World.Map.IsInMap(cell.X,cell.Y))
|
||||
|
||||
@@ -115,8 +115,7 @@ namespace OpenRA.Traits
|
||||
public interface ICrushable
|
||||
{
|
||||
void OnCrush(Actor crusher);
|
||||
bool IsCrushableBy(UnitMovementType umt, Player player);
|
||||
bool IsPathableCrush(UnitMovementType umt, Player player);
|
||||
IEnumerable<string> CrushClasses { get; }
|
||||
}
|
||||
|
||||
public struct Renderable
|
||||
|
||||
@@ -66,6 +66,12 @@ namespace OpenRA.Traits
|
||||
return influence[cell.X, cell.Y];
|
||||
}
|
||||
|
||||
public Actor GetBuildingBlocking(int2 cell)
|
||||
{
|
||||
if (!map.IsInMap(cell) || !blocked[cell.X, cell.Y]) return null;
|
||||
return influence[cell.X, cell.Y];
|
||||
}
|
||||
|
||||
public bool CanMoveHere(int2 cell)
|
||||
{
|
||||
return map.IsInMap(cell) && !blocked[cell.X, cell.Y];
|
||||
|
||||
@@ -38,7 +38,6 @@ namespace OpenRA.Traits
|
||||
|
||||
public HazardLayer( World world )
|
||||
{
|
||||
map = world.Map;
|
||||
hazards = new List<Pair<Actor, Hazard>>[world.Map.MapSize.X, world.Map.MapSize.Y];
|
||||
for (int i = 0; i < world.Map.MapSize.X; i++)
|
||||
for (int j = 0; j < world.Map.MapSize.Y; j++)
|
||||
|
||||
@@ -49,27 +49,6 @@ namespace OpenRA.Traits
|
||||
|
||||
public void Tick( Actor self )
|
||||
{
|
||||
// Does this belong here? NO, but it's your mess.
|
||||
|
||||
// Get the crushable actors
|
||||
foreach (var aa in self.World.Queries.WithTrait<ICrushable>())
|
||||
{
|
||||
var a = aa.Actor;
|
||||
// Are there any units in the same cell that can crush this?
|
||||
foreach( var ios in a.traits.WithInterface<IOccupySpace>() )
|
||||
foreach( var cell in ios.OccupiedCells() )
|
||||
{
|
||||
// There should only be one (counterexample: An infantry and a tank try to pick up a crate at the same time.)
|
||||
// If there is more than one, do action on the first crusher
|
||||
var crusher = GetUnitsAt(cell).Where(b => a != b && self.World.IsActorCrushableByActor(a, b)).FirstOrDefault();
|
||||
if (crusher != null)
|
||||
{
|
||||
// Apply the crush action
|
||||
foreach (var crush in a.traits.WithInterface<ICrushable>())
|
||||
crush.OnCrush(crusher);
|
||||
}
|
||||
}
|
||||
}
|
||||
SanityCheck( self );
|
||||
}
|
||||
|
||||
|
||||
@@ -49,29 +49,6 @@ namespace OpenRA
|
||||
.Buildable;
|
||||
}
|
||||
|
||||
public static bool IsActorCrushableByActor(this World world, Actor a, Actor b)
|
||||
{
|
||||
return false;
|
||||
//var movement = b.traits.GetOrDefault<IMove>();
|
||||
//return movement != null && world.IsActorCrushableByMovementType(a, movement.GetMovementType());
|
||||
}
|
||||
|
||||
// Todo: Reenable crushing based on actor, not umt
|
||||
/*
|
||||
public static bool IsActorPathableToCrush(this World world, Actor a, UnitMovementType umt)
|
||||
{
|
||||
return a != null &&
|
||||
a.traits.WithInterface<ICrushable>()
|
||||
.Any(c => c.IsPathableCrush(umt, a.Owner));
|
||||
}
|
||||
|
||||
public static bool IsActorCrushableByMovementType(this World world, Actor a, UnitMovementType umt)
|
||||
{
|
||||
return a != null &&
|
||||
a.traits.WithInterface<ICrushable>()
|
||||
.Any(c => c.IsCrushableBy(umt, a.Owner));
|
||||
}
|
||||
*/
|
||||
public static IEnumerable<Actor> FindUnitsAtMouse(this World world, int2 mouseLocation)
|
||||
{
|
||||
var loc = mouseLocation + Game.viewport.Location;
|
||||
|
||||
@@ -37,11 +37,11 @@ namespace OpenRA.Traits
|
||||
|
||||
public class MobileAir : Mobile, ITick, IOccupyAir
|
||||
{
|
||||
MobileAirInfo Info;
|
||||
MobileAirInfo AirInfo;
|
||||
public MobileAir (ActorInitializer init, MobileAirInfo info)
|
||||
: base(init, info)
|
||||
{
|
||||
Info = info;
|
||||
AirInfo = info;
|
||||
}
|
||||
|
||||
public override void AddInfluence()
|
||||
@@ -62,7 +62,9 @@ namespace OpenRA.Traits
|
||||
return self.World.WorldActor.traits.Get<AircraftInfluence>().GetUnitsAt(p).Count() == 0;
|
||||
}
|
||||
|
||||
public virtual float MovementCostForCell(Actor self, int2 cell)
|
||||
public override void FinishedMoving(Actor self) {}
|
||||
|
||||
public override float MovementCostForCell(Actor self, int2 cell)
|
||||
{
|
||||
if (!self.World.Map.IsInMap(cell.X,cell.Y))
|
||||
return float.PositiveInfinity;
|
||||
@@ -73,7 +75,7 @@ namespace OpenRA.Traits
|
||||
return additionalCost;
|
||||
}
|
||||
|
||||
public virtual float MovementSpeedForCell(Actor self, int2 cell)
|
||||
public override float MovementSpeedForCell(Actor self, int2 cell)
|
||||
{
|
||||
var unitInfo = self.Info.Traits.GetOrDefault<UnitInfo>();
|
||||
if( unitInfo == null )
|
||||
@@ -108,14 +110,14 @@ namespace OpenRA.Traits
|
||||
//if (unit.Altitude <= 0)
|
||||
// return;
|
||||
|
||||
if (unit.Altitude < Info.CruiseAltitude)
|
||||
if (unit.Altitude < AirInfo.CruiseAltitude)
|
||||
unit.Altitude++;
|
||||
|
||||
if (--offsetTicks <= 0)
|
||||
{
|
||||
self.CenterLocation += Info.InstabilityMagnitude * self.World.SharedRandom.Gauss2D(5);
|
||||
unit.Altitude += (int)(Info.InstabilityMagnitude * self.World.SharedRandom.Gauss1D(5));
|
||||
offsetTicks = Info.InstabilityTicks;
|
||||
self.CenterLocation += AirInfo.InstabilityMagnitude * self.World.SharedRandom.Gauss2D(5);
|
||||
unit.Altitude += (int)(AirInfo.InstabilityMagnitude * self.World.SharedRandom.Gauss1D(5));
|
||||
offsetTicks = AirInfo.InstabilityTicks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ namespace OpenRA.Mods.RA.Activities
|
||||
return NextActivity;
|
||||
}
|
||||
var unit = self.traits.Get<Unit>();
|
||||
var aircraft = self.traits.Get<Aircraft>();
|
||||
|
||||
var info = self.Info.Traits.Get<HelicopterInfo>();
|
||||
if (unit.Altitude != info.CruiseAltitude)
|
||||
{
|
||||
|
||||
@@ -28,22 +28,24 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
class MineInfo : ITraitInfo
|
||||
{
|
||||
public readonly UnitMovementType[] TriggeredBy = { };
|
||||
public readonly string[] CrushClasses = { };
|
||||
public readonly string Weapon = "ATMine";
|
||||
public readonly bool AvoidFriendly = true;
|
||||
|
||||
public object Create(ActorInitializer init) { return new Mine(init); }
|
||||
public object Create(ActorInitializer init) { return new Mine(init, this); }
|
||||
}
|
||||
|
||||
class Mine : ICrushable, IOccupySpace
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly MineInfo info;
|
||||
[Sync]
|
||||
readonly int2 location;
|
||||
|
||||
public Mine(ActorInitializer init)
|
||||
public Mine(ActorInitializer init, MineInfo info)
|
||||
{
|
||||
this.self = init.self;
|
||||
this.info = info;
|
||||
this.location = init.location;
|
||||
self.World.WorldActor.traits.Get<UnitInfluence>().Add(self, this);
|
||||
}
|
||||
@@ -58,15 +60,8 @@ namespace OpenRA.Mods.RA
|
||||
self.QueueActivity(new RemoveSelf());
|
||||
}
|
||||
|
||||
public bool IsPathableCrush(UnitMovementType umt, Player player)
|
||||
{
|
||||
return !self.Info.Traits.Get<MineInfo>().AvoidFriendly || (player != self.Owner);
|
||||
}
|
||||
|
||||
public bool IsCrushableBy(UnitMovementType umt, Player player)
|
||||
{
|
||||
return self.Info.Traits.Get<MineInfo>().TriggeredBy.Contains(umt);
|
||||
}
|
||||
// TODO: Re-implement friendly-mine avoidance using a Hazard
|
||||
public IEnumerable<string> CrushClasses { get { return info.CrushClasses; } }
|
||||
|
||||
public int2 TopLeft { get { return location; } }
|
||||
|
||||
|
||||
@@ -27,30 +27,24 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
public class WallInfo : ITraitInfo
|
||||
{
|
||||
public readonly UnitMovementType[] CrushableBy = { };
|
||||
public readonly string[] CrushClasses = { };
|
||||
|
||||
public object Create(ActorInitializer init) { return new Wall(init.self); }
|
||||
public object Create(ActorInitializer init) { return new Wall(init.self, this); }
|
||||
}
|
||||
|
||||
public class Wall : ICrushable, IBlocksBullets
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly WallInfo info;
|
||||
|
||||
public Wall(Actor self)
|
||||
public Wall(Actor self, WallInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
this.info = info;
|
||||
self.World.WorldActor.traits.Get<UnitInfluence>().Add(self, self.traits.Get<Building>());
|
||||
}
|
||||
|
||||
public IEnumerable<string> CrushClasses { get { return info.CrushClasses; } }
|
||||
public void OnCrush(Actor crusher) { self.InflictDamage(crusher, self.Health, null); }
|
||||
public bool IsCrushableBy(UnitMovementType umt, Player player)
|
||||
{
|
||||
return self.Info.Traits.Get<WallInfo>().CrushableBy.Contains(umt);
|
||||
}
|
||||
|
||||
public bool IsPathableCrush(UnitMovementType umt, Player player)
|
||||
{
|
||||
return IsCrushableBy(umt, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
### Todo: Need a ^Tank default for MovementType: Track
|
||||
^Vehicle:
|
||||
Category: Vehicle
|
||||
Unit:
|
||||
@@ -23,6 +21,7 @@
|
||||
Unit:
|
||||
ROT: 5
|
||||
Mobile:
|
||||
Crushes: wall
|
||||
TerrainTypes: Clear, Rough, Road, Tree, Water, Rock, Wall, Ore, Beach, River, Special
|
||||
TerrainSpeeds: 80%, 70%, 100%, 0%, 0%, 0%, 0%, 70%, 70%, 0%, 100%
|
||||
Selectable:
|
||||
@@ -112,6 +111,7 @@
|
||||
DamagedSound: xplos.aud
|
||||
DestroyedSound: xplobig4.aud
|
||||
Wall:
|
||||
CrushClasses: wall
|
||||
LineBuild:
|
||||
Selectable:
|
||||
Priority: 1
|
||||
|
||||
@@ -465,6 +465,8 @@ BRIK:
|
||||
Armor: none
|
||||
RenderBuildingWall:
|
||||
DamageStates: 4
|
||||
Wall:
|
||||
CrushClasses: heavywall
|
||||
|
||||
GUN:
|
||||
Category: Defense
|
||||
|
||||
@@ -209,7 +209,6 @@ World:
|
||||
ResourceLayer:
|
||||
ResourceType@green-tib:
|
||||
ResourceType: 1
|
||||
MovementTerrainType: Tiberium
|
||||
Palette: terrain
|
||||
SpriteNames: ti1,ti2,ti3,ti4,ti5,ti6,ti7,ti8,ti9,ti10,ti11,ti12
|
||||
ValuePerUnit: 30
|
||||
|
||||
@@ -294,6 +294,8 @@ HTNK:
|
||||
Explodes:
|
||||
Weapon: UnitExplodeSmall
|
||||
EmptyWeapon: UnitExplodeSmall
|
||||
Mobile:
|
||||
Crushes: wall, heavywall
|
||||
|
||||
MSAM:
|
||||
Inherits: ^Tank
|
||||
|
||||
Reference in New Issue
Block a user