This commit is contained in:
Chris Forbes
2010-01-19 15:17:02 +13:00
28 changed files with 564 additions and 77 deletions

View File

@@ -8,8 +8,9 @@ namespace OpenRa.FileFormats
{ {
public readonly Dictionary<ushort, Terrain> tiles = new Dictionary<ushort, Terrain>(); public readonly Dictionary<ushort, Terrain> tiles = new Dictionary<ushort, Terrain>();
readonly Dictionary<ushort, Dictionary<int, int>> walk = public readonly Walkability Walkability = new Walkability();
new Dictionary<ushort, Dictionary<int, int>>(); // cjf will fix public readonly Dictionary<ushort, TileTemplate> walk
= new Dictionary<ushort, TileTemplate>();
string NextLine( StreamReader reader ) string NextLine( StreamReader reader )
{ {
@@ -27,7 +28,7 @@ namespace OpenRa.FileFormats
public TileSet( string suffix ) public TileSet( string suffix )
{ {
Walkability walkability = new Walkability(); Walkability = new Walkability();
char tileSetChar = char.ToUpperInvariant( suffix[ 1 ] ); char tileSetChar = char.ToUpperInvariant( suffix[ 1 ] );
StreamReader tileIdFile = new StreamReader( FileSystem.Open( "tileSet.til" ) ); StreamReader tileIdFile = new StreamReader( FileSystem.Open( "tileSet.til" ) );
@@ -51,7 +52,7 @@ namespace OpenRa.FileFormats
string tilename = string.Format(pattern, i + 1); string tilename = string.Format(pattern, i + 1);
if (!walk.ContainsKey((ushort)(start + i))) if (!walk.ContainsKey((ushort)(start + i)))
walk.Add((ushort)(start + i), walkability.GetWalkability(tilename)); walk.Add((ushort)(start + i), Walkability.GetWalkability(tilename));
using( Stream s = FileSystem.Open( tilename + suffix ) ) using( Stream s = FileSystem.Open( tilename + suffix ) )
{ {
@@ -82,7 +83,7 @@ namespace OpenRa.FileFormats
if (r.tile == 0xff || r.tile == 0xffff) if (r.tile == 0xff || r.tile == 0xffff)
r.image = 0; r.image = 0;
return walk[r.tile][r.image]; return walk[r.tile].TerrainType[r.image];
} }
} }
} }

View File

@@ -1,35 +1,51 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Linq;
namespace OpenRa.FileFormats namespace OpenRa.FileFormats
{ {
public class TileTemplate
{
public int Index;
public string Name;
public int2 Size;
public string Bridge;
public float HP;
public Dictionary<int, int> TerrainType = new Dictionary<int, int>();
}
public class Walkability public class Walkability
{ {
Dictionary<string, Dictionary<int, int>> walkability = Dictionary<string, TileTemplate> walkability
new Dictionary<string, Dictionary<int, int>>(); = new Dictionary<string,TileTemplate>();
public Walkability() public Walkability()
{ {
IniFile file = new IniFile( FileSystem.Open( "templates.ini" ) ); var file = new IniFile( FileSystem.Open( "templates.ini" ) );
Regex pattern = new Regex(@"tiletype(\d+)");
foreach (IniSection section in file.Sections) foreach (var section in file.Sections)
{ {
string name = section.GetValue("Name", null).ToLowerInvariant(); var tile = new TileTemplate
Dictionary<int, int> tileWalkability = new Dictionary<int, int>();
foreach (KeyValuePair<string, string> p in section)
{ {
Match m = pattern.Match(p.Key); Size = new int2(
if (m != null && m.Success) int.Parse(section.GetValue("width", "0")),
tileWalkability.Add(int.Parse(m.Groups[1].Value), int.Parse(p.Value)); int.Parse(section.GetValue("height", "0"))),
} TerrainType = section
.Where(p => p.Key.StartsWith("tiletype"))
.ToDictionary(
p => int.Parse(p.Key.Substring(8)),
p => int.Parse(p.Value)),
Name = section.GetValue("Name", null).ToLowerInvariant(),
Index = int.Parse(section.Name.Substring(3)),
Bridge = section.GetValue("bridge", null),
HP = float.Parse(section.GetValue("hp", "0"))
};
walkability[name] = tileWalkability; walkability[tile.Name] = tile;
} }
} }
public Dictionary<int, int> GetWalkability(string terrainName) public TileTemplate GetWalkability(string terrainName)
{ {
return walkability[terrainName]; return walkability[terrainName];
} }

View File

@@ -120,6 +120,7 @@ namespace OpenRa
public bool IsDead { get { return Health <= 0; } } public bool IsDead { get { return Health <= 0; } }
public bool IsInWorld { get; set; } public bool IsInWorld { get; set; }
public bool RemoveOnDeath = true;
public DamageState GetDamageState() public DamageState GetDamageState()
{ {
@@ -145,7 +146,8 @@ namespace OpenRa
if (attacker.Owner != null) if (attacker.Owner != null)
attacker.Owner.Kills++; attacker.Owner.Kills++;
Game.world.AddFrameEndTask(w => w.Remove(this)); if (RemoveOnDeath)
Game.world.AddFrameEndTask(w => w.Remove(this));
} }
var maxHP = this.GetMaxHP(); var maxHP = this.GetMaxHP();

67
OpenRa.Game/Bridges.cs Normal file
View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Traits;
namespace OpenRa
{
static class Bridges
{
public static void MakeBridges(World w)
{
var mini = w.Map.XOffset; var maxi = w.Map.XOffset + w.Map.Width;
var minj = w.Map.YOffset; var maxj = w.Map.YOffset + w.Map.Height;
for (var j = minj; j < maxj; j++)
for (var i = mini; i < maxi; i++)
if (IsBridge(w, w.Map.MapTiles[i, j].tile))
ConvertBridgeToActor(w, i, j);
foreach (var br in w.Actors.SelectMany(a => a.traits.WithInterface<Bridge>()))
br.FinalizeBridges(w);
}
static void ConvertBridgeToActor(World w, int i, int j)
{
var tile = w.Map.MapTiles[i, j].tile;
var image = w.Map.MapTiles[i, j].image;
var template = w.TileSet.walk[tile];
// base position of the tile
var ni = i - image % template.Size.X;
var nj = j - image / template.Size.X;
var replacedTiles = new Dictionary<int2, int>();
for (var y = nj; y < nj + template.Size.Y; y++)
for (var x = ni; x < ni + template.Size.X; x++)
{
var n = (x - ni) + template.Size.X * (y - nj);
if (!template.TerrainType.ContainsKey(n)) continue;
if (w.Map.IsInMap(x, y))
if (w.Map.MapTiles[x, y].tile == tile
&& w.Map.MapTiles[x,y].image == n)
{
// stash it
replacedTiles[new int2(x, y)] = w.Map.MapTiles[x, y].image;
// remove the tile from the actual map
w.Map.MapTiles[x, y].tile = 0xfffe;
w.Map.MapTiles[x, y].image = 0;
}
}
if (replacedTiles.Any())
{
var a = w.CreateActor(template.Bridge, new int2(ni, nj), null);
var br = a.traits.Get<Bridge>();
br.SetTiles(w, template, replacedTiles);
}
}
static bool IsBridge(World w, ushort t)
{
return w.TileSet.walk[t].Bridge != null;
}
}
}

View File

@@ -58,6 +58,7 @@ namespace OpenRa
FileSystem.UnmountTemporaryPackages(); FileSystem.UnmountTemporaryPackages();
Rules.LoadRules(mapName, usingAftermath); Rules.LoadRules(mapName, usingAftermath);
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
world = new World(); world = new World();
Game.world.ActorAdded += a => Game.world.ActorAdded += a =>
{ {

View File

@@ -51,7 +51,9 @@ namespace OpenRa.Graphics
if (terrainTypeColors == null) if (terrainTypeColors == null)
{ {
var pal = new Palette(FileSystem.Open(world.Map.Theater + ".pal")); var pal = new Palette(FileSystem.Open(world.Map.Theater + ".pal"));
terrainTypeColors = new[] {theater.ToLowerInvariant() == "snow" ? 0xe3 :0x1a, 0x63, 0x2f, 0x1f, 0x14, 0x64, 0x1f, 0x68, 0x6b, 0x6d } terrainTypeColors = new[] {
theater.ToLowerInvariant() == "snow" ? 0xe3 :0x1a,
0x63, 0x2f, 0x1f, 0x14, 0x64, 0x1f, 0x68, 0x6b, 0x6d, 0x88 }
.Select( a => Color.FromArgb(alpha, pal.GetColor(a) )).ToArray(); .Select( a => Color.FromArgb(alpha, pal.GetColor(a) )).ToArray();
playerColors = Util.MakeArray<Color>( 8, b => Color.FromArgb(alpha, Chat.paletteColors[b]) ); playerColors = Util.MakeArray<Color>( 8, b => Color.FromArgb(alpha, Chat.paletteColors[b]) );

View File

@@ -107,8 +107,6 @@ namespace OpenRa.Graphics
public static Sprite GetImageFromCollection(Renderer renderer,string collection, string image) public static Sprite GetImageFromCollection(Renderer renderer,string collection, string image)
{ {
// Cached sprite // Cached sprite
if (cachedSprites.ContainsKey(collection) && cachedSprites[collection].ContainsKey(image)) if (cachedSprites.ContainsKey(collection) && cachedSprites[collection].ContainsKey(image))
return cachedSprites[collection][image]; return cachedSprites[collection][image];

View File

@@ -77,6 +77,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Bridges.cs" />
<Compile Include="Chat.cs" /> <Compile Include="Chat.cs" />
<Compile Include="Chrome.cs" /> <Compile Include="Chrome.cs" />
<Compile Include="Combat.cs" /> <Compile Include="Combat.cs" />
@@ -210,6 +211,7 @@
<Compile Include="Traits\AutoHeal.cs" /> <Compile Include="Traits\AutoHeal.cs" />
<Compile Include="Traits\AutoTarget.cs" /> <Compile Include="Traits\AutoTarget.cs" />
<Compile Include="Traits\BelowUnits.cs" /> <Compile Include="Traits\BelowUnits.cs" />
<Compile Include="Traits\Bridge.cs" />
<Compile Include="Traits\Buildable.cs" /> <Compile Include="Traits\Buildable.cs" />
<Compile Include="Traits\Building.cs" /> <Compile Include="Traits\Building.cs" />
<Compile Include="Traits\Cargo.cs" /> <Compile Include="Traits\Cargo.cs" />

View File

@@ -65,7 +65,7 @@ namespace OpenRa.Orders
} }
} }
} }
catch (IOException e) catch (IOException)
{ {
State = ConnectionState.NotConnected; State = ConnectionState.NotConnected;
} }

View File

@@ -4,6 +4,7 @@ using System.Linq;
using OpenRa.FileFormats; using OpenRa.FileFormats;
using OpenRa.Support; using OpenRa.Support;
using OpenRa.Traits; using OpenRa.Traits;
using System.Diagnostics;
namespace OpenRa namespace OpenRa
{ {
@@ -143,9 +144,7 @@ namespace OpenRa
return ret; return ret;
} }
[Conditional( "SANITY_CHECKS" )]
[System.Diagnostics.Conditional( "SANITY_CHECKS" )]
static void CheckSanePath( List<int2> path ) static void CheckSanePath( List<int2> path )
{ {
if( path.Count == 0 ) if( path.Count == 0 )
@@ -160,7 +159,7 @@ namespace OpenRa
} }
} }
[System.Diagnostics.Conditional("SANITY_CHECKS")] [Conditional("SANITY_CHECKS")]
static void CheckSanePath2(List<int2> path, int2 src, int2 dest) static void CheckSanePath2(List<int2> path, int2 src, int2 dest)
{ {
if (path.Count == 0) if (path.Count == 0)

View File

@@ -14,7 +14,6 @@ namespace OpenRa
public UnitMovementType umt; public UnitMovementType umt;
Func<int2, bool> customBlock; Func<int2, bool> customBlock;
public bool checkForBlocked; public bool checkForBlocked;
public bool ignoreTerrain;
public Actor ignoreBuilding; public Actor ignoreBuilding;
public PathSearch() public PathSearch()
@@ -40,9 +39,13 @@ namespace OpenRa
var p = queue.Pop(); var p = queue.Pop();
cellInfo[ p.Location.X, p.Location.Y ].Seen = true; cellInfo[ p.Location.X, p.Location.Y ].Seen = true;
if (!ignoreTerrain) var custom2 = Game.world.customTerrain[p.Location.X, p.Location.Y];
if (passableCost[(int)umt][p.Location.X, p.Location.Y] == float.PositiveInfinity) var thisCost = (custom2 != null)
return p.Location; ? custom2.GetCost(p.Location, umt)
: passableCost[(int)umt][p.Location.X, p.Location.Y];
if (thisCost == float.PositiveInfinity)
return p.Location;
foreach( int2 d in Util.directions ) foreach( int2 d in Util.directions )
{ {
@@ -51,17 +54,18 @@ namespace OpenRa
if (!Game.world.Map.IsInMap(newHere.X, newHere.Y)) continue; if (!Game.world.Map.IsInMap(newHere.X, newHere.Y)) continue;
if( cellInfo[ newHere.X, newHere.Y ].Seen ) if( cellInfo[ newHere.X, newHere.Y ].Seen )
continue; continue;
if (!ignoreTerrain) var custom = Game.world.customTerrain[newHere.X, newHere.Y];
{ var costHere = (custom != null) ? custom.GetCost(newHere, umt) : passableCost[(int)umt][newHere.X, newHere.Y];
if (passableCost[(int)umt][newHere.X, newHere.Y] == float.PositiveInfinity)
continue; if (costHere == float.PositiveInfinity)
if (!Game.world.BuildingInfluence.CanMoveHere(newHere) && continue;
Game.world.BuildingInfluence.GetBuildingAt(newHere) != ignoreBuilding)
continue; if (!Game.world.BuildingInfluence.CanMoveHere(newHere) &&
if (Game.world.Map.IsOverlaySolid(newHere)) Game.world.BuildingInfluence.GetBuildingAt(newHere) != ignoreBuilding)
continue; continue;
} if (Game.world.Map.IsOverlaySolid(newHere))
continue;
// Replicate real-ra behavior of not being able to enter a cell if there is a mixture of crushable and uncrushable units // 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.world.UnitInfluence.GetUnitsAt(newHere).Any(a => !Game.world.IsActorPathableToCrush(a, umt)))) if (checkForBlocked && (Game.world.UnitInfluence.GetUnitsAt(newHere).Any(a => !Game.world.IsActorPathableToCrush(a, umt))))
@@ -69,14 +73,12 @@ namespace OpenRa
if (customBlock != null && customBlock(newHere)) if (customBlock != null && customBlock(newHere))
continue; continue;
var est = heuristic( newHere ); var est = heuristic( newHere );
if( est == float.PositiveInfinity ) if( est == float.PositiveInfinity )
continue; continue;
float cellCost = ( ( d.X * d.Y != 0 ) ? 1.414213563f : 1.0f ) * float cellCost = ((d.X * d.Y != 0) ? 1.414213563f : 1.0f) * costHere;
(ignoreTerrain ? 1 : passableCost[ (int)umt ][ newHere.X, newHere.Y ]);
float newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost; float newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost;
if( newCost >= cellInfo[ newHere.X, newHere.Y ].MinCost ) if( newCost >= cellInfo[ newHere.X, newHere.Y ].MinCost )

View File

@@ -23,28 +23,29 @@ namespace OpenRa
Wall = 7, Wall = 7,
Beach = 8, Beach = 8,
Ore = 9, Ore = 9,
Special = 10,
} }
static class TerrainCosts static class TerrainCosts
{ {
static double[][] costs = Util.MakeArray<double[]>( 4, static float[][] costs = Util.MakeArray<float[]>(4,
a => Util.MakeArray<double>( 10, b => double.PositiveInfinity )); a => Util.MakeArray<float>(11, b => float.PositiveInfinity));
static TerrainCosts() static TerrainCosts()
{ {
for( int i = 0 ; i < 10 ; i++ ) for( int i = 0 ; i < 11 ; i++ )
{ {
if( i == 4 ) continue; if( i == 4 ) continue;
var section = Rules.AllRules.GetSection( ( (TerrainMovementType)i ).ToString() ); var section = Rules.AllRules.GetSection( ( (TerrainMovementType)i ).ToString() );
for( int j = 0 ; j < 4 ; j++ ) for( int j = 0 ; j < 4 ; j++ )
{ {
string val = section.GetValue( ( (UnitMovementType)j ).ToString(), "0%" ); string val = section.GetValue( ( (UnitMovementType)j ).ToString(), "0%" );
costs[ j ][ i ] = 100.0 / double.Parse( val.Substring( 0, val.Length - 1 ) ); costs[j][i] = 100f / float.Parse(val.Substring(0, val.Length - 1));
} }
} }
} }
public static double Cost( UnitMovementType unitMovementType, int r ) public static float Cost( UnitMovementType unitMovementType, int r )
{ {
return costs[ (byte)unitMovementType ][ r ]; return costs[ (byte)unitMovementType ][ r ];
} }

View File

@@ -180,9 +180,19 @@ namespace OpenRa.Traits
if (self == underCursor) return null; if (self == underCursor) return null;
var isHeal = self.GetPrimaryWeapon().Damage < 0; var isHeal = self.GetPrimaryWeapon().Damage < 0;
if (((underCursor.Owner == self.Owner) ^ isHeal) var forceFire = mi.Modifiers.HasModifier(Modifiers.Ctrl);
&& !mi.Modifiers.HasModifier( Modifiers.Ctrl )) return null;
if (isHeal)
{
if (underCursor.Owner == null)
return null;
if (underCursor.Owner != self.Owner && !forceFire)
return null;
}
else
if ((underCursor.Owner == self.Owner || underCursor.Owner == null) && !forceFire)
return null;
if (!Combat.HasAnyValidWeapons(self, underCursor)) return null; if (!Combat.HasAnyValidWeapons(self, underCursor)) return null;
return new Order(isHeal ? "Heal" : "Attack", self, underCursor, int2.Zero, null); return new Order(isHeal ? "Heal" : "Attack", self, underCursor, int2.Zero, null);

View File

@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Graphics;
using OpenRa.FileFormats;
using IjwFramework.Collections;
using System.Drawing;
namespace OpenRa.Traits
{
class BridgeInfo : ITraitInfo
{
public readonly bool Long = false;
public readonly bool UseAlternateNames = false;
public readonly int[] NorthOffset = null;
public readonly int[] SouthOffset = null;
public object Create(Actor self) { return new Bridge(self); }
}
class Bridge : IRender, ICustomTerrain, INotifyDamage
{
Dictionary<int2, int> Tiles;
List<Dictionary<int2, Sprite>> TileSprites = new List<Dictionary<int2,Sprite>>();
List<TileTemplate> Templates = new List<TileTemplate>();
Actor self;
int state;
Bridge northNeighbour, southNeighbour;
public Bridge(Actor self) { this.self = self; self.RemoveOnDeath = false; }
static string cachedTheater;
static Cache<TileReference, Sprite> sprites;
public IEnumerable<Renderable> Render(Actor self)
{
foreach (var t in TileSprites[state])
yield return new Renderable(t.Value, Game.CellSize * t.Key, PaletteType.Gold);
}
public int StateFromTemplate(TileTemplate t)
{
var info = self.Info.Traits.Get<BridgeInfo>();
if (info.UseAlternateNames)
{
if (t.Name.EndsWith("d")) return 2;
if (t.Name.EndsWith("h")) return 1;
return 0;
}
else
return t.Name[t.Name.Length - 1] - 'a';
}
public string NameFromState(TileTemplate t, int state)
{
var info = self.Info.Traits.Get<BridgeInfo>();
if (info.UseAlternateNames)
return t.Bridge + new[] { "", "h", "d" }[state];
else
return t.Bridge + (char)(state + 'a');
}
public void SetTiles(World world, TileTemplate template, Dictionary<int2, int> replacedTiles)
{
Tiles = replacedTiles;
state = StateFromTemplate(template);
foreach (var t in replacedTiles.Keys)
world.customTerrain[t.X, t.Y] = this;
if (cachedTheater != world.Map.Theater)
{
cachedTheater = world.Map.Theater;
sprites = new Cache<TileReference, Sprite>(
x => SheetBuilder.Add(world.TileSet.GetBytes(x),
new Size(Game.CellSize, Game.CellSize)));
}
var numStates = self.Info.Traits.Get<BridgeInfo>().Long ? 6 : 3;
for (var n = 0; n < numStates; n++)
{
var stateTemplate = world.TileSet.Walkability.GetWalkability(NameFromState(template, n));
Templates.Add( stateTemplate );
TileSprites.Add(replacedTiles.ToDictionary(
a => a.Key,
a => sprites[new TileReference { tile = (ushort)stateTemplate.Index, image = (byte)a.Value }]));
}
self.Health = (int)(self.GetMaxHP() * template.HP);
}
Bridge GetNeighbor(World world, int[] offset)
{
if (offset == null) return null;
var pos = self.Location + new int2(offset[0], offset[1]);
if (!world.Map.IsInMap(pos.X, pos.Y)) return null;
return world.customTerrain[pos.X, pos.Y] as Bridge;
}
public void FinalizeBridges(World world)
{
// go looking for our neighbors, if this is a long bridge.
var info = self.Info.Traits.Get<BridgeInfo>();
if (info.NorthOffset != null)
northNeighbour = GetNeighbor(world, info.NorthOffset);
if (info.SouthOffset != null)
southNeighbour = GetNeighbor(world, info.SouthOffset);
}
public float GetCost(int2 p, UnitMovementType umt)
{
// just use the standard walkability from templates.ini. no hackery.
return TerrainCosts.Cost(umt,
Templates[state].TerrainType[Tiles[p]]);
}
bool IsIntact(Bridge b)
{
return b != null && b.self.IsInWorld && b.self.Health > 0;
}
bool IsLong(Bridge b)
{
return b != null && b.self.IsInWorld && b.self.Info.Traits.Get<BridgeInfo>().Long;
}
void UpdateState()
{
var ds = self.GetDamageState();
if (!self.Info.Traits.Get<BridgeInfo>().Long)
{
state = (int)ds;
return;
}
bool waterToSouth = !IsIntact(southNeighbour) && (!IsLong(southNeighbour) || !IsIntact(this));
bool waterToNorth = !IsIntact(northNeighbour) && (!IsLong(northNeighbour) || !IsIntact(this));
if (waterToSouth && waterToNorth) { state = 5; return; }
if (waterToNorth) { state = 4; return; }
if (waterToSouth) { state = 3; return; }
state = (int)ds;
}
public void Damaged(Actor self, AttackInfo e)
{
if (e.DamageStateChanged)
{
UpdateState();
if (northNeighbour != null) northNeighbour.UpdateState();
if (southNeighbour != null) southNeighbour.UpdateState();
}
}
}
}

View File

@@ -9,7 +9,7 @@ namespace OpenRa.Traits
public readonly int[] SpawnOffset = null; public readonly int[] SpawnOffset = null;
public readonly string[] Produces = { }; public readonly string[] Produces = { };
public object Create(Actor self) { return new Production(self); } public virtual object Create(Actor self) { return new Production(self); }
} }
class Production : IIssueOrder, IResolveOrder, IProducer, ITags class Production : IIssueOrder, IResolveOrder, IProducer, ITags

View File

@@ -3,9 +3,9 @@ using OpenRa.GameRules;
namespace OpenRa.Traits namespace OpenRa.Traits
{ {
class ProductionSurroundInfo : ITraitInfo class ProductionSurroundInfo : ProductionInfo
{ {
public object Create(Actor self) { return new ProductionSurround(self); } public override object Create(Actor self) { return new ProductionSurround(self); }
} }
class ProductionSurround : Production class ProductionSurround : Production

View File

@@ -25,6 +25,8 @@ namespace OpenRa.Traits
public interface IAcceptThief { void OnSteal(Actor self, Actor thief); } public interface IAcceptThief { void OnSteal(Actor self, Actor thief); }
public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); } public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); }
public interface ICustomTerrain { float GetCost(int2 p, UnitMovementType umt); }
interface IProducer interface IProducer
{ {
bool Produce( Actor self, ActorInfo producee ); bool Produce( Actor self, ActorInfo producee );

View File

@@ -4,6 +4,7 @@ using OpenRa.Effects;
using OpenRa.Support; using OpenRa.Support;
using OpenRa.FileFormats; using OpenRa.FileFormats;
using OpenRa.Graphics; using OpenRa.Graphics;
using OpenRa.Traits;
namespace OpenRa namespace OpenRa
{ {
@@ -21,6 +22,9 @@ namespace OpenRa
public readonly Map Map; public readonly Map Map;
public readonly TileSet TileSet; public readonly TileSet TileSet;
// for tricky things like bridges.
public readonly ICustomTerrain[,] customTerrain = new ICustomTerrain[128, 128];
public readonly WorldRenderer WorldRenderer; public readonly WorldRenderer WorldRenderer;
internal readonly Minimap Minimap; internal readonly Minimap Minimap;
@@ -40,10 +44,11 @@ namespace OpenRa
oreTicks = oreFrequency; oreTicks = oreFrequency;
Map.InitOreDensity(); Map.InitOreDensity();
PathFinder = new PathFinder(this);
CreateActor("World", new int2(int.MaxValue, int.MaxValue), null); CreateActor("World", new int2(int.MaxValue, int.MaxValue), null);
Bridges.MakeBridges(this);
PathFinder = new PathFinder(this);
WorldRenderer = new WorldRenderer(this, Game.renderer); WorldRenderer = new WorldRenderer(this, Game.renderer);
Minimap = new Minimap(this, Game.renderer); Minimap = new Minimap(this, Game.renderer);
} }

View File

@@ -17,6 +17,7 @@ namespace OpenRa.Mods.RA
if (!underCursor.traits.Contains<Building>()) return null; if (!underCursor.traits.Contains<Building>()) return null;
// todo: other bits // todo: other bits
if (underCursor.Owner == null) return null; // don't allow capturing of bridges, etc.
return new Order(underCursor.Health <= EngineerDamage ? "Capture" : "Infiltrate", return new Order(underCursor.Health <= EngineerDamage ? "Capture" : "Infiltrate",
self, underCursor, int2.Zero, null); self, underCursor, int2.Zero, null);

View File

@@ -138,6 +138,10 @@ namespace RulesConverter
{ "Produces", "Produces" } } { "Produces", "Produces" } }
}, },
{ "ProductionSurround", new PL {
{ "Produces", "Produces" } }
},
{ "Minelayer", new PL { { "Minelayer", new PL {
{ "Mine", "Primary" } } { "Mine", "Primary" } }
}, },

BIN
bogus.sno Normal file

Binary file not shown.

BIN
bogus.tem Normal file

Binary file not shown.

View File

@@ -28,3 +28,23 @@ MINV:
Warhead: ATMine Warhead: ATMine
TriggeredBy: Wheel, Track TriggeredBy: Wheel, Track
AvoidFriendly: yes AvoidFriendly: yes
BR1:
Bridge:
SouthOffset:0,2
BR2:
Bridge:
NorthOffset:3,0
BR3:
Bridge:
Long: yes
NorthOffset: 2,0
SouthOffset: 0,1
BRIDGE1:
Bridge:
UseAlternateNames: yes
BRIDGE2:
Bridge:
UseAlternateNames: yes

59
ra.yaml
View File

@@ -83,6 +83,63 @@ MINV:
-Selectable: -Selectable:
-Building: -Building:
BR1:
Bridge:
SouthOffset: 0,2
Category: Building
Selectable:
BelowUnits:
Building:
Footprint: ____ ____
Dimensions: 4,2
HP: 1000
BR2:
Bridge:
NorthOffset: 3,0
Category: Building
Selectable:
BelowUnits:
Building:
Footprint: ____ ____
Dimensions: 4,2
HP: 1000
BR3:
Bridge:
Long: yes
NorthOffset: 2,0
SouthOffset: 0,1
Category: Building
Selectable:
BelowUnits:
Building:
Footprint: ____ ____
Dimensions: 4,2
HP: 1000
BRIDGE1:
Bridge:
UseAlternateNames: yes
Category: Building
Selectable:
BelowUnits:
Building:
Footprint: _____ _____ _____
Dimensions: 5,3
HP: 1000
BRIDGE2:
Bridge:
UseAlternateNames: yes
Category: Building
Selectable:
BelowUnits:
Building:
Footprint: _____ _____
Dimensions: 5,2
HP: 1000
V2RL: V2RL:
Inherits: ^Vehicle Inherits: ^Vehicle
Buildable: Buildable:
@@ -999,6 +1056,7 @@ SYRD:
Sight: 4 Sight: 4
RenderBuilding: RenderBuilding:
ProductionSurround: ProductionSurround:
Produces: Ship
IronCurtainable: IronCurtainable:
SPEN: SPEN:
@@ -1023,6 +1081,7 @@ SPEN:
Sight: 4 Sight: 4
RenderBuilding: RenderBuilding:
ProductionSurround: ProductionSurround:
Produces: Ship
IronCurtainable: IronCurtainable:
FACT: FACT:

View File

@@ -2525,6 +2525,14 @@ Wheel=0%
Float=0% Float=0%
Buildable=no Buildable=no
; special tile for bridge hacks
[Special]
Foot=100%
Track=100%
Wheel=100%
Float=100%
Buildable=no
; ******* Random Crate Powerups ******* ; ******* Random Crate Powerups *******
; This specifies the chance for the specified crate powerup to appear ; This specifies the chance for the specified crate powerup to appear

View File

@@ -1533,6 +1533,8 @@ tiletype8=0
Name=BRIDGE1 Name=BRIDGE1
width=5 width=5
height=3 height=3
bridge=bridge1
hp=1
tiletype1=3 tiletype1=3
tiletype2=2 tiletype2=2
tiletype3=2 tiletype3=2
@@ -1548,6 +1550,8 @@ tiletype12=3
Name=BRIDGE1D Name=BRIDGE1D
width=5 width=5
height=3 height=3
bridge=bridge1
hp=0
tiletype1=3 tiletype1=3
tiletype2=3 tiletype2=3
tiletype3=3 tiletype3=3
@@ -1563,6 +1567,8 @@ tiletype12=3
Name=BRIDGE2 Name=BRIDGE2
width=5 width=5
height=2 height=2
bridge=bridge2
hp=1
tiletype0=3 tiletype0=3
tiletype1=2 tiletype1=2
tiletype2=2 tiletype2=2
@@ -1577,6 +1583,8 @@ tiletype9=3
Name=BRIDGE2D Name=BRIDGE2D
width=5 width=5
height=2 height=2
bridge=bridge2
hp=0
tiletype0=3 tiletype0=3
tiletype1=3 tiletype1=3
tiletype2=3 tiletype2=3
@@ -2491,6 +2499,8 @@ tiletype3=3
Name=BR1A Name=BR1A
width=4 width=4
height=3 height=3
bridge=br1
hp=1
tiletype1=3 tiletype1=3
tiletype2=2 tiletype2=2
tiletype4=3 tiletype4=3
@@ -2505,6 +2515,8 @@ tiletype11=3
Name=BR1B Name=BR1B
width=4 width=4
height=3 height=3
bridge=br1
hp=.5
tiletype1=3 tiletype1=3
tiletype2=6 tiletype2=6
tiletype4=3 tiletype4=3
@@ -2519,6 +2531,8 @@ tiletype11=3
Name=BR1C Name=BR1C
width=4 width=4
height=3 height=3
bridge=br1
hp=0
tiletype1=3 tiletype1=3
tiletype2=3 tiletype2=3
tiletype4=3 tiletype4=3
@@ -2533,6 +2547,8 @@ tiletype11=3
Name=BR2A Name=BR2A
width=5 width=5
height=3 height=3
bridge=br2
hp=1
tiletype1=3 tiletype1=3
tiletype2=2 tiletype2=2
tiletype5=3 tiletype5=3
@@ -2548,6 +2564,8 @@ tiletype13=3
Name=BR2B Name=BR2B
width=5 width=5
height=3 height=3
bridge=br2
hp=.5
tiletype1=3 tiletype1=3
tiletype2=6 tiletype2=6
tiletype5=3 tiletype5=3
@@ -2563,6 +2581,8 @@ tiletype13=3
Name=BR2C Name=BR2C
width=5 width=5
height=3 height=3
bridge=br2
hp=0
tiletype1=1 tiletype1=1
tiletype2=1 tiletype2=1
tiletype5=3 tiletype5=3
@@ -2578,6 +2598,8 @@ tiletype13=3
Name=BR3A Name=BR3A
width=4 width=4
height=2 height=2
bridge=br3
hp=1
tiletype0=3 tiletype0=3
tiletype1=2 tiletype1=2
tiletype5=2 tiletype5=2
@@ -2588,6 +2610,8 @@ tiletype7=3
Name=BR3B Name=BR3B
width=4 width=4
height=2 height=2
bridge=br3
hp=.5
tiletype0=3 tiletype0=3
tiletype1=2 tiletype1=2
tiletype5=2 tiletype5=2
@@ -2598,6 +2622,8 @@ tiletype7=3
Name=BR3C Name=BR3C
width=4 width=4
height=2 height=2
bridge=br3
hp=0
tiletype0=3 tiletype0=3
tiletype1=3 tiletype1=3
tiletype5=3 tiletype5=3
@@ -2608,6 +2634,8 @@ tiletype7=3
Name=BR3D Name=BR3D
width=4 width=4
height=2 height=2
bridge=br3
hp=0
tiletype0=5 tiletype0=5
tiletype1=3 tiletype1=3
tiletype5=5 tiletype5=5
@@ -2618,6 +2646,8 @@ tiletype7=5
Name=BR3E Name=BR3E
width=4 width=4
height=2 height=2
bridge=br3
hp=0
tiletype0=1 tiletype0=1
tiletype1=1 tiletype1=1
tiletype5=3 tiletype5=3
@@ -2628,6 +2658,8 @@ tiletype7=1
Name=BR3F Name=BR3F
width=4 width=4
height=2 height=2
bridge=br3
hp=0
tiletype0=1 tiletype0=1
tiletype1=1 tiletype1=1
tiletype5=1 tiletype5=1
@@ -2726,6 +2758,8 @@ tiletype0=0
Name=BRIDGE1H Name=BRIDGE1H
width=5 width=5
height=3 height=3
bridge=bridge1
hp=.5
tiletype1=3 tiletype1=3
tiletype2=6 tiletype2=6
tiletype3=6 tiletype3=6
@@ -2741,6 +2775,8 @@ tiletype12=6
Name=BRIDGE2H Name=BRIDGE2H
width=5 width=5
height=2 height=2
bridge=bridge2
hp=.5
tiletype0=3 tiletype0=3
tiletype1=6 tiletype1=6
tiletype2=6 tiletype2=6
@@ -2798,3 +2834,9 @@ tiletype18=2
tiletype19=2 tiletype19=2
tiletype23=2 tiletype23=2
tiletype24=2 tiletype24=2
[TEM65534]
Name=Bogus
width=1
height=1
tiletype0=10

View File

@@ -91,18 +91,72 @@ TS-
00eb 00eb
br1a br1a
; long bridge (north end, damaged)
TS-
1
00ec
br1b
; long bridge (north end, broken)
TS-
1
00ed
br1c
; long bridge (south end) ; long bridge (south end)
TS- TS-
1 1
00ee 00ee
br2a br2a
; long bridge (south end, damaged)
TS-
1
00ef
br2b
; long bridge (south end, broken)
TS-
1
00f0
br2c
; long bridge (middle) ; long bridge (middle)
TS- TS-
1 1
00f1 00f1
br3a br3a
; long bridge (middle, damaged)
TS-
1
00f2
br3b
; long bridge (middle, broken)
TS-
1
00f3
br3c
; long bridge (middle, broken, south end missing)
TS-
1
00f4
br3d
; long bridge (middle, broken, north end missing)
TS-
1
00f5
br3e
; long bridge (water / totally broken)
TS-
1
00f6
br3f
; long bridge (north surround) ; long bridge (north surround)
TS- TS-
1 1
@@ -115,24 +169,6 @@ TS-
017d 017d
br2x br2x
; long bridge (north end, broken)
TS-
1
00ed
br1c
; long bridge (south end, broken)
TS-
1
00f0
br2c
; long bridge (water / totally broken)
TS-
1
00f6
br3f
; short bridge "/" ; short bridge "/"
TS- TS-
1 1
@@ -172,6 +208,12 @@ bridge2d
; short bridge "\" (damaged) ; short bridge "\" (damaged)
TS- TS-
1 1
017b
bridge2h
; short bridge "\" (surround)
TS-
1
017f 017f
bridge2x bridge2x
@@ -304,3 +346,8 @@ gflr{0:0000}
0118 0118
gstr{0:0000} gstr{0:0000}
; bogus
TS-
1
fffe
bogus

View File

@@ -253,6 +253,11 @@ DOMF
; pseudo-buildings ; pseudo-buildings
MINP MINP
MINV MINV
BR1
BR2
BR3
BRIDGE1
BRIDGE2
; `Dimensions` is the size of a box that will include the whole building, excluding bib. ; `Dimensions` is the size of a box that will include the whole building, excluding bib.
@@ -533,6 +538,41 @@ Selectable=no
Traits=Unit,RenderUnit,BelowUnits,InvisibleToOthers Traits=Unit,RenderUnit,BelowUnits,InvisibleToOthers
Selectable=no Selectable=no
[BR1]
Traits=Bridge, BelowUnits, Building
Strength=1000
Dimensions=4,2
Footprint=____ ____
Selectable=yes
[BR2]
Traits=Bridge, BelowUnits, Building
Strength=1000
Dimensions=4,2
Footprint=____ ____
Selectable=yes ;; temp hack
[BR3]
Traits=Bridge, BelowUnits, Building
Strength=1000
Dimensions=4,2
Footprint=____ ____
Selectable=yes ;; temp hack
[BRIDGE1]
Traits=Bridge, BelowUnits, Building
Strength=1000
Dimensions=5,3
Footprint=_____ _____ _____
Selectable = yes
[BRIDGE2]
Traits=Bridge, BelowUnits, Building
Strength=1000
Dimensions=5,2
Footprint=_____ _____
Selectable = yes
[InfantryTypes] [InfantryTypes]
DOG DOG
E1 E1