Reimplement unit levels using IUpgradable.
This commit is contained in:
@@ -8,9 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.GameRules;
|
using OpenRA.GameRules;
|
||||||
using OpenRA.Mods.RA.Effects;
|
using OpenRA.Mods.RA.Effects;
|
||||||
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
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.")]
|
[Desc("This actor's experience increases when it has killed a GivesExperience actor.")]
|
||||||
public class GainsExperienceInfo : ITraitInfo, Requires<ValuedInfo>
|
public class GainsExperienceInfo : ITraitInfo, Requires<ValuedInfo>
|
||||||
{
|
{
|
||||||
[Desc("XP requirements for each level, as multiples of our own cost.")]
|
[FieldLoader.LoadUsing("LoadUpgrades")]
|
||||||
public readonly float[] CostThreshold = { 2, 4, 8, 16 };
|
[Desc("Upgrades to grant at each level",
|
||||||
public readonly float[] FirepowerModifier = { 1.1f, 1.15f, 1.2f, 1.5f };
|
"Key is the XP requirements for each level as a percentage of our own value.",
|
||||||
public readonly float[] ArmorModifier = { 1.1f, 1.2f, 1.3f, 1.5f };
|
"Value is a list of the upgrade types to grant")]
|
||||||
public readonly decimal[] SpeedModifier = { 1.1m, 1.15m, 1.2m, 1.5m };
|
public readonly Dictionary<int, string[]> Upgrades = null;
|
||||||
|
|
||||||
|
[Desc("Palette for the chevron glyph rendered in the selection box.")]
|
||||||
public readonly string ChevronPalette = "effect";
|
public readonly string ChevronPalette = "effect";
|
||||||
|
|
||||||
|
[Desc("Palette for the level up sprite.")]
|
||||||
public readonly string LevelUpPalette = "effect";
|
public readonly string LevelUpPalette = "effect";
|
||||||
|
|
||||||
public object Create(ActorInitializer init) { return new GainsExperience(init, this); }
|
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 Actor self;
|
||||||
readonly int[] levels;
|
|
||||||
readonly GainsExperienceInfo info;
|
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)
|
public GainsExperience(ActorInitializer init, GainsExperienceInfo info)
|
||||||
{
|
{
|
||||||
self = init.self;
|
self = init.self;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
|
||||||
|
MaxLevel = info.Upgrades.Count;
|
||||||
|
|
||||||
var cost = self.Info.Traits.Get<ValuedInfo>().Cost;
|
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>())
|
if (init.Contains<ExperienceInit>())
|
||||||
GiveExperience(init.Get<ExperienceInit, int>());
|
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 bool CanGainLevel { get { return Level < MaxLevel; } }
|
||||||
|
|
||||||
public void GiveOneLevel()
|
|
||||||
{
|
|
||||||
if (Level < MaxLevel)
|
|
||||||
GiveExperience(levels[Level] - experience);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GiveLevels(int numLevels)
|
public void GiveLevels(int numLevels)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < numLevels; i++)
|
var newLevel = Math.Min(Level + numLevels, MaxLevel);
|
||||||
GiveOneLevel();
|
GiveExperience(nextLevel[newLevel - 1].First - experience);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GiveExperience(int amount)
|
public void GiveExperience(int amount)
|
||||||
{
|
{
|
||||||
experience += amount;
|
experience += amount;
|
||||||
|
|
||||||
while (Level < MaxLevel && experience >= levels[Level])
|
while (Level < MaxLevel && experience >= nextLevel[Level].First)
|
||||||
{
|
{
|
||||||
|
var upgrades = nextLevel[Level].Second;
|
||||||
|
|
||||||
Level++;
|
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);
|
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)));
|
self.World.AddFrameEndTask(w => w.Add(new CrateEffect(self, "levelup", info.LevelUpPalette)));
|
||||||
|
|
||||||
if (Level == 1)
|
if (Level == 1)
|
||||||
|
{
|
||||||
self.World.AddFrameEndTask(w =>
|
self.World.AddFrameEndTask(w =>
|
||||||
{
|
{
|
||||||
if (!self.IsDead())
|
if (!self.IsDead())
|
||||||
w.Add(new Rank(self, info.ChevronPalette));
|
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>
|
class ExperienceInit : IActorInit<int>
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ namespace OpenRA.Mods.RA
|
|||||||
var info = self.Info.Traits.Get<GivesExperienceInfo>();
|
var info = self.Info.Traits.Get<GivesExperienceInfo>();
|
||||||
var valued = self.Info.Traits.GetOrDefault<ValuedInfo>();
|
var valued = self.Info.Traits.GetOrDefault<ValuedInfo>();
|
||||||
|
|
||||||
|
// Default experience is 100 times our value
|
||||||
var exp = info.Experience >= 0
|
var exp = info.Experience >= 0
|
||||||
? info.Experience
|
? info.Experience
|
||||||
: valued != null ? valued.Cost : 0;
|
: valued != null ? valued.Cost * 100 : 0;
|
||||||
|
|
||||||
var killer = e.Attacker.TraitOrDefault<GainsExperience>();
|
var killer = e.Attacker.TraitOrDefault<GainsExperience>();
|
||||||
if (killer != null)
|
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);
|
UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
Huntable:
|
Huntable:
|
||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Tank:
|
^Tank:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -88,6 +89,7 @@
|
|||||||
Huntable:
|
Huntable:
|
||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Helicopter:
|
^Helicopter:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -119,6 +121,7 @@
|
|||||||
Huntable:
|
Huntable:
|
||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Infantry:
|
^Infantry:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -187,6 +190,7 @@
|
|||||||
DeathSounds@POISONED:
|
DeathSounds@POISONED:
|
||||||
DeathSound: Poisoned
|
DeathSound: Poisoned
|
||||||
InfDeaths: 6
|
InfDeaths: 6
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^CivInfantry:
|
^CivInfantry:
|
||||||
Inherits: ^Infantry
|
Inherits: ^Infantry
|
||||||
@@ -285,6 +289,7 @@
|
|||||||
AttackMove:
|
AttackMove:
|
||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Ship:
|
^Ship:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -311,6 +316,7 @@
|
|||||||
Huntable:
|
Huntable:
|
||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Building:
|
^Building:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
Demolishable:
|
Demolishable:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Tank:
|
^Tank:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -81,6 +82,7 @@
|
|||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
Demolishable:
|
Demolishable:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Husk:
|
^Husk:
|
||||||
Health:
|
Health:
|
||||||
@@ -198,6 +200,7 @@
|
|||||||
DeathSounds:
|
DeathSounds:
|
||||||
Parachutable:
|
Parachutable:
|
||||||
FallRate: 130
|
FallRate: 130
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Plane:
|
^Plane:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -223,6 +226,7 @@
|
|||||||
AttackMove:
|
AttackMove:
|
||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Helicopter:
|
^Helicopter:
|
||||||
Inherits: ^Plane
|
Inherits: ^Plane
|
||||||
|
|||||||
@@ -1293,28 +1293,19 @@ Rules:
|
|||||||
GivesBounty:
|
GivesBounty:
|
||||||
Percentage: 0
|
Percentage: 0
|
||||||
GainsExperience:
|
GainsExperience:
|
||||||
CostThreshold:
|
Upgrades:
|
||||||
FirepowerModifier:
|
|
||||||
ArmorModifier:
|
|
||||||
SpeedModifier:
|
|
||||||
^Tank:
|
^Tank:
|
||||||
ScriptInvulnerable:
|
ScriptInvulnerable:
|
||||||
GivesBounty:
|
GivesBounty:
|
||||||
Percentage: 0
|
Percentage: 0
|
||||||
GainsExperience:
|
GainsExperience:
|
||||||
CostThreshold:
|
Upgrades:
|
||||||
FirepowerModifier:
|
|
||||||
ArmorModifier:
|
|
||||||
SpeedModifier:
|
|
||||||
^Infantry:
|
^Infantry:
|
||||||
ScriptInvulnerable:
|
ScriptInvulnerable:
|
||||||
GivesBounty:
|
GivesBounty:
|
||||||
Percentage: 0
|
Percentage: 0
|
||||||
GainsExperience:
|
GainsExperience:
|
||||||
CostThreshold:
|
Upgrades:
|
||||||
FirepowerModifier:
|
|
||||||
ArmorModifier:
|
|
||||||
SpeedModifier:
|
|
||||||
DeathSounds@NORMAL:
|
DeathSounds@NORMAL:
|
||||||
VolumeMultiplier: 0.1
|
VolumeMultiplier: 0.1
|
||||||
DeathSounds@BURNED:
|
DeathSounds@BURNED:
|
||||||
@@ -1326,10 +1317,7 @@ Rules:
|
|||||||
GivesBounty:
|
GivesBounty:
|
||||||
Percentage: 0
|
Percentage: 0
|
||||||
GainsExperience:
|
GainsExperience:
|
||||||
CostThreshold:
|
Upgrades:
|
||||||
FirepowerModifier:
|
|
||||||
ArmorModifier:
|
|
||||||
SpeedModifier:
|
|
||||||
^Plane:
|
^Plane:
|
||||||
ScriptInvulnerable:
|
ScriptInvulnerable:
|
||||||
GivesBounty:
|
GivesBounty:
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
CaptureNotification:
|
CaptureNotification:
|
||||||
Notification: UnitStolen
|
Notification: UnitStolen
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Tank:
|
^Tank:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -111,6 +112,7 @@
|
|||||||
CaptureNotification:
|
CaptureNotification:
|
||||||
Notification: UnitStolen
|
Notification: UnitStolen
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Infantry:
|
^Infantry:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -182,6 +184,7 @@
|
|||||||
ShadowSequence: parach-shadow
|
ShadowSequence: parach-shadow
|
||||||
Cloneable:
|
Cloneable:
|
||||||
Types: Infantry
|
Types: Infantry
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Ship:
|
^Ship:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -215,6 +218,7 @@
|
|||||||
Huntable:
|
Huntable:
|
||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Plane:
|
^Plane:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
@@ -251,6 +255,7 @@
|
|||||||
Huntable:
|
Huntable:
|
||||||
LuaScriptEvents:
|
LuaScriptEvents:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
GainsStatUpgrades:
|
||||||
|
|
||||||
^Helicopter:
|
^Helicopter:
|
||||||
Inherits: ^Plane
|
Inherits: ^Plane
|
||||||
|
|||||||
@@ -113,7 +113,10 @@
|
|||||||
HiddenUnderFog:
|
HiddenUnderFog:
|
||||||
GainsExperience:
|
GainsExperience:
|
||||||
ChevronPalette: ra
|
ChevronPalette: ra
|
||||||
CostThreshold: 5, 10
|
Upgrades:
|
||||||
|
500: firepower, armor, speed
|
||||||
|
1000: firepower, armor, speed
|
||||||
|
GainsStatUpgrades:
|
||||||
FirepowerModifier: 1.2, 1.5
|
FirepowerModifier: 1.2, 1.5
|
||||||
ArmorModifier: 1.2, 1.5
|
ArmorModifier: 1.2, 1.5
|
||||||
SpeedModifier: 1.2, 1.5
|
SpeedModifier: 1.2, 1.5
|
||||||
@@ -199,7 +202,10 @@
|
|||||||
HiddenUnderFog:
|
HiddenUnderFog:
|
||||||
GainsExperience:
|
GainsExperience:
|
||||||
ChevronPalette: ra
|
ChevronPalette: ra
|
||||||
CostThreshold: 5, 10
|
Upgrades:
|
||||||
|
500: firepower, armor, speed
|
||||||
|
1000: firepower, armor, speed
|
||||||
|
GainsStatUpgrades:
|
||||||
FirepowerModifier: 1.2, 1.5
|
FirepowerModifier: 1.2, 1.5
|
||||||
ArmorModifier: 1.2, 1.5
|
ArmorModifier: 1.2, 1.5
|
||||||
SpeedModifier: 1.2, 1.5
|
SpeedModifier: 1.2, 1.5
|
||||||
@@ -248,7 +254,10 @@
|
|||||||
HiddenUnderFog:
|
HiddenUnderFog:
|
||||||
GainsExperience:
|
GainsExperience:
|
||||||
ChevronPalette: ra
|
ChevronPalette: ra
|
||||||
CostThreshold: 5, 10
|
Upgrades:
|
||||||
|
500: firepower, armor, speed
|
||||||
|
1000: firepower, armor, speed
|
||||||
|
GainsStatUpgrades:
|
||||||
FirepowerModifier: 1.2, 1.5
|
FirepowerModifier: 1.2, 1.5
|
||||||
ArmorModifier: 1.2, 1.5
|
ArmorModifier: 1.2, 1.5
|
||||||
SpeedModifier: 1.2, 1.5
|
SpeedModifier: 1.2, 1.5
|
||||||
@@ -291,7 +300,10 @@
|
|||||||
AttackMove:
|
AttackMove:
|
||||||
GainsExperience:
|
GainsExperience:
|
||||||
ChevronPalette: ra
|
ChevronPalette: ra
|
||||||
CostThreshold: 5, 10
|
Upgrades:
|
||||||
|
500: firepower, armor, speed
|
||||||
|
1000: firepower, armor, speed
|
||||||
|
GainsStatUpgrades:
|
||||||
FirepowerModifier: 1.2, 1.5
|
FirepowerModifier: 1.2, 1.5
|
||||||
ArmorModifier: 1.2, 1.5
|
ArmorModifier: 1.2, 1.5
|
||||||
SpeedModifier: 1.2, 1.5
|
SpeedModifier: 1.2, 1.5
|
||||||
|
|||||||
Reference in New Issue
Block a user