From 8249012e4b6cf7b405a1cbc2ee27b4f1c595b824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Sun, 15 Jun 2014 20:10:51 +0200 Subject: [PATCH 1/5] export health, cost and damage per section into a CSV file closes #3855 --- Makefile | 3 +- OpenRA.Utility/Command.cs | 49 ++++++++++++++++++++++++++++ OpenRA.Utility/OpenRA.Utility.csproj | 4 +++ OpenRA.Utility/Program.cs | 3 +- 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 55cdbfb537..c51c067e40 100644 --- a/Makefile +++ b/Makefile @@ -219,10 +219,11 @@ crashdialog: $(crashdialog_TARGET) utility_SRCS := $(shell find OpenRA.Utility/ -iname '*.cs') utility_TARGET = OpenRA.Utility.exe utility_KIND = exe -utility_DEPS = $(game_TARGET) +utility_DEPS = $(game_TARGET) $(mod_ra_TARGET) utility_LIBS = $(COMMON_LIBS) $(utility_DEPS) thirdparty/ICSharpCode.SharpZipLib.dll PROGRAMS += utility utility: $(utility_TARGET) + @$(CP) $(mod_ra_TARGET) . # Patches binary headers to work around a mono bug diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index 96fb4e16ee..e2ac801fcf 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -20,6 +20,7 @@ using System.Text; using OpenRA.FileFormats; using OpenRA.FileSystem; using OpenRA.Graphics; +using OpenRA.Mods.RA; using OpenRA.Scripting; using OpenRA.Traits; @@ -544,5 +545,53 @@ namespace OpenRA.Utility map.Save(dest); Console.WriteLine(dest + " saved."); } + + [Desc("MOD", "Export the game rules into a CSV file to inspect in a spreadheet.")] + public static void ExportCharacterSeparatedRules(string[] args) + { + var mod = args[1]; + Game.modData = new ModData(mod); + var rules = Game.modData.RulesetCache.LoadDefaultRules(); + var dump = new StringBuilder(); + dump.AppendLine("Name;Faction;Health;Cost;Damage per Second"); + foreach (var actorInfo in rules.Actors.Values) + { + if (actorInfo.Name.StartsWith("^")) + continue; + + var buildable = actorInfo.Traits.GetOrDefault(); + if (buildable == null) + continue; + var faction = FieldSaver.FormatValue(buildable.Owner, buildable.Owner.GetType()); + + var damagePerSecond = 0f; + var armaments = actorInfo.Traits.WithInterface(); + if (armaments.Any()) + { + var weapons = armaments.Select(a => a.Weapon).Select(w => rules.Weapons[w.ToLowerInvariant()]); + if (weapons.Any()) + { + var damage = weapons.Select(w => new { ROF = w.ROF > 0 ? w.ROF : 1, Damage = w.Burst * w.Warheads.Sum(z => z.Damage) }); + damagePerSecond = damage.Sum(d => (float)d.Damage / d.ROF * 25); + } + } + + var tooltip = actorInfo.Traits.GetOrDefault(); + var name = tooltip != null ? tooltip.Name : actorInfo.Name; + + var health = actorInfo.Traits.GetOrDefault(); + var hp = health != null ? health.HP : 0; + + var value = actorInfo.Traits.GetOrDefault(); + var cost = value != null ? value.Cost : 0; + + dump.AppendLine("{0};{1};{2};{3};{4}".F(name, faction, hp, cost, damagePerSecond)); + } + + var filename = "{0}-mod-rules.csv".F(mod); + using (StreamWriter outfile = new StreamWriter(filename)) + outfile.Write(dump.ToString()); + Console.WriteLine("{0} has been saved.\nOpen in a spreadsheet application as values separated by semicolon.".F(filename)); + } } } diff --git a/OpenRA.Utility/OpenRA.Utility.csproj b/OpenRA.Utility/OpenRA.Utility.csproj index 61464771f7..b2c1e38dd6 100644 --- a/OpenRA.Utility/OpenRA.Utility.csproj +++ b/OpenRA.Utility/OpenRA.Utility.csproj @@ -87,6 +87,10 @@ {0DFB103F-2962-400F-8C6D-E2C28CCBA633} OpenRA.Game + + {4A8A43B5-A9EF-4ED0-99DD-4BAB10A0DB6E} + OpenRA.Mods.RA + diff --git a/OpenRA.Utility/Program.cs b/OpenRA.Utility/Program.cs index 5f8a7ec73f..9c8aff6307 100644 --- a/OpenRA.Utility/Program.cs +++ b/OpenRA.Utility/Program.cs @@ -34,7 +34,8 @@ namespace OpenRA.Utility { "--upgrade-map", UpgradeRules.UpgradeMap }, { "--upgrade-mod", UpgradeRules.UpgradeMod }, { "--map-import", Command.ImportLegacyMap }, - { "--extract-language-strings", ExtractLanguageStrings.FromMod } + { "--extract-language-strings", ExtractLanguageStrings.FromMod }, + { "--csv", Command.ExportCharacterSeparatedRules } }; static void Main(string[] args) From de005c284c6046dc8fe12b626f93789521c291ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Wed, 28 May 2014 08:16:26 +0200 Subject: [PATCH 2/5] add armor types and move calculation into spreadsheet --- OpenRA.Utility/Command.cs | 69 +++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index e2ac801fcf..a30d3ac20d 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -552,8 +552,25 @@ namespace OpenRA.Utility var mod = args[1]; Game.modData = new ModData(mod); var rules = Game.modData.RulesetCache.LoadDefaultRules(); + + var armorList = new List(); + foreach (var actorInfo in rules.Actors.Values) + { + var armor = actorInfo.Traits.GetOrDefault(); + if (armor != null) + if (!armorList.Contains(armor.Type)) + armorList.Add(armor.Type); + } + + armorList.Sort(); + var vsArmor = ""; + foreach (var armorType in armorList) + vsArmor = vsArmor + ";vs. " + armorType; + var dump = new StringBuilder(); - dump.AppendLine("Name;Faction;Health;Cost;Damage per Second"); + dump.AppendLine("Name;Faction;Health;Cost;Damage;Burst;Rate of Fire;Damage per Second" + vsArmor); + + var line = 1; foreach (var actorInfo in rules.Actors.Values) { if (actorInfo.Name.StartsWith("^")) @@ -562,30 +579,54 @@ namespace OpenRA.Utility var buildable = actorInfo.Traits.GetOrDefault(); if (buildable == null) continue; - var faction = FieldSaver.FormatValue(buildable.Owner, buildable.Owner.GetType()); - var damagePerSecond = 0f; - var armaments = actorInfo.Traits.WithInterface(); - if (armaments.Any()) - { - var weapons = armaments.Select(a => a.Weapon).Select(w => rules.Weapons[w.ToLowerInvariant()]); - if (weapons.Any()) - { - var damage = weapons.Select(w => new { ROF = w.ROF > 0 ? w.ROF : 1, Damage = w.Burst * w.Warheads.Sum(z => z.Damage) }); - damagePerSecond = damage.Sum(d => (float)d.Damage / d.ROF * 25); - } - } + line++; var tooltip = actorInfo.Traits.GetOrDefault(); var name = tooltip != null ? tooltip.Name : actorInfo.Name; + var faction = FieldSaver.FormatValue(buildable.Owner, buildable.Owner.GetType()); + var health = actorInfo.Traits.GetOrDefault(); var hp = health != null ? health.HP : 0; var value = actorInfo.Traits.GetOrDefault(); var cost = value != null ? value.Cost : 0; - dump.AppendLine("{0};{1};{2};{3};{4}".F(name, faction, hp, cost, damagePerSecond)); + dump.Append("{0};{1};{2};{3}".F(name, faction, hp, cost)); + + var armaments = actorInfo.Traits.WithInterface(); + if (armaments.Any()) + { + var weapons = armaments.Select(a => a.Weapon).Select(w => rules.Weapons[w.ToLowerInvariant()]); + var weaponCount = 0; + foreach (var weapon in weapons) + { + weaponCount++; + if (weaponCount > 1) + { + line++; + dump.AppendLine(); + dump.Append(" ; ; ; "); + } + + var rateOfFire = (weapon.ROF > 1 ? weapon.ROF : 1).ToString(); + var burst = weapon.Burst.ToString(); + var warhead = weapon.Warheads.First(); // TODO + var damage = warhead.Damage.ToString(); + var damagePerSecond = "=(E{0}*F{0})/G{0}*25".F(line); + + var versus = ""; + foreach (var armorType in armorList) + { + var vs = warhead.Versus.ContainsKey(armorType) ? warhead.Versus[armorType] : 1f; + versus = versus + "=H{0}*{1};".F(line, vs); + } + + dump.Append(";{0};{1};{2};{3};{4}".F(damage, burst, rateOfFire, damagePerSecond, versus)); + } + } + dump.AppendLine(); } var filename = "{0}-mod-rules.csv".F(mod); From e0ba2046b54ad763c15705b0f4fbf4a02dc198a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Sun, 15 Jun 2014 20:12:24 +0200 Subject: [PATCH 3/5] add weapon name --- OpenRA.Utility/Command.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index a30d3ac20d..527de7b82e 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -568,7 +568,7 @@ namespace OpenRA.Utility vsArmor = vsArmor + ";vs. " + armorType; var dump = new StringBuilder(); - dump.AppendLine("Name;Faction;Health;Cost;Damage;Burst;Rate of Fire;Damage per Second" + vsArmor); + dump.AppendLine("Name;Faction;Health;Cost;Weapon;Damage;Burst;Rate of Fire;Damage per Second" + vsArmor); var line = 1; foreach (var actorInfo in rules.Actors.Values) @@ -598,10 +598,11 @@ namespace OpenRA.Utility var armaments = actorInfo.Traits.WithInterface(); if (armaments.Any()) { - var weapons = armaments.Select(a => a.Weapon).Select(w => rules.Weapons[w.ToLowerInvariant()]); + var weapons = armaments.Select(a => a.Weapon); var weaponCount = 0; - foreach (var weapon in weapons) + foreach (var weaponName in weapons) { + var weapon = rules.Weapons[weaponName.ToLowerInvariant()]; weaponCount++; if (weaponCount > 1) { @@ -614,16 +615,16 @@ namespace OpenRA.Utility var burst = weapon.Burst.ToString(); var warhead = weapon.Warheads.First(); // TODO var damage = warhead.Damage.ToString(); - var damagePerSecond = "=(E{0}*F{0})/G{0}*25".F(line); + var damagePerSecond = "=(F{0}*G{0})/H{0}*25".F(line); var versus = ""; foreach (var armorType in armorList) { var vs = warhead.Versus.ContainsKey(armorType) ? warhead.Versus[armorType] : 1f; - versus = versus + "=H{0}*{1};".F(line, vs); + versus = versus + "=I{0}*{1};".F(line, vs); } - dump.Append(";{0};{1};{2};{3};{4}".F(damage, burst, rateOfFire, damagePerSecond, versus)); + dump.Append(";{0};{1};{2};{3};{4};{5}".F(weaponName, damage, burst, rateOfFire, damagePerSecond, versus)); } } dump.AppendLine(); From 6d2dfabb414ed8ec58359144c46cc799e89dcd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Sun, 15 Jun 2014 20:12:47 +0200 Subject: [PATCH 4/5] factor in burst delay --- OpenRA.Utility/Command.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index 527de7b82e..ff73e3b5aa 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -568,7 +568,7 @@ namespace OpenRA.Utility vsArmor = vsArmor + ";vs. " + armorType; var dump = new StringBuilder(); - dump.AppendLine("Name;Faction;Health;Cost;Weapon;Damage;Burst;Rate of Fire;Damage per Second" + vsArmor); + dump.AppendLine("Name;Faction;Health;Cost;Weapon;Damage;Burst;Delay;Rate of Fire;Damage per Second" + vsArmor); var line = 1; foreach (var actorInfo in rules.Actors.Values) @@ -615,16 +615,17 @@ namespace OpenRA.Utility var burst = weapon.Burst.ToString(); var warhead = weapon.Warheads.First(); // TODO var damage = warhead.Damage.ToString(); - var damagePerSecond = "=(F{0}*G{0})/H{0}*25".F(line); + var delay = weapon.BurstDelay; + var damagePerSecond = "=(F{0}*G{0})/(H{0}+G{0}*I{0})*25".F(line); var versus = ""; foreach (var armorType in armorList) { var vs = warhead.Versus.ContainsKey(armorType) ? warhead.Versus[armorType] : 1f; - versus = versus + "=I{0}*{1};".F(line, vs); + versus = versus + "=J{0}*{1};".F(line, vs); } - dump.Append(";{0};{1};{2};{3};{4};{5}".F(weaponName, damage, burst, rateOfFire, damagePerSecond, versus)); + dump.Append(";{0};{1};{2};{3};{4};{5};{6}".F(weaponName, damage, burst, delay, rateOfFire, damagePerSecond, versus)); } } dump.AppendLine(); From 1d276e4186595992190639cd7f33fa5e07586d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Sun, 15 Jun 2014 20:13:14 +0200 Subject: [PATCH 5/5] add a pure data export for non-spreadsheet applications --- OpenRA.Utility/Command.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index ff73e3b5aa..9c8432650f 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -546,10 +546,11 @@ namespace OpenRA.Utility Console.WriteLine(dest + " saved."); } - [Desc("MOD", "Export the game rules into a CSV file to inspect in a spreadheet.")] + [Desc("MOD", "[--pure-data]", "Export the game rules into a CSV file for inspection.")] public static void ExportCharacterSeparatedRules(string[] args) { var mod = args[1]; + var pureData = args.Contains("--pure-data"); Game.modData = new ModData(mod); var rules = Game.modData.RulesetCache.LoadDefaultRules(); @@ -568,7 +569,10 @@ namespace OpenRA.Utility vsArmor = vsArmor + ";vs. " + armorType; var dump = new StringBuilder(); - dump.AppendLine("Name;Faction;Health;Cost;Weapon;Damage;Burst;Delay;Rate of Fire;Damage per Second" + vsArmor); + if (pureData) + dump.AppendLine("Name;Faction;Health;Cost;Weapon;Damage;Burst;Delay;Rate of Fire"); + else + dump.AppendLine("Name;Faction;Health;Cost;Weapon;Damage;Burst;Delay;Rate of Fire;Damage per Second" + vsArmor); var line = 1; foreach (var actorInfo in rules.Actors.Values) @@ -625,7 +629,10 @@ namespace OpenRA.Utility versus = versus + "=J{0}*{1};".F(line, vs); } - dump.Append(";{0};{1};{2};{3};{4};{5};{6}".F(weaponName, damage, burst, delay, rateOfFire, damagePerSecond, versus)); + if (pureData) + dump.Append(";{0};{1};{2};{3};{4}".F(weaponName, damage, burst, delay, rateOfFire)); + else + dump.Append(";{0};{1};{2};{3};{4};{5};{6}".F(weaponName, damage, burst, delay, rateOfFire, damagePerSecond, versus)); } } dump.AppendLine(); @@ -634,7 +641,9 @@ namespace OpenRA.Utility var filename = "{0}-mod-rules.csv".F(mod); using (StreamWriter outfile = new StreamWriter(filename)) outfile.Write(dump.ToString()); - Console.WriteLine("{0} has been saved.\nOpen in a spreadsheet application as values separated by semicolon.".F(filename)); + Console.WriteLine("{0} has been saved.".F(filename)); + if (!pureData) + Console.WriteLine("Open in a spreadsheet application as values separated by semicolon."); } } }