New crush code, now with less bs

This commit is contained in:
Paul Chote
2010-06-25 20:57:06 +12:00
parent 00b91bd7ad
commit 7c3a10396c
16 changed files with 70 additions and 94 deletions

View File

@@ -35,7 +35,6 @@ namespace OpenRA
public PathFinder( World world )
{
this.world = world;
var map = world.Map;
}
class CachedPath

View File

@@ -306,6 +306,7 @@ namespace OpenRA.Traits.Activities
{
self.CenterLocation = Util.CenterOfCell( mobile.toCell );
mobile.fromCell = mobile.toCell;
mobile.FinishedMoving(self);
return null;
}
}

View File

@@ -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))
return false;
// 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))

View File

@@ -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

View File

@@ -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];

View File

@@ -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++)

View File

@@ -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 );
}

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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)
{

View File

@@ -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; } }

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -465,6 +465,8 @@ BRIK:
Armor: none
RenderBuildingWall:
DamageStates: 4
Wall:
CrushClasses: heavywall
GUN:
Category: Defense

View File

@@ -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

View File

@@ -294,6 +294,8 @@ HTNK:
Explodes:
Weapon: UnitExplodeSmall
EmptyWeapon: UnitExplodeSmall
Mobile:
Crushes: wall, heavywall
MSAM:
Inherits: ^Tank