From de775e2f56d48edd134fd3ce81c6301fc926e774 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 30 Jul 2014 20:14:13 +1200 Subject: [PATCH] Reimplement unit levels using IUpgradable. --- OpenRA.Mods.RA/GainsExperience.cs | 96 +++++++++++++++++---------- OpenRA.Mods.RA/GivesExperience.cs | 3 +- OpenRA.Utility/UpgradeRules.cs | 7 ++ mods/cnc/rules/defaults.yaml | 6 ++ mods/d2k/rules/defaults.yaml | 4 ++ mods/ra/maps/desert-shellmap/map.yaml | 20 ++---- mods/ra/rules/defaults.yaml | 5 ++ mods/ts/rules/defaults.yaml | 20 ++++-- 8 files changed, 104 insertions(+), 57 deletions(-) diff --git a/OpenRA.Mods.RA/GainsExperience.cs b/OpenRA.Mods.RA/GainsExperience.cs index 60bbad63e7..d8d179ea1c 100644 --- a/OpenRA.Mods.RA/GainsExperience.cs +++ b/OpenRA.Mods.RA/GainsExperience.cs @@ -8,9 +8,12 @@ */ #endregion +using System; +using System.Collections.Generic; using System.Linq; using OpenRA.GameRules; using OpenRA.Mods.RA.Effects; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -18,84 +21,105 @@ namespace OpenRA.Mods.RA [Desc("This actor's experience increases when it has killed a GivesExperience actor.")] public class GainsExperienceInfo : ITraitInfo, Requires { - [Desc("XP requirements for each level, as multiples of our own cost.")] - public readonly float[] CostThreshold = { 2, 4, 8, 16 }; - public readonly float[] FirepowerModifier = { 1.1f, 1.15f, 1.2f, 1.5f }; - public readonly float[] ArmorModifier = { 1.1f, 1.2f, 1.3f, 1.5f }; - public readonly decimal[] SpeedModifier = { 1.1m, 1.15m, 1.2m, 1.5m }; + [FieldLoader.LoadUsing("LoadUpgrades")] + [Desc("Upgrades to grant at each level", + "Key is the XP requirements for each level as a percentage of our own value.", + "Value is a list of the upgrade types to grant")] + public readonly Dictionary Upgrades = null; + + [Desc("Palette for the chevron glyph rendered in the selection box.")] public readonly string ChevronPalette = "effect"; + + [Desc("Palette for the level up sprite.")] public readonly string LevelUpPalette = "effect"; + public object Create(ActorInitializer init) { return new GainsExperience(init, this); } + + static object LoadUpgrades(MiniYaml y) + { + MiniYaml upgrades; + + if (!y.ToDictionary().TryGetValue("Upgrades", out upgrades)) + { + return new Dictionary() + { + { 200, new[] { "firepower", "armor", "speed" } }, + { 400, new[] { "firepower", "armor", "speed" } }, + { 800, new[] { "firepower", "armor", "speed" } }, + { 1600, new[] { "firepower", "armor", "speed" } } + }; + } + + return upgrades.Nodes.ToDictionary( + kv => FieldLoader.GetValue("(key)", kv.Key), + kv => FieldLoader.GetValue("(value)", kv.Value.Value)); + } } - public class GainsExperience : IFirepowerModifier, ISpeedModifier, IDamageModifier, ISync + public class GainsExperience : ISync { readonly Actor self; - readonly int[] levels; readonly GainsExperienceInfo info; + readonly List> nextLevel = new List>(); + + // Stored as a percentage of our value + [Sync] int experience = 0; + + [Sync] public int Level { get; private set; } + public readonly int MaxLevel; + public GainsExperience(ActorInitializer init, GainsExperienceInfo info) { self = init.self; this.info = info; + + MaxLevel = info.Upgrades.Count; + var cost = self.Info.Traits.Get().Cost; - levels = info.CostThreshold.Select(t => (int)(t * cost)).ToArray(); + foreach (var kv in info.Upgrades) + nextLevel.Add(Pair.New(kv.Key * cost, kv.Value)); if (init.Contains()) GiveExperience(init.Get()); } - [Sync] int experience = 0; - [Sync] public int Level { get; private set; } - - int MaxLevel { get { return levels.Length; } } public bool CanGainLevel { get { return Level < MaxLevel; } } - public void GiveOneLevel() - { - if (Level < MaxLevel) - GiveExperience(levels[Level] - experience); - } - public void GiveLevels(int numLevels) { - for (var i = 0; i < numLevels; i++) - GiveOneLevel(); + var newLevel = Math.Min(Level + numLevels, MaxLevel); + GiveExperience(nextLevel[newLevel - 1].First - experience); } public void GiveExperience(int amount) { experience += amount; - while (Level < MaxLevel && experience >= levels[Level]) + while (Level < MaxLevel && experience >= nextLevel[Level].First) { + var upgrades = nextLevel[Level].Second; + Level++; + foreach (var up in self.TraitsImplementing()) + foreach (var u in upgrades) + if (up.AcceptsUpgrade(u)) + up.UpgradeAvailable(self, u, true); + Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Sounds", "LevelUp", self.Owner.Country.Race); self.World.AddFrameEndTask(w => w.Add(new CrateEffect(self, "levelup", info.LevelUpPalette))); + if (Level == 1) + { self.World.AddFrameEndTask(w => { if (!self.IsDead()) w.Add(new Rank(self, info.ChevronPalette)); }); + } } } - - public float GetDamageModifier(Actor attacker, DamageWarhead warhead) - { - return Level > 0 ? 1 / info.ArmorModifier[Level - 1] : 1; - } - - public float GetFirepowerModifier() - { - return Level > 0 ? info.FirepowerModifier[Level - 1] : 1; - } - - public decimal GetSpeedModifier() - { - return Level > 0 ? info.SpeedModifier[Level - 1] : 1m; - } } class ExperienceInit : IActorInit diff --git a/OpenRA.Mods.RA/GivesExperience.cs b/OpenRA.Mods.RA/GivesExperience.cs index 947e34961a..813cdd4934 100644 --- a/OpenRA.Mods.RA/GivesExperience.cs +++ b/OpenRA.Mods.RA/GivesExperience.cs @@ -30,9 +30,10 @@ namespace OpenRA.Mods.RA var info = self.Info.Traits.Get(); var valued = self.Info.Traits.GetOrDefault(); + // Default experience is 100 times our value var exp = info.Experience >= 0 ? info.Experience - : valued != null ? valued.Cost : 0; + : valued != null ? valued.Cost * 100 : 0; var killer = e.Attacker.TraitOrDefault(); if (killer != null) diff --git a/OpenRA.Utility/UpgradeRules.cs b/OpenRA.Utility/UpgradeRules.cs index 27386372fe..c2c7276b13 100644 --- a/OpenRA.Utility/UpgradeRules.cs +++ b/OpenRA.Utility/UpgradeRules.cs @@ -364,6 +364,13 @@ namespace OpenRA.Utility } } + // Veterancy was changed to use the upgrades system + if (engineVersion < 20140807) + { + if (depth == 0 && node.Value.Nodes.Any(n => n.Key.StartsWith("GainsExperience"))) + node.Value.Nodes.Add(new MiniYamlNode("GainsStatUpgrades", new MiniYaml(""))); + } + UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } } diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 51c36dacc5..ab2bf64913 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -41,6 +41,7 @@ Huntable: LuaScriptEvents: ScriptTriggers: + GainsStatUpgrades: ^Tank: AppearsOnRadar: @@ -88,6 +89,7 @@ Huntable: LuaScriptEvents: ScriptTriggers: + GainsStatUpgrades: ^Helicopter: AppearsOnRadar: @@ -119,6 +121,7 @@ Huntable: LuaScriptEvents: ScriptTriggers: + GainsStatUpgrades: ^Infantry: AppearsOnRadar: @@ -187,6 +190,7 @@ DeathSounds@POISONED: DeathSound: Poisoned InfDeaths: 6 + GainsStatUpgrades: ^CivInfantry: Inherits: ^Infantry @@ -285,6 +289,7 @@ AttackMove: LuaScriptEvents: ScriptTriggers: + GainsStatUpgrades: ^Ship: AppearsOnRadar: @@ -311,6 +316,7 @@ Huntable: LuaScriptEvents: ScriptTriggers: + GainsStatUpgrades: ^Building: AppearsOnRadar: diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index a9eaa8b4e5..fd26a51cce 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -39,6 +39,7 @@ LuaScriptEvents: Demolishable: ScriptTriggers: + GainsStatUpgrades: ^Tank: AppearsOnRadar: @@ -81,6 +82,7 @@ LuaScriptEvents: Demolishable: ScriptTriggers: + GainsStatUpgrades: ^Husk: Health: @@ -198,6 +200,7 @@ DeathSounds: Parachutable: FallRate: 130 + GainsStatUpgrades: ^Plane: AppearsOnRadar: @@ -223,6 +226,7 @@ AttackMove: LuaScriptEvents: ScriptTriggers: + GainsStatUpgrades: ^Helicopter: Inherits: ^Plane diff --git a/mods/ra/maps/desert-shellmap/map.yaml b/mods/ra/maps/desert-shellmap/map.yaml index f2abcb15a3..9fc0a2cdfe 100644 --- a/mods/ra/maps/desert-shellmap/map.yaml +++ b/mods/ra/maps/desert-shellmap/map.yaml @@ -1293,28 +1293,19 @@ Rules: GivesBounty: Percentage: 0 GainsExperience: - CostThreshold: - FirepowerModifier: - ArmorModifier: - SpeedModifier: + Upgrades: ^Tank: ScriptInvulnerable: GivesBounty: Percentage: 0 GainsExperience: - CostThreshold: - FirepowerModifier: - ArmorModifier: - SpeedModifier: + Upgrades: ^Infantry: ScriptInvulnerable: GivesBounty: Percentage: 0 GainsExperience: - CostThreshold: - FirepowerModifier: - ArmorModifier: - SpeedModifier: + Upgrades: DeathSounds@NORMAL: VolumeMultiplier: 0.1 DeathSounds@BURNED: @@ -1326,10 +1317,7 @@ Rules: GivesBounty: Percentage: 0 GainsExperience: - CostThreshold: - FirepowerModifier: - ArmorModifier: - SpeedModifier: + Upgrades: ^Plane: ScriptInvulnerable: GivesBounty: diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 10730dac6e..1fe2145be0 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -54,6 +54,7 @@ CaptureNotification: Notification: UnitStolen ScriptTriggers: + GainsStatUpgrades: ^Tank: AppearsOnRadar: @@ -111,6 +112,7 @@ CaptureNotification: Notification: UnitStolen ScriptTriggers: + GainsStatUpgrades: ^Infantry: AppearsOnRadar: @@ -182,6 +184,7 @@ ShadowSequence: parach-shadow Cloneable: Types: Infantry + GainsStatUpgrades: ^Ship: AppearsOnRadar: @@ -215,6 +218,7 @@ Huntable: LuaScriptEvents: ScriptTriggers: + GainsStatUpgrades: ^Plane: AppearsOnRadar: @@ -251,6 +255,7 @@ Huntable: LuaScriptEvents: ScriptTriggers: + GainsStatUpgrades: ^Helicopter: Inherits: ^Plane diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index 655d2adda3..e867dca41a 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -113,7 +113,10 @@ HiddenUnderFog: GainsExperience: ChevronPalette: ra - CostThreshold: 5, 10 + Upgrades: + 500: firepower, armor, speed + 1000: firepower, armor, speed + GainsStatUpgrades: FirepowerModifier: 1.2, 1.5 ArmorModifier: 1.2, 1.5 SpeedModifier: 1.2, 1.5 @@ -199,7 +202,10 @@ HiddenUnderFog: GainsExperience: ChevronPalette: ra - CostThreshold: 5, 10 + Upgrades: + 500: firepower, armor, speed + 1000: firepower, armor, speed + GainsStatUpgrades: FirepowerModifier: 1.2, 1.5 ArmorModifier: 1.2, 1.5 SpeedModifier: 1.2, 1.5 @@ -248,7 +254,10 @@ HiddenUnderFog: GainsExperience: ChevronPalette: ra - CostThreshold: 5, 10 + Upgrades: + 500: firepower, armor, speed + 1000: firepower, armor, speed + GainsStatUpgrades: FirepowerModifier: 1.2, 1.5 ArmorModifier: 1.2, 1.5 SpeedModifier: 1.2, 1.5 @@ -291,7 +300,10 @@ AttackMove: GainsExperience: ChevronPalette: ra - CostThreshold: 5, 10 + Upgrades: + 500: firepower, armor, speed + 1000: firepower, armor, speed + GainsStatUpgrades: FirepowerModifier: 1.2, 1.5 ArmorModifier: 1.2, 1.5 SpeedModifier: 1.2, 1.5