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..9c8432650f 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,105 @@ namespace OpenRA.Utility map.Save(dest); Console.WriteLine(dest + " saved."); } + + [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(); + + 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(); + 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) + { + if (actorInfo.Name.StartsWith("^")) + continue; + + var buildable = actorInfo.Traits.GetOrDefault(); + if (buildable == null) + continue; + + 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.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); + var weaponCount = 0; + foreach (var weaponName in weapons) + { + var weapon = rules.Weapons[weaponName.ToLowerInvariant()]; + 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 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 + "=J{0}*{1};".F(line, vs); + } + + 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(); + } + + var filename = "{0}-mod-rules.csv".F(mod); + using (StreamWriter outfile = new StreamWriter(filename)) + outfile.Write(dump.ToString()); + Console.WriteLine("{0} has been saved.".F(filename)); + if (!pureData) + Console.WriteLine("Open in a spreadsheet application as values separated by semicolon."); + } } } 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 d5ee6a3b1f..687b949ba9 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)