Merge branch 'master' of git://github.com/chrisforbes/OpenRA
This commit is contained in:
@@ -86,7 +86,9 @@ namespace OpenRa.Game
|
|||||||
if (!Rules.Map.IsInMap(xy.X, xy.Y))
|
if (!Rules.Map.IsInMap(xy.X, xy.Y))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var underCursor = Game.UnitInfluence.GetUnitAt( xy )
|
// HACK: Get the first unit in the cell
|
||||||
|
// This will need to be updated for multiple-infantry-in-a-cell
|
||||||
|
var underCursor = Game.UnitInfluence.GetUnitsAt( xy ).FirstOrDefault()
|
||||||
?? Game.BuildingInfluence.GetBuildingAt( xy );
|
?? Game.BuildingInfluence.GetBuildingAt( xy );
|
||||||
|
|
||||||
if (underCursor != null && !underCursor.Info.Selectable)
|
if (underCursor != null && !underCursor.Info.Selectable)
|
||||||
|
|||||||
@@ -228,13 +228,35 @@ namespace OpenRa.Game
|
|||||||
public static bool IsCellBuildable(int2 a, UnitMovementType umt, Actor toIgnore)
|
public static bool IsCellBuildable(int2 a, UnitMovementType umt, Actor toIgnore)
|
||||||
{
|
{
|
||||||
if (BuildingInfluence.GetBuildingAt(a) != null) return false;
|
if (BuildingInfluence.GetBuildingAt(a) != null) return false;
|
||||||
if (UnitInfluence.GetUnitAt(a) != null && UnitInfluence.GetUnitAt(a) != toIgnore) return false;
|
if (UnitInfluence.GetUnitsAt(a).Any(b => b != toIgnore)) return false;
|
||||||
|
|
||||||
return Rules.Map.IsInMap(a.X, a.Y) &&
|
return Rules.Map.IsInMap(a.X, a.Y) &&
|
||||||
TerrainCosts.Cost(umt,
|
TerrainCosts.Cost(umt,
|
||||||
Rules.TileSet.GetWalkability(Rules.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity;
|
Rules.TileSet.GetWalkability(Rules.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsActorCrushableByActor(Actor a, Actor b)
|
||||||
|
{
|
||||||
|
return IsActorCrushableByMovementType(a, b.traits.WithInterface<IMovement>().FirstOrDefault().GetMovementType());
|
||||||
|
}
|
||||||
|
public static bool IsActorCrushableByMovementType(Actor a, UnitMovementType umt)
|
||||||
|
{
|
||||||
|
if (a != null)
|
||||||
|
{
|
||||||
|
foreach (var crush in a.traits.WithInterface<ICrushable>())
|
||||||
|
{
|
||||||
|
if (((crush.IsCrushableByEnemy() && a.Owner != Game.LocalPlayer) || (crush.IsCrushableByFriend() && a.Owner == Game.LocalPlayer))
|
||||||
|
&& crush.CrushableBy().Contains(umt))
|
||||||
|
{
|
||||||
|
Log.Write("{0} is crushable by MovementType {1}", a.Info.Name, umt);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.Write("{0} is NOT crushable by MovementType {1}", a.Info.Name, umt);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsWater(int2 a)
|
public static bool IsWater(int2 a)
|
||||||
{
|
{
|
||||||
return Rules.Map.IsInMap(a.X, a.Y) &&
|
return Rules.Map.IsInMap(a.X, a.Y) &&
|
||||||
|
|||||||
@@ -173,6 +173,7 @@
|
|||||||
<Compile Include="Traits\Fake.cs" />
|
<Compile Include="Traits\Fake.cs" />
|
||||||
<Compile Include="Traits\Harvester.cs" />
|
<Compile Include="Traits\Harvester.cs" />
|
||||||
<Compile Include="Traits\Helicopter.cs" />
|
<Compile Include="Traits\Helicopter.cs" />
|
||||||
|
<Compile Include="Traits\Infantry.cs" />
|
||||||
<Compile Include="Traits\Plane.cs" />
|
<Compile Include="Traits\Plane.cs" />
|
||||||
<Compile Include="Traits\ProductionQueue.cs" />
|
<Compile Include="Traits\ProductionQueue.cs" />
|
||||||
<Compile Include="Traits\RenderBuildingCharge.cs" />
|
<Compile Include="Traits\RenderBuildingCharge.cs" />
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRa.FileFormats;
|
using OpenRa.FileFormats;
|
||||||
using OpenRa.Game.Support;
|
using OpenRa.Game.Support;
|
||||||
|
using OpenRa.Game.Traits;
|
||||||
|
|
||||||
namespace OpenRa.Game
|
namespace OpenRa.Game
|
||||||
{
|
{
|
||||||
@@ -22,20 +23,6 @@ namespace OpenRa.Game
|
|||||||
: float.PositiveInfinity;
|
: float.PositiveInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsBlocked(int2 from, UnitMovementType umt)
|
|
||||||
{
|
|
||||||
for (int v = -1; v < 2; v++)
|
|
||||||
for (int u = -1; u < 2; u++)
|
|
||||||
if (u != 0 || v != 0)
|
|
||||||
{
|
|
||||||
var p = from + new int2(u, v);
|
|
||||||
if (passableCost[(int)umt][from.X + u, from.Y + v] < float.PositiveInfinity)
|
|
||||||
if (Game.BuildingInfluence.CanMoveHere(p) && (Game.UnitInfluence.GetUnitAt(p) == null))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<int2> FindUnitPath( int2 from, int2 target, UnitMovementType umt )
|
public List<int2> FindUnitPath( int2 from, int2 target, UnitMovementType umt )
|
||||||
{
|
{
|
||||||
using (new PerfSample("find_unit_path"))
|
using (new PerfSample("find_unit_path"))
|
||||||
@@ -67,7 +54,7 @@ namespace OpenRa.Game
|
|||||||
return q =>
|
return q =>
|
||||||
p != q &&
|
p != q &&
|
||||||
((p - q).LengthSquared < dist * dist) &&
|
((p - q).LengthSquared < dist * dist) &&
|
||||||
(Game.UnitInfluence.GetUnitAt(q) != null);
|
(Game.UnitInfluence.GetUnitsAt(q).Any());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<int2> FindPath( PathSearch search )
|
public List<int2> FindPath( PathSearch search )
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using IjwFramework.Collections;
|
using IjwFramework.Collections;
|
||||||
using OpenRa.Game.Graphics;
|
using OpenRa.Game.Graphics;
|
||||||
|
|
||||||
@@ -54,8 +55,10 @@ namespace OpenRa.Game
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( checkForBlocked && Game.UnitInfluence.GetUnitAt( newHere ) != null )
|
// Replicate real-ra behavior of not being able to enter a cell if there is a mixture of crushable and uncrushable units
|
||||||
|
if (checkForBlocked && (Game.UnitInfluence.GetUnitsAt(newHere).Any(a => !Game.IsActorCrushableByMovementType(a, umt))))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (customBlock != null && customBlock(newHere))
|
if (customBlock != null && customBlock(newHere))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -75,6 +78,7 @@ namespace OpenRa.Game
|
|||||||
cellInfo[ newHere.X, newHere.Y ].MinCost = newCost;
|
cellInfo[ newHere.X, newHere.Y ].MinCost = newCost;
|
||||||
|
|
||||||
queue.Add( new PathDistance( newCost + est, newHere ) );
|
queue.Add( new PathDistance( newCost + est, newHere ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
return p.Location;
|
return p.Location;
|
||||||
}
|
}
|
||||||
@@ -96,7 +100,6 @@ namespace OpenRa.Game
|
|||||||
checkForBlocked = checkForBlocked };
|
checkForBlocked = checkForBlocked };
|
||||||
|
|
||||||
search.AddInitialCell( from );
|
search.AddInitialCell( from );
|
||||||
|
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,10 @@ namespace OpenRa.Game.Traits.Activities
|
|||||||
static bool CanEnterCell( int2 c, Actor self )
|
static bool CanEnterCell( int2 c, Actor self )
|
||||||
{
|
{
|
||||||
if (!Game.BuildingInfluence.CanMoveHere(c)) return false;
|
if (!Game.BuildingInfluence.CanMoveHere(c)) return false;
|
||||||
var u = Game.UnitInfluence.GetUnitAt( c );
|
|
||||||
return (u == null || u == self);
|
// Cannot enter a cell if any unit inside is uncrushable
|
||||||
|
// This will need to be updated for multiple-infantry-in-a-cell
|
||||||
|
return (!Game.UnitInfluence.GetUnitsAt(c).Any(a => a != self && !Game.IsActorCrushableByActor(a, self)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActivity Tick( Actor self )
|
public IActivity Tick( Actor self )
|
||||||
|
|||||||
38
OpenRa.Game/Traits/Infantry.cs
Normal file
38
OpenRa.Game/Traits/Infantry.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenRa.Game.Traits
|
||||||
|
{
|
||||||
|
class Infantry : ICrushable
|
||||||
|
{
|
||||||
|
readonly Actor self;
|
||||||
|
public Infantry(Actor self)
|
||||||
|
{
|
||||||
|
this.self = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCrushableByFriend()
|
||||||
|
{
|
||||||
|
// HACK: should be false
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool IsCrushableByEnemy()
|
||||||
|
{
|
||||||
|
// HACK: should be based off crushable tag
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCrush(Actor crusher)
|
||||||
|
{
|
||||||
|
self.InflictDamage(crusher, self.Health, Rules.WarheadInfo["Crush"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<UnitMovementType> CrushableBy()
|
||||||
|
{
|
||||||
|
yield return UnitMovementType.Track;
|
||||||
|
//yield return UnitMovementType.Wheel; // Can infantry be crushed by wheel?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,9 +80,27 @@ namespace OpenRa.Game.Traits
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanEnterCell(int2 location)
|
public bool CanEnterCell(int2 a)
|
||||||
{
|
{
|
||||||
return Game.IsCellBuildable( location, GetMovementType(), self );
|
if (Game.BuildingInfluence.GetBuildingAt(a) != null) return false;
|
||||||
|
|
||||||
|
var crushable = true;
|
||||||
|
foreach (Actor actor in Game.UnitInfluence.GetUnitsAt(a))
|
||||||
|
{
|
||||||
|
if (actor == self) continue;
|
||||||
|
|
||||||
|
if (!Game.IsActorCrushableByActor(actor, self))
|
||||||
|
{
|
||||||
|
crushable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!crushable) return false;
|
||||||
|
|
||||||
|
return Rules.Map.IsInMap(a.X, a.Y) &&
|
||||||
|
TerrainCosts.Cost(GetMovementType(),
|
||||||
|
Rules.TileSet.GetWalkability(Rules.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<int2> GetCurrentPath()
|
public IEnumerable<int2> GetCurrentPath()
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace OpenRa.Game.Traits
|
|||||||
public bool Produce( Actor self, UnitInfo producee )
|
public bool Produce( Actor self, UnitInfo producee )
|
||||||
{
|
{
|
||||||
var location = CreationLocation( self, producee );
|
var location = CreationLocation( self, producee );
|
||||||
if( location == null || Game.UnitInfluence.GetUnitAt( location.Value ) != null )
|
if( location == null || Game.UnitInfluence.GetUnitsAt( location.Value ).Any() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var newUnit = new Actor( producee, location.Value, self.Owner );
|
var newUnit = new Actor( producee, location.Value, self.Owner );
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using OpenRa.Game.Graphics;
|
using OpenRa.Game.Graphics;
|
||||||
|
|
||||||
namespace OpenRa.Game.Traits
|
namespace OpenRa.Game.Traits
|
||||||
@@ -35,7 +36,7 @@ namespace OpenRa.Game.Traits
|
|||||||
if (doneBuilding) roof.Tick();
|
if (doneBuilding) roof.Tick();
|
||||||
|
|
||||||
var b = self.Bounds;
|
var b = self.Bounds;
|
||||||
if (isOpen && null == Game.UnitInfluence.GetUnitAt(((1/24f) * self.CenterLocation).ToInt2()))
|
if (isOpen && !Game.UnitInfluence.GetUnitsAt(((1/24f) * self.CenterLocation).ToInt2()).Any())
|
||||||
{
|
{
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
roof.PlayBackwardsThen(prefix + "build-top", () => roof.Play(prefix + "idle-top"));
|
roof.PlayBackwardsThen(prefix + "build-top", () => roof.Play(prefix + "idle-top"));
|
||||||
|
|||||||
@@ -58,4 +58,12 @@ namespace OpenRa.Game.Traits
|
|||||||
UnitMovementType GetMovementType();
|
UnitMovementType GetMovementType();
|
||||||
bool CanEnterCell(int2 location);
|
bool CanEnterCell(int2 location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ICrushable
|
||||||
|
{
|
||||||
|
bool IsCrushableByFriend();
|
||||||
|
bool IsCrushableByEnemy();
|
||||||
|
void OnCrush(Actor crusher);
|
||||||
|
IEnumerable<UnitMovementType>CrushableBy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using OpenRa.Game.GameRules;
|
using OpenRa.Game.GameRules;
|
||||||
using OpenRa.Game.Graphics;
|
using OpenRa.Game.Graphics;
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ namespace OpenRa.Game
|
|||||||
if (ShowUnitDebug)
|
if (ShowUnitDebug)
|
||||||
for (var j = 0; j < 128; j++)
|
for (var j = 0; j < 128; j++)
|
||||||
for (var i = 0; i < 128; i++)
|
for (var i = 0; i < 128; i++)
|
||||||
if (Game.UnitInfluence.GetUnitAt(new int2(i, j)) != null)
|
if (Game.UnitInfluence.GetUnitsAt(new int2(i, j)).Any())
|
||||||
spriteRenderer.DrawSprite(unitDebug, Game.CellSize * new float2(i, j), 0);
|
spriteRenderer.DrawSprite(unitDebug, Game.CellSize * new float2(i, j), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,50 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
using OpenRa.Game.Traits;
|
using OpenRa.Game.Traits;
|
||||||
|
|
||||||
namespace OpenRa.Game
|
namespace OpenRa.Game
|
||||||
{
|
{
|
||||||
class UnitInfluenceMap
|
class UnitInfluenceMap
|
||||||
{
|
{
|
||||||
Actor[,] influence = new Actor[128, 128];
|
List<Actor>[,] influence = new List<Actor>[128, 128];
|
||||||
readonly int2 searchDistance = new int2(2,2);
|
readonly int2 searchDistance = new int2(2,2);
|
||||||
|
|
||||||
public UnitInfluenceMap()
|
public UnitInfluenceMap()
|
||||||
{
|
{
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
for (int j = 0; j < 128; j++)
|
||||||
|
influence[ i, j ] = new List<Actor>();
|
||||||
|
|
||||||
Game.world.ActorRemoved += a => Remove(a, a.traits.WithInterface<IOccupySpace>().FirstOrDefault());
|
Game.world.ActorRemoved += a => Remove(a, a.traits.WithInterface<IOccupySpace>().FirstOrDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Tick()
|
public void Tick()
|
||||||
{
|
{
|
||||||
|
// Does this belong here?
|
||||||
|
|
||||||
|
// Get the crushable actors
|
||||||
|
foreach (var a in Game.world.Actors.Where(b => b.traits.WithInterface<ICrushable>().Any()))
|
||||||
|
{
|
||||||
|
// 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 && Game.IsActorCrushableByActor(a, b)).FirstOrDefault();
|
||||||
|
if (crusher != null)
|
||||||
|
{
|
||||||
|
Log.Write("{0} crushes {1}", crusher.Info.Name, a.Info.Name);
|
||||||
|
// Apply the crush action
|
||||||
|
foreach (var crush in a.traits.WithInterface<ICrushable>())
|
||||||
|
{
|
||||||
|
crush.OnCrush(crusher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
SanityCheck();
|
SanityCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,25 +53,30 @@ namespace OpenRa.Game
|
|||||||
{
|
{
|
||||||
for( int y = 0 ; y < 128 ; y++ )
|
for( int y = 0 ; y < 128 ; y++ )
|
||||||
for( int x = 0 ; x < 128 ; x++ )
|
for( int x = 0 ; x < 128 ; x++ )
|
||||||
if( influence[ x, y ] != null && !influence[ x, y ].traits.WithInterface<IOccupySpace>().First().OccupiedCells().Contains( new int2( x, y ) ) )
|
if( influence[ x, y ] != null )
|
||||||
|
foreach (var a in influence[ x, y ])
|
||||||
|
if (!a.traits.WithInterface<IOccupySpace>().First().OccupiedCells().Contains( new int2( x, y ) ) )
|
||||||
throw new InvalidOperationException( "UIM: Sanity check failed A" );
|
throw new InvalidOperationException( "UIM: Sanity check failed A" );
|
||||||
|
|
||||||
foreach( var a in Game.world.Actors )
|
foreach( Actor a in Game.world.Actors )
|
||||||
foreach( var ios in a.traits.WithInterface<IOccupySpace>() )
|
foreach( var ios in a.traits.WithInterface<IOccupySpace>() )
|
||||||
foreach( var cell in ios.OccupiedCells() )
|
foreach( var cell in ios.OccupiedCells() )
|
||||||
if( influence[ cell.X, cell.Y ] != a )
|
if (!influence[cell.X, cell.Y].Contains(a))
|
||||||
|
//if( influence[ cell.X, cell.Y ] != a )
|
||||||
throw new InvalidOperationException( "UIM: Sanity check failed B" );
|
throw new InvalidOperationException( "UIM: Sanity check failed B" );
|
||||||
}
|
}
|
||||||
|
|
||||||
[Conditional( "SANITY_CHECKS" )]
|
[Conditional( "SANITY_CHECKS" )]
|
||||||
void SanityCheckAdd( IOccupySpace a )
|
void SanityCheckAdd( IOccupySpace a )
|
||||||
{
|
{
|
||||||
|
/* This check is too strict now that we can have multiple units in a cell
|
||||||
foreach( var c in a.OccupiedCells() )
|
foreach( var c in a.OccupiedCells() )
|
||||||
if( influence[c.X, c.Y] != null )
|
if( influence[c.X, c.Y].Any())
|
||||||
throw new InvalidOperationException( "UIM: Sanity check failed (Add)" );
|
throw new InvalidOperationException( "UIM: Sanity check failed (Add)" );
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public Actor GetUnitAt( int2 a )
|
public IEnumerable<Actor> GetUnitsAt( int2 a )
|
||||||
{
|
{
|
||||||
return influence[ a.X, a.Y ];
|
return influence[ a.X, a.Y ];
|
||||||
}
|
}
|
||||||
@@ -52,14 +85,14 @@ namespace OpenRa.Game
|
|||||||
{
|
{
|
||||||
SanityCheckAdd( unit );
|
SanityCheckAdd( unit );
|
||||||
foreach( var c in unit.OccupiedCells() )
|
foreach( var c in unit.OccupiedCells() )
|
||||||
influence[c.X, c.Y] = self;
|
influence[c.X, c.Y].Add(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove( Actor self, IOccupySpace unit )
|
public void Remove( Actor self, IOccupySpace unit )
|
||||||
{
|
{
|
||||||
if (unit != null)
|
if (unit != null)
|
||||||
foreach (var c in unit.OccupiedCells())
|
foreach (var c in unit.OccupiedCells())
|
||||||
influence[c.X, c.Y] = null;
|
influence[c.X, c.Y].Remove(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(Actor self, IOccupySpace unit)
|
public void Update(Actor self, IOccupySpace unit)
|
||||||
|
|||||||
@@ -498,10 +498,12 @@
|
|||||||
<sequence name="standup-5" start="124" length="2" />
|
<sequence name="standup-5" start="124" length="2" />
|
||||||
<sequence name="standup-6" start="126" length="2" />
|
<sequence name="standup-6" start="126" length="2" />
|
||||||
<sequence name="standup-7" start="128" length="2" />
|
<sequence name="standup-7" start="128" length="2" />
|
||||||
|
<sequence name="die1" start="196" length="5" />
|
||||||
<sequence name="die2" start="201" length="8" />
|
<sequence name="die2" start="201" length="8" />
|
||||||
<sequence name="die3" start="209" length="8" />
|
<sequence name="die3" start="209" length="8" />
|
||||||
<sequence name="die4" start="217" length="12" />
|
<sequence name="die4" start="217" length="12" />
|
||||||
<sequence name="die5" start="229" length="18" />
|
<sequence name="die5" start="229" length="18" />
|
||||||
|
<sequence name="die6" start="0" length="14" src="electro" />
|
||||||
<sequence name="crawl-0" start="130" length="4" />
|
<sequence name="crawl-0" start="130" length="4" />
|
||||||
<sequence name="crawl-1" start="134" length="4" />
|
<sequence name="crawl-1" start="134" length="4" />
|
||||||
<sequence name="crawl-2" start="138" length="4" />
|
<sequence name="crawl-2" start="138" length="4" />
|
||||||
|
|||||||
25
units.ini
25
units.ini
@@ -522,52 +522,52 @@ MEDI
|
|||||||
Description=Attack Dog
|
Description=Attack Dog
|
||||||
BuiltAt=KENN
|
BuiltAt=KENN
|
||||||
Voice=DogVoice
|
Voice=DogVoice
|
||||||
Traits=Unit, Mobile, RenderInfantry
|
Traits=Unit, Mobile, RenderInfantry, Infantry
|
||||||
LongDesc=Anti-infantry unit. Not fooled by the \nSpy's disguise.\n Strong vs Infantry\n Weak vs Vehicles
|
LongDesc=Anti-infantry unit. Not fooled by the \nSpy's disguise.\n Strong vs Infantry\n Weak vs Vehicles
|
||||||
[E1]
|
[E1]
|
||||||
Description=Rifle Infantry
|
Description=Rifle Infantry
|
||||||
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry
|
||||||
LongDesc=General-purpose infantry. Strong vs Infantry\n Weak vs Vehicles
|
LongDesc=General-purpose infantry. Strong vs Infantry\n Weak vs Vehicles
|
||||||
[E2]
|
[E2]
|
||||||
Description=Grenadier
|
Description=Grenadier
|
||||||
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry
|
||||||
FireDelay=15
|
FireDelay=15
|
||||||
PrimaryOffset=0,0,0,-13
|
PrimaryOffset=0,0,0,-13
|
||||||
LongDesc=Infantry armed with grenades. \n Strong vs Buildings, Infantry\n Weak vs Vehicles
|
LongDesc=Infantry armed with grenades. \n Strong vs Buildings, Infantry\n Weak vs Vehicles
|
||||||
[E3]
|
[E3]
|
||||||
Description=Rocket Soldier
|
Description=Rocket Soldier
|
||||||
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry
|
||||||
PrimaryOffset=0,0,0,-13
|
PrimaryOffset=0,0,0,-13
|
||||||
LongDesc=Anti-tank/Anti-aircraft infantry.\n Strong vs Tanks, Aircraft\n Weak vs Infantry
|
LongDesc=Anti-tank/Anti-aircraft infantry.\n Strong vs Tanks, Aircraft\n Weak vs Infantry
|
||||||
[E4]
|
[E4]
|
||||||
Description=Flamethrower
|
Description=Flamethrower
|
||||||
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry
|
||||||
FireDelay=8
|
FireDelay=8
|
||||||
LongDesc=Advanced Anti-infantry unit.\n Strong vs Infantry, Buildings\n Weak vs Vehicles
|
LongDesc=Advanced Anti-infantry unit.\n Strong vs Infantry, Buildings\n Weak vs Vehicles
|
||||||
[E6]
|
[E6]
|
||||||
Description=Engineer
|
Description=Engineer
|
||||||
Traits=Unit, Mobile, RenderInfantry, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, TakeCover, Infantry
|
||||||
Voice=EngineerVoice
|
Voice=EngineerVoice
|
||||||
LongDesc=Infiltrates and captures enemy structures.\n Strong vs Nothing\n Weak vs Everything
|
LongDesc=Infiltrates and captures enemy structures.\n Strong vs Nothing\n Weak vs Everything
|
||||||
[SPY]
|
[SPY]
|
||||||
Description=Spy
|
Description=Spy
|
||||||
Voice=SpyVoice
|
Voice=SpyVoice
|
||||||
Traits=Unit, Mobile, RenderInfantry, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, TakeCover, Infantry
|
||||||
LongDesc=Infiltrates enemy structures to gather \nintelligence. Exact effect depends on the \nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised
|
LongDesc=Infiltrates enemy structures to gather \nintelligence. Exact effect depends on the \nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised
|
||||||
[THF]
|
[THF]
|
||||||
Description=Thief
|
Description=Thief
|
||||||
Voice=ThiefVoice
|
Voice=ThiefVoice
|
||||||
Traits=Unit, Mobile, RenderInfantry, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, TakeCover, Infantry
|
||||||
LongDesc=Infiltrates enemy refineries & \nsilos, and steals money stored there.\n Unarmed
|
LongDesc=Infiltrates enemy refineries & \nsilos, and steals money stored there.\n Unarmed
|
||||||
[E7]
|
[E7]
|
||||||
Description=Tanya
|
Description=Tanya
|
||||||
Voice=TanyaVoice
|
Voice=TanyaVoice
|
||||||
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry
|
||||||
LongDesc=Elite commando infantry, armed with \ndual pistols and C4.\n Strong vs Infantry, Buildings\n Weak vs Vehicles\n Special Ability: Destroy Building with C4
|
LongDesc=Elite commando infantry, armed with \ndual pistols and C4.\n Strong vs Infantry, Buildings\n Weak vs Vehicles\n Special Ability: Destroy Building with C4
|
||||||
[MEDI]
|
[MEDI]
|
||||||
Description=Medic
|
Description=Medic
|
||||||
Voice=MedicVoice
|
Voice=MedicVoice
|
||||||
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover
|
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry
|
||||||
LongDesc=Heals nearby infantry.\n Strong vs Nothing\n Weak vs Everything
|
LongDesc=Heals nearby infantry.\n Strong vs Nothing\n Weak vs Everything
|
||||||
|
|
||||||
|
|
||||||
@@ -657,6 +657,7 @@ Super
|
|||||||
Organic
|
Organic
|
||||||
Nuke
|
Nuke
|
||||||
UnitExplodeWarhead
|
UnitExplodeWarhead
|
||||||
|
Crush
|
||||||
|
|
||||||
[HE]
|
[HE]
|
||||||
ImpactSound=kaboom25
|
ImpactSound=kaboom25
|
||||||
@@ -669,6 +670,10 @@ Explosion=8
|
|||||||
InfDeath=3
|
InfDeath=3
|
||||||
ImpactSound=kaboom15
|
ImpactSound=kaboom15
|
||||||
|
|
||||||
|
[Crush]
|
||||||
|
Verses=100%,100%,100%,100%,100%
|
||||||
|
ImpactSound=squishy2
|
||||||
|
|
||||||
[General]
|
[General]
|
||||||
OreChance=.02
|
OreChance=.02
|
||||||
LowPowerSlowdown=3
|
LowPowerSlowdown=3
|
||||||
|
|||||||
Reference in New Issue
Block a user