diff --git a/OpenRa.FileFormats/Map.cs b/OpenRa.FileFormats/Map.cs index 1fe7a8c71e..dc34583e6b 100644 --- a/OpenRa.FileFormats/Map.cs +++ b/OpenRa.FileFormats/Map.cs @@ -23,33 +23,6 @@ namespace OpenRa.FileFormats public readonly TileReference[ , ] MapTiles = new TileReference[ 128, 128 ]; public readonly List Trees = new List(); - 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, - }; - static string Truncate( string s, int maxLength ) { return s.Length <= maxLength ? s : s.Substring(0,maxLength ); @@ -78,118 +51,6 @@ namespace OpenRa.FileFormats UnpackTileData(ReadPackedSection(file.GetSection("MapPack"))); UnpackOverlayData(ReadPackedSection(file.GetSection("OverlayPack"))); ReadTrees(file); - - InitOreDensity(); - } - - IEnumerable AdjacentTiles(int2 p) - { - for (var u = -1; u < 2; u++) - for (var v = -1; v < 2; v++) - yield return new int2(u, v) + p; - } - - byte GetOreDensity(int i, int j) - { - // perf fix. it's ugly, i know :( - int sum = 0; - for( var u = -1 ; u < 2 ; u++ ) - for( var v = -1 ; v < 2 ; v++ ) - if( ContainsOre( i + u, j + v ) ) - ++sum; - sum = sum * 3 / 2; - if( sum > 11 ) - return 11; - return (byte)sum; - } - - byte GetGemDensity(int i, int j) - { - return (byte)Math.Min(2, (AdjacentTiles(new int2(i, j)).Sum( - p => ContainsGem(p.X, p.Y) ? 1 : 0) / 3)); - } - - void InitOreDensity() - { - for( int j = 0; j < 128; j++ ) - for (int i = 0; i < 128; i++) - { - if (ContainsOre(i,j)) MapTiles[i, j].density = GetOreDensity(i, j); - if (ContainsGem(i,j)) MapTiles[i,j].density = GetGemDensity(i,j); - } - } - - bool HasOverlay(int i, int j) - { - return MapTiles[i, j].overlay < overlayIsOre.Length; - } - - bool ContainsOre(int i, int j) - { - return HasOverlay(i,j) && overlayIsOre[MapTiles[i,j].overlay]; - } - - bool ContainsGem(int i, int j) - { - return HasOverlay(i, j) && overlayIsGems[MapTiles[i, j].overlay]; - } - - public bool ContainsResource(int2 p) { return ContainsGem(p.X,p.Y) || ContainsOre(p.X, p.Y); } - - const float oreRate = .02f; - const float gemRate = .01f; - - public bool Harvest(int2 p, out bool isGems) /* harvests one unit if possible */ - { - isGems = ContainsGem(p.X, p.Y); - if (MapTiles[p.X, p.Y].density == 0) return false; - - if (--MapTiles[p.X, p.Y].density == 0) - MapTiles[p.X, p.Y].overlay = 0xff; - - return true; - } - - byte ore = 5; - byte ChooseOre() - { - if (++ore > 8) ore = 5; - return ore; - } - - public void GrowOre( Func canSpreadIntoCell, Random r ) /* todo: deal with ore pits */ - { - /* phase 1: grow into neighboring regions */ - var newOverlay = new byte[128, 128]; - var mini = this.XOffset; - var minj = this.YOffset; - var maxi = this.XOffset + Width; - var maxj = this.YOffset + Height; - - for (int j = minj; j < maxj; j++) - for (int i = mini; i < maxi; i++) - { - newOverlay[i,j] = 0xff; - if (!HasOverlay(i, j) && r.NextDouble() < oreRate && GetOreDensity(i, j) > 0 && canSpreadIntoCell(new int2(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) - MapTiles[i, j].overlay = newOverlay[i, j]; - - /* 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 (ContainsOre(i, j)) newDensity[i,j] = GetOreDensity(i, j); - - for (int j = minj; j < maxj; j++) - for (int i = mini; i < maxi; i++) - if (MapTiles[i, j].density < newDensity[i, j]) - ++MapTiles[i, j].density; } static MemoryStream ReadPackedSection(IniSection mapPackSection) diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 928d946987..30de9e587a 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -116,7 +116,7 @@ namespace OpenRa.Game } } - var halfStrength = unitInfo.Strength / 2; + var halfStrength = unitInfo.Strength * Rules.General.ConditionYellow; if (Health < halfStrength && (Health + damage) >= halfStrength) { /* we just went below half health! */ diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index f248c40f35..e10c64f540 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -51,6 +51,7 @@ namespace OpenRa.Game var mapFile = new IniFile(FileSystem.Open(mapName)); map = new Map(mapFile); + map.InitOreDensity(); FileSystem.Mount(new Package(map.Theater + ".mix")); viewport = new Viewport( clientSize, map.Offset, map.Offset + map.Size, renderer ); diff --git a/OpenRa.Game/GameRules/GeneralInfo.cs b/OpenRa.Game/GameRules/GeneralInfo.cs new file mode 100644 index 0000000000..99a2ee81d4 --- /dev/null +++ b/OpenRa.Game/GameRules/GeneralInfo.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.GameRules +{ + class GeneralInfo + { + /* Crates */ + public readonly int CrateMinimum; + public readonly int CrateMaximum; + public readonly float CrateRadius; + public readonly float CrateRegen; + public readonly string UnitCrateType; /* =none, if any */ + public readonly float WaterCrateChance; + + public readonly int SoloCrateMoney; + public readonly string SilverCrate; /* solo play crate contents */ + public readonly string WaterCrate; + public readonly string WoodCrate; + + /* Special Weapons */ + public readonly int ChronoDuration; + public readonly bool ChronoKillCargo; + public readonly int ChronoTechLevel; + public readonly int GPSTechLevel; + public readonly int GapRadius; + public readonly float GapRegenInterval; + public readonly float IronCurtain; /* minutes */ + public readonly int ParaTech; + public readonly int ParabombTech; + public readonly int RadarJamRadius; + public readonly int SpyPlaneTech; + public readonly int BadgerBombCount; + + /* Chrono Side Effects */ + public readonly float QuakeChance; + public readonly float QuakeDamage; /* percent */ + public readonly float VortexChance; + public readonly int VortexDamage; + public readonly int VortexRange; + public readonly int VortexSpeed; + + /* Repair & Refit */ + public readonly float RefundPercent; + public readonly float ReloadRate; + public readonly float RepairPercent; + public readonly float RepairRate; + public readonly int RepairStep; + public readonly float URepairPercent; + public readonly int URepairStep; + + /* Combat & Damage */ + public readonly float TurboBoost; + public readonly int APMineDamage; + public readonly int AVMineDamage; + public readonly int AtomDamage; + public readonly float BallisticScatter; + public readonly int BridgeStrength; + public readonly float C4Delay; + public readonly float Crush; + public readonly float ExpSpread; + public readonly int FireSupress; + public readonly float HomingScatter; + public readonly int MaxDamage; + public readonly int MinDamage; + public readonly bool OreExplosive; + public readonly bool PlayerAutoCrush; + public readonly bool PlayerReturnFire; + public readonly bool PlayerScatter; + public readonly float ProneDamage; + public readonly bool TreeTargeting; + public readonly int Incoming; + + /* Income & Production */ + public readonly int BailCount; + public readonly float BuildSpeed; + public readonly float BuildupTime; + public readonly int GemValue; + public readonly int GoldValue; + public readonly float GrowthRate; + public readonly bool OreGrows; + public readonly bool OreSpreads; + public readonly float OreTruckRate; + public readonly bool SeparateAircraft; + public readonly float SurvivorRate; + + /* Audo/Visual Map Controls */ + public readonly bool AllyReveal; + public readonly float ConditionRed; + public readonly float ConditionYellow; + public readonly int DropZoneRadius; + public readonly bool EnemyHealth; + public readonly int Gravity; + public readonly float IdleActionFrequency; + public readonly float MessageDelay; + public readonly float MovieTime; + public readonly bool NamedCivilians; + public readonly float SavourDelay; + public readonly int ShroudRate; + public readonly int SpeakDelay; + public readonly int TimerWarning; + public readonly bool FlashLowPower; + + /* Computer & Movement Controls */ + public readonly bool CurleyShuffle; + public readonly float BaseBias; + public readonly float BaseDefenseDelay; + public readonly float CloseEnough; + public readonly int DamageDelay; + public readonly int GameSpeeBias; + public readonly int LZScanRadius; + public readonly bool MineAware; + public readonly float Stray; + public readonly float SubmergeDelay; + public readonly float SuspendDelay; + public readonly int SuspendPriority; + public readonly float TeamDelay; + + /* Misc */ + public readonly bool FineDiffControl; + public readonly bool MCVUndeploy; + + /* OpenRA-specific */ + public readonly float OreChance; /* chance of spreading to a + * particular eligible cell */ + } +} diff --git a/OpenRa.Game/GameRules/Rules.cs b/OpenRa.Game/GameRules/Rules.cs index 0f7d38c7fe..4b305b8c2d 100755 --- a/OpenRa.Game/GameRules/Rules.cs +++ b/OpenRa.Game/GameRules/Rules.cs @@ -16,6 +16,7 @@ namespace OpenRa.Game public static InfoLoader WeaponInfo; public static InfoLoader WarheadInfo; public static InfoLoader ProjectileInfo; + public static GeneralInfo General; public static TechTree TechTree; public static void LoadRules( string mapFileName ) @@ -26,6 +27,9 @@ namespace OpenRa.Game FileSystem.Open( "units.ini" ), FileSystem.Open( "campaignUnits.ini" ) ); + General = new GeneralInfo(); + FieldLoader.Load(General, AllRules.GetSection("General")); + LoadCategories( "Building", "Infantry", diff --git a/OpenRa.Game/Graphics/OverlayRenderer.cs b/OpenRa.Game/Graphics/OverlayRenderer.cs index eb4ddabd84..1883146744 100755 --- a/OpenRa.Game/Graphics/OverlayRenderer.cs +++ b/OpenRa.Game/Graphics/OverlayRenderer.cs @@ -57,9 +57,9 @@ namespace OpenRa.Game.Graphics var location = new int2(x, y); var sprites = overlaySprites[o]; var spriteIndex = 0; - if (Map.overlayIsFence[o]) spriteIndex = NearbyFences(x, y); - else if (Map.overlayIsOre[o]) spriteIndex = map.MapTiles[x,y].density; - else if (Map.overlayIsGems[o]) spriteIndex = map.MapTiles[x,y].density; + if (Ore.overlayIsFence[o]) spriteIndex = NearbyFences(x, y); + else if (Ore.overlayIsOre[o]) spriteIndex = map.MapTiles[x,y].density; + else if (Ore.overlayIsGems[o]) spriteIndex = map.MapTiles[x,y].density; spriteRenderer.DrawSprite(sprites[spriteIndex], Game.CellSize * (float2)location, 0); } @@ -71,8 +71,8 @@ namespace OpenRa.Game.Graphics bool IsFence( int x, int y ) { var o = map.MapTiles[ x, y ].overlay; - if (o < Map.overlayIsFence.Length) - return Map.overlayIsFence[o]; + if (o < Ore.overlayIsFence.Length) + return Ore.overlayIsFence[o]; return false; } diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index df699158c5..b9d36453f8 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -106,9 +106,6 @@ namespace OpenRa.Game.Graphics Game.OreTime * 1000), new int2(5, 5), Color.White); } - const float conditionYellow = 0.5f; /* todo: get these from gamerules */ - const float conditionRed = 0.25f; - void DrawSelectionBox(Actor selectedUnit, Color c, bool drawHealthBar) { var center = selectedUnit.CenterLocation; @@ -136,8 +133,8 @@ namespace OpenRa.Game.Graphics lineRenderer.DrawLine(Xy + new float2(0, -2), Xy + new float2(0, -4), c, c); var healthAmount = (float)selectedUnit.Health / selectedUnit.unitInfo.Strength; - var healthColor = (healthAmount < conditionRed) ? Color.Red - : (healthAmount < conditionYellow) ? Color.Yellow + var healthColor = (healthAmount < Rules.General.ConditionRed) ? Color.Red + : (healthAmount < Rules.General.ConditionYellow) ? Color.Yellow : Color.LimeGreen; var healthColor2 = Color.FromArgb( diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 003196d3ed..32682964cc 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -74,8 +74,10 @@ + + diff --git a/OpenRa.Game/Ore.cs b/OpenRa.Game/Ore.cs new file mode 100644 index 0000000000..1bcc61df07 --- /dev/null +++ b/OpenRa.Game/Ore.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.FileFormats; + +namespace OpenRa.Game +{ + public static class Ore + { + /* todo: deal with ore pits */ + + public static void GrowOre(this Map map, + Func canSpreadIntoCell, Random r) + { + 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 + && canSpreadIntoCell(new int2(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); + + 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 IEnumerable AdjacentTiles(int2 p) + { + for (var u = -1; u < 2; u++) + for (var v = -1; v < 2; v++) + yield return new int2(u, v) + p; + } + + static byte GetOreDensity(this Map map, int i, int j) + { + // perf fix. it's ugly, i know :( + 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 * 3 / 2; + if (sum > 11) + return 11; + return (byte)sum; + } + + static byte GetGemDensity(this Map map, int i, int j) + { + return (byte)Math.Min(2, (AdjacentTiles(new int2(i, j)).Sum( + p => map.ContainsGem(p.X, p.Y) ? 1 : 0) / 3)); + } + + public static bool HasOverlay(this Map map, int i, int j) + { + return map.MapTiles[i, j].overlay < overlayIsOre.Length; + } + + public static bool ContainsOre(this Map map, int i, int j) + { + return map.HasOverlay(i, j) && overlayIsOre[map.MapTiles[i, j].overlay]; + } + + public 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[] 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, + }; + } +} diff --git a/units.ini b/units.ini index d69717d991..759c693bd3 100755 --- a/units.ini +++ b/units.ini @@ -492,3 +492,5 @@ Nuke ImpactSound=kaboom25 WaterImpactSound=splash9 +[General] +OreChance=.02 \ No newline at end of file