Reimplement unit levels using IUpgradable.
This commit is contained in:
@@ -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<ValuedInfo>
|
||||
{
|
||||
[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<int, string[]> 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<int, string[]>()
|
||||
{
|
||||
{ 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<int>("(key)", kv.Key),
|
||||
kv => FieldLoader.GetValue<string[]>("(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<Pair<int, string[]>> nextLevel = new List<Pair<int, string[]>>();
|
||||
|
||||
// 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<ValuedInfo>().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<ExperienceInit>())
|
||||
GiveExperience(init.Get<ExperienceInit, int>());
|
||||
}
|
||||
|
||||
[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<IUpgradable>())
|
||||
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<int>
|
||||
|
||||
@@ -30,9 +30,10 @@ namespace OpenRA.Mods.RA
|
||||
var info = self.Info.Traits.Get<GivesExperienceInfo>();
|
||||
var valued = self.Info.Traits.GetOrDefault<ValuedInfo>();
|
||||
|
||||
// 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<GainsExperience>();
|
||||
if (killer != null)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user