diff --git a/.gitignore b/.gitignore index 871d120b0a..9d2ab70a49 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ obj *.vcproj* *.suo *.user +*.sln.cache mods/*/*.dll # Red Alert binary files diff --git a/OpenRA.Server/Server.cs b/OpenRA.Server/Server.cs index c0adf90611..cbf8cf2d9f 100644 --- a/OpenRA.Server/Server.cs +++ b/OpenRA.Server/Server.cs @@ -24,7 +24,7 @@ namespace OpenRA.Server const int DownloadChunkInterval = 20000; const int DownloadChunkSize = 16384; - public static void Main(string[] args) + public static int Main(string[] args) { if (args.Length > 0) defaultMods = args; lobbyInfo = new Session(); @@ -39,10 +39,10 @@ namespace OpenRA.Server listener.Start(); Console.WriteLine("Server started."); } - catch (Exception e) + catch (Exception) { Console.WriteLine("Server failed to start."); - Environment.Exit(1); + return 1; } for (; ; ) diff --git a/OpenRa.FileFormats/FileSystem.cs b/OpenRa.FileFormats/FileSystem.cs index 5d015acddc..7408916860 100644 --- a/OpenRa.FileFormats/FileSystem.cs +++ b/OpenRa.FileFormats/FileSystem.cs @@ -2,44 +2,17 @@ using System.Collections.Generic; using System.IO; using System.Linq; using IjwFramework.Collections; +using System; namespace OpenRa.FileFormats { public static class FileSystem { static List mountedFolders = new List(); - static List temporaryMounts = new List(); static Cache> allFiles = new Cache>( _ => new List() ); - static Cache> allTemporaryFiles = new Cache>( _ => new List() ); - public static void MountDefaultPackages() - { - FileSystem.Mount(new Folder("./")); - if( FileSystem.Exists( "main.mix" ) ) - FileSystem.Mount( new Package( "main.mix" ) ); - FileSystem.Mount( new Package( "redalert.mix" ) ); - FileSystem.Mount( new Package( "conquer.mix" ) ); - FileSystem.Mount( new Package( "hires.mix" ) ); - FileSystem.Mount( new Package( "general.mix" ) ); - FileSystem.Mount( new Package( "local.mix" ) ); - FileSystem.Mount( new Package( "sounds.mix" ) ); - FileSystem.Mount( new Package( "speech.mix" ) ); - FileSystem.Mount( new Package( "allies.mix" ) ); - FileSystem.Mount( new Package( "russian.mix" ) ); - - FileSystem.Mount( new Package( "temperat.mix" ) ); - FileSystem.Mount( new Package( "snow.mix" ) ); - FileSystem.Mount( new Package( "interior.mix" ) ); - } - - public static void MountAftermathPackages() - { - FileSystem.Mount( new Package( "expand2.mix" ) ); - FileSystem.Mount( new Package( "hires1.mix" ) ); - } - - public static void Mount(IFolder folder) + static void MountInner(IFolder folder) { mountedFolders.Add(folder); @@ -51,25 +24,27 @@ namespace OpenRa.FileFormats } } - public static void MountTemporary(IFolder folder) + public static void Mount(string name) { - mountedFolders.Add(folder); - temporaryMounts.Add(folder); + name = name.ToLowerInvariant(); + var optional = name.StartsWith("~"); + if (optional) name = name.Substring(1); - foreach( var hash in folder.AllFileHashes() ) - { - var l = allTemporaryFiles[hash]; - if( !l.Contains( folder ) ) - l.Add( folder ); - } + var a = name.EndsWith(".mix") + ? (Action)(() => FileSystem.MountInner(new Package(name))) + : () => FileSystem.MountInner(new Folder(name)); + + if (optional) + try { a(); } + catch { } + else + a(); } - public static void UnmountTemporaryPackages() + public static void UnmountAll() { - mountedFolders.RemoveAll(f => temporaryMounts.Contains(f)); - temporaryMounts.Clear(); - - allTemporaryFiles = new Cache>( _ => new List() ); + mountedFolders.Clear(); + allFiles = new Cache>( _ => new List() ); } static Stream GetFromCache( Cache> index, string filename ) @@ -87,8 +62,7 @@ namespace OpenRa.FileFormats { if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 ) { - var ret = GetFromCache( allFiles, filename ) - ?? GetFromCache( allTemporaryFiles, filename ); + var ret = GetFromCache( allFiles, filename ); if( ret != null ) return ret; } @@ -109,8 +83,7 @@ namespace OpenRa.FileFormats { foreach( var ext in exts ) { - var s = GetFromCache( allFiles, filename + ext ) - ?? GetFromCache( allTemporaryFiles, filename + ext ); + var s = GetFromCache( allFiles, filename + ext ); if( s != null ) return s; } diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 018cc82eef..0d4c6a5606 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -356,10 +356,8 @@ namespace OpenRa while (!PaletteAvailable(newIndex) && newIndex != (int)Game.world.LocalPlayer.PaletteIndex) newIndex = (newIndex + d) % Player.PlayerColors.Count(); - Game.world.Minimap.InvalidateSpawnPoints(); Game.IssueOrder( Order.Chat("/pal " + newIndex)); - } void CycleRace(bool left) @@ -1193,5 +1191,13 @@ namespace OpenRa renderer.DrawText(sp.Info.LongDesc.Replace("\\n", "\n"), pos, Color.White); } } + + public void SetCurrentTab(string produces) + { + if (!paletteOpen) + paletteAnimating = true; + paletteOpen = true; + currentTab = produces; + } } } diff --git a/OpenRa.Game/Controller.cs b/OpenRa.Game/Controller.cs index 62b0e6047d..74d81d81f2 100644 --- a/OpenRa.Game/Controller.cs +++ b/OpenRa.Game/Controller.cs @@ -13,6 +13,7 @@ namespace OpenRa public class Controller : IHandleInput { public IOrderGenerator orderGenerator; + public Selection selection = new Selection(); readonly Func GetModifierKeys; @@ -22,10 +23,7 @@ namespace OpenRa CancelInputMode(); } - public void CancelInputMode() - { - orderGenerator = new UnitOrderGenerator(new Actor[] { }); - } + public void CancelInputMode() { orderGenerator = new UnitOrderGenerator(); } public bool ToggleInputMode() where T : IOrderGenerator, new() { @@ -83,7 +81,7 @@ namespace OpenRa if (orderGenerator is UnitOrderGenerator) { var newSelection = world.SelectActorsInBox(Game.CellSize * dragStart, Game.CellSize * xy); - CombineSelection(world, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy); + selection.Combine(world, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy); } dragStart = dragEnd = xy; @@ -98,29 +96,6 @@ namespace OpenRa return true; } - void CombineSelection(World world, IEnumerable newSelection, bool isCombine, bool isClick) - { - var oldSelection = (orderGenerator is UnitOrderGenerator) - ? (orderGenerator as UnitOrderGenerator).selection : new Actor[] { }.AsEnumerable(); - - if (isClick) - { - var adjNewSelection = newSelection.Take(1); /* todo: select BEST, not FIRST */ - orderGenerator = new UnitOrderGenerator(isCombine - ? oldSelection.SymmetricDifference(adjNewSelection) : adjNewSelection); - } - else - orderGenerator = new UnitOrderGenerator(isCombine - ? oldSelection.Union(newSelection) : newSelection); - - var voicedUnit = ((UnitOrderGenerator)orderGenerator).selection - .Where(a => a.traits.Contains() - && a.Owner == world.LocalPlayer) - .FirstOrDefault(); - - Sound.PlayVoice("Select", voicedUnit); - } - public Pair? SelectionBox { get @@ -153,42 +128,5 @@ namespace OpenRa throw new InvalidOperationException( "Desync in Controller.ChooseCursor" ); } } - - Cache> controlGroups = new Cache>(_ => new List()); - - public void DoControlGroup(World world, int group, Modifiers mods) - { - var uog = orderGenerator as UnitOrderGenerator; - if (uog == null) return; - - if (mods.HasModifier(Modifiers.Ctrl)) - { - if (!uog.selection.Any()) - return; - - controlGroups[group].Clear(); - - for (var i = 0; i < 10; i++) /* all control groups */ - controlGroups[i].RemoveAll(a => uog.selection.Contains(a)); - - controlGroups[group].AddRange(uog.selection); - return; - } - - if (mods.HasModifier(Modifiers.Alt)) - { - Game.viewport.Center(controlGroups[group]); - return; - } - - CombineSelection(world, controlGroups[group], mods.HasModifier(Modifiers.Shift), false); - } - - public int? GetControlGroupForActor(Actor a) - { - return controlGroups.Where(g => g.Value.Contains(a)) - .Select(g => (int?)g.Key) - .FirstOrDefault(); - } } } diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index 003936aded..dbc8949625 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -37,19 +37,12 @@ namespace OpenRa public static void LoadModPackages(Manifest manifest) { - FileSystem.UnmountTemporaryPackages(); + FileSystem.UnmountAll(); Timer.Time("reset: {0}"); - foreach (var dir in manifest.Folders) - FileSystem.MountTemporary(new Folder(dir)); - - foreach (var pkg in manifest.Packages) - if (pkg.StartsWith( "~")) // this package is optional. - try { FileSystem.MountTemporary(new Package(pkg.Substring(1))); } - catch { } - else - FileSystem.MountTemporary(new Package(pkg)); - + foreach (var dir in manifest.Folders) FileSystem.Mount(dir); + foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg); + Timer.Time("mount temporary packages: {0}"); } @@ -87,7 +80,6 @@ namespace OpenRa viewport = new Viewport(clientSize, Game.world.Map.Offset, Game.world.Map.Offset + Game.world.Map.Size, renderer); 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); @@ -161,9 +153,9 @@ namespace OpenRa if (orderManager.IsReadyForNextFrame) { - orderManager.Tick( world ); - if (controller.orderGenerator != null) - controller.orderGenerator.Tick( world ); + orderManager.Tick(world); + controller.orderGenerator.Tick(world); + controller.selection.Tick(world); world.Tick(); } @@ -300,7 +292,8 @@ namespace OpenRa if( !Game.chat.isChatting ) if( e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9 ) - Game.controller.DoControlGroup( world, (int)e.KeyCode - (int)Keys.D0, (Modifiers)(int)e.Modifiers ); + Game.controller.selection.DoControlGroup( world, + (int)e.KeyCode - (int)Keys.D0, (Modifiers)(int)e.Modifiers ); if( sync != Game.world.SyncHash() ) throw new InvalidOperationException( "Desync in OnKeyDown" ); diff --git a/OpenRa.Game/GameRules/GeneralInfo.cs b/OpenRa.Game/GameRules/GeneralInfo.cs index ea8fa66894..2f0207d545 100644 --- a/OpenRa.Game/GameRules/GeneralInfo.cs +++ b/OpenRa.Game/GameRules/GeneralInfo.cs @@ -46,9 +46,6 @@ namespace OpenRa.GameRules public readonly float BuildupTime = 0; public readonly int GemValue = 0; public readonly int GoldValue = 0; - public readonly float GrowthRate = 0; - public readonly bool OreGrows = true; - public readonly bool OreSpreads = true; public readonly float OreTruckRate = 0; public readonly bool SeparateAircraft = true; public readonly float SurvivorRate = 0; @@ -90,7 +87,6 @@ namespace OpenRa.GameRules public readonly bool FineDiffControl = false; /* OpenRA-specific */ - public readonly float OreChance = 0; /* chance of spreading to a particular eligible cell */ public readonly int LowPowerSlowdown = 3; /* build time multiplier */ } } diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs index a2f3cbe934..5067dc13f3 100644 --- a/OpenRa.Game/Graphics/Minimap.cs +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -17,7 +17,7 @@ namespace OpenRa.Graphics SpriteRenderer rgbaRenderer; LineRenderer lineRenderer; Sprite sprite, mapOnlySprite, mapSpawnPointSprite; - Bitmap terrain, oreLayer, spawnPointsLayer; + Bitmap terrain, oreLayer; Rectangle bounds; Sprite ownedSpawnPoint; @@ -74,7 +74,6 @@ namespace OpenRa.Graphics static Color shroudColor; public void InvalidateOre() { oreLayer = null; } - public void InvalidateSpawnPoints() { spawnPointsLayer = null; } public static Bitmap RenderTerrainBitmap(Map map, TileSet tileset) { diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index 60fc661407..10d180f94c 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -234,7 +234,7 @@ namespace OpenRa.Graphics void DrawControlGroup(Actor selectedUnit, float2 basePosition) { - var group = Game.controller.GetControlGroupForActor(selectedUnit); + var group = Game.controller.selection.GetControlGroupForActor(selectedUnit); if (group == null) return; var pipImages = new Animation("pips"); diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index a91281d69b..e0280bea3b 100755 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -74,11 +74,11 @@ namespace OpenRa { Game.Settings = new UserSettings(); var settingsFile = settings.GetValue("settings", "settings.ini"); - FileSystem.MountTemporary(new Folder("./")); + FileSystem.Mount("./"); if (FileSystem.Exists(settingsFile)) FieldLoader.Load(Game.Settings, new IniFile(FileSystem.Open(settingsFile)).GetSection("Settings")); - FileSystem.UnmountTemporaryPackages(); + FileSystem.UnmountAll(); } internal void Run() diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index bb1abf8cb2..41f680b6fc 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -73,7 +73,6 @@ - @@ -111,13 +110,18 @@ + + + + + @@ -313,4 +317,4 @@ --> - \ No newline at end of file + diff --git a/OpenRa.Game/Orders/UnitOrderGenerator.cs b/OpenRa.Game/Orders/UnitOrderGenerator.cs index 2821664a0a..ccc4ae3d97 100644 --- a/OpenRa.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRa.Game/Orders/UnitOrderGenerator.cs @@ -8,16 +8,9 @@ namespace OpenRa.Orders { class UnitOrderGenerator : IOrderGenerator { - public readonly List selection; - - public UnitOrderGenerator( IEnumerable selected ) - { - selection = selected.ToList(); - } - public IEnumerable Order( World world, int2 xy, MouseInput mi ) { - foreach( var unit in selection ) + foreach( var unit in Game.controller.selection.Actors ) { var ret = unit.Order( xy, mi ); if( ret != null ) @@ -25,14 +18,11 @@ namespace OpenRa.Orders } } - public void Tick( World world ) - { - selection.RemoveAll(a => !a.IsInWorld); - } + public void Tick( World world ) {} public void Render( World world ) { - foreach( var a in selection ) + foreach( var a in Game.controller.selection.Actors ) world.WorldRenderer.DrawSelectionBox( a, Color.White, true ); } diff --git a/OpenRa.Game/Ore.cs b/OpenRa.Game/Ore.cs index 34318cd38b..c671ed7330 100644 --- a/OpenRa.Game/Ore.cs +++ b/OpenRa.Game/Ore.cs @@ -8,14 +8,13 @@ namespace OpenRa { public static void AddOre(this Map map, int i, int j) { - if (Rules.General.OreSpreads) - 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; - } + 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) @@ -37,48 +36,49 @@ namespace OpenRa < 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; - var chance = Rules.General.OreChance; - - /* phase 1: grow into neighboring regions */ - if (Rules.General.OreSpreads) - { - 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]; - } /* phase 2: increase density of existing areas */ - if (Rules.General.OreGrows) - { - 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); + 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; - } + 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 ) diff --git a/OpenRa.Game/Selection.cs b/OpenRa.Game/Selection.cs new file mode 100644 index 0000000000..696d7c54cb --- /dev/null +++ b/OpenRa.Game/Selection.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Traits; +using IjwFramework.Collections; + +namespace OpenRa +{ + public class Selection + { + List actors = new List(); + + public void Combine(World world, IEnumerable newSelection, bool isCombine, bool isClick) + { + var oldSelection = actors.AsEnumerable(); + + if (isClick) + { + var adjNewSelection = newSelection.Take(1); /* todo: select BEST, not FIRST */ + actors = (isCombine ? oldSelection.SymmetricDifference(adjNewSelection) : adjNewSelection).ToList(); + } + else + actors = (isCombine ? oldSelection.Union(newSelection) : newSelection).ToList(); + + var voicedUnit = actors.FirstOrDefault(a => a.traits.Contains() && a.Owner == world.LocalPlayer); + Sound.PlayVoice("Select", voicedUnit); + + foreach (var ns in world.WorldActor.traits.WithInterface()) + ns.SelectionChanged(); + } + + public IEnumerable Actors { get { return actors; } } + public void Clear() { actors = new List(); } + + public void Tick(World world) + { + actors.RemoveAll(a => !a.IsInWorld); + } + + Cache> controlGroups = new Cache>(_ => new List()); + + public void DoControlGroup(World world, int group, Modifiers mods) + { + if (mods.HasModifier(Modifiers.Ctrl)) + { + if (actors.Count == 0) + return; + + controlGroups[group].Clear(); + + for (var i = 0; i < 10; i++) /* all control groups */ + controlGroups[i].RemoveAll(a => actors.Contains(a)); + + controlGroups[group].AddRange(actors); + return; + } + + if (mods.HasModifier(Modifiers.Alt)) + { + Game.viewport.Center(controlGroups[group]); + return; + } + + Combine(world, controlGroups[group], + mods.HasModifier(Modifiers.Shift), false); + } + + public int? GetControlGroupForActor(Actor a) + { + return controlGroups.Where(g => g.Value.Contains(a)) + .Select(g => (int?)g.Key) + .FirstOrDefault(); + } + } +} diff --git a/OpenRa.Game/Traits/AttackOmni.cs b/OpenRa.Game/Traits/AttackOmni.cs new file mode 100644 index 0000000000..526cc1bc2b --- /dev/null +++ b/OpenRa.Game/Traits/AttackOmni.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Traits +{ + class AttackOmniInfo : AttackBaseInfo + { + public override object Create(Actor self) { return new AttackOmni(self); } + } + + class AttackOmni : AttackBase, INotifyBuildComplete + { + bool buildComplete = false; + public void BuildingComplete(Actor self) { buildComplete = true; } + + public AttackOmni(Actor self) : base(self) { } + + public override void Tick(Actor self) + { + base.Tick(self); + + if (!CanAttack(self)) return; + if (self.traits.Contains() && !buildComplete) return; + + DoAttack(self); + } + + protected override void QueueAttack(Actor self, Order order) + { + target = order.TargetActor; + } + } +} diff --git a/OpenRa.Game/Bridges.cs b/OpenRa.Game/Traits/BridgeLoadHook.cs similarity index 81% rename from OpenRa.Game/Bridges.cs rename to OpenRa.Game/Traits/BridgeLoadHook.cs index 28d00bcdf0..1f045175fe 100644 --- a/OpenRa.Game/Bridges.cs +++ b/OpenRa.Game/Traits/BridgeLoadHook.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using OpenRa.Traits; -namespace OpenRa +namespace OpenRa.Traits { - static class Bridges + class BridgeLoadHookInfo : StatelessTraitInfo { } + + class BridgeLoadHook : ILoadWorldHook { - public static void MakeBridges(World w) + static void MakeBridges(World w) { var mini = w.Map.XOffset; var maxi = w.Map.XOffset + w.Map.Width; var minj = w.Map.YOffset; var maxj = w.Map.YOffset + w.Map.Height; @@ -40,8 +41,8 @@ namespace OpenRa if (!template.TerrainType.ContainsKey(n)) continue; if (w.Map.IsInMap(x, y)) - if (w.Map.MapTiles[x, y].tile == tile - && w.Map.MapTiles[x,y].image == n) + if (w.Map.MapTiles[x, y].tile == tile + && w.Map.MapTiles[x, y].image == n) { // stash it replacedTiles[new int2(x, y)] = w.Map.MapTiles[x, y].image; @@ -63,5 +64,7 @@ namespace OpenRa { return w.TileSet.walk[t].Bridge != null; } + + public void WorldLoaded(World w) { MakeBridges(w); } } } diff --git a/OpenRa.Game/Traits/ChoosePaletteOnSelect.cs b/OpenRa.Game/Traits/ChoosePaletteOnSelect.cs new file mode 100644 index 0000000000..95bd9d386c --- /dev/null +++ b/OpenRa.Game/Traits/ChoosePaletteOnSelect.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Traits +{ + class ChoosePaletteOnSelectInfo : StatelessTraitInfo { } + + class ChoosePaletteOnSelect : INotifySelection + { + public void SelectionChanged() + { + var firstItem = Game.controller.selection.Actors.FirstOrDefault( + a => a.World.LocalPlayer == a.Owner && a.traits.Contains()); + + if (firstItem == null) + return; + + var produces = firstItem.Info.Traits.Get().Produces.FirstOrDefault(); + if (produces == null) + return; + + Game.chrome.SetCurrentTab(produces); + } + } +} diff --git a/OpenRa.Game/Traits/OreGrowth.cs b/OpenRa.Game/Traits/OreGrowth.cs new file mode 100644 index 0000000000..f79b21decc --- /dev/null +++ b/OpenRa.Game/Traits/OreGrowth.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Graphics; + +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(); + + if (info.Spreads) + Ore.SpreadOre(self.World, + Game.SharedRandom, + info.Chance); + + if (info.Grows) + Ore.GrowOre(self.World, Game.SharedRandom); + + self.World.Minimap.InvalidateOre(); + remainingTicks = (int)(info.Interval * 60 * 25); + } + } + + public void WorldLoaded(World w) + { + Ore.InitOreDensity(w.Map); + } + } +} diff --git a/OpenRa.Game/Traits/RallyPoint.cs b/OpenRa.Game/Traits/RallyPoint.cs index 3978b98d48..15870ff06a 100644 --- a/OpenRa.Game/Traits/RallyPoint.cs +++ b/OpenRa.Game/Traits/RallyPoint.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using OpenRa.Graphics; using OpenRa.Orders; @@ -27,8 +28,7 @@ namespace OpenRa.Traits public IEnumerable Render(Actor self) { - var uog = Game.controller.orderGenerator as UnitOrderGenerator; - if (uog != null && self.Owner == self.World.LocalPlayer && uog.selection.Contains(self)) + if (self.Owner == self.World.LocalPlayer && Game.controller.selection.Actors.Contains(self)) yield return Util.Centered(self, anim.Image, Util.CenterOfCell(rallyPoint)); } diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index 7d08e53276..6fe8ff525a 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -99,5 +99,8 @@ namespace OpenRa.Traits public object Create(Actor self) { return Instance.Value; } } - interface ITraitPrerequisite { } + public interface ITraitPrerequisite { } + + public interface INotifySelection { void SelectionChanged(); } + public interface ILoadWorldHook { void WorldLoaded(World w); } } diff --git a/OpenRa.Game/World.cs b/OpenRa.Game/World.cs index 7b1f3730b6..584131b246 100644 --- a/OpenRa.Game/World.cs +++ b/OpenRa.Game/World.cs @@ -34,7 +34,6 @@ namespace OpenRa } if (!string.IsNullOrEmpty(Game.Settings.PlayerName) && LocalPlayer.PlayerName != Game.Settings.PlayerName) Game.IssueOrder(Order.Chat("/name " + Game.Settings.PlayerName)); - } public readonly Actor WorldActor; @@ -50,9 +49,6 @@ namespace OpenRa public readonly WorldRenderer WorldRenderer; internal readonly Minimap Minimap; - readonly int oreFrequency; - int oreTicks; - public World() { Timer.Time( "----World.ctor" ); @@ -66,26 +62,21 @@ namespace OpenRa WorldRenderer = new WorldRenderer(this, Game.renderer); Timer.Time("renderer: {0}"); - - oreFrequency = (int)(Rules.General.GrowthRate * 60 * 25); - oreTicks = oreFrequency; - Map.InitOreDensity(); - Timer.Time( "Ore: {0}" ); - WorldActor = CreateActor("World", new int2(int.MaxValue, int.MaxValue), null); for (int i = 0; i < 8; i++) - { players[i] = new Player(this, i, Game.LobbyInfo.Clients.FirstOrDefault(a => a.Index == i)); - } + Timer.Time( "worldActor, players: {0}" ); Queries = new AllQueries( this ); Timer.Time( "queries: {0}" ); - Bridges.MakeBridges(this); + foreach (var wlh in WorldActor.traits.WithInterface()) + wlh.WorldLoaded(this); + PathFinder = new PathFinder(this); - Timer.Time( "bridge, pathing: {0}" ); + Timer.Time( "hooks, pathing: {0}" ); Minimap = new Minimap(this, Game.renderer); Timer.Time( "minimap: {0}" ); @@ -124,14 +115,6 @@ namespace OpenRa public void Tick() { - if (--oreTicks == 0) - using( new PerfSample( "ore" ) ) - { - this.GrowOre( Game.SharedRandom ); - Minimap.InvalidateOre(); - oreTicks = oreFrequency; - } - foreach (var a in actors) a.Tick(); Queries.WithTraitMultiple().Do( x => x.Trait.Tick( x.Actor ) ); diff --git a/OpenRa.sln b/OpenRa.sln index cbdee7c2e3..eab68ff896 100644 --- a/OpenRa.sln +++ b/OpenRa.sln @@ -5,10 +5,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRa.FileFormats", "OpenR EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRa.Game", "OpenRa.Game\OpenRa.Game.csproj", "{0DFB103F-2962-400F-8C6D-E2C28CCBA633}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaletteUsage", "PaletteUsage\PaletteUsage.csproj", "{54577061-E2D2-4336-90A2-A9A7106A30CD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaletteMatch", "PaletteMatch\PaletteMatch.csproj", "{31411761-224C-4C54-A5FE-280890A70259}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SequenceEditor", "SequenceEditor\SequenceEditor.csproj", "{230F65CE-A6DE-4235-8B38-13A3D606C7F7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.Server", "OpenRA.Server\OpenRA.Server.csproj", "{76F621A1-3D8E-4A99-9F7E-B071EB657817}" @@ -33,14 +29,6 @@ Global {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release|Any CPU.ActiveCfg = Release|Any CPU {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release|Any CPU.Build.0 = Release|Any CPU - {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release|Any CPU.Build.0 = Release|Any CPU - {31411761-224C-4C54-A5FE-280890A70259}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {31411761-224C-4C54-A5FE-280890A70259}.Debug|Any CPU.Build.0 = Debug|Any CPU - {31411761-224C-4C54-A5FE-280890A70259}.Release|Any CPU.ActiveCfg = Release|Any CPU - {31411761-224C-4C54-A5FE-280890A70259}.Release|Any CPU.Build.0 = Release|Any CPU {230F65CE-A6DE-4235-8B38-13A3D606C7F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {230F65CE-A6DE-4235-8B38-13A3D606C7F7}.Debug|Any CPU.Build.0 = Debug|Any CPU {230F65CE-A6DE-4235-8B38-13A3D606C7F7}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/PaletteMatch/PaletteMatch.csproj b/PaletteMatch/PaletteMatch.csproj deleted file mode 100644 index 1069f840a5..0000000000 --- a/PaletteMatch/PaletteMatch.csproj +++ /dev/null @@ -1,65 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {31411761-224C-4C54-A5FE-280890A70259} - Exe - Properties - PaletteMatch - PaletteMatch - v3.5 - 512 - - - true - bin\Debug\ - DEBUG;TRACE - full - AnyCPU - prompt - - - bin\Release\ - TRACE - true - pdbonly - AnyCPU - prompt - - - - - 3.5 - - - - 3.5 - - - 3.5 - - - - - - - - - - - {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA} - OpenRa.FileFormats - - - - - \ No newline at end of file diff --git a/PaletteMatch/Program.cs b/PaletteMatch/Program.cs deleted file mode 100644 index ab6ba92dee..0000000000 --- a/PaletteMatch/Program.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using OpenRa.FileFormats; -using System.Drawing; - -namespace PaletteMatch -{ - /* a simple little hack to work out a sane matching between TD and RA palettes (or, indeed, from RA -> RA) */ - /* usage: PaletteMatch srcpal destpal */ - - static class Program - { - static void Main(string[] args) - { - var tdPalette = WithStream(args[0], s => new Palette(s)); - var raPalette = WithStream(args[1], s => new Palette(s)); - - var ms = tdPalette.Entries().Select( - (a, i) => new - { - Src = i, - Dest = raPalette.Entries().Select( - (b, j) => new { Color = b, Index = j }) - .OrderBy(x => x.Color, new ColorDistanceComparer(a)).First().Index - }); - - foreach( var m in ms ) - Console.WriteLine("{0:x2} -> {1:x2}", m.Src, m.Dest); - } - - static IEnumerable Entries(this Palette p) - { - for (var i = 0; i < 256; i++) - yield return p.GetColor(i); - } - - static T WithStream(string filename, Func f) - { - using (var s = File.OpenRead(filename)) - return f(s); - } - } - - class ColorDistanceComparer : IComparer - { - readonly Color r; - - public ColorDistanceComparer(Color r) - { - this.r = r; - } - - float Distance(Color a) - { - var b = a.GetBrightness() - r.GetBrightness(); - var h = a.GetHue() - r.GetHue(); - var s = a.GetSaturation() - r.GetSaturation(); - - return b * b + h * h + s * s; - } - - public int Compare(Color x, Color y) - { - return Math.Sign(Distance(x) - Distance(y)); - } - } - -} diff --git a/PaletteMatch/Properties/AssemblyInfo.cs b/PaletteMatch/Properties/AssemblyInfo.cs deleted file mode 100644 index 2f6ead4761..0000000000 --- a/PaletteMatch/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("PaletteMatch")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("PaletteMatch")] -[assembly: AssemblyCopyright("Copyright © 2009")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("eb944988-f387-46a5-bb5b-392d482df964")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PaletteUsage/PaletteUsage.csproj b/PaletteUsage/PaletteUsage.csproj deleted file mode 100644 index 05766f435b..0000000000 --- a/PaletteUsage/PaletteUsage.csproj +++ /dev/null @@ -1,53 +0,0 @@ - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {54577061-E2D2-4336-90A2-A9A7106A30CD} - Exe - Properties - PaletteUsage - PaletteUsage - - - 2.0 - - - - - true - bin\Debug\ - DEBUG;TRACE - full - AnyCPU - prompt - - - bin\Release\ - TRACE - true - pdbonly - AnyCPU - prompt - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/PaletteUsage/Program.cs b/PaletteUsage/Program.cs deleted file mode 100644 index ccc00752ea..0000000000 --- a/PaletteUsage/Program.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows.Forms; -using System.Drawing; - -namespace PaletteUsage -{ - class Program - { - static void Main(string[] args) - { - OpenFileDialog ofd = new OpenFileDialog(); - ofd.RestoreDirectory = true; - ofd.Filter = "PNG Image Cache (*.png)|*.png"; - - if (DialogResult.OK != ofd.ShowDialog()) - return; - - Bitmap bitmap = new Bitmap(ofd.FileName); - int[] f = new int[256]; - - foreach (byte b in ImageBytes(bitmap)) - ++f[b]; - - Console.WriteLine("Unused palette entries:"); - - for (int i = 0; i < 256; i++) - if (f[i] == 0) - Console.WriteLine("0x{0:x}\t\t{0}", i); - } - - static IEnumerable ImageBytes(Bitmap bitmap) - { - int width = bitmap.Width; - int height = bitmap.Height; - - for( int i = 0; i < width; i++ ) - for (int j = 0; j < height; j++) - { - Color c = bitmap.GetPixel(i, j); - yield return (byte)c.R; - yield return (byte)c.G; - yield return (byte)c.B; - yield return (byte)c.A; - } - } - } -} diff --git a/PaletteUsage/Properties/AssemblyInfo.cs b/PaletteUsage/Properties/AssemblyInfo.cs deleted file mode 100644 index 5099516f48..0000000000 --- a/PaletteUsage/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("PaletteUsage")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("PaletteUsage")] -[assembly: AssemblyCopyright("Copyright © 2007")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("93fb03d7-e484-45a8-bfe0-c0560814553a")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SequenceEditor/Program.cs b/SequenceEditor/Program.cs index 1059ccc730..41937a6e8a 100644 --- a/SequenceEditor/Program.cs +++ b/SequenceEditor/Program.cs @@ -69,24 +69,28 @@ namespace SequenceEditor { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - FileSystem.MountDefaultPackages(); - try - { - FileSystem.MountAftermathPackages(); - } - catch( FileNotFoundException ){} - XmlFilename = args.FirstOrDefault( x => x.EndsWith(".xml") ) ?? "sequences.xml"; + if (args.Length != 3) + { + MessageBox.Show( "usage: SequenceEditor mod[,mod]* sequences-file.xml palette.pal"); + return; + } + + var mods = args[0].Split(','); + var manifest = new Manifest(mods); + + foreach (var folder in manifest.Folders) FileSystem.Mount(folder); + foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg); + + XmlFilename = args[1]; Doc = new XmlDocument(); Doc.Load(XmlFilename); - var tempPal = new Palette(FileSystem.Open("temperat.pal")); - Pal = tempPal; //new Palette(tempPal, new ShroudPaletteRemap()); + var tempPal = new Palette(FileSystem.Open(args[2])); + Pal = tempPal; - UnitName = args.FirstOrDefault( x => !x.EndsWith(".xml") ); - if (UnitName == null) - UnitName = GetTextForm.GetString("Unit to edit?", "e1"); - if (UnitName == null) + UnitName = GetTextForm.GetString("Unit to edit?", "e1"); + if (string.IsNullOrEmpty(UnitName)) return; LoadAndResolve(UnitName); @@ -95,10 +99,7 @@ namespace SequenceEditor foreach (XmlElement e in Doc.SelectNodes(xpath)) { if (e.HasAttribute("src")) - { - var src = e.GetAttribute("src"); - LoadAndResolve(src); - } + LoadAndResolve(e.GetAttribute("src")); Sequences[e.GetAttribute("name")] = new Sequence(e); } diff --git a/build-deps.cmd b/build-deps.cmd new file mode 100644 index 0000000000..df7c88c68b --- /dev/null +++ b/build-deps.cmd @@ -0,0 +1,19 @@ +set MSBUILD="c:\windows\Microsoft.NET\Framework\v3.5\msbuild.exe" + +call git submodule init +call git submodule update + +pushd Ijw.DirectX +call git submodule init +call git submodule update + +pushd Ijw.Framework +%MSBUILD% /t:Rebuild /p:Configuration=Debug IjwFramework.sln +%MSBUILD% /t:Rebuild /p:Configuration=Release IjwFramework.sln +popd + +%MSBUILD% Ijw.DirectX.sln /p:Configuration=Debug +%MSBUILD% Ijw.DirectX.sln /p:Configuration=Release +popd + +%MSBUILD% OpenRA.sln /t:Rebuild /p:Configuration=Debug diff --git a/mods/cnc/minimal.ini b/mods/cnc/minimal.ini index a6d3813237..5b45ded674 100644 --- a/mods/cnc/minimal.ini +++ b/mods/cnc/minimal.ini @@ -10,14 +10,11 @@ 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] -OreGrows=yes ; Does ore grow denser over time? -OreSpreads=yes ; Does ore spread into adjacent areas GemValue=50 ; gem credits per 'bail' carried by a harvester GoldValue=25 ; gold credits per 'bail' carried by a harvester GrowthRate=.3 ; minutes between ore (Tiberium) growth BailCount=28 ; number of 'bails' carried by a harvester -;; OreChance is missing from rules.ini but referenced -;; LowPowerSlowdown is missing from rules.ini but referenced +LowPowerSlowdown=3 ; slowdown factor for low power GapRegenInterval=.1 ; gap generators will regenerate their shroud at this time interval SubmergeDelay=.02 ; forced delay that subs will remain on surface before allowing to submerge diff --git a/mods/cnc/structures.yaml b/mods/cnc/structures.yaml index 0c9d813bb0..862f5b1ed7 100644 --- a/mods/cnc/structures.yaml +++ b/mods/cnc/structures.yaml @@ -343,10 +343,9 @@ OBLI: Armor: light Crewed: no Sight: 5 - Turreted: RenderBuildingCharge: ChargeAudio: obelpowr.aud - AttackTurreted: + AttackOmni: PrimaryWeapon: Laser FireDelay: 8 AutoTarget: diff --git a/mods/cnc/system.yaml b/mods/cnc/system.yaml index 1778a8f392..371a12d26d 100644 --- a/mods/cnc/system.yaml +++ b/mods/cnc/system.yaml @@ -14,6 +14,7 @@ World: WaterPaletteRotation: BuildingInfluence: UnitInfluence: + BridgeLoadHook: PaletteFromFile@terrain_temperat: Name: terrain Theater: temperat @@ -104,4 +105,9 @@ World: G: 0 B: 0 A: 180 - ShroudPalette: \ No newline at end of file + ShroudPalette: + OreGrowth: + Interval: .3 + Chance: .02 + Spreads: yes + Grows: yes \ No newline at end of file diff --git a/mods/ra/rules.ini b/mods/ra/rules.ini index fa457dbbfb..1937a50348 100644 --- a/mods/ra/rules.ini +++ b/mods/ra/rules.ini @@ -69,9 +69,6 @@ BuildSpeed=.8 ; general build speed [time (in minutes) to produce a 10 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 -GrowthRate=.3 ; minutes between ore (Tiberium) growth -OreGrows=yes ; Does ore grow denser over time? -OreSpreads=yes ; Does ore spread into adjacent areas? 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 @@ -110,6 +107,7 @@ TeamDelay=.6 ; interval between checking for and creating teams ; misc FineDiffControl=no ; Allow 5 difficulty settings instead of only 3 settings? +LowPowerSlowdown=3 ; ******* Weapon Statistics ******* @@ -1011,10 +1009,6 @@ Verses=100%,100%,100%,100%,100% ImpactSound=kaboom25 Explosion=7 -[General] -OreChance=.02 -LowPowerSlowdown=3 - [VoiceTypes] diff --git a/mods/ra/rules.yaml b/mods/ra/rules.yaml index 11f089cb56..696e79e170 100644 --- a/mods/ra/rules.yaml +++ b/mods/ra/rules.yaml @@ -71,6 +71,8 @@ World: LightPaletteRotator: BuildingInfluence: UnitInfluence: + ChoosePaletteOnSelect: + BridgeLoadHook: PaletteFromFile@terrain_temperat: Name: terrain Filename: temperat.pal @@ -158,6 +160,11 @@ World: B: 0 A: 180 ShroudPalette: + OreGrowth: + Interval: .3 + Chance: .02 + Spreads: yes + Grows: yes MGG: GeneratesGap: @@ -453,9 +460,8 @@ TSLA: Armor: heavy Crewed: yes Sight: 8 - Turreted: RenderBuildingCharge: - AttackTurreted: + AttackOmni: PrimaryWeapon: TeslaZap FireDelay: 8 AutoTarget: @@ -1162,8 +1168,7 @@ PBOX: Armor: wood Crewed: yes Sight: 5 - Turreted: - AttackTurreted: + AttackOmni: PrimaryWeapon: Vulcan AutoTarget: IronCurtainable: @@ -1183,8 +1188,7 @@ HBOX: Armor: wood Crewed: yes Sight: 5 - Turreted: - AttackTurreted: + AttackOmni: PrimaryWeapon: Vulcan AutoTarget: IronCurtainable: @@ -1223,15 +1227,13 @@ FTUR: Cost: 600 Description: Flame Turret LongDesc: Anti-Infantry base defense.\n Strong vs Infantry\n Weak vs Aircraft - Turreted: - ROT: 10 Building: Power: -20 HP: 400 Armor: heavy Crewed: yes Sight: 6 - AttackTurreted: + AttackOmni: PrimaryWeapon: FireballLauncher PrimaryOffset: 0,0,12,8 AutoTarget: