#region Copyright & License Information /* * Copyright 2007-2014 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, * see COPYING. */ #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 { [Desc("This actor's experience increases when it has killed a GivesExperience actor.")] public class GainsExperienceInfo : ITraitInfo, Requires { [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", "damage", "speed", "reload", "inaccuracy" } }, { 400, new[] { "firepower", "damage", "speed", "reload", "inaccuracy" } }, { 800, new[] { "firepower", "damage", "speed", "reload", "inaccuracy" } }, { 1600, new[] { "firepower", "damage", "speed", "reload", "inaccuracy" } } }; } return upgrades.Nodes.ToDictionary( kv => FieldLoader.GetValue("(key)", kv.Key), kv => FieldLoader.GetValue("(value)", kv.Value.Value)); } } public class GainsExperience : ISync { readonly Actor self; 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; foreach (var kv in info.Upgrades) nextLevel.Add(Pair.New(kv.Key * cost, kv.Value)); if (init.Contains()) GiveExperience(init.Get()); } public bool CanGainLevel { get { return Level < MaxLevel; } } public void GiveLevels(int numLevels) { var newLevel = Math.Min(Level + numLevels, MaxLevel); GiveExperience(nextLevel[newLevel - 1].First - experience); } public void GiveExperience(int amount) { experience += amount; 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)); }); } } } } class ExperienceInit : IActorInit { [FieldFromYamlKey] public readonly int value = 0; public ExperienceInit() { } public ExperienceInit(int init) { value = init; } public int Value(World world) { return value; } } }