Merge branch 'master' of github.com:chrisforbes/OpenRA into nsis
This commit is contained in:
@@ -18,23 +18,18 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public struct TreeReference
|
||||
public struct ActorReference
|
||||
{
|
||||
public readonly int X;
|
||||
public readonly int Y;
|
||||
public readonly string Image;
|
||||
|
||||
public TreeReference(int xy, string image)
|
||||
public readonly int2 Location;
|
||||
public readonly string Name;
|
||||
public readonly string Owner;
|
||||
public ActorReference( string name, int2 location, string owner )
|
||||
{
|
||||
X = xy % 128;
|
||||
Y = xy / 128;
|
||||
Image = image;
|
||||
Name = name;
|
||||
Location = location;
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public Point Location { get { return new Point(X, Y); } }
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,9 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public readonly string Title;
|
||||
public readonly string Theater;
|
||||
public readonly int INIFormat;
|
||||
|
||||
public readonly int MapSize;
|
||||
public readonly int XOffset;
|
||||
public readonly int YOffset;
|
||||
public int2 Offset { get { return new int2( XOffset, YOffset ); } }
|
||||
@@ -39,8 +41,8 @@ namespace OpenRA.FileFormats
|
||||
public readonly int Height;
|
||||
public int2 Size { get { return new int2(Width, Height); } }
|
||||
|
||||
public readonly TileReference[ , ] MapTiles = new TileReference[ 128, 128 ];
|
||||
public readonly List<TreeReference> Trees = new List<TreeReference>();
|
||||
public readonly TileReference[ , ] MapTiles;
|
||||
public readonly List<ActorReference> Actors = new List<ActorReference>();
|
||||
|
||||
public readonly IEnumerable<int2> SpawnPoints;
|
||||
|
||||
@@ -49,35 +51,53 @@ namespace OpenRA.FileFormats
|
||||
return s.Length <= maxLength ? s : s.Substring(0,maxLength );
|
||||
}
|
||||
|
||||
public string TileSuffix { get { return "." + Truncate(Theater, 3); } }
|
||||
|
||||
public Map(IniFile file)
|
||||
{
|
||||
for (int j = 0; j < 128; j++)
|
||||
for (int i = 0; i < 128; i++)
|
||||
MapTiles[i, j] = new TileReference();
|
||||
|
||||
public Map(string filename)
|
||||
{
|
||||
IniFile file = new IniFile(FileSystem.Open(filename));
|
||||
|
||||
IniSection basic = file.GetSection("Basic");
|
||||
Title = basic.GetValue("Name", "(null)");
|
||||
INIFormat = int.Parse(basic.GetValue("NewINIFormat", "0"));
|
||||
|
||||
IniSection map = file.GetSection("Map");
|
||||
Theater = Truncate(map.GetValue("Theater", "TEMPERATE"), 8);
|
||||
Theater = Truncate(map.GetValue("Theater", "TEMPERAT"), 8);
|
||||
|
||||
XOffset = int.Parse(map.GetValue("X", "0"));
|
||||
YOffset = int.Parse(map.GetValue("Y", "0"));
|
||||
|
||||
Width = int.Parse(map.GetValue("Width", "0"));
|
||||
Height = int.Parse(map.GetValue("Height", "0"));
|
||||
MapSize = (INIFormat == 3) ? 128 : 64;
|
||||
|
||||
MapTiles = new TileReference[ MapSize, MapSize ];
|
||||
for (int j = 0; j < MapSize; j++)
|
||||
for (int i = 0; i < MapSize; i++)
|
||||
MapTiles[i, j] = new TileReference();
|
||||
|
||||
UnpackTileData(ReadPackedSection(file.GetSection("MapPack")));
|
||||
UnpackOverlayData(ReadPackedSection(file.GetSection("OverlayPack")));
|
||||
ReadTrees(file);
|
||||
|
||||
|
||||
if (INIFormat == 3) // RA map
|
||||
{
|
||||
UnpackRATileData(ReadPackedSection(file.GetSection("MapPack")));
|
||||
UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack")));
|
||||
ReadRATrees(file);
|
||||
}
|
||||
else // CNC
|
||||
{
|
||||
UnpackCncTileData(FileSystem.Open(filename.Substring(0,filename.Length-4)+".bin"));
|
||||
ReadCncOverlay(file);
|
||||
ReadCncTrees(file);
|
||||
}
|
||||
|
||||
LoadActors(file, "STRUCTURES");
|
||||
LoadActors(file, "UNITS");
|
||||
LoadActors(file, "INFANTRY");
|
||||
|
||||
SpawnPoints = file.GetSection("Waypoints")
|
||||
.Select(kv => Pair.New(int.Parse(kv.Key), new int2(int.Parse(kv.Value) % 128, int.Parse(kv.Value) / 128)))
|
||||
.Where(a => a.First < 8)
|
||||
.Select(a => a.Second)
|
||||
.ToArray();
|
||||
.Where(kv => int.Parse(kv.Value) > 0)
|
||||
.Select(kv => Pair.New(int.Parse(kv.Key), new int2(int.Parse(kv.Value) % MapSize, int.Parse(kv.Value) / MapSize)))
|
||||
.Where(a => a.First < 8)
|
||||
.Select(a => a.Second)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
static MemoryStream ReadPackedSection(IniSection mapPackSection)
|
||||
@@ -136,38 +156,112 @@ namespace OpenRA.FileFormats
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UnpackTileData( MemoryStream ms )
|
||||
void UnpackRATileData( MemoryStream ms )
|
||||
{
|
||||
for( int i = 0 ; i < 128 ; i++ )
|
||||
for( int j = 0 ; j < 128 ; j++ )
|
||||
for( int i = 0 ; i < MapSize ; i++ )
|
||||
for( int j = 0 ; j < MapSize ; j++ )
|
||||
MapTiles[j, i].tile = ReadWord(ms);
|
||||
|
||||
for( int i = 0 ; i < 128 ; i++ )
|
||||
for( int j = 0 ; j < 128 ; j++ )
|
||||
for( int i = 0 ; i < MapSize ; i++ )
|
||||
for( int j = 0 ; j < MapSize ; j++ )
|
||||
{
|
||||
MapTiles[j, i].image = (byte)ms.ReadByte();
|
||||
if( MapTiles[ j, i ].tile == 0xff || MapTiles[ j, i ].tile == 0xffff )
|
||||
MapTiles[ j, i ].image = (byte)( i % 4 + ( j % 4 ) * 4 );
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackOverlayData( MemoryStream ms )
|
||||
|
||||
static string[] raOverlayNames =
|
||||
{
|
||||
for( int i = 0 ; i < 128 ; i++ )
|
||||
for( int j = 0 ; j < 128 ; j++ )
|
||||
MapTiles[ j, i ].overlay = ReadByte( ms );
|
||||
"sbag", "cycl", "brik", "fenc", "wood",
|
||||
"gold01", "gold02", "gold03", "gold04",
|
||||
"gem01", "gem02", "gem03", "gem04",
|
||||
"v12", "v13", "v14", "v15", "v16", "v17", "v18",
|
||||
"fpls", "wcrate", "scrate", "barb", "sbag",
|
||||
};
|
||||
|
||||
void UnpackRAOverlayData( MemoryStream ms )
|
||||
{
|
||||
for( int i = 0 ; i < MapSize ; i++ )
|
||||
for( int j = 0 ; j < MapSize ; j++ )
|
||||
{
|
||||
byte o = ReadByte( ms );
|
||||
MapTiles[ j, i ].overlay = (o == 255) ? null : raOverlayNames[o];
|
||||
}
|
||||
}
|
||||
|
||||
void ReadTrees( IniFile file )
|
||||
void ReadRATrees( IniFile file )
|
||||
{
|
||||
IniSection terrain = file.GetSection( "TERRAIN", true );
|
||||
if( terrain == null )
|
||||
return;
|
||||
|
||||
foreach( KeyValuePair<string, string> kv in terrain )
|
||||
{
|
||||
var loc = int.Parse( kv.Key );
|
||||
Actors.Add( new ActorReference(kv.Value, new int2(loc % MapSize, loc / MapSize), null ) );
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackCncTileData( Stream ms )
|
||||
{
|
||||
for( int i = 0 ; i < MapSize ; i++ )
|
||||
for( int j = 0 ; j < MapSize ; j++ )
|
||||
{
|
||||
MapTiles[j, i].tile = (byte)ms.ReadByte();
|
||||
MapTiles[j, i].image = (byte)ms.ReadByte();
|
||||
|
||||
if( MapTiles[ j, i ].tile == 0xff )
|
||||
MapTiles[ j, i ].image = (byte)( i % 4 + ( j % 4 ) * 4 );
|
||||
}
|
||||
}
|
||||
|
||||
void ReadCncOverlay( IniFile file )
|
||||
{
|
||||
IniSection overlay = file.GetSection( "OVERLAY", true );
|
||||
if( overlay == null )
|
||||
return;
|
||||
|
||||
foreach( KeyValuePair<string, string> kv in overlay )
|
||||
{
|
||||
var loc = int.Parse( kv.Key );
|
||||
int2 cell = new int2(loc % MapSize, loc / MapSize);
|
||||
|
||||
Log.Write("Overlay {0} at ({1},{2})",kv.Value,cell.X,cell.Y);
|
||||
MapTiles[ cell.X, cell.Y ].overlay = kv.Value.ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ReadCncTrees( IniFile file )
|
||||
{
|
||||
IniSection terrain = file.GetSection( "TERRAIN", true );
|
||||
if( terrain == null )
|
||||
return;
|
||||
|
||||
foreach( KeyValuePair<string, string> kv in terrain )
|
||||
Trees.Add( new TreeReference( int.Parse( kv.Key ), kv.Value ) );
|
||||
{
|
||||
var loc = int.Parse( kv.Key );
|
||||
Actors.Add( new ActorReference( kv.Value.Split(',')[0], new int2(loc % MapSize, loc / MapSize),null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LoadActors(IniFile file, string section)
|
||||
{
|
||||
foreach (var s in file.GetSection(section, true))
|
||||
{
|
||||
//num=owner,type,health,location,facing,...
|
||||
var parts = s.Value.Split( ',' );
|
||||
var loc = int.Parse(parts[3]);
|
||||
Actors.Add( new ActorReference( parts[1].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), parts[0]));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInMap(int2 xy)
|
||||
{
|
||||
return IsInMap(xy.X,xy.Y);
|
||||
}
|
||||
|
||||
public bool IsInMap(int x, int y)
|
||||
{
|
||||
return (x >= XOffset && y >= YOffset && x < XOffset + Width && y < YOffset + Height);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -90,10 +90,10 @@
|
||||
<Compile Include="Terrain.cs" />
|
||||
<Compile Include="TileReference.cs" />
|
||||
<Compile Include="TileSet.cs" />
|
||||
<Compile Include="TreeReference.cs" />
|
||||
<Compile Include="Tuple.cs" />
|
||||
<Compile Include="TypeDictionary.cs" />
|
||||
<Compile Include="Walkability.cs" />
|
||||
<Compile Include="ActorReference.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
@@ -47,7 +47,7 @@ namespace OpenRA.FileFormats
|
||||
|
||||
public class Global
|
||||
{
|
||||
public string Map = "scm12ea.ini";
|
||||
public string Map = "scm02ea.ini";
|
||||
public string[] Packages = {}; // filename:sha1 pairs.
|
||||
public string[] Mods = { "ra" }; // mod names
|
||||
public int OrderLatency = 3;
|
||||
|
||||
@@ -28,28 +28,49 @@ namespace OpenRA.FileFormats
|
||||
public readonly List<byte[]> TileBitmapBytes = new List<byte[]>();
|
||||
|
||||
public Terrain( Stream stream )
|
||||
{
|
||||
int Width, Height;
|
||||
|
||||
{
|
||||
// Try loading as a cnc .tem
|
||||
BinaryReader reader = new BinaryReader( stream );
|
||||
Width = reader.ReadUInt16();
|
||||
Height = reader.ReadUInt16();
|
||||
int Width = reader.ReadUInt16();
|
||||
int Height = reader.ReadUInt16();
|
||||
|
||||
if( Width != 24 || Height != 24 )
|
||||
throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) );
|
||||
|
||||
|
||||
/*NumTiles = */reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
/*XDim = */reader.ReadUInt16();
|
||||
/*YDim = */reader.ReadUInt16();
|
||||
/*uint FileSize = */reader.ReadUInt32();
|
||||
/*Zero1 = */reader.ReadUInt16();
|
||||
/*uint Size = */reader.ReadUInt32();
|
||||
uint ImgStart = reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
int IndexEnd = reader.ReadInt32();
|
||||
reader.ReadUInt32();
|
||||
int IndexStart = reader.ReadInt32();
|
||||
|
||||
/*Zero2 = */reader.ReadUInt32();
|
||||
|
||||
int IndexEnd, IndexStart;
|
||||
if (reader.ReadUInt16() == 65535) // ID1 = FFFFh for cnc
|
||||
{
|
||||
/*ID2 = */reader.ReadUInt16();
|
||||
IndexEnd = reader.ReadInt32();
|
||||
IndexStart = reader.ReadInt32();
|
||||
}
|
||||
else // Load as a ra .tem
|
||||
{
|
||||
stream.Position = 0;
|
||||
reader = new BinaryReader( stream );
|
||||
Width = reader.ReadUInt16();
|
||||
Height = reader.ReadUInt16();
|
||||
if( Width != 24 || Height != 24 )
|
||||
throw new InvalidDataException( string.Format( "{0}x{1}", Width, Height ) );
|
||||
|
||||
/*NumTiles = */reader.ReadUInt16();
|
||||
reader.ReadUInt16();
|
||||
/*XDim = */reader.ReadUInt16();
|
||||
/*YDim = */reader.ReadUInt16();
|
||||
/*uint FileSize = */reader.ReadUInt32();
|
||||
ImgStart = reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
IndexEnd = reader.ReadInt32();
|
||||
reader.ReadUInt32();
|
||||
IndexStart = reader.ReadInt32();
|
||||
}
|
||||
stream.Position = IndexStart;
|
||||
|
||||
foreach( byte b in new BinaryReader(stream).ReadBytes(IndexEnd - IndexStart) )
|
||||
|
||||
@@ -24,9 +24,8 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public ushort tile;
|
||||
public byte image;
|
||||
public byte overlay;
|
||||
public string overlay;
|
||||
public byte smudge;
|
||||
public byte density; /* used for ore/gems */
|
||||
|
||||
public override int GetHashCode() { return tile.GetHashCode() ^ image.GetHashCode(); }
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public readonly Dictionary<ushort, Terrain> tiles = new Dictionary<ushort, Terrain>();
|
||||
|
||||
public readonly Walkability Walkability = new Walkability();
|
||||
public readonly Walkability Walkability;
|
||||
public readonly Dictionary<ushort, TileTemplate> walk
|
||||
= new Dictionary<ushort, TileTemplate>();
|
||||
|
||||
@@ -46,12 +46,12 @@ namespace OpenRA.FileFormats
|
||||
return ret;
|
||||
}
|
||||
|
||||
public TileSet( string suffix )
|
||||
public TileSet( string tilesetFile, string templatesFile, string suffix )
|
||||
{
|
||||
Walkability = new Walkability();
|
||||
Walkability = new Walkability(templatesFile);
|
||||
|
||||
char tileSetChar = char.ToUpperInvariant( suffix[ 1 ] );
|
||||
StreamReader tileIdFile = new StreamReader( FileSystem.Open( "tileSet.til" ) );
|
||||
char tileSetChar = char.ToUpperInvariant( suffix[ 0 ] );
|
||||
StreamReader tileIdFile = new StreamReader( FileSystem.Open(tilesetFile) );
|
||||
|
||||
while( true )
|
||||
{
|
||||
@@ -74,7 +74,7 @@ namespace OpenRA.FileFormats
|
||||
if (!walk.ContainsKey((ushort)(start + i)))
|
||||
walk.Add((ushort)(start + i), Walkability.GetWalkability(tilename));
|
||||
|
||||
using( Stream s = FileSystem.Open( tilename + suffix ) )
|
||||
using( Stream s = FileSystem.Open( tilename + "." + suffix ) )
|
||||
{
|
||||
if( !tiles.ContainsKey( (ushort)( start + i ) ) )
|
||||
tiles.Add( (ushort)( start + i ), new Terrain( s ) );
|
||||
@@ -88,9 +88,10 @@ namespace OpenRA.FileFormats
|
||||
public byte[] GetBytes(TileReference r)
|
||||
{
|
||||
Terrain tile;
|
||||
|
||||
if( tiles.TryGetValue( r.tile, out tile ) )
|
||||
return tile.TileBitmapBytes[ r.image ];
|
||||
|
||||
|
||||
byte[] missingTile = new byte[ 24 * 24 ];
|
||||
for( int i = 0 ; i < missingTile.Length ; i++ )
|
||||
missingTile[ i ] = 0x36;
|
||||
@@ -102,8 +103,15 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
if (r.tile == 0xff || r.tile == 0xffff)
|
||||
r.image = 0;
|
||||
|
||||
return walk[r.tile].TerrainType[r.image];
|
||||
|
||||
try {
|
||||
return walk[r.tile].TerrainType[r.image];
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
return 0; // Default zero (walkable)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ namespace OpenRA.FileFormats
|
||||
Dictionary<string, TileTemplate> walkability
|
||||
= new Dictionary<string,TileTemplate>();
|
||||
|
||||
public Walkability()
|
||||
public Walkability(string templatesFile)
|
||||
{
|
||||
var file = new IniFile( FileSystem.Open( "templates.ini" ) );
|
||||
var file = new IniFile( FileSystem.Open( templatesFile ) );
|
||||
|
||||
foreach (var section in file.Sections)
|
||||
{
|
||||
|
||||
@@ -139,8 +139,6 @@ namespace OpenRA
|
||||
ready = new Animation("pips");
|
||||
ready.PlayRepeating("ready");
|
||||
clock = new Animation("clock");
|
||||
|
||||
mapChooserSheet = new Sheet(r, new Size(128, 128));
|
||||
}
|
||||
|
||||
List<string> visibleTabs = new List<string>();
|
||||
@@ -251,7 +249,7 @@ namespace OpenRA
|
||||
public MapInfo(string filename)
|
||||
{
|
||||
Filename = filename.ToLowerInvariant();
|
||||
Map = new Map(new IniFile(FileSystem.Open(Filename)));
|
||||
Map = new Map(Filename);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -301,6 +299,9 @@ namespace OpenRA
|
||||
|
||||
if (mapPreviewDirty)
|
||||
{
|
||||
if (mapChooserSheet == null || mapChooserSheet.Size.Width != currentMap.Map.MapSize)
|
||||
mapChooserSheet = new Sheet(renderer, new Size(currentMap.Map.MapSize, currentMap.Map.MapSize));
|
||||
|
||||
var b = Minimap.RenderTerrainBitmapWithSpawnPoints(currentMap.Map, Game.world.TileSet); // tileset -> hack
|
||||
mapChooserSheet.Texture.SetData(b);
|
||||
mapChooserSprite = new Sprite(mapChooserSheet,
|
||||
@@ -318,9 +319,10 @@ namespace OpenRA
|
||||
|
||||
var y = r.Top + 50;
|
||||
|
||||
int numListItems = ((r.Bottom - 60 - y ) / 20);
|
||||
int maxListItems = ((r.Bottom - 60 - y ) / 20);
|
||||
|
||||
for(int i = mapOffset; i < numListItems + mapOffset; i++, y += 20){
|
||||
for(int i = mapOffset; i < Math.Min(maxListItems + mapOffset, mapList.Value.Count()); i++, y += 20){
|
||||
|
||||
var map = mapList.Value.ElementAt(i);
|
||||
var itemRect = new Rectangle(r.Left + 50, y - 2, r.Width - 340, 20);
|
||||
if (map == currentMap)
|
||||
@@ -338,7 +340,9 @@ namespace OpenRA
|
||||
DrawCentered("Size: {0}x{1}".F(currentMap.Map.Width, currentMap.Map.Height),
|
||||
new int2(mapRect.Left + mapRect.Width / 2, y), Color.White);
|
||||
y += 20;
|
||||
DrawCentered("Theater: {0}".F(currentMap.Map.Theater, currentMap.Map.Height),
|
||||
|
||||
var theaterInfo = Game.world.WorldActor.Info.Traits.WithInterface<TheaterInfo>().FirstOrDefault(t => t.Theater == currentMap.Map.Theater);
|
||||
DrawCentered("Theater: {0}".F(theaterInfo.Name, currentMap.Map.Height),
|
||||
new int2(mapRect.Left + mapRect.Width / 2, y), Color.White);
|
||||
y += 20;
|
||||
DrawCentered("Spawnpoints: {0}".F(currentMap.Map.SpawnPoints.Count()),
|
||||
@@ -355,7 +359,7 @@ namespace OpenRA
|
||||
AddUiButton(new int2(mapRect.Left + mapRect.Width / 2, y), "\\/",
|
||||
_ =>
|
||||
{
|
||||
mapOffset = (mapOffset + 1 > mapList.Value.Count() - numListItems) ? mapOffset : mapOffset + 1;
|
||||
mapOffset = (mapOffset + 1 > mapList.Value.Count() - maxListItems) ? mapOffset : mapOffset + 1;
|
||||
});
|
||||
|
||||
AddButton(r, _ => { });
|
||||
@@ -424,8 +428,8 @@ namespace OpenRA
|
||||
DrawDialogBackground(r, "dialog");
|
||||
DrawCentered("OpenRA Multiplayer Lobby", new int2(r.Left + w / 2, r.Top + 20), Color.White);
|
||||
|
||||
DrawDialogBackground(new Rectangle(r.Right - 324, r.Top + 43, 304, 244),"dialog2");
|
||||
var minimapRect = new Rectangle(r.Right - 322, r.Top + 45, 300, 240);
|
||||
DrawDialogBackground(new Rectangle(r.Right - 264, r.Top + 43, 244, 244),"dialog2");
|
||||
var minimapRect = new Rectangle(r.Right - 262, r.Top + 45, 240, 240);
|
||||
|
||||
world.Minimap.Update();
|
||||
world.Minimap.Draw(minimapRect, true);
|
||||
|
||||
@@ -48,7 +48,8 @@ namespace OpenRA
|
||||
if (impactSound != null) Sound.Play(impactSound + ".aud");
|
||||
|
||||
if (!isWater) world.Map.AddSmudge(targetTile, warhead);
|
||||
if (warhead.Ore) world.Map.DestroyOre(targetTile.X, targetTile.Y);
|
||||
if (warhead.Ore)
|
||||
world.WorldActor.traits.Get<ResourceLayer>().Destroy(targetTile);
|
||||
|
||||
var firepowerModifier = firedBy.traits
|
||||
.WithInterface<IFirepowerModifier>()
|
||||
|
||||
@@ -101,11 +101,8 @@ namespace OpenRA
|
||||
Timer.Time( "ChromeProv, SeqProv, viewport: {0}" );
|
||||
|
||||
skipMakeAnims = true;
|
||||
foreach (var treeReference in Game.world.Map.Trees)
|
||||
world.CreateActor(treeReference.Image, new int2(treeReference.Location), null);
|
||||
Timer.Time( "trees: {0}" );
|
||||
|
||||
world.LoadMapActors(Rules.AllRules);
|
||||
foreach (var actorReference in world.Map.Actors)
|
||||
world.CreateActor(actorReference.Name, actorReference.Location, world.players.Values.FirstOrDefault(p => p.InternalName == actorReference.Owner) ?? world.players[0]);
|
||||
skipMakeAnims = false;
|
||||
Timer.Time( "map actors: {0}" );
|
||||
|
||||
|
||||
@@ -64,8 +64,6 @@ namespace OpenRA.GameRules
|
||||
/* Income & Production */
|
||||
public readonly float BuildSpeed = 0;
|
||||
public readonly float BuildupTime = 0;
|
||||
public readonly int GemValue = 0;
|
||||
public readonly int GoldValue = 0;
|
||||
public readonly float OreTruckRate = 0;
|
||||
public readonly bool SeparateAircraft = true;
|
||||
public readonly float SurvivorRate = 0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
@@ -39,7 +39,7 @@ namespace OpenRA.GameRules
|
||||
// External game settings
|
||||
public readonly string NetworkHost = "";
|
||||
public readonly int NetworkPort = 0;
|
||||
public readonly string Map = "scm12ea.ini";
|
||||
public readonly string Map = "scm02ea.ini";
|
||||
public readonly int Player = 1;
|
||||
public readonly string Replay = "";
|
||||
public readonly string PlayerName = "";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
@@ -47,8 +47,8 @@ namespace OpenRA.Graphics
|
||||
public Minimap(World world, Renderer r)
|
||||
{
|
||||
this.world = world;
|
||||
sheet = new Sheet(r, new Size(128, 128));
|
||||
mapOnlySheet = new Sheet(r, new Size(128, 128));
|
||||
sheet = new Sheet(r, new Size(world.Map.MapSize, world.Map.MapSize));
|
||||
mapOnlySheet = new Sheet(r, new Size(world.Map.MapSize, world.Map.MapSize));
|
||||
|
||||
lineRenderer = new LineRenderer(r);
|
||||
rgbaRenderer = new SpriteRenderer(r, true, r.RgbaSpriteShader);
|
||||
@@ -93,9 +93,9 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap RenderTerrainBitmap(Map map, TileSet tileset)
|
||||
{
|
||||
var colors = terrainTypeColors[map.Theater.ToLowerInvariant()];
|
||||
var terrain = new Bitmap(128, 128);
|
||||
for (var y = 0; y < 128; y++)
|
||||
for (var x = 0; x < 128; x++)
|
||||
var terrain = new Bitmap(map.MapSize, map.MapSize);
|
||||
for (var y = 0; y < map.MapSize; y++)
|
||||
for (var x = 0; x < map.MapSize; x++)
|
||||
terrain.SetPixel(x, y, map.IsInMap(x, y)
|
||||
? colors[tileset.GetWalkability(map.MapTiles[x, y])]
|
||||
: shroudColor);
|
||||
@@ -105,14 +105,13 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap RenderTerrainBitmapWithSpawnPoints(Map map, TileSet tileset)
|
||||
{
|
||||
/* todo: do this a bit nicer */
|
||||
|
||||
var terrain = RenderTerrainBitmap(map, tileset);
|
||||
foreach (var sp in map.SpawnPoints)
|
||||
terrain.SetPixel(sp.X, sp.Y, Color.White);
|
||||
|
||||
return terrain;
|
||||
}
|
||||
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (terrain == null)
|
||||
@@ -120,11 +119,13 @@ namespace OpenRA.Graphics
|
||||
|
||||
if (oreLayer == null)
|
||||
{
|
||||
var res = world.WorldActor.traits.Get<ResourceLayer>();
|
||||
var colors = terrainTypeColors[world.Map.Theater.ToLowerInvariant()];
|
||||
|
||||
oreLayer = new Bitmap(terrain);
|
||||
for (var y = world.Map.YOffset; y < world.Map.YOffset + world.Map.Height; y++)
|
||||
for (var x = world.Map.XOffset; x < world.Map.XOffset + world.Map.Width; x++)
|
||||
if (world.Map.ContainsResource(new int2(x, y)))
|
||||
if (res.GetResource(new int2(x,y)) != null)
|
||||
oreLayer.SetPixel(x, y, colors[(int)TerrainMovementType.Ore]);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
@@ -65,12 +66,14 @@ namespace OpenRA.Graphics
|
||||
static void LoadSequencesForUnit(XmlElement eUnit)
|
||||
{
|
||||
string unitName = eUnit.GetAttribute("name");
|
||||
Log.Write("Loading sequence {0}", unitName);
|
||||
var sequences = eUnit.SelectNodes("./sequence").OfType<XmlElement>()
|
||||
.Select(e => new Sequence(unitName, e))
|
||||
.ToDictionary(s => s.Name);
|
||||
|
||||
units.Add(unitName, sequences);
|
||||
// Log.Write("Loading sequence {0}", unitName);
|
||||
try {
|
||||
var sequences = eUnit.SelectNodes("./sequence").OfType<XmlElement>()
|
||||
.Select(e => new Sequence(unitName, e))
|
||||
.ToDictionary(s => s.Name);
|
||||
|
||||
units.Add(unitName, sequences);
|
||||
} catch (FileNotFoundException) {} // Do nothing; we can crash later if we actually wanted art
|
||||
}
|
||||
|
||||
public static Sequence GetSequence(string unitName, string sequenceName)
|
||||
|
||||
50
OpenRA.Game/Graphics/OverlayRenderer.cs → OpenRA.Game/Graphics/SmudgeRenderer.cs
Executable file → Normal file
50
OpenRA.Game/Graphics/OverlayRenderer.cs → OpenRA.Game/Graphics/SmudgeRenderer.cs
Executable file → Normal file
@@ -23,35 +23,24 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
class OverlayRenderer
|
||||
class SmudgeRenderer
|
||||
{
|
||||
static string[] overlaySpriteNames =
|
||||
{
|
||||
"sbag", "cycl", "brik", "fenc", "wood",
|
||||
"gold01", "gold02", "gold03", "gold04",
|
||||
"gem01", "gem02", "gem03", "gem04",
|
||||
"v12", "v13", "v14", "v15", "v16", "v17", "v18",
|
||||
"fpls", "wcrate", "scrate", "barb", "sbag",
|
||||
};
|
||||
|
||||
static string[] smudgeSpriteNames =
|
||||
{
|
||||
"bib3", "bib2", "bib1", "sc1", "sc2", "sc3", "sc4", "sc5", "sc6",
|
||||
"cr1", "cr2", "cr3", "cr4", "cr5", "cr6",
|
||||
};
|
||||
|
||||
readonly Sprite[][] overlaySprites;
|
||||
readonly Sprite[] smudgeSprites;
|
||||
|
||||
SpriteRenderer spriteRenderer;
|
||||
Map map;
|
||||
|
||||
public OverlayRenderer( Renderer renderer, Map map )
|
||||
public SmudgeRenderer( Renderer renderer, Map map )
|
||||
{
|
||||
this.spriteRenderer = new SpriteRenderer( renderer, true );
|
||||
this.map = map;
|
||||
|
||||
overlaySprites = overlaySpriteNames.Select(f => SpriteSheetBuilder.LoadAllSprites(f)).ToArray();
|
||||
smudgeSprites = smudgeSpriteNames.SelectMany(f => SpriteSheetBuilder.LoadAllSprites(f)).ToArray();
|
||||
}
|
||||
|
||||
@@ -71,44 +60,9 @@ namespace OpenRA.Graphics
|
||||
spriteRenderer.DrawSprite(smudgeSprites[tr.smudge - 1],
|
||||
Game.CellSize * (float2)location, "terrain");
|
||||
}
|
||||
|
||||
var o = tr.overlay;
|
||||
if (o < overlaySprites.Length)
|
||||
{
|
||||
var location = new int2(x, y);
|
||||
var sprites = overlaySprites[o];
|
||||
var spriteIndex = 0;
|
||||
if (Ore.overlayIsFence[o]) spriteIndex = NearbyFences(x, y);
|
||||
else if (Ore.overlayIsOre[o]) spriteIndex = map.MapTiles[x,y].density - 1;
|
||||
else if (Ore.overlayIsGems[o]) spriteIndex = map.MapTiles[x,y].density - 1;
|
||||
spriteRenderer.DrawSprite(sprites[spriteIndex],
|
||||
Game.CellSize * (float2)location, "terrain");
|
||||
}
|
||||
}
|
||||
|
||||
spriteRenderer.Flush();
|
||||
}
|
||||
|
||||
bool IsFence( int x, int y )
|
||||
{
|
||||
var o = map.MapTiles[ x, y ].overlay;
|
||||
if (o < Ore.overlayIsFence.Length)
|
||||
return Ore.overlayIsFence[o];
|
||||
return false;
|
||||
}
|
||||
|
||||
int NearbyFences( int x, int y )
|
||||
{
|
||||
int ret = 0;
|
||||
if( IsFence( x, y - 1 ) )
|
||||
ret |= 1;
|
||||
if( IsFence( x + 1, y ) )
|
||||
ret |= 2;
|
||||
if( IsFence( x, y + 1 ) )
|
||||
ret |= 4;
|
||||
if( IsFence( x - 1, y ) )
|
||||
ret |= 8;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
@@ -32,7 +33,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
Renderer renderer;
|
||||
Map map;
|
||||
OverlayRenderer overlayRenderer;
|
||||
SmudgeRenderer overlayRenderer;
|
||||
|
||||
public TerrainRenderer(World world, Renderer renderer, WorldRenderer wr)
|
||||
{
|
||||
@@ -68,7 +69,7 @@ namespace OpenRA.Graphics
|
||||
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
|
||||
indexBuffer.SetData( indices );
|
||||
|
||||
overlayRenderer = new OverlayRenderer( renderer, map );
|
||||
overlayRenderer = new SmudgeRenderer( renderer, map );
|
||||
}
|
||||
|
||||
public void Draw( Viewport viewport )
|
||||
@@ -104,6 +105,9 @@ namespace OpenRA.Graphics
|
||||
new Range<int>(indicesPerRow * firstRow, indicesPerRow * lastRow),
|
||||
terrainSheet.Texture, PrimitiveType.TriangleList, renderer.SpriteShader));
|
||||
|
||||
foreach (var r in Game.world.WorldActor.traits.WithInterface<IRenderOverlay>())
|
||||
r.Render();
|
||||
|
||||
overlayRenderer.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
<Compile Include="Network\OrderManager.cs" />
|
||||
<Compile Include="Orders\RepairOrderGenerator.cs" />
|
||||
<Compile Include="Orders\SellOrderGenerator.cs" />
|
||||
<Compile Include="Ore.cs" />
|
||||
<Compile Include="PackageDownloader.cs" />
|
||||
<Compile Include="PathSearch.cs" />
|
||||
<Compile Include="Selection.cs" />
|
||||
@@ -115,7 +114,6 @@
|
||||
<Compile Include="Traits\World\ChoosePaletteOnSelect.cs" />
|
||||
<Compile Include="Traits\World\Country.cs" />
|
||||
<Compile Include="Traits\World\CrateSpawner.cs" />
|
||||
<Compile Include="Traits\World\OreGrowth.cs" />
|
||||
<Compile Include="Traits\OreRefinery.cs" />
|
||||
<Compile Include="Traits\Activities\Attack.cs" />
|
||||
<Compile Include="Traits\Activities\CallFunc.cs" />
|
||||
@@ -145,7 +143,7 @@
|
||||
<Compile Include="Graphics\CursorSequence.cs" />
|
||||
<Compile Include="Graphics\CursorSheetBuilder.cs" />
|
||||
<Compile Include="Graphics\LineRenderer.cs" />
|
||||
<Compile Include="Graphics\OverlayRenderer.cs" />
|
||||
<Compile Include="Graphics\SmudgeRenderer.cs" />
|
||||
<Compile Include="Graphics\WorldRenderer.cs" />
|
||||
<Compile Include="Traits\Activities\Idle.cs" />
|
||||
<Compile Include="Traits\Activities\Land.cs" />
|
||||
@@ -216,6 +214,8 @@
|
||||
<Compile Include="Traits\Passenger.cs" />
|
||||
<Compile Include="Traits\Player\PlaceBuilding.cs" />
|
||||
<Compile Include="Traits\World\PlayerColorPalette.cs" />
|
||||
<Compile Include="Traits\World\ResourceLayer.cs" />
|
||||
<Compile Include="Traits\World\ResourceType.cs" />
|
||||
<Compile Include="Traits\World\ShroudPalette.cs" />
|
||||
<Compile Include="Traits\SupportPowers\SupportPower.cs" />
|
||||
<Compile Include="Traits\ProvidesRadar.cs" />
|
||||
@@ -245,7 +245,7 @@
|
||||
<Compile Include="Traits\Render\RenderUnitRotor.cs" />
|
||||
<Compile Include="Traits\Render\RenderUnitSpinner.cs" />
|
||||
<Compile Include="Traits\Render\RenderUnitTurreted.cs" />
|
||||
<Compile Include="Traits\SeedsOre.cs" />
|
||||
<Compile Include="Traits\SeedsResource.cs" />
|
||||
<Compile Include="Traits\StoresOre.cs" />
|
||||
<Compile Include="Traits\Submarine.cs" />
|
||||
<Compile Include="Traits\AI\TakeCover.cs" />
|
||||
@@ -253,6 +253,7 @@
|
||||
<Compile Include="Traits\Turreted.cs" />
|
||||
<Compile Include="Traits\Unit.cs" />
|
||||
<Compile Include="Traits\World\UnitInfluence.cs" />
|
||||
<Compile Include="Traits\World\WallLoadHook.cs" />
|
||||
<Compile Include="Traits\World\WaterPaletteRotation.cs" />
|
||||
<Compile Include="Traits\Modifiers\WithShadow.cs" />
|
||||
<Compile Include="Network\UnitOrders.cs" />
|
||||
@@ -268,6 +269,7 @@
|
||||
<Compile Include="Traits\Player\EvaAlerts.cs" />
|
||||
<Compile Include="Traits\World\ScreenShaker.cs" />
|
||||
<Compile Include="Traits\LineBuild.cs" />
|
||||
<Compile Include="Traits\World\Theater.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
*
|
||||
* OpenRA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OpenRA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public static class Ore
|
||||
{
|
||||
public static void AddOre(this Map map, int i, int j)
|
||||
{
|
||||
if (map.ContainsOre(i, j) && map.MapTiles[i, j].density < 12)
|
||||
map.MapTiles[i, j].density++;
|
||||
else if (map.MapTiles[i, j].overlay == 0xff)
|
||||
{
|
||||
map.MapTiles[i, j].overlay = ChooseOre();
|
||||
map.MapTiles[i, j].density = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyOre(this Map map, int i, int j)
|
||||
{
|
||||
if (map.ContainsResource(new int2(i, j)))
|
||||
{
|
||||
map.MapTiles[i, j].density = 0;
|
||||
map.MapTiles[i, j].overlay = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool OreCanSpreadInto(this World world, int i, int j)
|
||||
{
|
||||
if (world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(new int2(i, j)) != null)
|
||||
return false;
|
||||
|
||||
return TerrainCosts.Cost(UnitMovementType.Wheel,
|
||||
world.TileSet.GetWalkability(world.Map.MapTiles[i, j]))
|
||||
< double.PositiveInfinity;
|
||||
}
|
||||
|
||||
public static void SpreadOre(this World world, Random r, float chance)
|
||||
{
|
||||
var map = world.Map;
|
||||
|
||||
var mini = map.XOffset; var maxi = map.XOffset + map.Width;
|
||||
var minj = map.YOffset; var maxj = map.YOffset + map.Height;
|
||||
|
||||
/* phase 1: grow into neighboring regions */
|
||||
var newOverlay = new byte[128, 128];
|
||||
for (int j = minj; j < maxj; j++)
|
||||
for (int i = mini; i < maxi; i++)
|
||||
{
|
||||
newOverlay[i, j] = 0xff;
|
||||
if (!map.HasOverlay(i, j)
|
||||
&& r.NextDouble() < chance
|
||||
&& map.GetOreDensity(i, j) > 0
|
||||
&& world.OreCanSpreadInto(i, j))
|
||||
newOverlay[i, j] = ChooseOre();
|
||||
}
|
||||
|
||||
for (int j = minj; j < maxj; j++)
|
||||
for (int i = mini; i < maxi; i++)
|
||||
if (newOverlay[i, j] != 0xff)
|
||||
map.MapTiles[i, j].overlay = newOverlay[i, j];
|
||||
}
|
||||
|
||||
public static void GrowOre(this World world, Random r)
|
||||
{
|
||||
var map = world.Map;
|
||||
|
||||
var mini = map.XOffset; var maxi = map.XOffset + map.Width;
|
||||
var minj = map.YOffset; var maxj = map.YOffset + map.Height;
|
||||
|
||||
/* phase 2: increase density of existing areas */
|
||||
var newDensity = new byte[128, 128];
|
||||
for (int j = minj; j < maxj; j++)
|
||||
for (int i = mini; i < maxi; i++)
|
||||
if (map.ContainsOre(i, j)) newDensity[i, j] = map.GetOreDensity(i, j);
|
||||
|
||||
for (int j = minj; j < maxj; j++)
|
||||
for (int i = mini; i < maxi; i++)
|
||||
if (map.MapTiles[i, j].density < newDensity[i, j])
|
||||
++map.MapTiles[i, j].density;
|
||||
}
|
||||
|
||||
public static void InitOreDensity( this Map map )
|
||||
{
|
||||
for (int j = 0; j < 128; j++)
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
if (map.ContainsOre(i, j)) map.MapTiles[i, j].density = map.GetOreDensity(i, j);
|
||||
if (map.ContainsGem(i, j)) map.MapTiles[i, j].density = map.GetGemDensity(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
static byte GetOreDensity(this Map map, int i, int j)
|
||||
{
|
||||
int sum = 0;
|
||||
for (var u = -1; u < 2; u++)
|
||||
for (var v = -1; v < 2; v++)
|
||||
if (map.ContainsOre(i + u, j + v))
|
||||
++sum;
|
||||
sum = (sum * 4 + 2) / 3;
|
||||
return (byte)sum;
|
||||
}
|
||||
|
||||
static byte GetGemDensity(this Map map, int i, int j)
|
||||
{
|
||||
int sum = 0;
|
||||
for (var u = -1; u < 2; u++)
|
||||
for (var v = -1; v < 2; v++)
|
||||
if (map.ContainsGem(i + u, j + v))
|
||||
++sum;
|
||||
sum = (sum+2) / 3; /* 3 gem units/tile is full. */
|
||||
return (byte)sum;
|
||||
}
|
||||
|
||||
static bool HasOverlay(this Map map, int i, int j)
|
||||
{
|
||||
return map.MapTiles[i, j].overlay < overlayIsOre.Length;
|
||||
}
|
||||
|
||||
static bool ContainsOre(this Map map, int i, int j)
|
||||
{
|
||||
return map.HasOverlay(i, j) && overlayIsOre[map.MapTiles[i, j].overlay];
|
||||
}
|
||||
|
||||
static bool ContainsGem(this Map map, int i, int j)
|
||||
{
|
||||
return map.HasOverlay(i, j) && overlayIsGems[map.MapTiles[i, j].overlay];
|
||||
}
|
||||
|
||||
public static bool ContainsResource(this Map map, int2 p)
|
||||
{
|
||||
return map.ContainsGem(p.X, p.Y) || map.ContainsOre(p.X, p.Y);
|
||||
}
|
||||
|
||||
public static bool Harvest(this Map map, int2 p, out bool isGems) /* harvests one unit if possible */
|
||||
{
|
||||
isGems = map.ContainsGem(p.X, p.Y);
|
||||
if (map.MapTiles[p.X, p.Y].density == 0) return false;
|
||||
|
||||
if (--map.MapTiles[p.X, p.Y].density == 0)
|
||||
map.MapTiles[p.X, p.Y].overlay = 0xff;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static byte ore = 5;
|
||||
static byte ChooseOre()
|
||||
{
|
||||
if (++ore > 8) ore = 5;
|
||||
return ore;
|
||||
}
|
||||
|
||||
public static bool IsOverlaySolid(this Map map, int2 p)
|
||||
{
|
||||
var o = map.MapTiles[p.X, p.Y].overlay;
|
||||
return o < overlayIsFence.Length && overlayIsFence[o];
|
||||
}
|
||||
|
||||
public static bool[] overlayIsFence =
|
||||
{
|
||||
true, true, true, true, true,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false, false, false, false,
|
||||
false, false, false, true, true,
|
||||
};
|
||||
|
||||
public static bool[] overlayIsOre =
|
||||
{
|
||||
false, false, false, false, false,
|
||||
true, true, true, true,
|
||||
false, false, false, false,
|
||||
false, false, false, false, false, false, false,
|
||||
false, false, false, false, false,
|
||||
};
|
||||
|
||||
public static bool[] overlayIsGems =
|
||||
{
|
||||
false, false, false, false, false,
|
||||
false, false, false, false,
|
||||
true, true, true, true,
|
||||
false, false, false, false, false, false, false,
|
||||
false, false, false, false, false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -35,10 +35,11 @@ namespace OpenRA
|
||||
public PathFinder( World world )
|
||||
{
|
||||
this.world = world;
|
||||
var map = world.Map;
|
||||
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++)
|
||||
passableCost[(int)umt] = new float[128, 128];
|
||||
for( int x = 0 ; x < 128 ; x++ )
|
||||
for( int y = 0 ; y < 128 ; y++ )
|
||||
passableCost[(int)umt] = new float[map.MapSize, map.MapSize];
|
||||
for( int x = 0 ; x < map.MapSize ; x++ )
|
||||
for( int y = 0 ; y < map.MapSize ; y++ )
|
||||
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++ )
|
||||
passableCost[(int)umt][ x, y ] = ( world.Map.IsInMap( x, y ) )
|
||||
? (float)TerrainCosts.Cost( umt, world.TileSet.GetWalkability( world.Map.MapTiles[ x, y ] ) )
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
@@ -84,9 +84,7 @@ namespace OpenRA
|
||||
if (!world.WorldActor.traits.Get<BuildingInfluence>().CanMoveHere(newHere) &&
|
||||
world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(newHere) != ignoreBuilding)
|
||||
continue;
|
||||
if (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
|
||||
if (checkForBlocked && (world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(newHere).Any(a => !world.IsActorPathableToCrush(a, umt))))
|
||||
continue;
|
||||
@@ -162,9 +160,9 @@ namespace OpenRA
|
||||
|
||||
static CellInfo[ , ] InitCellInfo()
|
||||
{
|
||||
var cellInfo = new CellInfo[ 128, 128 ];
|
||||
for( int x = 0 ; x < 128 ; x++ )
|
||||
for( int y = 0 ; y < 128 ; y++ )
|
||||
var cellInfo = new CellInfo[ Game.world.Map.MapSize, Game.world.Map.MapSize ];
|
||||
for( int x = 0 ; x < Game.world.Map.MapSize ; x++ )
|
||||
for( int y = 0 ; y < Game.world.Map.MapSize ; y++ )
|
||||
cellInfo[ x, y ] = new CellInfo( float.PositiveInfinity, new int2( x, y ), false );
|
||||
return cellInfo;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
@@ -30,22 +30,31 @@ namespace OpenRA
|
||||
{
|
||||
public class Shroud
|
||||
{
|
||||
bool[,] explored = new bool[128, 128];
|
||||
bool[,] explored;
|
||||
Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow");
|
||||
Sprite[,] sprites = new Sprite[128, 128];
|
||||
Sprite[,] sprites;
|
||||
int gapOpaqueTicks = (int)(Rules.General.GapRegenInterval * 25 * 60);
|
||||
int gapTicks;
|
||||
int[,] gapField;
|
||||
bool[,] gapActive;
|
||||
|
||||
bool dirty = true;
|
||||
bool hasGPS = false;
|
||||
Player owner;
|
||||
Map map;
|
||||
public Rectangle? bounds;
|
||||
|
||||
public Shroud(Player owner, Map map) { this.owner = owner; this.map = map; }
|
||||
|
||||
int gapOpaqueTicks = (int)(Rules.General.GapRegenInterval * 25 * 60);
|
||||
int gapTicks;
|
||||
int[,] gapField = new int[128, 128];
|
||||
bool[,] gapActive = new bool[128, 128];
|
||||
|
||||
public Shroud(Player owner, Map map)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.map = map;
|
||||
|
||||
explored = new bool[map.MapSize, map.MapSize];
|
||||
sprites = new Sprite[map.MapSize, map.MapSize];
|
||||
gapField = new int[map.MapSize, map.MapSize];
|
||||
gapActive = new bool[map.MapSize, map.MapSize];
|
||||
}
|
||||
|
||||
public bool HasGPS
|
||||
{
|
||||
get { return hasGPS; }
|
||||
@@ -57,7 +66,7 @@ namespace OpenRA
|
||||
if (gapTicks > 0) { --gapTicks; return; }
|
||||
|
||||
// Clear active flags
|
||||
gapActive = new bool[128, 128];
|
||||
gapActive = new bool[map.MapSize, map.MapSize];
|
||||
foreach (var a in world.Queries.WithTrait<GeneratesGap>().Where(a => owner != a.Actor.Owner))
|
||||
foreach (var t in a.Trait.GetShroudedTiles())
|
||||
{
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public class Harvest : IActivity
|
||||
@@ -39,7 +41,7 @@ namespace OpenRA.Traits.Activities
|
||||
return this;
|
||||
else
|
||||
{
|
||||
FindMoreOre(self);
|
||||
FindMoreResource(self);
|
||||
return NextActivity;
|
||||
}
|
||||
}
|
||||
@@ -49,28 +51,31 @@ namespace OpenRA.Traits.Activities
|
||||
var harv = self.traits.Get<Harvester>();
|
||||
var renderUnit = self.traits.Get<RenderUnit>(); /* better have one of these! */
|
||||
|
||||
var isGem = false;
|
||||
if (!self.World.Map.ContainsResource(self.Location) ||
|
||||
!self.World.Map.Harvest(self.Location, out isGem))
|
||||
var resource = self.World.WorldActor.traits.Get<ResourceLayer>().Harvest(self.Location);
|
||||
if (resource == null)
|
||||
return false;
|
||||
|
||||
|
||||
if (renderUnit.anim.CurrentSequence.Name != "harvest")
|
||||
{
|
||||
isHarvesting = true;
|
||||
renderUnit.PlayCustomAnimation(self, "harvest", () => isHarvesting = false);
|
||||
}
|
||||
harv.AcceptResource(isGem);
|
||||
harv.AcceptResource(resource);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FindMoreOre(Actor self)
|
||||
void FindMoreResource(Actor self)
|
||||
{
|
||||
var res = self.World.WorldActor.traits.Get<ResourceLayer>();
|
||||
var harv = self.Info.Traits.Get<HarvesterInfo>();
|
||||
|
||||
self.QueueActivity(new Move(
|
||||
() =>
|
||||
{
|
||||
var search = new PathSearch
|
||||
{
|
||||
heuristic = loc => (self.World.Map.ContainsResource(loc) ? 0 : 1),
|
||||
heuristic = loc => (res.GetResource(loc) != null
|
||||
&& harv.Resources.Contains( res.GetResource(loc).Name )) ? 0 : 1,
|
||||
umt = UnitMovementType.Wheel,
|
||||
checkForBlocked = true
|
||||
};
|
||||
|
||||
@@ -19,24 +19,23 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits.Activities;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class HarvesterInfo : ITraitInfo
|
||||
{
|
||||
public readonly int BailCount = 28;
|
||||
public readonly int Capacity = 28;
|
||||
public readonly int PipCount = 7;
|
||||
public readonly string[] Resources = { };
|
||||
|
||||
public object Create(Actor self) { return new Harvester(self); }
|
||||
}
|
||||
|
||||
public class Harvester : IIssueOrder, IResolveOrder, IPips
|
||||
{
|
||||
[Sync]
|
||||
public int oreCarried = 0; /* sum of these must not exceed capacity */
|
||||
[Sync]
|
||||
public int gemsCarried = 0;
|
||||
Dictionary<ResourceTypeInfo, int> contents = new Dictionary<ResourceTypeInfo, int>();
|
||||
|
||||
Actor self;
|
||||
public Harvester(Actor self)
|
||||
@@ -44,21 +43,19 @@ namespace OpenRA.Traits
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public bool IsFull { get { return oreCarried + gemsCarried == self.Info.Traits.Get<HarvesterInfo>().BailCount; } }
|
||||
public bool IsEmpty { get { return oreCarried == 0 && gemsCarried == 0; } }
|
||||
public bool IsFull { get { return contents.Values.Sum() == self.Info.Traits.Get<HarvesterInfo>().Capacity; } }
|
||||
public bool IsEmpty { get { return contents.Values.Sum() == 0; } }
|
||||
|
||||
public void AcceptResource(bool isGem)
|
||||
public void AcceptResource(ResourceTypeInfo type)
|
||||
{
|
||||
if (isGem) gemsCarried++;
|
||||
else oreCarried++;
|
||||
if (!contents.ContainsKey(type)) contents[type] = 1;
|
||||
else contents[type]++;
|
||||
}
|
||||
|
||||
public void Deliver(Actor self, Actor proc)
|
||||
{
|
||||
proc.Owner.GiveOre(oreCarried * Rules.General.GoldValue);
|
||||
proc.Owner.GiveOre(gemsCarried * Rules.General.GemValue);
|
||||
oreCarried = 0;
|
||||
gemsCarried = 0;
|
||||
proc.Owner.GiveOre(contents.Sum(kv => kv.Key.ValuePerUnit * kv.Value));
|
||||
contents.Clear();
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
@@ -70,7 +67,10 @@ namespace OpenRA.Traits
|
||||
&& underCursor.traits.Contains<IAcceptOre>() && !IsEmpty)
|
||||
return new Order("Deliver", self, underCursor);
|
||||
|
||||
if (underCursor == null && self.World.Map.ContainsResource(xy))
|
||||
var res = self.World.WorldActor.traits.Get<ResourceLayer>().GetResource(xy);
|
||||
var info = self.Info.Traits.Get<HarvesterInfo>();
|
||||
|
||||
if (underCursor == null && res != null && info.Resources.Contains(res.Name))
|
||||
return new Order("Harvest", self, xy);
|
||||
|
||||
return null;
|
||||
@@ -94,16 +94,12 @@ namespace OpenRA.Traits
|
||||
public IEnumerable<PipType> GetPips(Actor self)
|
||||
{
|
||||
int numPips = self.Info.Traits.Get<HarvesterInfo>().PipCount;
|
||||
int n = contents.Values.Sum();
|
||||
|
||||
for (int i = 0; i < numPips; i++)
|
||||
{
|
||||
if (gemsCarried * 1.0f / self.Info.Traits.Get<HarvesterInfo>().BailCount > i * 1.0f / numPips)
|
||||
{
|
||||
yield return PipType.Red;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((gemsCarried + oreCarried) * 1.0f / self.Info.Traits.Get<HarvesterInfo>().BailCount > i * 1.0f / numPips)
|
||||
// todo: pip colors based on ResourceTypeInfo
|
||||
if (n * 1.0f / self.Info.Traits.Get<HarvesterInfo>().Capacity > i * 1.0f / numPips)
|
||||
{
|
||||
yield return PipType.Yellow;
|
||||
continue;
|
||||
|
||||
@@ -18,17 +18,21 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class SeedsOreInfo : ITraitInfo
|
||||
class SeedsResourceInfo : ITraitInfo
|
||||
{
|
||||
public readonly float Chance = .05f;
|
||||
public readonly int Interval = 5;
|
||||
public readonly string ResourceType = "Ore";
|
||||
|
||||
public object Create(Actor self) { return new SeedsOre(); }
|
||||
public object Create(Actor self) { return new SeedsResource(); }
|
||||
}
|
||||
|
||||
class SeedsOre : ITick
|
||||
class SeedsResource : ITick
|
||||
{
|
||||
int ticks;
|
||||
|
||||
@@ -36,13 +40,21 @@ namespace OpenRA.Traits
|
||||
{
|
||||
if (--ticks <= 0)
|
||||
{
|
||||
var info = self.Info.Traits.Get<SeedsOreInfo>();
|
||||
var info = self.Info.Traits.Get<SeedsResourceInfo>();
|
||||
var resourceType = self.World.WorldActor.Info.Traits
|
||||
.WithInterface<ResourceTypeInfo>()
|
||||
.FirstOrDefault(t => t.Name == info.ResourceType);
|
||||
|
||||
if (resourceType == null)
|
||||
throw new InvalidOperationException("No such resource type `{0}`".F(info.ResourceType));
|
||||
|
||||
var resLayer = self.World.WorldActor.traits.Get<ResourceLayer>();
|
||||
|
||||
for (var j = -1; j < 2; j++)
|
||||
for (var i = -1; i < 2; i++)
|
||||
if (self.World.SharedRandom.NextDouble() < info.Chance)
|
||||
if (self.World.OreCanSpreadInto(self.Location.X + i, self.Location.Y + j))
|
||||
self.World.Map.AddOre(self.Location.X + i, self.Location.Y + j);
|
||||
if (self.World.IsCellBuildable(self.Location + new int2(i, j), UnitMovementType.Wheel))
|
||||
resLayer.AddResource(resourceType, self.Location.X + i, self.Location.Y + j, 1);
|
||||
|
||||
ticks = info.Interval;
|
||||
}
|
||||
@@ -140,4 +140,6 @@ namespace OpenRA.Traits
|
||||
bool Pressed { get; }
|
||||
void OnClick();
|
||||
}
|
||||
|
||||
public interface IRenderOverlay { void Render(); }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
@@ -19,6 +19,7 @@
|
||||
#endregion
|
||||
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -29,11 +30,17 @@ namespace OpenRA.Traits
|
||||
|
||||
public class BuildingInfluence
|
||||
{
|
||||
bool[,] blocked = new bool[128, 128];
|
||||
Actor[,] influence = new Actor[128, 128];
|
||||
bool[,] blocked;
|
||||
Actor[,] influence;
|
||||
Map map;
|
||||
|
||||
public BuildingInfluence( Actor self )
|
||||
{
|
||||
map = self.World.Map;
|
||||
|
||||
blocked = new bool[map.MapSize, map.MapSize];
|
||||
influence = new Actor[map.MapSize, map.MapSize];
|
||||
|
||||
self.World.ActorAdded +=
|
||||
a => { if (a.traits.Contains<Building>())
|
||||
ChangeInfluence(a, a.traits.Get<Building>(), true); };
|
||||
@@ -45,27 +52,22 @@ namespace OpenRA.Traits
|
||||
void ChangeInfluence( Actor a, Building building, bool isAdd )
|
||||
{
|
||||
foreach( var u in Footprint.UnpathableTiles( a.Info.Name, a.Info.Traits.Get<BuildingInfo>(), a.Location ) )
|
||||
if( IsValid( u ) )
|
||||
if( map.IsInMap( u ) )
|
||||
blocked[ u.X, u.Y ] = isAdd;
|
||||
|
||||
foreach( var u in Footprint.Tiles( a.Info.Name, a.Info.Traits.Get<BuildingInfo>(), a.Location ) )
|
||||
if( IsValid( u ) )
|
||||
if( map.IsInMap( u ) )
|
||||
influence[ u.X, u.Y ] = isAdd ? a : null;
|
||||
}
|
||||
|
||||
bool IsValid(int2 t)
|
||||
{
|
||||
return !(t.X < 0 || t.Y < 0 || t.X >= 128 || t.Y >= 128);
|
||||
}
|
||||
|
||||
public Actor GetBuildingAt(int2 cell)
|
||||
{
|
||||
if (!IsValid(cell)) return null;
|
||||
if (!map.IsInMap(cell)) return null;
|
||||
return influence[cell.X, cell.Y];
|
||||
}
|
||||
|
||||
public bool CanMoveHere(int2 cell)
|
||||
{
|
||||
return IsValid(cell) && !blocked[cell.X, cell.Y];
|
||||
return map.IsInMap(cell) && !blocked[cell.X, cell.Y];
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
*
|
||||
* OpenRA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OpenRA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class OreGrowthInfo : ITraitInfo
|
||||
{
|
||||
public readonly float Interval = 1f;
|
||||
public readonly float Chance = .02f;
|
||||
public readonly bool Spreads = true;
|
||||
public readonly bool Grows = true;
|
||||
|
||||
public object Create(Actor self) { return new OreGrowth(); }
|
||||
}
|
||||
|
||||
class OreGrowth : ITick, ILoadWorldHook
|
||||
{
|
||||
int remainingTicks;
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (--remainingTicks <= 0)
|
||||
{
|
||||
var info = self.Info.Traits.Get<OreGrowthInfo>();
|
||||
|
||||
if (info.Spreads)
|
||||
Ore.SpreadOre(self.World,
|
||||
self.World.SharedRandom,
|
||||
info.Chance);
|
||||
|
||||
if (info.Grows)
|
||||
Ore.GrowOre(self.World, self.World.SharedRandom);
|
||||
|
||||
self.World.Minimap.InvalidateOre();
|
||||
remainingTicks = (int)(info.Interval * 60 * 25);
|
||||
}
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
Ore.InitOreDensity(w.Map);
|
||||
}
|
||||
}
|
||||
}
|
||||
201
OpenRA.Game/Traits/World/ResourceLayer.cs
Normal file
201
OpenRA.Game/Traits/World/ResourceLayer.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
*
|
||||
* OpenRA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OpenRA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class ResourceLayerInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new ResourceLayer(self); }
|
||||
}
|
||||
|
||||
class ResourceLayer : IRenderOverlay, ILoadWorldHook
|
||||
{
|
||||
SpriteRenderer sr;
|
||||
World w;
|
||||
|
||||
public ResourceTypeInfo[] resourceTypes;
|
||||
CellContents[,] content;
|
||||
|
||||
public ResourceLayer(Actor self)
|
||||
{
|
||||
sr = new SpriteRenderer( Game.renderer, true );
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
var shroud = Game.world.LocalPlayer.Shroud;
|
||||
var map = Game.world.Map;
|
||||
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
|
||||
{
|
||||
if (!shroud.IsExplored(new int2(x, y))) continue;
|
||||
|
||||
var c = content[x, y];
|
||||
if (c.image != null)
|
||||
sr.DrawSprite(c.image[c.density],
|
||||
Game.CellSize * new int2(x, y),
|
||||
c.type.Palette);
|
||||
}
|
||||
|
||||
sr.Flush();
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
this.w = w;
|
||||
content = new CellContents[w.Map.MapSize, w.Map.MapSize];
|
||||
|
||||
resourceTypes = w.WorldActor.Info.Traits.WithInterface<ResourceTypeInfo>().ToArray();
|
||||
foreach (var rt in resourceTypes)
|
||||
rt.Sprites = rt.SpriteNames.Select(a => SpriteSheetBuilder.LoadAllSprites(a)).ToArray();
|
||||
|
||||
var map = w.Map;
|
||||
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
|
||||
{
|
||||
content[x,y].type = resourceTypes.FirstOrDefault(
|
||||
r => r.Overlays.Contains(w.Map.MapTiles[x, y].overlay));
|
||||
if (content[x, y].type != null)
|
||||
content[x, y].image = ChooseContent(content[x, y].type);
|
||||
}
|
||||
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
|
||||
if (content[x, y].type != null)
|
||||
content[x, y].density = GetIdealDensity(x, y);
|
||||
}
|
||||
|
||||
public Sprite[] ChooseContent(ResourceTypeInfo info)
|
||||
{
|
||||
return info.Sprites[w.SharedRandom.Next(info.Sprites.Length)];
|
||||
}
|
||||
|
||||
public int GetAdjacentCellsWith(ResourceTypeInfo info, int i, int j)
|
||||
{
|
||||
int sum = 0;
|
||||
for (var u = -1; u < 2; u++)
|
||||
for (var v = -1; v < 2; v++)
|
||||
if (content[i+u, j+v].type == info)
|
||||
++sum;
|
||||
return sum;
|
||||
}
|
||||
|
||||
public int GetIdealDensity(int x, int y)
|
||||
{
|
||||
return (GetAdjacentCellsWith(content[x, y].type, x, y) *
|
||||
(content[x, y].image.Length - 1)) / 9;
|
||||
}
|
||||
|
||||
public void AddResource(ResourceTypeInfo info, int i, int j, int n)
|
||||
{
|
||||
if (content[i, j].type == null)
|
||||
{
|
||||
content[i, j].type = info;
|
||||
content[i, j].image = ChooseContent(info);
|
||||
content[i, j].density = -1;
|
||||
}
|
||||
|
||||
if (content[i, j].type != info)
|
||||
return;
|
||||
|
||||
content[i, j].density = Math.Min(
|
||||
content[i, j].image.Length - 1,
|
||||
content[i, j].density + n);
|
||||
}
|
||||
|
||||
public ResourceTypeInfo Harvest(int2 p)
|
||||
{
|
||||
var type = content[p.X,p.Y].type;
|
||||
if (type == null) return null;
|
||||
|
||||
if (--content[p.X, p.Y].density < 0)
|
||||
{
|
||||
content[p.X, p.Y].type = null;
|
||||
content[p.X, p.Y].image = null;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public void Destroy(int2 p)
|
||||
{
|
||||
content[p.X, p.Y].type = null;
|
||||
content[p.X, p.Y].image = null;
|
||||
content[p.X, p.Y].density = 0;
|
||||
}
|
||||
|
||||
public void Grow(ResourceTypeInfo info)
|
||||
{
|
||||
var map = w.Map;
|
||||
var mini = map.XOffset; var maxi = map.XOffset + map.Width;
|
||||
var minj = map.YOffset; var maxj = map.YOffset + map.Height;
|
||||
|
||||
var newDensity = new byte[map.MapSize, map.MapSize];
|
||||
for (int j = minj; j < maxj; j++)
|
||||
for (int i = mini; i < maxi; i++)
|
||||
if (content[i, j].type == info)
|
||||
newDensity[i, j] = (byte)GetIdealDensity(i, j);
|
||||
|
||||
for (int j = minj; j < maxj; j++)
|
||||
for (int i = mini; i < maxi; i++)
|
||||
if (content[i, j].type == info && content[i, j].density < newDensity[i, j])
|
||||
++content[i, j].density;
|
||||
}
|
||||
|
||||
public void Spread(ResourceTypeInfo info)
|
||||
{
|
||||
var map = w.Map;
|
||||
|
||||
var mini = map.XOffset; var maxi = map.XOffset + map.Width;
|
||||
var minj = map.YOffset; var maxj = map.YOffset + map.Height;
|
||||
|
||||
var growMask = new bool[map.MapSize, map.MapSize];
|
||||
for (int j = minj; j < maxj; j++)
|
||||
for (int i = mini; i < maxi; i++)
|
||||
if (content[i,j].type == null
|
||||
&& GetAdjacentCellsWith(info, i,j ) > 0
|
||||
&& w.IsCellBuildable(new int2(i, j), UnitMovementType.Wheel))
|
||||
growMask[i, j] = true;
|
||||
|
||||
for (int j = minj; j < maxj; j++)
|
||||
for (int i = mini; i < maxi; i++)
|
||||
if (growMask[i, j])
|
||||
{
|
||||
content[i, j].type = info;
|
||||
content[i, j].image = ChooseContent(info);
|
||||
content[i, j].density = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceTypeInfo GetResource(int2 p) { return content[p.X, p.Y].type; }
|
||||
|
||||
public struct CellContents
|
||||
{
|
||||
public ResourceTypeInfo type;
|
||||
public Sprite[] image;
|
||||
public int density;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
OpenRA.Game/Traits/World/ResourceType.cs
Normal file
67
OpenRA.Game/Traits/World/ResourceType.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
*
|
||||
* OpenRA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OpenRA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ResourceTypeInfo : ITraitInfo
|
||||
{
|
||||
public readonly string[] Overlays = { };
|
||||
public readonly string[] SpriteNames = { };
|
||||
public readonly string Palette = "terrain";
|
||||
|
||||
public readonly int ValuePerUnit = 0;
|
||||
public readonly string Name = null;
|
||||
|
||||
public readonly float GrowthInterval = 0;
|
||||
public readonly float SpreadInterval = 0;
|
||||
|
||||
public Sprite[][] Sprites;
|
||||
|
||||
public object Create(Actor self) { return new ResourceType(this); }
|
||||
}
|
||||
|
||||
class ResourceType : ITick
|
||||
{
|
||||
int growthTicks;
|
||||
int spreadTicks;
|
||||
ResourceTypeInfo info;
|
||||
|
||||
public ResourceType(ResourceTypeInfo info) { this.info = info; }
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (info.GrowthInterval != 0 && --growthTicks <= 0)
|
||||
{
|
||||
growthTicks = (int)(info.GrowthInterval * 25 * 60);
|
||||
self.World.WorldActor.traits.Get<ResourceLayer>().Grow(info);
|
||||
self.World.Minimap.InvalidateOre();
|
||||
}
|
||||
|
||||
if (info.SpreadInterval != 0 && --spreadTicks <= 0)
|
||||
{
|
||||
spreadTicks = (int)(info.SpreadInterval * 25 * 60);
|
||||
self.World.WorldActor.traits.Get<ResourceLayer>().Spread(info);
|
||||
self.World.Minimap.InvalidateOre();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
OpenRA.Game/Traits/World/Theater.cs
Normal file
32
OpenRA.Game/Traits/World/Theater.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
*
|
||||
* OpenRA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OpenRA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class TheaterInfo : StatelessTraitInfo<Theater>
|
||||
{
|
||||
public readonly string Name = null;
|
||||
public readonly string Theater = null;
|
||||
public readonly string Suffix = null;
|
||||
public readonly string Tileset = null;
|
||||
public readonly string Templates = null;
|
||||
}
|
||||
class Theater {}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
|
||||
* This file is part of OpenRA.
|
||||
@@ -32,12 +32,14 @@ namespace OpenRA.Traits
|
||||
|
||||
public class UnitInfluence : ITick
|
||||
{
|
||||
List<Actor>[,] influence = new List<Actor>[128, 128];
|
||||
List<Actor>[,] influence;
|
||||
|
||||
public UnitInfluence( Actor self )
|
||||
{
|
||||
for (int i = 0; i < 128; i++)
|
||||
for (int j = 0; j < 128; j++)
|
||||
int size = self.World.Map.MapSize;
|
||||
influence = new List<Actor>[size, size];
|
||||
for (int i = 0; i < size; i++)
|
||||
for (int j = 0; j < size; j++)
|
||||
influence[ i, j ] = new List<Actor>();
|
||||
|
||||
self.World.ActorRemoved += a => Remove( a, a.traits.GetOrDefault<IOccupySpace>() );
|
||||
@@ -73,8 +75,8 @@ namespace OpenRA.Traits
|
||||
[Conditional( "SANITY_CHECKS" )]
|
||||
void SanityCheck( Actor self )
|
||||
{
|
||||
for( int y = 0 ; y < 128 ; y++ )
|
||||
for( int x = 0 ; x < 128 ; x++ )
|
||||
for( int y = 0 ; y < self.World.Map.MapSize ; y++ )
|
||||
for( int x = 0 ; x < self.World.Map.MapSize ; x++ )
|
||||
if( influence[ x, y ] != null )
|
||||
foreach (var a in influence[ x, y ])
|
||||
if (!a.traits.Get<IOccupySpace>().OccupiedCells().Contains( new int2( x, y ) ) )
|
||||
|
||||
34
OpenRA.Game/Traits/World/WallLoadHook.cs
Normal file
34
OpenRA.Game/Traits/World/WallLoadHook.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class WallLoadHookInfo : ITraitInfo
|
||||
{
|
||||
public readonly string[] OverlayTypes = { };
|
||||
public readonly string ActorType = "brik";
|
||||
|
||||
public object Create(Actor self) { return new WallLoadHook( self, this ); }
|
||||
}
|
||||
|
||||
class WallLoadHook : ILoadWorldHook
|
||||
{
|
||||
WallLoadHookInfo info;
|
||||
public WallLoadHook(Actor self, WallLoadHookInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
var map = w.Map;
|
||||
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
|
||||
if (info.OverlayTypes.Contains(w.Map.MapTiles[x, y].overlay))
|
||||
w.CreateActor(info.ActorType, new int2(x, y), w.players[0]); // todo: neutral player or null?
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,8 +56,8 @@ namespace OpenRA
|
||||
public void Draw( World world )
|
||||
{
|
||||
if (ShowUnitDebug)
|
||||
for (var j = 0; j < 128; j++)
|
||||
for (var i = 0; i < 128; i++)
|
||||
for (var j = 0; j < world.Map.MapSize; j++)
|
||||
for (var i = 0; i < world.Map.MapSize; i++)
|
||||
if (world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(new int2(i, j)).Any())
|
||||
spriteRenderer.DrawSprite(unitDebug, Game.CellSize * new float2(i, j), "terrain");
|
||||
}
|
||||
@@ -67,10 +67,11 @@ namespace OpenRA
|
||||
var position = Game.controller.MousePosition.ToInt2();
|
||||
var topLeft = position - Footprint.AdjustForBuildingSize( bi );
|
||||
var isCloseEnough = world.IsCloseEnoughToBase(world.LocalPlayer, name, bi, topLeft);
|
||||
var res = world.WorldActor.traits.Get<ResourceLayer>();
|
||||
|
||||
foreach( var t in Footprint.Tiles( name, bi, topLeft ) )
|
||||
spriteRenderer.DrawSprite( ( isCloseEnough && world.IsCellBuildable( t, bi.WaterBound
|
||||
? UnitMovementType.Float : UnitMovementType.Wheel ) && !world.Map.ContainsResource( t ) )
|
||||
? UnitMovementType.Float : UnitMovementType.Wheel ) && res.GetResource(t) == null )
|
||||
? buildOk : buildBlocked, Game.CellSize * t, "terrain" );
|
||||
|
||||
// Linebuild for walls.
|
||||
|
||||
@@ -59,15 +59,14 @@ namespace OpenRA
|
||||
Game.IssueOrder(Order.Chat("/name " + Game.Settings.PlayerName));
|
||||
}
|
||||
|
||||
public readonly Actor WorldActor;
|
||||
|
||||
public readonly Actor WorldActor;
|
||||
public readonly PathFinder PathFinder;
|
||||
|
||||
public readonly Map Map;
|
||||
public readonly TileSet TileSet;
|
||||
|
||||
// for tricky things like bridges.
|
||||
public readonly ICustomTerrain[,] customTerrain = new ICustomTerrain[128, 128];
|
||||
public readonly ICustomTerrain[,] customTerrain;
|
||||
|
||||
public readonly WorldRenderer WorldRenderer;
|
||||
internal readonly Minimap Minimap;
|
||||
@@ -76,9 +75,13 @@ namespace OpenRA
|
||||
{
|
||||
Timer.Time( "----World.ctor" );
|
||||
|
||||
Map = new Map( Rules.AllRules );
|
||||
Map = new Map( Game.LobbyInfo.GlobalSettings.Map );
|
||||
customTerrain = new ICustomTerrain[Map.MapSize, Map.MapSize];
|
||||
Timer.Time( "new Map: {0}" );
|
||||
TileSet = new TileSet( Map.TileSuffix );
|
||||
|
||||
var theaterInfo = Rules.Info["world"].Traits.WithInterface<TheaterInfo>().FirstOrDefault(t => t.Theater == Map.Theater);
|
||||
TileSet = new TileSet(theaterInfo.Tileset, theaterInfo.Templates, theaterInfo.Suffix);
|
||||
|
||||
SpriteSheetBuilder.Initialize( Map );
|
||||
Timer.Time( "Tileset: {0}" );
|
||||
|
||||
|
||||
@@ -149,8 +149,9 @@ namespace OpenRA
|
||||
|
||||
public static bool CanPlaceBuilding(this World world, string name, BuildingInfo building, int2 topLeft, Actor toIgnore)
|
||||
{
|
||||
var res = world.WorldActor.traits.Get<ResourceLayer>();
|
||||
return !Footprint.Tiles(name, building, topLeft).Any(
|
||||
t => !world.Map.IsInMap(t.X, t.Y) || world.Map.ContainsResource(t) || !world.IsCellBuildable(t,
|
||||
t => !world.Map.IsInMap(t.X, t.Y) || res.GetResource(t) != null || !world.IsCellBuildable(t,
|
||||
building.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel,
|
||||
toIgnore));
|
||||
}
|
||||
@@ -199,22 +200,6 @@ namespace OpenRA
|
||||
return xy;
|
||||
}
|
||||
|
||||
public static void LoadMapActors(this World world, IniFile mapfile)
|
||||
{
|
||||
var toLoad =
|
||||
mapfile.GetSection("STRUCTURES", true)
|
||||
.Concat(mapfile.GetSection("UNITS", true));
|
||||
|
||||
foreach (var s in toLoad)
|
||||
{
|
||||
//num=owner,type,health,location,facing,...
|
||||
var parts = s.Value.Split( ',' );
|
||||
var loc = int.Parse(parts[3]);
|
||||
world.CreateActor(parts[1].ToLowerInvariant(), new int2(loc % 128, loc / 128),
|
||||
world.players.Values.FirstOrDefault(p => p.InternalName == parts[0]) ?? world.players[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public static int2 ChooseRandomEdgeCell(this World w)
|
||||
{
|
||||
var isX = w.SharedRandom.Next(2) == 0;
|
||||
|
||||
625
doc/cncff.txt
Normal file
625
doc/cncff.txt
Normal file
@@ -0,0 +1,625 @@
|
||||
COMMAND & CONQUER FILE FORMATS
|
||||
|
||||
Revision 4
|
||||
|
||||
by Vladan Bato (bat22@geocities.com)
|
||||
|
||||
This document explains the file formats used by Command & Conquer.
|
||||
|
||||
Command & Conquer is a tradmark of Westwood Studios, Inc.
|
||||
Command & Conquer is Copyright (C)1995 Westwood Studios, Inc.
|
||||
|
||||
The information provided here is meant for programmers that want to make
|
||||
editor and utilites for Command & Conquer. My explanation might not be
|
||||
the best one, but it should be enough.
|
||||
|
||||
I can't guarantee that the information in here is correct. If you find any
|
||||
errors, please report them to me.
|
||||
|
||||
In this document I'll use Pascal notation, and any code samples will be in
|
||||
Pascal....
|
||||
I wanted to rewrite them in C, but I don't have the time to test the code.
|
||||
So, to avoid any risks, I'll use the code from Mix Manager.
|
||||
|
||||
In case you don't know, the information contained here has been used to
|
||||
make the program Mix Manager, which contains a lot of conversion utilities
|
||||
for the various formats. For more info, check my homepage (see the end of
|
||||
the document).
|
||||
|
||||
===================
|
||||
1. THE .MIX FILES
|
||||
===================
|
||||
|
||||
You probably already know the format of these files, but I will add a
|
||||
description here for completeness.
|
||||
|
||||
The MIX file consists of two parts :
|
||||
-A header including the index of all the files contained within
|
||||
-A body containing all the files
|
||||
|
||||
It's format is :
|
||||
|
||||
Header : record
|
||||
NumFiles : word; {Number of files in MIX}
|
||||
DataSize : longint; {Size of body}
|
||||
Index : array [1..NumFiles] of
|
||||
record
|
||||
ID : longint; {File ID}
|
||||
Start : longint; {Offset of file from the start of the
|
||||
body}
|
||||
Size : longint; {file size}
|
||||
end;
|
||||
end;
|
||||
|
||||
The ID field is computed from the original filename, which is not stored in
|
||||
the MIX.
|
||||
The records are always sorted by the ID field (the numbers are signed
|
||||
longints).
|
||||
Note that the offsets are relative to the start of the body so to find the
|
||||
actual offset in the MIX you have to add the size of the header which is
|
||||
NumFiles*12+6
|
||||
|
||||
===================
|
||||
2. THE .PAL FILES
|
||||
===================
|
||||
|
||||
The most easiest files....
|
||||
These files contain the palette in the same format used by VGA cards.
|
||||
|
||||
Palette : array [0..255] of record
|
||||
red,green,blue:byte;
|
||||
end;
|
||||
|
||||
Note that only the first 6 bits of each number are used, giving a total of
|
||||
262144 possible colors (as opposed to the 8 bits used by .PCX files for
|
||||
example).
|
||||
|
||||
=================================
|
||||
3. THE TEMPLATE AND .BIN FILES
|
||||
=================================
|
||||
|
||||
The Template files contain the map graphics, and can be found in the
|
||||
theater specific MIX files (TEMPERAT.MIX, WINTER.MIX, DESERT.MIX).
|
||||
The .BIN files contain the maps for the missions and are used in conjunction
|
||||
with the .INI files.
|
||||
|
||||
I won't explain them here. They are explained with great detail in the
|
||||
document titled "Command & Conquer maps" I wrote some time ago.
|
||||
The said document can be found on my homepage.
|
||||
|
||||
===================
|
||||
5. THE .SHP FILES
|
||||
===================
|
||||
|
||||
The .SHP files contain almost all the graphics : units, structures,
|
||||
trees,...
|
||||
The header has the following structure :
|
||||
|
||||
Header : record
|
||||
NumImages : word; {Number of images}
|
||||
A,B : word; {Unknown}
|
||||
Width,
|
||||
Height : word; {Width and Height of the images}
|
||||
C : longint; {Unknown}
|
||||
end;
|
||||
|
||||
If you know something about those unknown fields, please e-mail me.
|
||||
Following that there's an array of records, one for each image :
|
||||
|
||||
Offsets : array [0..NumImages+1] of
|
||||
record
|
||||
Offset : longint; {Offset and format of image in file}
|
||||
RefOffs : longint; {Offset and format of image on
|
||||
which it is based}
|
||||
end;
|
||||
|
||||
The most significant byte (last) of the Offset and RefOffs fields
|
||||
contains the format, while the lower three are used for the offset.
|
||||
The format byte can have one of the three values : 80h, 40h, 20h.
|
||||
I will call the three image formats Format80, Format40 and Format20.
|
||||
|
||||
The Format80 images are compressed with a compression method I'll explain
|
||||
later.
|
||||
|
||||
The Format40 images must be xor-ed with a Format80 image. That's what the
|
||||
RefOffs field is used for. It tells which Format80 image they are
|
||||
based upon. The Format40 will be explained in detail later.
|
||||
|
||||
The Format20 images use the same format as the Format40, the difference is
|
||||
that they are xor-ed with the image that precedes them in the file. That can
|
||||
be either in Format20 or in Format40.
|
||||
The offset part of the RefOffs field contains the number of the first
|
||||
Format40 image in the chain, and the format field is always 48h.
|
||||
|
||||
Here's an example :
|
||||
|
||||
0) Off0(three bytes) 80h 000000h 00h
|
||||
1) Off1(three bytes) 80h 000000h 00h
|
||||
2) Off2(three bytes) 40h Off1 80h
|
||||
3) Off3(three bytes) 80h 000000h 00h
|
||||
4) Off4(three bytes) 40h Off1 80h
|
||||
5) Off5(three bytes) 20h 000400h 48h
|
||||
6) Off6(three bytes) 20h 000400h 48h
|
||||
7) Off7(three bytes) 40h Off3 80h
|
||||
|
||||
For example to draw image 7, you have to draw the image 3 first (whose
|
||||
offset
|
||||
and format are given) and then xor image 7 over it.
|
||||
|
||||
To draw image 6, you have to xor it over the previous image, i.e. 5, which
|
||||
is format20 again, that means that it has to be xor-ed over image 4, which
|
||||
is in format40, i.e. it must be xor-ed over the image in format80 it has a
|
||||
reference to. In this case it's image 1. Thus the chain is 1,4,5,6.
|
||||
This is one way to see it, the other could be :
|
||||
Image 6 is in Format20, the RefOffs field contains the number of the first
|
||||
Format40 image in the chain, in this case image 4. To draw Image 4, the
|
||||
Image 1 has to be drawn first, next is image 4, and then all the images
|
||||
from the 4th to the 6th have to be xor-ed over the previous.
|
||||
|
||||
I made some experiments and found out that you don't have to use the
|
||||
Format40 and Format20 images. I tried converting all of them into Format80
|
||||
and it worked.
|
||||
|
||||
Also, when changing graphics, note that all the unit and structure graphics
|
||||
should be drawn using the GDI colors, which will be automatically converted
|
||||
for the other sides.
|
||||
The palette you should use is one of those found in DESERT.MIX, WINTER.MIX
|
||||
and TEMPERAT.MIX. The GDI colors are colors 0B0h-0BFh. The other colors
|
||||
won't be converted and will remain the same for all the sides (be sure to
|
||||
use only the colors that are the same all three palettes).
|
||||
|
||||
The above applies only to the graphics that appear in all three theaters
|
||||
(the .SHP file found in CONQUER.MIX). The graphics for the structures and
|
||||
overlays that appear in a single theater (found inside the theater specific
|
||||
MIX) can use the palette entries that are unique for that theater (and will
|
||||
be shown with garbled colors in the others).
|
||||
|
||||
Also a special color is used for shadows. It's color 04h. In the palettes
|
||||
it's bright green, but C&C puts a shadow instead of it. I don't know how
|
||||
the shadows are calculated however.
|
||||
|
||||
You should've noticed that the array has NumImages+2 elements when only
|
||||
NumImages elements are needed. The last one contains zeros, and the one
|
||||
before
|
||||
that points to the end of the file. These two can be used to identify the
|
||||
file as a .SHP.
|
||||
|
||||
Here's the description of the compression formats : Format80 and Format40.
|
||||
|
||||
----------
|
||||
Format80
|
||||
----------
|
||||
|
||||
There are several different commands, with different sizes : form 1 to 5
|
||||
bytes.
|
||||
The positions mentioned below always refer to the destination buffer (i.e.
|
||||
the uncompressed image). The relative positions are relative to the current
|
||||
position in the destination buffer, which is one byte beyond the last
|
||||
written
|
||||
byte.
|
||||
|
||||
I will give some sample code at the end.
|
||||
|
||||
(1) 1 byte
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| 1 | 0 | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
\_______________________/
|
||||
|
|
||||
Count
|
||||
|
||||
This one means : copy next Count bytes as is from Source to Dest.
|
||||
|
||||
(2) 2 bytes
|
||||
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
|
||||
| 0 | | | | | | | | | | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
|
||||
\___________/\__________________________________________________/
|
||||
| |
|
||||
Count-3 Relative Pos.
|
||||
|
||||
This means copy Count bytes from Dest at Current Pos.-Rel. Pos. to
|
||||
Current position.
|
||||
Note that you have to add 3 to the number you find in the bits 4-6 of the
|
||||
first byte to obtain the Count.
|
||||
Note that if the Rel. Pos. is 1, that means repeat Count times the
|
||||
previous
|
||||
byte.
|
||||
|
||||
(3) 3 bytes
|
||||
+---+---+---+---+---+---+---+---+ +---------------+---------------+
|
||||
| 1 | 1 | | | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+ +---------------+---------------+
|
||||
\_______________________/ Pos
|
||||
|
|
||||
Count-3
|
||||
|
||||
Copy Count bytes from Pos, where Pos is absolute from the start of the
|
||||
destination buffer. (Pos is a word, that means that the images can't be
|
||||
larger than 64K)
|
||||
|
||||
(4) 4 bytes
|
||||
+---+---+---+---+---+---+---+---+ +-------+-------+ +-------+
|
||||
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | | | | | |
|
||||
+---+---+---+---+---+---+---+---+ +-------+-------+ +-------+
|
||||
Count Color
|
||||
|
||||
Write Color Count times.
|
||||
(Count is a word, color is a byte)
|
||||
|
||||
(5) 5 bytes
|
||||
+---+---+---+---+---+---+---+---+ +-------+-------+ +-------+-------+
|
||||
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+ +-------+-------+ +-------+-------+
|
||||
Count Pos
|
||||
|
||||
Copy Count bytes from Dest. starting at Pos. Pos is absolute from the
|
||||
start of the Destination buffer.
|
||||
Both Count and Pos are words.
|
||||
|
||||
These are all the commands I found out. Maybe there are other ones, but I
|
||||
haven't seen them yet.
|
||||
|
||||
All the images end with a 80h command.
|
||||
|
||||
To make things more clearer here's a piece of code that will uncompress the
|
||||
image.
|
||||
|
||||
DP = destination pointer
|
||||
SP = source pointer
|
||||
Source and Dest are the two buffers
|
||||
|
||||
|
||||
SP:=0;
|
||||
DP:=0;
|
||||
repeat
|
||||
Com:=Source[SP];
|
||||
inc(SP);
|
||||
b7:=Com shr 7; {b7 is bit 7 of Com}
|
||||
case b7 of
|
||||
0 : begin {copy command (2)}
|
||||
{Count is bits 4-6 + 3}
|
||||
Count:=(Com and $7F) shr 4 + 3;
|
||||
{Position is bits 0-3, with bits 0-7 of next byte}
|
||||
Posit:=(Com and $0F) shl 8+Source[SP];
|
||||
Inc(SP);
|
||||
{Starting pos=Cur pos. - calculated value}
|
||||
Posit:=DP-Posit;
|
||||
for i:=Posit to Posit+Count-1 do
|
||||
begin
|
||||
Dest[DP]:=Dest[i];
|
||||
Inc(DP);
|
||||
end;
|
||||
end;
|
||||
1 : begin
|
||||
{Check bit 6 of Com}
|
||||
b6:=(Com and $40) shr 6;
|
||||
case b6 of
|
||||
0 : begin {Copy as is command (1)}
|
||||
Count:=Com and $3F; {mask 2 topmost bits}
|
||||
if Count=0 then break; {EOF marker}
|
||||
for i:=1 to Count do
|
||||
begin
|
||||
Dest[DP]:=Source[SP];
|
||||
Inc(DP);
|
||||
Inc(SP);
|
||||
end;
|
||||
end;
|
||||
1 : begin {large copy, very large copy and fill commands}
|
||||
{Count = (bits 0-5 of Com) +3}
|
||||
{if Com=FEh then fill, if Com=FFh then very large copy}
|
||||
Count:=Com and $3F;
|
||||
if Count<$3E then {large copy (3)}
|
||||
begin
|
||||
Inc(Count,3);
|
||||
{Next word = pos. from start of image}
|
||||
Posit:=Word(Source[SP]);
|
||||
Inc(SP,2);
|
||||
for i:=Posit to Posit+Count-1 do
|
||||
begin
|
||||
Dest[DP]:=Dest[i];
|
||||
Inc(DP);
|
||||
end;
|
||||
end
|
||||
else if Count=$3F then {very large copy (5)}
|
||||
begin
|
||||
{next 2 words are Count and Pos}
|
||||
Count:=Word(Source[SP]);
|
||||
Posit:=Word(Source[SP+2]);
|
||||
Inc(SP,4);
|
||||
for i:=Posit to Posit+Count-1 do
|
||||
begin
|
||||
Dest[DP]:=Dest[i];
|
||||
Inc(DP);
|
||||
end;
|
||||
end else
|
||||
begin {Count=$3E, fill (4)}
|
||||
{Next word is count, the byte after is color}
|
||||
Count:=Word(Source[SP]);
|
||||
Inc(SP,2);
|
||||
b:=Source[SP];
|
||||
Inc(SP);
|
||||
for i:=0 to Count-1 do
|
||||
begin
|
||||
Dest[DP]:=b;
|
||||
inc(DP);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
until false;
|
||||
|
||||
Note that you won't be able to compile this code, because the typecasting
|
||||
won't work. (But I'm sure you'll be able to fix it).
|
||||
|
||||
|
||||
----------
|
||||
Format40
|
||||
----------
|
||||
|
||||
As I said before the images in Format40 must be xor-ed over a previous
|
||||
image, or against a black screen (as in the .WSA format).
|
||||
It is used when there are only minor changes between an image and a
|
||||
following one.
|
||||
|
||||
Here I'll assume that the old image is in Dest, and that the Dest pointer is
|
||||
set to the beginning of that buffer.
|
||||
|
||||
As for the Format80, there are many commands :
|
||||
|
||||
|
||||
(1) 1 byte
|
||||
byte
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| 1 | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
\___________________________/
|
||||
|
|
||||
Count
|
||||
|
||||
Skip count bytes in Dest (move the pointer forward).
|
||||
|
||||
(2) 3 bytes
|
||||
byte word
|
||||
+---+---+---+---+---+---+---+---+ +---+-----+-------+
|
||||
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 0 | ... | |
|
||||
+---+---+---+---+---+---+---+---+ +---+-----+-------+
|
||||
\_____________/
|
||||
|
|
||||
Count
|
||||
|
||||
Skip count bytes.
|
||||
|
||||
(3) 3 bytes
|
||||
byte word
|
||||
+---+---+---+---+---+---+---+---+ +---+---+-----+-------+
|
||||
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 1 | 0 | ... | |
|
||||
+---+---+---+---+---+---+---+---+ +---+---+-----+-------+
|
||||
\_____________/
|
||||
|
|
||||
Count
|
||||
|
||||
Xor next count bytes. That means xor count bytes from Source with bytes
|
||||
in Dest.
|
||||
|
||||
(4) 4 bytes
|
||||
byte word byte
|
||||
+---+---+---+---+---+---+---+---+ +---+---+-----+-------+ +-------+
|
||||
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 1 | 1 | ... | | | |
|
||||
+---+---+---+---+---+---+---+---+ +---+---+-----+-------+ +-------+
|
||||
\_____________/ value
|
||||
|
|
||||
Count
|
||||
|
||||
Xor next count bytes in Dest with value.
|
||||
|
||||
5) 1 byte
|
||||
byte
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| 0 | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
\___________________________/
|
||||
|
|
||||
Count
|
||||
|
||||
Xor next count bytes from source with dest.
|
||||
|
||||
6) 3 bytes
|
||||
byte byte byte
|
||||
+---+---+---+---+---+---+---+---+ +-------+ +-------+
|
||||
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | | | |
|
||||
+---+---+---+---+---+---+---+---+ +-------+ +-------+
|
||||
Count Value
|
||||
|
||||
Xor next count bytes with value.
|
||||
|
||||
|
||||
All images end with a 80h 00h 00h command.
|
||||
|
||||
I think these are all the commands, but there might be some other.
|
||||
If you find anything new, please e-mail me.
|
||||
|
||||
As before here's some code :
|
||||
|
||||
DP = destination pointer
|
||||
SP = source pointer
|
||||
Source is buffer containing the Format40 data
|
||||
Dest is the buffer containing the image over which the second has
|
||||
to be xor-ed
|
||||
|
||||
|
||||
SP:=0;
|
||||
DP:=0;
|
||||
repeat
|
||||
Com:=Source[SP];
|
||||
Inc(SP);
|
||||
|
||||
if (Com and $80)<>0 then {if bit 7 set}
|
||||
begin
|
||||
if Com<>$80 then {small skip command (1)}
|
||||
begin
|
||||
Count:=Com and $7F;
|
||||
Inc(DP,Count);
|
||||
end
|
||||
else {Big commands}
|
||||
begin
|
||||
Count:=Word(Source[SP]);
|
||||
if Count=0 then break;
|
||||
Inc(SP,2);
|
||||
|
||||
Tc:=(Count and $C000) shr 14; {Tc=two topmost bits of count}
|
||||
|
||||
case Tc of
|
||||
0,1 : begin {Big skip (2)}
|
||||
Inc(DP,Count);
|
||||
end;
|
||||
2 : begin {big xor (3)}
|
||||
Count:=Count and $3FFF;
|
||||
for i:=1 to Count do
|
||||
begin
|
||||
Dest[DP]:=Dest[DP] xor Source[SP];
|
||||
Inc(DP);
|
||||
Inc(SP);
|
||||
end;
|
||||
end;
|
||||
3 : begin {big repeated xor (4)}
|
||||
Count:=Count and $3FFF;
|
||||
b:=Source[SP];
|
||||
Inc(SP);
|
||||
for i:=1 to Count do
|
||||
begin
|
||||
Dest[DP]:=Dest[DP] xor b;
|
||||
Inc(DP);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end else {xor command}
|
||||
begin
|
||||
Count:=Com;
|
||||
if Count=0 then
|
||||
begin {repeated xor (6)}
|
||||
Count:=Source[SP];
|
||||
Inc(SP);
|
||||
b:=Source[SP];
|
||||
Inc(SP);
|
||||
for i:=1 to Count do
|
||||
begin
|
||||
Dest[DP]:=Dest[DP] xor b;
|
||||
Inc(DP);
|
||||
end;
|
||||
end else {copy xor (5)}
|
||||
for i:=1 to Count do
|
||||
begin
|
||||
Dest[DP]:=Dest[DP] xor Source[SP];
|
||||
Inc(DP);
|
||||
Inc(SP);
|
||||
end;
|
||||
end;
|
||||
until false;
|
||||
|
||||
|
||||
|
||||
===================
|
||||
6. THE .CPS FILES
|
||||
===================
|
||||
|
||||
The .CPS files contain 320x200x256 images. The images are compressed with
|
||||
the Format80 compression method. They may or may not contain a palette.
|
||||
|
||||
The header has the following structure :
|
||||
|
||||
Header : record
|
||||
Size : word; {File size - 2}
|
||||
Unknown : word; {Always 0004h}
|
||||
ImSize : word; {Size of uncompressed image (always 0FA00h)}
|
||||
Palette : longint; {Is there a palette ?}
|
||||
end;
|
||||
|
||||
If Palette is 03000000h then there's a palette after the header, otherwise
|
||||
the image follows. CPS file without palette can be found in the SETUP.MIX
|
||||
file, and they all use the Palette that can be found inside the same .MIX.
|
||||
|
||||
The image that follows the palette (or the Header) is in Format80 which is
|
||||
explained above.
|
||||
|
||||
===================
|
||||
7. THE .WSA FILES
|
||||
===================
|
||||
|
||||
|
||||
WSA files contain short animations and can be found in the GENERAL.MIX
|
||||
files.
|
||||
They are basically a series of Format40 images, that are then compressed
|
||||
with
|
||||
Format80.
|
||||
|
||||
The header is :
|
||||
|
||||
Header : record
|
||||
NumFrames : word; {Number of frames}
|
||||
X,Y : word; {Position on screen of the upper left
|
||||
corner}
|
||||
W,H : word; {Width and height of the images}
|
||||
Delta : longint; {Frames/Sec = Delta/(2^10)}
|
||||
end;
|
||||
|
||||
Following that there's an array of offsets :
|
||||
|
||||
Offsets : array [0..NumFrames+1] of longint;
|
||||
|
||||
The obtain the actual offset, you have to add 300h. That is the size of the
|
||||
palette that follows the Offsets array.
|
||||
As for .SHP files the two last offsets have a special meaning.
|
||||
If the last offset is 0 then the one before it points to the end of file
|
||||
(after you added 300h of course).
|
||||
If the last one is <>0 then it points to the end of the file, and the
|
||||
one before it points to a special frame that gives you the difference
|
||||
between the last and the first frame. This is used when you have to loop the
|
||||
animation.
|
||||
|
||||
As I said before, the images are in Format40 but are then compressed with
|
||||
Format80. That means that you first have to uncompress the Format80 and then
|
||||
decode the Format40 image you obtain.
|
||||
The first frame should be xor-ed over a black image (filled with zeros), all
|
||||
the other are xor-ed over the previous one.
|
||||
|
||||
There is a variant of the file without the palette that can be found in
|
||||
SETUP.MIX but I wasn't able to decode it (maybe there are some commands I
|
||||
don't know about)...
|
||||
|
||||
=====================
|
||||
8. ADDITIONAL NOTES
|
||||
=====================
|
||||
|
||||
The VQA files (that contain movies) have been decoded by Aaron Glover
|
||||
(arn@ibm.net), and are explained in a document he wrote up.
|
||||
You can find the document on my homepage (or ask him directly).
|
||||
|
||||
What is still missing are the .AUD files.
|
||||
It seems that the AUD files use some kind of lossy sound compression,
|
||||
which means that it is almost impossible to decode them.
|
||||
However if someone manages to work them out, I'd really appreciate some
|
||||
info.
|
||||
|
||||
I know my explanations are not very good, but you'll have to bear them,
|
||||
unless someone else wants to rewrite this.
|
||||
|
||||
============
|
||||
9. CREDITS
|
||||
============
|
||||
|
||||
I wish to thank the following people :
|
||||
|
||||
-Andrew Griffin (buggy@adam.com.au) for starting it all.
|
||||
-Aaron Glover (arn@ibm.net) and
|
||||
Denis Moeller (d.moeller@rendsburg.netsurf.de) for their work on .SHP
|
||||
files.
|
||||
-Aaron Glover for decoding the VQA files.
|
||||
-Carl Kenner (andrew.kenner@unisa.edu.au) for the info on .CPS files.
|
||||
|
||||
|
||||
Vladan Bato (bat22@geocities.com)
|
||||
http://www.geocities.com/SiliconValley/8682
|
||||
500
doc/cncmap.txt
Normal file
500
doc/cncmap.txt
Normal file
@@ -0,0 +1,500 @@
|
||||
THE COMMAND & CONQUER MAPS
|
||||
|
||||
Rev. 1f
|
||||
|
||||
by Vladan Bato (bat22@geocities.com)
|
||||
|
||||
This document explains the format of the maps and the associated graphics
|
||||
files. It has also a complete listing of all available map values.
|
||||
This document is meant for people who want to make a C&C scenery editor.
|
||||
You can also use it to edit manually the maps but IMHO it's a suicide if you
|
||||
can't see what you are doing.
|
||||
|
||||
ABOUT .MIX FILES
|
||||
|
||||
First of all I will explain the structure of MIX files, since all the
|
||||
graphics are in the TEMPERAT, DESERT, and WINTER.MIX files.
|
||||
|
||||
Each MIX file contains several internal files that can be extracted. I will
|
||||
refer to the internal files as just "files".
|
||||
The MIX file is made up of two parts: the first one is the Header, the
|
||||
second one is the Body that contains all the files.
|
||||
|
||||
The structure of the header is:
|
||||
(I will use pascal notation here)
|
||||
|
||||
Header = record
|
||||
NumFiles : word; {Number of internal files}
|
||||
BodyLength : longint; {Length of the body}
|
||||
Index : array [1..NumFiles] of
|
||||
record
|
||||
ID : longint; {ID of file, computed from filename}
|
||||
Start : longint; {Offset of file in the body}
|
||||
Size : longint; {Size of the file}
|
||||
end;
|
||||
end;
|
||||
|
||||
Of course you can't use directly such a structure in pascal because its
|
||||
length is not fixed.
|
||||
Note that the offsets are relative to the start of the body so to find the
|
||||
actual offset in the MIX you have to add the size of the header which is
|
||||
NumFiles*12+6
|
||||
|
||||
Note also that the records in the Index are not in the same order as the
|
||||
files are physically stored in the MIX. In this document I will always refer
|
||||
to the record number in the index and not to the file's actual position in
|
||||
the MIX.
|
||||
|
||||
ABOUT THE MAP
|
||||
|
||||
All the maps are 64x64 squares large. There are 2 bytes of information for
|
||||
each square, thus the file is 8192 bytes long.
|
||||
|
||||
The two bytes indicate which image should be placed there. The first one
|
||||
indicates in which of the internal files of TEMPERAT, DESERT or WINTER.MIX
|
||||
it is. Each of these internal files contains several images; the second byte
|
||||
tells which of those images should be taken. The images inside one of the
|
||||
internal files, if put together, form a larger image. It can be a bridge,
|
||||
a road section, etc. These are called "templates". Thus, each internal file
|
||||
contains a template. Each template is made of several "tiles" (images).
|
||||
Each square of the map contains one tile. It's not necessary to put all
|
||||
the tiles of a template on the map.
|
||||
|
||||
There are templates of various sizes: from 1x1 to 6x8.
|
||||
(I will always write the dimensions as WidthxHeight)
|
||||
The tile numbers range from 0 to WxH-1.
|
||||
However there are some tiles, which I call "empty tiles", that don't have
|
||||
any images associated with them. If you try using them C&C will display
|
||||
the default terrain for that Theater instead. There are empty tiles
|
||||
especially in the corners of large templates.
|
||||
|
||||
An example may be useful:
|
||||
|
||||
The SW-NE bridge in the temperate theater has two empty tiles:
|
||||
XXOr X - Empty tile O - other tiles
|
||||
wbbO b - Bridge
|
||||
Obbw w - Water (This is probably wrong, I can't check now)
|
||||
rOOO r - road
|
||||
|
||||
We can see that in the upper left corner there are two empty tiles.
|
||||
We can put the values 00 and 01 in our map (as the second byte; the first
|
||||
would be A5h for the bridge), in that case we'll see some grass there. But
|
||||
we can replace those two tiles with anything else without disturbing the
|
||||
rest. What I mean, is that if we changed any other tile, a piece of river
|
||||
would be missing or a rock could be cut, ruining the map; but if we
|
||||
replace the empty tiles everything is OK.
|
||||
|
||||
So, when we have an empty tile, we can leave it there, or replace it with
|
||||
anything else. There are two exceptions to this rule however:
|
||||
|
||||
1) Sometimes the empty tiles should be water, but if we don't replace them
|
||||
C&C will show land in the middle of our lake or sea;
|
||||
2) There are templates containing roads that finish in one of the corners,
|
||||
so that the next template must have an empty tile in the opposite corner
|
||||
to stick to the other.
|
||||
|
||||
An example might help:
|
||||
|
||||
Imagine that we have two road sections like these:
|
||||
OOrr OOrr
|
||||
Orrr Orrr
|
||||
rrrO rrrO
|
||||
rrOO rrOO
|
||||
|
||||
and we want to stick them diagonally:
|
||||
OOrr
|
||||
Orrr
|
||||
rrrO
|
||||
rrOO
|
||||
OOrr
|
||||
Orrr
|
||||
rrrO
|
||||
rrOO
|
||||
|
||||
Something is obviously missing. We need to add some tiles to fill it like
|
||||
this:
|
||||
OOrr
|
||||
Orrr
|
||||
rrrO
|
||||
RrrOO
|
||||
OOrrR
|
||||
Orrr
|
||||
rrrO
|
||||
rrOO
|
||||
|
||||
The solution could be to have two templates like these:
|
||||
OOOO ROOO
|
||||
OOOO OOOO
|
||||
OOOO OOOO
|
||||
OOOR OOOO
|
||||
or to have one little template with empty tiles:
|
||||
RX
|
||||
XR (Where X are empty tiles)
|
||||
|
||||
Now we can put this between the two road sections, replacing the empty
|
||||
tiles with the corner tiles of the road sections.
|
||||
|
||||
There are many road sections like this and I've indicated them with
|
||||
"(Conn.)" in the table at the end of this document.
|
||||
|
||||
ABOUT THE DESERT, TEMPERAT, and WINTER.MIX FILES
|
||||
|
||||
These are the files that hold the graphics for the templates. There's one
|
||||
file inside the MIX for each template, and each file has several tiles
|
||||
inside.
|
||||
There are other files inside the MIXes, probably for the trees and other
|
||||
overlay elements but I don't know the format. If somebody knows their
|
||||
format, please let me know.
|
||||
|
||||
In each MIX there's also a palette, the entries are:
|
||||
DESERT.MIX entry n. 26
|
||||
TEMPERAT.MIX entry n. 62
|
||||
WINTER.MIX entry n. 62
|
||||
|
||||
I will now explain the format of the files with map graphics.
|
||||
First of all there's a header with the following structure:
|
||||
|
||||
Header = record
|
||||
Width : word; {Width of images, always 24 (18h)}
|
||||
Heigth : word; {Heigth of images, always 24}
|
||||
NumTil : word; {Number of Tiles (may differ from num. of Images}
|
||||
Zero1 : word; {Seems to be always 0000h}
|
||||
Size : longint; {size of file}
|
||||
ImgStart : longint; {Offset of first image}
|
||||
Zero2 : longint; {Seems to be always 00000000h}
|
||||
ID1 : word; {Always FFFFh}
|
||||
ID2 : word; {Always 1A0Dh (or 0D1Ah I can't remeber}
|
||||
Index2 : longint; {Offset of Index2}
|
||||
Index1 : longint; {Offset of Index1} {I will explain these
|
||||
later}
|
||||
end;
|
||||
|
||||
The images follow the header but I suppose they could be anywhere.
|
||||
They are all 24x24 pixel, uncompressed and are one after the other.
|
||||
Note that the number of images may differ from the number of tiles if
|
||||
there are some empty tiles. If there are empty tiles, the actual number of
|
||||
images can be smaller than the number of tiles. To work out the number
|
||||
of images you can use the formula : (Index1-ImgStart)/(24*24).
|
||||
However, you won't have to do this if the index is not corrupt.
|
||||
|
||||
Index1 has the following format:
|
||||
|
||||
Index1 : array [0..NumTil-1] of byte;
|
||||
|
||||
where NumTil is the number of tiles.
|
||||
|
||||
Each entry in Index1 corresponds to one tile, and indicates which image
|
||||
(of that file) is associated with it. If the entry is FFh than that tile
|
||||
is empty.
|
||||
|
||||
Index2 is an array of NumImages bytes where NumImages is the real
|
||||
number of images in the file. However it's always filled with zeros
|
||||
(sometimes there's a 1 somewhere but I don't know it's meaning).
|
||||
|
||||
Note that there's no way to know the dimensions (Width and Height) of the
|
||||
template. If there are 6 tiles it could be 6x1, 1x6, 3x2, 2x3. I worked out
|
||||
the dimensions of all templates myself (It's easy, all you have to do is to
|
||||
try different widths and look at the screen).
|
||||
|
||||
|
||||
For example a procedure that has to display template 61h, tile 3 of the
|
||||
Desert theater would do:
|
||||
1) Look in the table and find in which file it is in (entry 168 of
|
||||
DESERT.MIX)
|
||||
2) Open that file (seek it inside the MIX)
|
||||
3) Read the Header
|
||||
4) Read Index1 and read the 4th byte (for tile 3), let it be N
|
||||
5) Seek ImgStart+Width*Height*N
|
||||
6) Read the Image and display it
|
||||
|
||||
AND FINALLY THE TABLE
|
||||
|
||||
Here is the table of all available map values (template numbers), the
|
||||
dimensions and the relative entries in the DESERT, WINTER, and TEMPERAT.MIX.
|
||||
There's also a brief description for those that don't want or don't know
|
||||
how to write an editor. However, I think that it will be difficult to stick
|
||||
the templates together without seeing them.
|
||||
|
||||
An "x" means that the template doesn't exist in that theater. There are many
|
||||
templates that exist only in one theater and will show as black holes in the
|
||||
others (causing the HOM effect). The WINTER and TEMPERATE theaters are
|
||||
however very similar, and differ only in a few templates.
|
||||
The roads and cliffs are mostly the same for the three theaters, but be
|
||||
careful about the river and coast templates because they are not the same.
|
||||
|
||||
V | DES | TEM | WIN | Dim. | Name | Description
|
||||
-----+-----+-----+-----+-------+----------+---------------------------------
|
||||
--
|
||||
00h | 007 | 011 | 028 | [4x4] | CLEAR1 | Default terrain
|
||||
01h | 002 | 007 | 007 | [1x1] | W1 | Water (not animated)
|
||||
02h | x | 009 | 009 | [2x2] | W2 | Water
|
||||
03h | x | 087 | 087 | [3x3] | SH1 | Coast WD (1)
|
||||
04h | x | 106 | 105 | [3x3] | SH2 | Coast WD
|
||||
05h | x | 126 | 124 | [1x1] | SH3 | Rock in water
|
||||
06h | x | 143 | 140 | [2x1] | SH4 | Rock in water
|
||||
07h | x | 159 | 157 | [3x3] | SH5 | Coast WD
|
||||
08h | x | 018 | 017 | [3x3] | SH11 | Fjord WD
|
||||
09h | x | 024 | 023 | [3x3] | SH12 | Coast WU
|
||||
0Ah | x | 031 | 031 | [3x3] | SH13 | Coast WU
|
||||
0Bh | x | 037 | 037 | [3x3] | SH14 | Coast WU
|
||||
0Ch | x | 042 | 042 | [3x3] | SH15 | Coast WU
|
||||
0Dh | 106 | 074 | 074 | [2x2] | S01 | Cliff Left Edge
|
||||
0Eh | 122 | 093 | 092 | [2x3] | S02 | Cliff Wu-Wd (2)
|
||||
0Fh | 138 | 112 | 110 | [2x2] | S03 | Cliff W-E
|
||||
10h | 154 | 131 | 128 | [2x2] | S04 | Cliff W-E
|
||||
11h | 170 | 147 | 144 | [2x2] | S05 | Cliff W-E
|
||||
12h | 185 | 163 | 161 | [2x3] | S06 | Cliff Wd-Eu
|
||||
13h | 200 | 180 | 179 | [2x2] | S07 | Cliff Right Edge
|
||||
14h | 212 | 195 | 195 | [2x2] | S08 | Cliff Top Edge
|
||||
15h | 225 | 208 | 209 | [3x2] | S09 | Cliff N-S
|
||||
16h | 096 | 064 | 064 | [2x2] | S10 | Cliff N-S
|
||||
17h | 108 | 078 | 078 | [2x2] | S11 | Cliff N-S
|
||||
18h | 124 | 097 | 096 | [2x2] | S12 | Cliff N-S
|
||||
19h | 140 | 117 | 115 | [3x2] | S13 | Cliff N-S
|
||||
1Ah | 157 | 135 | 132 | [2x2] | S14 | Cliff Bottom Edge
|
||||
1Bh | 172 | 151 | 149 | [2x2] | S15 | Cliff Left Edge
|
||||
1Ch | 187 | 167 | 166 | [2x3] | S16 | Cliff Wu-Ed
|
||||
1Dh | 202 | 184 | 184 | [2x2] | S17 | Cliff W-E
|
||||
1Eh | 215 | 199 | 200 | [2x2] | S18 | Cliff W-E
|
||||
1Fh | 228 | 211 | 213 | [2x2] | S19 | Cliff W-E
|
||||
20h | 098 | 068 | 069 | [2x3] | S20 | Cliff Wu-Ed
|
||||
21h | 110 | 082 | 082 | [1x2] | S21 | Cliff Right Edge
|
||||
22h | 126 | 101 | 100 | [2x1] | S22 | Cliff Corner S-E Internal
|
||||
23h | 142 | 121 | 119 | [3x2] | S23 | Cliff Sl-Nr
|
||||
24h | 159 | 139 | 136 | [2x2] | S24 | Cliff N-S
|
||||
25h | 174 | 155 | 153 | [2x2] | S25 | Cliff N-S
|
||||
26h | 189 | 171 | 170 | [2x2] | S26 | Cliff N-S
|
||||
27h | 204 | 188 | 188 | [3x2] | S27 | Cliff Nl-Sr
|
||||
28h | 218 | 202 | 203 | [2x2] | S28 | Cliff Bottom Edge
|
||||
29h | 230 | 213 | 215 | [2x2] | S29 | Cliff Corner N-E External
|
||||
2Ah | 101 | 070 | 071 | [2x2] | S30 | Cliff Corner S-E Ext
|
||||
2Bh | 113 | 084 | 084 | [2x2] | S31 | Cliff Corner W-S Ext
|
||||
2Ch | 129 | 103 | 102 | [2x2] | S32 | Cliff Corner N-W Ext
|
||||
2Dh | 145 | 123 | 121 | [2x2] | S33 | Cliff Corner N-E Internal
|
||||
2Eh | 162 | 141 | 138 | [2x2] | S34 | Cliff Corner S-E Int
|
||||
2Fh | 177 | 157 | 155 | [2x2] | S35 | Cliff Corner W-S Int
|
||||
30h | 192 | 173 | 172 | [2x2] | S36 | Cliff Corner W-N Int
|
||||
31h | 207 | 190 | 190 | [2x2] | S37 | Cliff Junction NW-SE
|
||||
32h | 221 | 204 | 205 | [2x2] | S38 | Cliff Junction SW-NE
|
||||
33h | x | 027 | 026 | [3x3] | SH32 | Coast Corner N-W Int
|
||||
34h | x | 033 | 033 | [3x3] | SH33 | Coast Corner N-E Int
|
||||
35h | 017 | x | x | [4x1] | SH20 | Coast WD
|
||||
36h | 024 | x | x | [3x1] | SH21 | Coast WD
|
||||
37h | 041 | x | x | [6x2] | SH22 | Coast WD
|
||||
38h | 049 | x | x | [2x2] | SH23 | Coast WD
|
||||
39h | 118 | x | x | [1x1] | BR1 | Bush
|
||||
3Ah | 134 | x | x | [1x1] | BR2 | Bush
|
||||
3Bh | 150 | x | x | [1x1] | BR3 | Cactus
|
||||
3Ch | 166 | x | x | [1x1] | BR4 | Cactus
|
||||
3Dh | 181 | x | x | [1x1] | BR5 | ??? Purple square (bug ?)
|
||||
3Eh | 196 | x | x | [2x2] | BR6 | Bushes
|
||||
3Fh | 210 | x | x | [2x2] | BR7 | Bushes
|
||||
40h | 223 | x | x | [3x2] | BR8 | Bushes
|
||||
41h | 234 | x | x | [3x2] | BR9 | Bushes
|
||||
42h | 016 | x | x | [2x1] | BR10 | ??? Purple squares (bug ?)
|
||||
43h | 105 | 073 | x | [1x1] | P01 | Bones / Wall (3)
|
||||
44h | 121 | 092 | x | [1x1] | P02 | Bones / Wall (3)
|
||||
45h | 137 | 111 | x | [1x1] | P03 | Mud / UFO (3) (6)
|
||||
46h | 153 | 130 | x | [1x1] | P04 | Rock / UFO (3) (6)
|
||||
47h | 169 | x | x | [2x2] | P05 | Gray Sand
|
||||
48h | 184 | x | x | [6x4] | P06 | Gray Sand
|
||||
49h | 199 | 179 | 178 | [4x2] | P07 | Mud
|
||||
4Ah | x | 194 | 194 | [3x2] | P08 | Mud
|
||||
4Bh | x | 045 | 045 | [3x2] | SH16 | Fjord WU
|
||||
4Ch | 072 | 047 | 047 | [2x2] | SH17 | Water (anim.)
|
||||
4Dh | 078 | 049 | 049 | [2x2] | SH18 | Water (anim.)
|
||||
4Eh | 084 | x | x | [3x2] | SH19 | Coast WD
|
||||
4Fh | x | 116 | 114 | [3x2] | P13 | Destroyed House
|
||||
50h | x | 134 | 131 | [2x1] | P14 | Walls
|
||||
51h | x | x | 148 | [4x2] | P15 | Snow
|
||||
52h | 001 | 006 | 006 | [1x1] | B1 | Rock
|
||||
53h | 003 | 008 | 008 | [2x1] | B2 | Rock
|
||||
54h | x | 010 | 010 | [3x1] | B3 | Rock
|
||||
55h | 004 | x | x | [1x1] | B4 | ?? Rock (7)
|
||||
56h | 005 | x | x | [1x1] | B5 | ?? Rock (7)
|
||||
57h | 006 | x | x | [1x1] | B6 | ?? Rock (7)
|
||||
58h | x | 175 | 174 | [3x3] | SH6 | Coast WD
|
||||
59h | x | 191 | 191 | [2x2] | SH7 | Coast Corner W-N External
|
||||
5Ah | x | 205 | 206 | [3x3] | SH8 | Coast Corner S-E Ext
|
||||
5Bh | x | 215 | 217 | [3x3] | SH9 | Coast Corner W-S Ext
|
||||
5Ch | x | 012 | 011 | [2x2] | SH10 | Coast Corner N-E Ext
|
||||
5Dh | 104 | 072 | 073 | [2x2] | D01 | Road Bottom End
|
||||
5Eh | 120 | 091 | 091 | [2x2] | D02 | Road Left End
|
||||
5Fh | 136 | 110 | 109 | [1x2] | D03 | Road Top End
|
||||
60h | 152 | 129 | 127 | [2x2] | D04 | Road Right End
|
||||
61h | 168 | 146 | 143 | [3x4] | D05 | Road S-N
|
||||
62h | 183 | 162 | 160 | [2x3] | D06 | Road S-N
|
||||
63h | 198 | 178 | 177 | [3x2] | D07 | Road S-N
|
||||
64h | 211 | 193 | 193 | [3x2] | D08 | Road S-N
|
||||
65h | 224 | 207 | 208 | [4x3] | D09 | Road W-E
|
||||
66h | 095 | 063 | 063 | [4x2] | D10 | Road W-E
|
||||
67h | 107 | 077 | 077 | [2x3] | D11 | Road W-E
|
||||
68h | 123 | 096 | 095 | [2x2] | D12 | Road W-E
|
||||
69h | 139 | 115 | 113 | [4x3] | D13 | Road Wu-Ed
|
||||
6Ah | 156 | 133 | 130 | [3x3] | D14 | Road T N--W+E (4)
|
||||
6Bh | 171 | 150 | 147 | [3x3] | D15 | Road Y S--N+E (4)
|
||||
6Ch | 186 | 166 | 164 | [3x3] | D16 | Road Y S--N+E
|
||||
6Dh | 201 | 183 | 182 | [3x2] | D17 | Road T S--W+E
|
||||
6Eh | 214 | 198 | 198 | [3x3] | D18 | Road T W--N+S
|
||||
6Fh | 227 | 210 | 211 | [3x3] | D19 | Road + W-N-E-S
|
||||
70h | 097 | 067 | 067 | [3x3] | D20 | Road Corner N-E
|
||||
71h | 109 | 081 | 081 | [3x2] | D21 | Road Corner S-E
|
||||
72h | 125 | 100 | 099 | [3x3] | D22 | Road Corner W-S
|
||||
73h | 141 | 120 | 118 | [3x3] | D23 | Road Corner W-N
|
||||
74h | 158 | 138 | 135 | [3x3] | D24 | Road Diagonal NW-SE (5)
|
||||
75h | 173 | 154 | 152 | [3x3] | D25 | Road Diag NW-SE
|
||||
76h | 188 | 170 | 169 | [2x2] | D26 | Road Diag NW-SE (Conn.) (5)
|
||||
77h | 203 | 187 | 187 | [2x2] | D27 | Road Diag NW-SE (Conn.)
|
||||
78h | 217 | 201 | 202 | [2x2] | D28 | Road Corner W-SE (Conn.)
|
||||
79h | 229 | 212 | 214 | [2x2] | D29 | Road Corner N-SE (Conn.)
|
||||
7Ah | 100 | 069 | 070 | [2x2] | D30 | Road Y SE--N+W (Conn.)
|
||||
7Bh | 112 | 083 | 083 | [2x2] | D31 | Road Corner E-NW (Conn.)
|
||||
7Ch | 128 | 102 | 101 | [2x2] | D32 | Road Corner S-NW (Conn.)
|
||||
7Dh | 144 | 122 | 120 | [2x2] | D33 | Road Y NW--S+E (Conn.)
|
||||
7Eh | 161 | 140 | 137 | [3x3] | D34 | Road Diag SW-NE
|
||||
7Fh | 176 | 156 | 154 | [3x3] | D35 | Road Diag SW-NE
|
||||
80h | 191 | 172 | 171 | [2x2] | D36 | Road Diag SW-NE (Conn.)
|
||||
81h | 206 | 189 | 189 | [2x2] | D37 | Road Diag SW-NE (Conn.)
|
||||
82h | 220 | 203 | 204 | [2x2] | D38 | Road Corner E-SW (Conn.)
|
||||
83h | 232 | 214 | 216 | [2x2] | D39 | Road Corner N-SW (Conn.)
|
||||
84h | 103 | 071 | 072 | [2x2] | D40 | Road Y SW--N+E (Conn.)
|
||||
85h | 115 | 085 | 085 | [2x2] | D41 | Road Corner W-NE (Conn.)
|
||||
86h | 131 | 104 | 103 | [2x2] | D42 | Road Corner S-NE (Conn.)
|
||||
87h | 147 | 124 | 122 | [2x2] | D43 | Road Y NE--W+S (Conn.)
|
||||
88h | x | 017 | 016 | [5x4] | RV01 | River W-E
|
||||
89h | x | 023 | 022 | [5x3] | RV02 | River W-E
|
||||
8Ah | x | 030 | 030 | [4x4] | RV03 | River Wu-Ed
|
||||
8Bh | x | 036 | 036 | [4x4] | RV04 | River Wd-Eu
|
||||
8Ch | x | 041 | 041 | [3x3] | RV05 | River N-S
|
||||
8Dh | x | 044 | 044 | [3x2] | RV06 | River N-S
|
||||
8Eh | x | 046 | 046 | [3x2] | RV07 | River N-S
|
||||
8Fh | x | 048 | 048 | [2x2] | RV08 | River Corner S-E
|
||||
90h | x | 052 | 052 | [2x2] | RV09 | River Corner W-S
|
||||
91h | x | 014 | 013 | [2x2] | RV10 | River Corner N-E
|
||||
92h | x | 020 | 019 | [2x2] | RV11 | River Corner W-N
|
||||
93h | x | 026 | 025 | [3x4] | RV12 | River Y N--W+S
|
||||
94h | x | 032 | 032 | [4x4] | RV13 | River Y Eu--W+S
|
||||
95h | 055 | x | x | [4x3] | RV14 | River W-E
|
||||
96h | 060 | x | x | [4x3] | RV15 | River W-E
|
||||
97h | 067 | x | x | [6x4] | RV16 | River Wd-Eu
|
||||
98h | 073 | x | x | [6x5] | RV17 | River Wu-Ed
|
||||
99h | 079 | x | x | [4x4] | RV18 | River N-S
|
||||
9Ah | 085 | x | x | [4x4] | RV19 | River N-S
|
||||
9Bh | 018 | x | x | [6x8] | RV20 | River Nr-Sl
|
||||
9Ch | 025 | x | x | [5x8] | RV21 | River Nl-Sr
|
||||
9Dh | 042 | x | x | [3x3] | RV22 | River Corner E-S
|
||||
9Eh | 050 | x | x | [3x3] | RV23 | River Corner W-S
|
||||
9Fh | 057 | x | x | [3x3] | RV24 | River Corner N-E
|
||||
A0h | 062 | x | x | [3x3] | RV25 | River Corner N-W
|
||||
A1h | 009 | 002 | 004 | [3x3] | FORD1 | River Crossing (Road W-E)
|
||||
A2h | 010 | 003 | 005 | [3x3] | FORD2 | River Crossing (Road N-S)
|
||||
A3h | 047 | 057 | 057 | [3x3] | FALLS1 | Falls W-E
|
||||
A4h | 048 | 058 | 058 | [3x2] | FALLS2 | Falls N-S
|
||||
A5h | x | 218 | 220 | [4x4] | BRIDGE1 | Bridge SW-NE
|
||||
A6h | x | 059 | 059 | [4x4] | BRIDGE1D | Fallen Bridge SW-NE
|
||||
A7h | x | 219 | 221 | [5x5] | BRIDGE2 | Bridge NW-SE
|
||||
A8h | x | 060 | 060 | [5x5] | BRIDGE2D | Fallen Bridge NW-SE
|
||||
A9h | 236 | x | x | [6x5] | BRIDGE3 | Bridge SW-NE
|
||||
AAh | 092 | x | x | [6x5] | BRIDGE3D | Fallen Bridge SW-NE
|
||||
ABh | 237 | x | x | [6x4] | BRIDGE4 | Bridge NW-SE
|
||||
ACh | 093 | x | x | [6x4] | BRIDGE4D | Fallen Bridge NW-SE
|
||||
ADh | 056 | x | x | [3x3] | SH24 | Fjord WD
|
||||
AEh | 061 | x | x | [3x2] | SH25 | Coast WU
|
||||
AFh | 068 | x | x | [3x2] | SH26 | Coast WU
|
||||
B0h | 074 | x | x | [4x1] | SH27 | Coast WU
|
||||
B1h | 080 | x | x | [3x1] | SH28 | Coast WU
|
||||
B2h | 086 | x | x | [6x2] | SH29 | Coast WU
|
||||
B3h | 019 | x | x | [2x2] | SH30 | Coast WU
|
||||
B4h | 027 | x | x | [3x3] | SH31 | Fjord WU
|
||||
B5h | x | x | 165 | [2x2] | P16 | Snow
|
||||
B6h | x | x | 183 | [4x2] | P17 | Snow
|
||||
B7h | x | x | 199 | [4x3] | P18 | Snow
|
||||
B8h | x | x | 212 | [4x3] | P19 | Snow
|
||||
B9h | x | x | 068 | [4x3] | P20 | Snow
|
||||
BAh | x | 038 | 038 | [3x3] | SH34 | Coast WR
|
||||
BBh | x | 043 | 043 | [3x3] | SH35 | Coast WL
|
||||
BCh | 069 | x | x | [1x1] | SH36 | Coast Corner S-E Int
|
||||
BDh | 075 | x | x | [1x1] | SH37 | Coast Corner W-S Int
|
||||
BEh | 081 | x | x | [1x1] | SH38 | Coast Corner N-E Int
|
||||
BFh | 087 | x | x | [1x1] | SH39 | Coast Corner N-W Int
|
||||
C0h | 020 | x | x | [3x3] | SH40 | Coast Corner S-E Int
|
||||
C1h | 028 | x | x | [3x3] | SH41 | Coast Corner N-W Int
|
||||
C2h | 043 | x | x | [1x2] | SH42 | Coast WL
|
||||
C3h | 051 | x | x | [1x3] | SH43 | Coast WL
|
||||
C4h | 058 | x | x | [1x3] | SH44 | Coast WR
|
||||
C5h | 063 | x | x | [1x2] | SH45 | Coast WR
|
||||
C6h | 070 | x | x | [3x3] | SH46 | Coast Corner S-E Int
|
||||
C7h | 076 | x | x | [3x3] | SH47 | Coast Corner S-E Int
|
||||
C8h | 082 | x | x | [3x3] | SH48 | Coast Corner N-E Int
|
||||
C9h | 088 | x | x | [3x3] | SH49 | Coast Corner N-W Int
|
||||
CAh | 021 | x | x | [4x3] | SH50 | Coast Corner S-E Ext
|
||||
CBh | 029 | x | x | [4x3] | SH51 | Coast Corner W-S Ext
|
||||
CCh | 044 | x | x | [4x3] | SH52 | Coast Corner N-E Ext
|
||||
CDh | 052 | x | x | [4x3] | SH53 | Coast Corner N-W Ext
|
||||
CEh | 059 | x | x | [3x2] | SH54 | Coast WD
|
||||
CFh | 064 | x | x | [3x2] | SH55 | Coast WD
|
||||
D0h | 071 | x | x | [3x2] | SH56 | Coast WU
|
||||
D1h | 077 | x | x | [3x2] | SH57 | Coast WU
|
||||
D2h | 083 | x | x | [2x3] | SH58 | Coast WR
|
||||
D3h | 089 | x | x | [2x3] | SH59 | Coast WR
|
||||
D4h | 022 | x | x | [2x3] | SH60 | Coast WL
|
||||
D5h | 030 | x | x | [2x3] | SH61 | Coast WL
|
||||
D6h | 045 | x | x | [6x1] | SH62 | Coast WD
|
||||
D7h | 053 | x | x | [4x1] | SH63 | Coast WD
|
||||
|
||||
|
||||
!! Warning !!
|
||||
Values from D8h-FEh will cause the game to crash (it just locks up on
|
||||
my computer)!!!
|
||||
|
||||
The value FFh indicates the default terrain (I think the 4x4 template is
|
||||
used).
|
||||
|
||||
Notes:
|
||||
|
||||
(0a) There may be some errors in this table because I typed it in a hurry
|
||||
(you don't know how much time it takes), so if you find any errors
|
||||
please report them to me.
|
||||
(0b) The names are taken from the GAME.DAT file. I matched them with the
|
||||
files in the theater mix files. The complete filenames are the names
|
||||
above plus an extension that depends on the theater (.DES, .TEM, .WIN).
|
||||
(1) For Coasts, WD, WU, WL, and WR mean : Water on the bottom
|
||||
(Down), Top (Up), left and right.
|
||||
(2) For cliffs and roads the two letters indicate from which to which side
|
||||
the Road (or cliff) goes. The lowercase letter means up, down, left,
|
||||
right to indicate in which part of that side it starts.
|
||||
For Example:
|
||||
|
||||
River Wu-Ed :
|
||||
OOOOO
|
||||
rOOOO
|
||||
OrrOO
|
||||
OOOrr
|
||||
OOOOO
|
||||
|
||||
(3) These templates exist in both the DESERT and the TEMPERATE theaters but
|
||||
are not the same. I've put a description of both.
|
||||
|
||||
(4) For Roads:
|
||||
Roads T and Y mean that the road splits in the shape of a T or a Y.
|
||||
E--N+S means it starts from the east edge then splits in two parts, one
|
||||
going to the north and the other to the south edge
|
||||
|
||||
(5) NW or any other corner means that the road ends in that corner and if it
|
||||
says (Conn.), that means that it has an empty tile in that corner.
|
||||
So you have to use the (Conn.) templates to stick together the other
|
||||
ones.
|
||||
|
||||
(6) In TEMPERAT.MIX these two files are buggy, they report there are 67h
|
||||
tiles, but if you look at the index you'll see they all point to the
|
||||
second image which (I think) is of uniform color. Only the first tile is
|
||||
ever used.
|
||||
|
||||
(7) These three templates don't work in C&C (HOM effect), but their graphics
|
||||
exist in the DESERT.MIX file. Do not use them !
|
||||
|
||||
That's all. I hope this info will be used by somebody to make a scenery
|
||||
editor.
|
||||
|
||||
Report any errors to me. Also, if you have any info about other file formats
|
||||
please share it with me.
|
||||
Binary file not shown.
BIN
mods/cnc/chem.shp
Normal file
BIN
mods/cnc/chem.shp
Normal file
Binary file not shown.
@@ -32,10 +32,3 @@ BR3:
|
||||
Footprint: ____ ____
|
||||
Dimensions: 4,2
|
||||
HP: 1000
|
||||
|
||||
MINE:
|
||||
Inherits: ^Building
|
||||
RenderBuilding:
|
||||
Palette: terrain
|
||||
SeedsOre:
|
||||
-Selectable:
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
Building:
|
||||
Dimensions: 1,1
|
||||
Footprint: x
|
||||
BaseNormal: no
|
||||
BuildSounds: constru2.aud, hvydoor1.aud
|
||||
SellSounds: cashturn.aud
|
||||
RenderBuilding:
|
||||
@@ -64,6 +63,7 @@
|
||||
SellSounds: cashturn.aud
|
||||
Capturable: false
|
||||
Bib: no
|
||||
BaseNormal: no
|
||||
Crewed: no
|
||||
Sight: 0
|
||||
Wall:
|
||||
|
||||
BIN
mods/cnc/flame.shp
Normal file
BIN
mods/cnc/flame.shp
Normal file
Binary file not shown.
@@ -10,8 +10,6 @@ URepairPercent=20% ; [units only] percent cost to fully repair as ratio of
|
||||
URepairStep=10 ; [units only] hit points to heal per repair 'tick' for units
|
||||
BuildSpeed=.1 ; general build speed [time (in minutes) to produce a 1000 credit cost item]
|
||||
|
||||
GemValue=50 ; gem credits per 'bail' carried by a harvester
|
||||
GoldValue=25 ; gold credits per 'bail' carried by a harvester
|
||||
LowPowerSlowdown=3 ; slowdown factor for low power
|
||||
|
||||
GapRegenInterval=.1 ; gap generators will regenerate their shroud at this time interval
|
||||
|
||||
17
mods/cnc/missions.pkt
Normal file
17
mods/cnc/missions.pkt
Normal file
@@ -0,0 +1,17 @@
|
||||
[Missions]
|
||||
SCM01EA.INI=Green Acres
|
||||
SCM02EA.INI=Sand Trap
|
||||
SCM03EA.INI=Lost Arena
|
||||
SCM04EA.INI=River Raid
|
||||
SCM05EA.INI=Eye of the Storm
|
||||
SCM06EA.INI=Lakefront Clash
|
||||
SCM07EA.INI=Desert Madness
|
||||
SCM08EA.INI=Pitfall
|
||||
SCM09EA.INI=Moosehead Barrons
|
||||
SCM70EA.INI=Winter Waterland
|
||||
SCM71EA.INI=One Pass Fits All
|
||||
SCM72EA.INI=Straight and Narrow
|
||||
SCM73EA.INI=King takes Pawn
|
||||
SCM74EA.INI=Nowhere to Hide
|
||||
SCM77EA.INI=Marooned
|
||||
SCM96EA.INI=Tiberium Garden
|
||||
@@ -11,20 +11,16 @@ Packages:
|
||||
mods/cnc/packages/cclocal.mix
|
||||
mods/cnc/packages/speech.mix
|
||||
mods/cnc/packages/conquer.mix
|
||||
# mods/cnc/packages/general.mix
|
||||
mods/cnc/packages/general.mix
|
||||
mods/cnc/packages/sounds.mix
|
||||
mods/cnc/packages/tempicnh.mix
|
||||
mods/cnc/packages/updatec.mix
|
||||
# Cannot qualify the RA names because they may live inside a mix
|
||||
mods/cnc/packages/temperat.mix
|
||||
mods/cnc/packages/winter.mix
|
||||
mods/cnc/packages/desert.mix
|
||||
# TODO: Obsolete conquer.mix
|
||||
~main.mix
|
||||
redalert.mix
|
||||
speech.mix
|
||||
temperat.mix
|
||||
snow.mix
|
||||
interior.mix
|
||||
general.mix
|
||||
conquer.mix
|
||||
sounds.mix
|
||||
|
||||
LegacyRules:
|
||||
mods/cnc/minimal.ini: Minimal rules definitions
|
||||
@@ -44,6 +40,7 @@ Sequences:
|
||||
mods/cnc/sequences-structures.xml:
|
||||
mods/cnc/sequences-vehicles.xml:
|
||||
mods/cnc/sequences-infantry.xml:
|
||||
mods/cnc/sequences-map.xml: Trees etc
|
||||
mods/cnc/sequences.xml: Obsolete; will disappear once done converting
|
||||
|
||||
Chrome:
|
||||
@@ -52,7 +49,3 @@ Chrome:
|
||||
Assemblies:
|
||||
mods/cnc/OpenRA.Mods.Cnc.dll: Cnc mod traits
|
||||
mods/ra/OpenRA.Mods.RA.dll: Red alert mod traits
|
||||
|
||||
Maps:
|
||||
scg01ea.ini: GDI Mission 1
|
||||
scm01ea.ini: Green Acres
|
||||
|
||||
207
mods/cnc/sequences-map.xml
Normal file
207
mods/cnc/sequences-map.xml
Normal file
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<sequences>
|
||||
<!-- Blossom Trees -->
|
||||
<unit name="split2">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="split3">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
|
||||
<!-- Rocks -->
|
||||
<unit name="rock1">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="rock2">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="rock3">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="rock4">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="rock5">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="rock6">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="rock7">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
|
||||
<!-- Trees -->
|
||||
<unit name="tc04">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="tc05">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="tc03">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="tc02">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="tc01">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t18">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t17">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t16">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t15">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="10" />
|
||||
</unit>
|
||||
<unit name="t14">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t13">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t12">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t11">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="10" />
|
||||
</unit>
|
||||
<unit name="t10">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t09">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t08">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t07">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t06">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t05">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t04">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t03">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t02">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t01">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
|
||||
<!-- Civilian Structures -->
|
||||
<unit name="v01">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v02">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v03">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v04">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="2" length="1" />
|
||||
<sequence name="active" start="1" length="1" />
|
||||
<sequence name="damaged-active" start="3" length="1" />
|
||||
</unit>
|
||||
<unit name="v05">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="2" length="1" />
|
||||
</unit>
|
||||
<unit name="v06">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v07">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="2" length="1" />
|
||||
</unit>
|
||||
<unit name="v08">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v09">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v10">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v11">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v12">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v13">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v14">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v15">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v16">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v17">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v18">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v19">
|
||||
<sequence name="idle" start="0" length="14" />
|
||||
<sequence name="damaged-idle" start="14" length="15" />
|
||||
</unit>
|
||||
</sequences>
|
||||
@@ -85,116 +85,6 @@
|
||||
<sequence name="loop" start="49" length="42" />
|
||||
<sequence name="end" start="0" length="26" />
|
||||
</unit>
|
||||
<unit name="tc04">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="tc05">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="tc03">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="tc02">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="tc01">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t17">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t16">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t15">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="10" />
|
||||
</unit>
|
||||
<unit name="t14">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t13">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t12">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t11">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="10" />
|
||||
</unit>
|
||||
<unit name="t10">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t08">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t07">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t06">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t05">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t03">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t02">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="t01">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="burn" start="1" length="9" />
|
||||
</unit>
|
||||
<unit name="boxes01">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="boxes02">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="boxes03">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="boxes04">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="boxes05">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="boxes06">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="boxes07">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="boxes08">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="boxes09">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="mine">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
</unit>
|
||||
<unit name="dragon">
|
||||
<sequence name="idle" start="0" facings="32" />
|
||||
</unit>
|
||||
@@ -210,90 +100,6 @@
|
||||
<unit name="moveflsh">
|
||||
<sequence name="idle" start="0" length="5" />
|
||||
</unit>
|
||||
<unit name="v01">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v02">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v03">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v04">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="2" length="1" />
|
||||
<sequence name="active" start="1" length="1" />
|
||||
<sequence name="damaged-active" start="3" length="1" />
|
||||
</unit>
|
||||
<unit name="v05">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="2" length="1" />
|
||||
</unit>
|
||||
<unit name="v06">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v07">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="2" length="1" />
|
||||
</unit>
|
||||
<unit name="v08">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v09">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v10">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v11">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v12">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v13">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v14">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v15">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v16">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v17">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v18">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="1" length="1" />
|
||||
</unit>
|
||||
<unit name="v19">
|
||||
<sequence name="idle" start="0" length="14" />
|
||||
<sequence name="damaged-idle" start="14" length="15" />
|
||||
</unit>
|
||||
<unit name="barl">
|
||||
<sequence name="idle" start="0" length="3" />
|
||||
</unit>
|
||||
<unit name="brl3">
|
||||
<sequence name="idle" start="0" length="3" />
|
||||
</unit>
|
||||
<unit name="miss">
|
||||
<sequence name="idle" start="0" length="1" />
|
||||
<sequence name="damaged-idle" start="2" length="1" />
|
||||
|
||||
Binary file not shown.
@@ -25,18 +25,34 @@ Player:
|
||||
SpawnDefaultUnits:
|
||||
|
||||
World:
|
||||
WaterPaletteRotation:
|
||||
# WaterPaletteRotation:
|
||||
BuildingInfluence:
|
||||
UnitInfluence:
|
||||
BridgeLoadHook:
|
||||
PaletteFromFile@terrain_temperat:
|
||||
# BridgeLoadHook:
|
||||
PaletteFromFile@terrain_desert:
|
||||
Name: terrain
|
||||
Theater: desert
|
||||
Filename: desert.pal
|
||||
PaletteFromFile@terrain_temperate:
|
||||
Name: terrain
|
||||
Theater: temperat
|
||||
Filename: temperat_ra.pal
|
||||
Filename: temperat.pal
|
||||
PaletteFromFile@terrain_winter:
|
||||
Name: terrain
|
||||
Theater: winter
|
||||
Filename: winter.pal
|
||||
PaletteFromFile@player_desert:
|
||||
Name: player
|
||||
Theater: desert
|
||||
Filename: desert.pal
|
||||
PaletteFromFile@player_temperat:
|
||||
Name: player
|
||||
Theater: temperat
|
||||
Filename: temperat.pal
|
||||
PaletteFromFile@player_winter:
|
||||
Name: player
|
||||
Theater: winter
|
||||
Filename: winter.pal
|
||||
PaletteFromFile@terrain_snow:
|
||||
Name: terrain
|
||||
Theater: snow
|
||||
@@ -153,11 +169,6 @@ World:
|
||||
B: 0
|
||||
A: 180
|
||||
ShroudPalette:
|
||||
OreGrowth:
|
||||
Interval: .3
|
||||
Chance: .02
|
||||
Spreads: yes
|
||||
Grows: yes
|
||||
Country@gdi:
|
||||
Name: GDI
|
||||
Race: gdi
|
||||
@@ -165,4 +176,50 @@ World:
|
||||
Name: Nod
|
||||
Race: nod
|
||||
SellButton:
|
||||
RepairButton:
|
||||
RepairButton:
|
||||
ChoosePaletteOnSelect:
|
||||
WallLoadHook@sbag:
|
||||
ActorType: sbag
|
||||
OverlayTypes: sbag
|
||||
WallLoadHook@cycl:
|
||||
ActorType: cycl
|
||||
OverlayTypes: cycl
|
||||
WallLoadHook@brik:
|
||||
ActorType: brik
|
||||
OverlayTypes: brik
|
||||
WallLoadHook@fenc:
|
||||
ActorType: fenc
|
||||
OverlayTypes: fenc
|
||||
WallLoadHook@wood:
|
||||
ActorType: wood
|
||||
OverlayTypes: wood
|
||||
WallLoadHook@barb:
|
||||
ActorType: barb
|
||||
OverlayTypes: barb
|
||||
ResourceLayer:
|
||||
ResourceType@green-tib:
|
||||
Overlays: ti1,ti2,ti3,ti4,ti5,ti6,ti7,ti8,ti9,ti10,ti11,ti12
|
||||
Palette: player
|
||||
SpriteNames: ti1,ti2,ti3,ti4,ti5,ti6,ti7,ti8,ti9,ti10,ti11,ti12
|
||||
ValuePerUnit: 30
|
||||
Name: Tiberium
|
||||
GrowthInterval: 1
|
||||
SpreadInterval: 6
|
||||
Theater@DESERT:
|
||||
Name:Desert
|
||||
Theater:DESERT
|
||||
Suffix:des
|
||||
Templates:templates.ini
|
||||
Tileset:tileSet.til
|
||||
Theater@WINTER:
|
||||
Name:Winter
|
||||
Theater:WINTER
|
||||
Suffix:win
|
||||
Templates:templates.ini
|
||||
Tileset:tileSet.til
|
||||
Theater@TEMPERAT:
|
||||
Name:Temperate
|
||||
Theater:TEMPERAT
|
||||
Suffix:tem
|
||||
Templates:templates.ini
|
||||
Tileset:tileSet.til
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,350 +1,580 @@
|
||||
; clear ground
|
||||
TSI
|
||||
DTW
|
||||
1
|
||||
ff
|
||||
clear1
|
||||
|
||||
; clear ground
|
||||
TSI
|
||||
DTW
|
||||
1
|
||||
ffff
|
||||
0000
|
||||
clear1
|
||||
|
||||
; sandy shorelines
|
||||
TS-
|
||||
56
|
||||
0003
|
||||
sh{0:00}
|
||||
|
||||
; plain water
|
||||
TS-
|
||||
2
|
||||
DTW
|
||||
1
|
||||
0001
|
||||
w{0}
|
||||
w1
|
||||
|
||||
; cliffs
|
||||
TS-
|
||||
-TW
|
||||
1
|
||||
0002
|
||||
w2
|
||||
|
||||
; Coastline
|
||||
-TW
|
||||
5
|
||||
0003
|
||||
sh{0}
|
||||
|
||||
-TW
|
||||
1
|
||||
0008
|
||||
sh11
|
||||
|
||||
-TW
|
||||
1
|
||||
0009
|
||||
sh12
|
||||
|
||||
-TW
|
||||
1
|
||||
000A
|
||||
sh13
|
||||
|
||||
-TW
|
||||
1
|
||||
000B
|
||||
sh14
|
||||
|
||||
-TW
|
||||
1
|
||||
000C
|
||||
sh15
|
||||
|
||||
; Cliffs
|
||||
DTW
|
||||
38
|
||||
0087
|
||||
000D
|
||||
s{0:00}
|
||||
|
||||
; rocky coast
|
||||
TS-
|
||||
38
|
||||
003b
|
||||
wc{0:00}
|
||||
; More Coast
|
||||
-TW
|
||||
1
|
||||
0033
|
||||
sh32
|
||||
|
||||
-TW
|
||||
1
|
||||
0034
|
||||
sh33
|
||||
|
||||
|
||||
D--
|
||||
1
|
||||
0035
|
||||
sh20
|
||||
|
||||
D--
|
||||
1
|
||||
0036
|
||||
sh21
|
||||
|
||||
D--
|
||||
1
|
||||
0037
|
||||
sh22
|
||||
|
||||
D--
|
||||
1
|
||||
0038
|
||||
sh23
|
||||
|
||||
|
||||
; Bushes
|
||||
D--
|
||||
10
|
||||
0039
|
||||
br{0}
|
||||
|
||||
; Bones/Wall/Mud/UFO/Rock
|
||||
DT-
|
||||
4
|
||||
0043
|
||||
p{0:00}
|
||||
|
||||
D--
|
||||
1
|
||||
0047
|
||||
p05
|
||||
|
||||
D--
|
||||
1
|
||||
0048
|
||||
p06
|
||||
|
||||
DTW
|
||||
1
|
||||
0049
|
||||
p07
|
||||
|
||||
-TW
|
||||
1
|
||||
004A
|
||||
p08
|
||||
|
||||
; Ford WU
|
||||
-TW
|
||||
1
|
||||
004B
|
||||
sh16
|
||||
|
||||
; Water
|
||||
DTW
|
||||
1
|
||||
004C
|
||||
sh17
|
||||
|
||||
; Water
|
||||
DTW
|
||||
1
|
||||
004D
|
||||
sh18
|
||||
|
||||
D--
|
||||
1
|
||||
004E
|
||||
sh19
|
||||
|
||||
|
||||
; Destroyed house
|
||||
-TW
|
||||
1
|
||||
004F
|
||||
p13
|
||||
|
||||
; Walls
|
||||
-TW
|
||||
1
|
||||
0050
|
||||
p14
|
||||
|
||||
; Snow
|
||||
--W
|
||||
1
|
||||
0051
|
||||
p15
|
||||
|
||||
; Rocks
|
||||
DTW
|
||||
2
|
||||
0052
|
||||
b{0}
|
||||
|
||||
-TW
|
||||
1
|
||||
0054
|
||||
b3
|
||||
|
||||
D--
|
||||
1
|
||||
0055
|
||||
b4
|
||||
|
||||
D--
|
||||
1
|
||||
0056
|
||||
b5
|
||||
|
||||
D--
|
||||
1
|
||||
0057
|
||||
b6
|
||||
|
||||
; More coast
|
||||
-TW
|
||||
1
|
||||
0058
|
||||
sh6
|
||||
|
||||
-TW
|
||||
1
|
||||
0059
|
||||
sh7
|
||||
|
||||
-TW
|
||||
1
|
||||
005A
|
||||
sh8
|
||||
|
||||
-TW
|
||||
1
|
||||
005B
|
||||
sh9
|
||||
|
||||
-TW
|
||||
1
|
||||
005C
|
||||
sh10
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ROADS
|
||||
|
||||
; roads
|
||||
TS-
|
||||
DTW
|
||||
43
|
||||
00ad
|
||||
005d
|
||||
d{0:00}
|
||||
|
||||
; road
|
||||
TS-
|
||||
1
|
||||
00e3
|
||||
d44
|
||||
|
||||
; road
|
||||
TS-
|
||||
1
|
||||
00e4
|
||||
d45
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; RIVERS
|
||||
|
||||
; river emerging from cliff
|
||||
TS-
|
||||
4
|
||||
00e7
|
||||
rc{0:00}
|
||||
|
||||
; rivers
|
||||
TS-
|
||||
-TW
|
||||
13
|
||||
0070
|
||||
0088
|
||||
rv{0:00}
|
||||
|
||||
; river
|
||||
TS-
|
||||
D--
|
||||
1
|
||||
00e5
|
||||
0095
|
||||
rv14
|
||||
|
||||
; river
|
||||
TS-
|
||||
D--
|
||||
1
|
||||
00e6
|
||||
0096
|
||||
rv15
|
||||
|
||||
D--
|
||||
1
|
||||
0097
|
||||
rv16
|
||||
|
||||
D--
|
||||
1
|
||||
0098
|
||||
rv17
|
||||
|
||||
D--
|
||||
1
|
||||
0099
|
||||
rv18
|
||||
|
||||
D--
|
||||
1
|
||||
009A
|
||||
rv19
|
||||
|
||||
D--
|
||||
1
|
||||
009B
|
||||
rv20
|
||||
|
||||
D--
|
||||
1
|
||||
009C
|
||||
rv21
|
||||
|
||||
D--
|
||||
1
|
||||
009D
|
||||
rv22
|
||||
|
||||
D--
|
||||
1
|
||||
009E
|
||||
rv23
|
||||
|
||||
D--
|
||||
1
|
||||
009F
|
||||
rv24
|
||||
|
||||
D--
|
||||
1
|
||||
00A0
|
||||
rv25
|
||||
|
||||
; River Crossing
|
||||
DTW
|
||||
2
|
||||
00A1
|
||||
ford{0}
|
||||
|
||||
; Waterfalls
|
||||
DTW
|
||||
2
|
||||
00A3
|
||||
falls{0}
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; BRIDGES
|
||||
|
||||
; long bridge (north end)
|
||||
TS-
|
||||
1
|
||||
00eb
|
||||
br1a
|
||||
|
||||
; long bridge (north end, damaged)
|
||||
TS-
|
||||
1
|
||||
00ec
|
||||
br1b
|
||||
|
||||
; long bridge (north end, broken)
|
||||
TS-
|
||||
1
|
||||
00ed
|
||||
br1c
|
||||
|
||||
; long bridge (south end)
|
||||
TS-
|
||||
1
|
||||
00ee
|
||||
br2a
|
||||
|
||||
; long bridge (south end, damaged)
|
||||
TS-
|
||||
1
|
||||
00ef
|
||||
br2b
|
||||
|
||||
; long bridge (south end, broken)
|
||||
TS-
|
||||
1
|
||||
00f0
|
||||
br2c
|
||||
|
||||
; long bridge (middle)
|
||||
TS-
|
||||
1
|
||||
00f1
|
||||
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)
|
||||
TS-
|
||||
1
|
||||
017c
|
||||
br1x
|
||||
|
||||
; long bridge (south surround)
|
||||
TS-
|
||||
1
|
||||
017d
|
||||
br2x
|
||||
|
||||
; short bridge "/"
|
||||
TS-
|
||||
-TW
|
||||
1
|
||||
0083
|
||||
00A5
|
||||
bridge1
|
||||
|
||||
; short bridge "/" (destroyed)
|
||||
TS-
|
||||
-TW
|
||||
1
|
||||
0084
|
||||
00A6
|
||||
bridge1d
|
||||
|
||||
; short bridge "/" (damaged)
|
||||
TS-
|
||||
1
|
||||
017a
|
||||
bridge1h
|
||||
|
||||
; short bridge "/" (surround)
|
||||
TS-
|
||||
1
|
||||
017e
|
||||
bridge1x
|
||||
|
||||
; short bridge "\"
|
||||
TS-
|
||||
-TW
|
||||
1
|
||||
0085
|
||||
00A7
|
||||
bridge2
|
||||
|
||||
; short bridge "\" (destroyed)
|
||||
TS-
|
||||
-TW
|
||||
1
|
||||
0086
|
||||
00A8
|
||||
bridge2d
|
||||
|
||||
; short bridge "\" (damaged)
|
||||
TS-
|
||||
; desert short bridge "/"
|
||||
D--
|
||||
1
|
||||
017b
|
||||
bridge2h
|
||||
00A9
|
||||
bridge3
|
||||
|
||||
; short bridge "\" (surround)
|
||||
TS-
|
||||
; desert short bridge "/" (destroyed)
|
||||
D--
|
||||
1
|
||||
017f
|
||||
bridge2x
|
||||
00AA
|
||||
bridge3d
|
||||
|
||||
; fyords
|
||||
TS-
|
||||
6
|
||||
00f7
|
||||
f{0:00}
|
||||
|
||||
; short fyord
|
||||
TS-
|
||||
2
|
||||
0081
|
||||
ford{0}
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; WATERFALLS
|
||||
|
||||
; waterfall (E-W)
|
||||
TS-
|
||||
; desert short bridge "\"
|
||||
D--
|
||||
1
|
||||
007d
|
||||
falls1
|
||||
00AB
|
||||
bridge4
|
||||
|
||||
; waterfall (E-W, into sea)
|
||||
TS-
|
||||
; desert short bridge "\" (destroyed)
|
||||
D--
|
||||
1
|
||||
007e
|
||||
falls1a
|
||||
00AC
|
||||
bridge4d
|
||||
|
||||
; waterfall (N-S)
|
||||
TS-
|
||||
; Desert coast
|
||||
D--
|
||||
1
|
||||
007f
|
||||
falls2
|
||||
00AD
|
||||
sh24
|
||||
|
||||
; waterfall (N-S, into sea)
|
||||
TS-
|
||||
D--
|
||||
1
|
||||
0080
|
||||
falls2a
|
||||
00AE
|
||||
sh25
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; DEBRIS / ROCKS
|
||||
|
||||
; random rock chunks (impassable)
|
||||
TS-
|
||||
3
|
||||
0061
|
||||
b{0}
|
||||
|
||||
; random rock chunks (passable)
|
||||
TS-
|
||||
11
|
||||
00d8
|
||||
rf{0:00}
|
||||
|
||||
; random debris
|
||||
TS-
|
||||
4
|
||||
0067
|
||||
p{0:00}
|
||||
|
||||
; random debris
|
||||
TS-
|
||||
D--
|
||||
1
|
||||
006b
|
||||
p07
|
||||
00AF
|
||||
sh26
|
||||
|
||||
; random debris
|
||||
TS-
|
||||
D--
|
||||
1
|
||||
006c
|
||||
p08
|
||||
00B0
|
||||
sh27
|
||||
|
||||
; random debris
|
||||
TS-
|
||||
D--
|
||||
1
|
||||
006d
|
||||
p13
|
||||
00B1
|
||||
sh28
|
||||
|
||||
; random debris
|
||||
TS-
|
||||
D--
|
||||
1
|
||||
006e
|
||||
p14
|
||||
00B2
|
||||
sh29
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; INTERIOR
|
||||
D--
|
||||
1
|
||||
00B3
|
||||
sh30
|
||||
|
||||
; walls
|
||||
--I
|
||||
49
|
||||
0149
|
||||
wall{0:0000}
|
||||
D--
|
||||
1
|
||||
00B4
|
||||
sh31
|
||||
|
||||
; black floor
|
||||
--I
|
||||
7
|
||||
010c
|
||||
flor{0:0000}
|
||||
; Snow
|
||||
--W
|
||||
1
|
||||
00B5
|
||||
p16
|
||||
|
||||
; walls with stuff, random tiles
|
||||
--I
|
||||
16
|
||||
0180
|
||||
xtra{0:0000}
|
||||
--W
|
||||
1
|
||||
00B6
|
||||
p17
|
||||
|
||||
; black/yellow stripe
|
||||
--I
|
||||
11
|
||||
013e
|
||||
strp{0:0000}
|
||||
--W
|
||||
1
|
||||
00B7
|
||||
p18
|
||||
|
||||
; red stripe
|
||||
--I
|
||||
15
|
||||
00fd
|
||||
arro{0:0000}
|
||||
--W
|
||||
1
|
||||
00B8
|
||||
p19
|
||||
|
||||
; white floor
|
||||
--I
|
||||
5
|
||||
0113
|
||||
gflr{0:0000}
|
||||
--W
|
||||
1
|
||||
00B9
|
||||
p20
|
||||
|
||||
; white floor with black/yellow stripe
|
||||
--I
|
||||
11
|
||||
0118
|
||||
gstr{0:0000}
|
||||
; More coast
|
||||
-TW
|
||||
1
|
||||
00BA
|
||||
sh34
|
||||
|
||||
-TW
|
||||
1
|
||||
00BB
|
||||
sh35
|
||||
|
||||
D--
|
||||
1
|
||||
00BC
|
||||
sh36
|
||||
|
||||
D--
|
||||
1
|
||||
00BD
|
||||
sh37
|
||||
|
||||
D--
|
||||
1
|
||||
00BE
|
||||
sh38
|
||||
|
||||
D--
|
||||
1
|
||||
00BF
|
||||
sh39
|
||||
|
||||
D--
|
||||
1
|
||||
00C0
|
||||
sh40
|
||||
|
||||
D--
|
||||
1
|
||||
00C1
|
||||
sh41
|
||||
|
||||
D--
|
||||
1
|
||||
00C2
|
||||
sh42
|
||||
|
||||
D--
|
||||
1
|
||||
00C3
|
||||
sh43
|
||||
|
||||
D--
|
||||
1
|
||||
00C4
|
||||
sh44
|
||||
|
||||
D--
|
||||
1
|
||||
00C5
|
||||
sh45
|
||||
|
||||
D--
|
||||
1
|
||||
00C6
|
||||
sh46
|
||||
|
||||
D--
|
||||
1
|
||||
00C7
|
||||
sh47
|
||||
|
||||
D--
|
||||
1
|
||||
00C8
|
||||
sh48
|
||||
|
||||
D--
|
||||
1
|
||||
00C9
|
||||
sh49
|
||||
|
||||
D--
|
||||
1
|
||||
00CA
|
||||
sh50
|
||||
|
||||
D--
|
||||
1
|
||||
00CB
|
||||
sh51
|
||||
|
||||
D--
|
||||
1
|
||||
00CC
|
||||
sh52
|
||||
|
||||
D--
|
||||
1
|
||||
00CD
|
||||
sh53
|
||||
|
||||
D--
|
||||
1
|
||||
00CE
|
||||
sh54
|
||||
|
||||
D--
|
||||
1
|
||||
00CF
|
||||
sh55
|
||||
|
||||
D--
|
||||
1
|
||||
00D0
|
||||
sh56
|
||||
|
||||
D--
|
||||
1
|
||||
00D1
|
||||
sh57
|
||||
|
||||
D--
|
||||
1
|
||||
00D2
|
||||
sh58
|
||||
|
||||
D--
|
||||
1
|
||||
00D3
|
||||
sh59
|
||||
|
||||
D--
|
||||
1
|
||||
00D4
|
||||
sh60
|
||||
|
||||
D--
|
||||
1
|
||||
00D5
|
||||
sh61
|
||||
|
||||
D--
|
||||
1
|
||||
00D6
|
||||
sh62
|
||||
|
||||
D--
|
||||
1
|
||||
00D7
|
||||
sh63
|
||||
|
||||
; bogus
|
||||
TS-
|
||||
|
||||
@@ -1,3 +1,31 @@
|
||||
SPLIT2:
|
||||
Inherits: ^Building
|
||||
RenderBuilding:
|
||||
Palette: terrain
|
||||
SeedsResource:
|
||||
ResourceType:Tiberium
|
||||
-Selectable:
|
||||
SPLIT3:
|
||||
Inherits: ^Building
|
||||
RenderBuilding:
|
||||
Palette: terrain
|
||||
SeedsResource:
|
||||
ResourceType:Tiberium
|
||||
-Selectable:
|
||||
ROCK1:
|
||||
Inherits: ^Tree
|
||||
ROCK2:
|
||||
Inherits: ^Tree
|
||||
ROCK3:
|
||||
Inherits: ^Tree
|
||||
ROCK4:
|
||||
Inherits: ^Tree
|
||||
ROCK5:
|
||||
Inherits: ^Tree
|
||||
ROCK6:
|
||||
Inherits: ^Tree
|
||||
ROCK7:
|
||||
Inherits: ^Tree
|
||||
|
||||
T01:
|
||||
Inherits: ^Tree
|
||||
@@ -8,6 +36,9 @@ T02:
|
||||
T03:
|
||||
Inherits: ^Tree
|
||||
|
||||
T04:
|
||||
Inherits: ^Tree
|
||||
|
||||
T05:
|
||||
Inherits: ^Tree
|
||||
|
||||
@@ -23,6 +54,12 @@ T08:
|
||||
Footprint: x_
|
||||
Dimensions: 2,1
|
||||
|
||||
T09:
|
||||
Inherits: ^Tree
|
||||
Building:
|
||||
Footprint: x_
|
||||
Dimensions: 2,1
|
||||
|
||||
T10:
|
||||
Inherits: ^Tree
|
||||
Building:
|
||||
@@ -55,7 +92,12 @@ T16:
|
||||
|
||||
T17:
|
||||
Inherits: ^Tree
|
||||
|
||||
Building:
|
||||
Footprint: ___ xx_
|
||||
Dimensions: 3,2
|
||||
T18:
|
||||
Inherits: ^Tree
|
||||
|
||||
TC01:
|
||||
Inherits: ^Tree
|
||||
Building:
|
||||
|
||||
@@ -21,7 +21,7 @@ MCV:
|
||||
Offset:-1,-1
|
||||
DeployDirections: 96
|
||||
TransformSounds: constru2.aud, hvydoor1.aud
|
||||
NoTransformSounds: nodeply1.aud
|
||||
NoTransformSounds: deploy1.aud
|
||||
RenderUnit:
|
||||
|
||||
HARV:
|
||||
@@ -37,6 +37,8 @@ HARV:
|
||||
Selectable:
|
||||
Priority: 7
|
||||
Harvester:
|
||||
Resources: Tiberium
|
||||
Capacity: 28
|
||||
Unit:
|
||||
HP: 600
|
||||
Armor: light
|
||||
|
||||
@@ -49,8 +49,6 @@ Incoming=10 ; If an incoming projectile is as slow or slower than th
|
||||
; income and production
|
||||
BuildSpeed=.8 ; general build speed [time (in minutes) to produce a 1000 credit cost item]
|
||||
BuildupTime=.06 ; average minutes that building build-up animation runs
|
||||
GemValue=50 ; gem credits per 'bail' carried by a harvester
|
||||
GoldValue=25 ; gold credits per 'bail' carried by a harvester
|
||||
OreTruckRate=1 ; speed that harvester truck manages ore [larger means slower]
|
||||
SeparateAircraft=no ; Is first helicopter to be purchased separately from helipad?
|
||||
SurvivorRate=.4 ; fraction of building cost to be converted to survivors when sold
|
||||
|
||||
@@ -184,11 +184,6 @@ World:
|
||||
B: 0
|
||||
A: 180
|
||||
ShroudPalette:
|
||||
OreGrowth:
|
||||
Interval: .3
|
||||
Chance: .02
|
||||
Spreads: yes
|
||||
Grows: yes
|
||||
Country@0:
|
||||
Name: England
|
||||
Race: allies
|
||||
@@ -216,7 +211,58 @@ World:
|
||||
SellButton:
|
||||
RepairButton:
|
||||
PowerDownButton:
|
||||
|
||||
WallLoadHook@sbag:
|
||||
ActorType: sbag
|
||||
OverlayTypes: sbag
|
||||
WallLoadHook@cycl:
|
||||
ActorType: cycl
|
||||
OverlayTypes: cycl
|
||||
WallLoadHook@brik:
|
||||
ActorType: brik
|
||||
OverlayTypes: brik
|
||||
WallLoadHook@fenc:
|
||||
ActorType: fenc
|
||||
OverlayTypes: fenc
|
||||
WallLoadHook@wood:
|
||||
ActorType: wood
|
||||
OverlayTypes: wood
|
||||
WallLoadHook@barb:
|
||||
ActorType: barb
|
||||
OverlayTypes: barb
|
||||
ResourceLayer:
|
||||
ResourceType@ore:
|
||||
Overlays: gold01,gold02,gold03,gold04
|
||||
Palette: terrain
|
||||
SpriteNames: gold01,gold02,gold03,gold04
|
||||
ValuePerUnit: 25
|
||||
Name: Ore
|
||||
GrowthInterval: .3
|
||||
SpreadInterval: .7
|
||||
ResourceType@gem:
|
||||
Overlays: gem01,gem02,gem03,gem04
|
||||
Palette: terrain
|
||||
SpriteNames: gem01,gem02,gem03,gem04
|
||||
ValuePerUnit: 50
|
||||
Name: Gems
|
||||
Theater@SNOW:
|
||||
Name:Snow
|
||||
Theater:SNOW
|
||||
Suffix:sno
|
||||
Templates:templates.ini
|
||||
Tileset:tileSet.til
|
||||
Theater@TEMPERAT:
|
||||
Name:Temperate
|
||||
Theater:TEMPERAT
|
||||
Suffix:tem
|
||||
Templates:templates.ini
|
||||
Tileset:tileSet.til
|
||||
Theater@INTERIOR:
|
||||
Name:Interior
|
||||
Theater:INTERIOR
|
||||
Suffix:int
|
||||
Templates:templates.ini
|
||||
Tileset:tileSet.til
|
||||
|
||||
MGG:
|
||||
GeneratesGap:
|
||||
Range: 10
|
||||
@@ -773,6 +819,8 @@ HARV:
|
||||
Selectable:
|
||||
Priority: 7
|
||||
Harvester:
|
||||
Capacity: 28
|
||||
Resources: Ore,Gems
|
||||
Unit:
|
||||
HP: 600
|
||||
Armor: heavy
|
||||
@@ -1892,7 +1940,7 @@ TC05:
|
||||
|
||||
MINE:
|
||||
Inherits: ^Building
|
||||
SeedsOre:
|
||||
SeedsResource:
|
||||
-Selectable:
|
||||
|
||||
BOXES01:
|
||||
|
||||
Reference in New Issue
Block a user