diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 324674b94b..fa44f8d02b 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -245,6 +245,7 @@ + @@ -388,6 +389,7 @@ + diff --git a/OpenRA.Mods.Common/Scripting/Properties/PlayerExperienceProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/PlayerExperienceProperties.cs new file mode 100644 index 0000000000..87aae502f1 --- /dev/null +++ b/OpenRA.Mods.Common/Scripting/Properties/PlayerExperienceProperties.cs @@ -0,0 +1,43 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using Eluant; +using OpenRA.Mods.Common.Traits; +using OpenRA.Scripting; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Scripting +{ + [ScriptPropertyGroup("Player")] + public class PlayerExperienceProperties : ScriptPlayerProperties, Requires + { + readonly PlayerExperience exp; + + public PlayerExperienceProperties(ScriptContext context, Player player) + : base(context, player) + { + exp = player.PlayerActor.Trait(); + } + + public int Experience + { + get + { + return exp.Experience; + } + + set + { + exp.GiveExperience(value - exp.Experience); + } + } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.Common/Traits/GivesExperience.cs b/OpenRA.Mods.Common/Traits/GivesExperience.cs index c08d066387..14573f1d28 100644 --- a/OpenRA.Mods.Common/Traits/GivesExperience.cs +++ b/OpenRA.Mods.Common/Traits/GivesExperience.cs @@ -22,6 +22,12 @@ namespace OpenRA.Mods.Common.Traits [Desc("Stance the attacking player needs to receive the experience.")] public readonly Stance ValidStances = Stance.Neutral | Stance.Enemy; + [Desc("Percentage of the `Experience` value that is being granted to the killing actor.")] + public readonly int ActorExperienceModifier = 10000; + + [Desc("Percentage of the `Experience` value that is being granted to the player owning the killing actor.")] + public readonly int PlayerExperienceModifier = 0; + public object Create(ActorInitializer init) { return new GivesExperience(init.Self, this); } } @@ -44,14 +50,17 @@ namespace OpenRA.Mods.Common.Traits var valued = self.Info.TraitInfoOrDefault(); - // Default experience is 100 times our value var exp = info.Experience >= 0 ? info.Experience - : valued != null ? valued.Cost * 100 : 0; + : valued != null ? valued.Cost : 0; var killer = e.Attacker.TraitOrDefault(); if (killer != null) - killer.GiveExperience(exp); + killer.GiveExperience(Util.ApplyPercentageModifiers(exp, new[] { info.ActorExperienceModifier })); + + var attackerExp = e.Attacker.Owner.PlayerActor.TraitOrDefault(); + if (attackerExp != null) + attackerExp.GiveExperience(Util.ApplyPercentageModifiers(exp, new[] { info.PlayerExperienceModifier })); } } } diff --git a/OpenRA.Mods.Common/Traits/Player/PlayerExperience.cs b/OpenRA.Mods.Common/Traits/Player/PlayerExperience.cs new file mode 100644 index 0000000000..a632787f26 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Player/PlayerExperience.cs @@ -0,0 +1,35 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("This trait can be used to track player experience based on units killed with the `GivesExperience` trait.", + "It can also be used as a point score system in scripted maps, for example.", + "Attach this to the player actor.")] + public class PlayerExperienceInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new PlayerExperience(); } + } + + public class PlayerExperience : ISync + { + [Sync] public int Experience { get; private set; } + + public void GiveExperience(int num) + { + Experience += num; + } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.Common/Traits/Player/PlayerStatistics.cs b/OpenRA.Mods.Common/Traits/Player/PlayerStatistics.cs index c8e34a01d8..ab6aa46eca 100644 --- a/OpenRA.Mods.Common/Traits/Player/PlayerStatistics.cs +++ b/OpenRA.Mods.Common/Traits/Player/PlayerStatistics.cs @@ -20,10 +20,10 @@ namespace OpenRA.Mods.Common.Traits public object Create(ActorInitializer init) { return new PlayerStatistics(init.Self); } } - public class PlayerStatistics : ITick, IResolveOrder + public class PlayerStatistics : ITick, IResolveOrder, INotifyCreated { - World world; - Player player; + PlayerResources resources; + PlayerExperience experience; public int OrderCount; @@ -31,7 +31,15 @@ namespace OpenRA.Mods.Common.Traits { get { - return player.PlayerActor.Trait().Earned - earnedAtBeginningOfMinute; + return resources != null ? resources.Earned - earnedAtBeginningOfMinute : 0; + } + } + + public int Experience + { + get + { + return experience != null ? experience.Experience : 0; } } @@ -47,23 +55,25 @@ namespace OpenRA.Mods.Common.Traits public int BuildingsKilled; public int BuildingsDead; - public PlayerStatistics(Actor self) + public PlayerStatistics(Actor self) { } + + void INotifyCreated.Created(Actor self) { - world = self.World; - player = self.Owner; + resources = self.TraitOrDefault(); + experience = self.TraitOrDefault(); } void UpdateEarnedThisMinute() { EarnedSamples.Enqueue(EarnedThisMinute); - earnedAtBeginningOfMinute = player.PlayerActor.Trait().Earned; + earnedAtBeginningOfMinute = resources != null ? resources.Earned : 0; if (EarnedSamples.Count > 100) EarnedSamples.Dequeue(); } public void Tick(Actor self) { - if (world.WorldTick % 1500 == 1) + if (self.World.WorldTick % 1500 == 1) UpdateEarnedThisMinute(); }