Reimplement unit levels using IUpgradable.

This commit is contained in:
Paul Chote
2014-07-30 20:14:13 +12:00
parent 0ca5336072
commit de775e2f56
8 changed files with 104 additions and 57 deletions

View File

@@ -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>

View File

@@ -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)

View File

@@ -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);
} }
} }

View File

@@ -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:

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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