1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System.Collections.Generic;
13 using OpenRA.Mods.Common.Activities;
14 using OpenRA.Mods.Common.Orders;
15 using OpenRA.Primitives;
16 using OpenRA.Traits;
17 
18 namespace OpenRA.Mods.Common.Traits
19 {
20 	[Desc("This actor can grant experience levels equal to it's own current level via entering to other actors with the `AcceptsDeliveredExperience` trait.")]
21 	class DeliversExperienceInfo : ITraitInfo, Requires<GainsExperienceInfo>
22 	{
23 		[Desc("The amount of experience the donating player receives.")]
24 		public readonly int PlayerExperience = 0;
25 
26 		[Desc("Identifier checked against AcceptsDeliveredExperience.ValidTypes. Only needed if the latter is not empty.")]
27 		public readonly string Type = null;
28 
29 		[VoiceReference]
30 		public readonly string Voice = "Action";
31 
Create(ActorInitializer init)32 		public object Create(ActorInitializer init) { return new DeliversExperience(init, this); }
33 	}
34 
35 	class DeliversExperience : IIssueOrder, IResolveOrder, IOrderVoice
36 	{
37 		readonly DeliversExperienceInfo info;
38 		readonly Actor self;
39 		readonly GainsExperience gainsExperience;
40 
DeliversExperience(ActorInitializer init, DeliversExperienceInfo info)41 		public DeliversExperience(ActorInitializer init, DeliversExperienceInfo info)
42 		{
43 			this.info = info;
44 			self = init.Self;
45 			gainsExperience = self.Trait<GainsExperience>();
46 		}
47 
48 		public IEnumerable<IOrderTargeter> Orders
49 		{
50 			get
51 			{
52 				if (gainsExperience.Level != 0)
53 					yield return new DeliversExperienceOrderTargeter();
54 			}
55 		}
56 
IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)57 		public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
58 		{
59 			if (order.OrderID != "DeliverExperience")
60 				return null;
61 
62 			return new Order(order.OrderID, self, target, queued);
63 		}
64 
VoicePhraseForOrder(Actor self, Order order)65 		public string VoicePhraseForOrder(Actor self, Order order)
66 		{
67 			if (order.OrderString != "DeliverExperience")
68 				return null;
69 
70 			return info.Voice;
71 		}
72 
ResolveOrder(Actor self, Order order)73 		public void ResolveOrder(Actor self, Order order)
74 		{
75 			if (order.OrderString != "DeliverExperience")
76 				return;
77 
78 			if (order.Target.Type == TargetType.Actor)
79 			{
80 				var targetGainsExperience = order.Target.Actor.Trait<GainsExperience>();
81 				if (targetGainsExperience.Level == targetGainsExperience.MaxLevel)
82 					return;
83 			}
84 			else if (order.Target.Type != TargetType.FrozenActor)
85 				return;
86 
87 			self.QueueActivity(order.Queued, new DonateExperience(self, order.Target, gainsExperience.Level, info.PlayerExperience));
88 			self.ShowTargetLines();
89 		}
90 
91 		public class DeliversExperienceOrderTargeter : UnitOrderTargeter
92 		{
DeliversExperienceOrderTargeter()93 			public DeliversExperienceOrderTargeter()
94 				: base("DeliverExperience", 5, "enter", true, true) { }
95 
CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)96 			public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
97 			{
98 				if (target == self)
99 					return false;
100 
101 				var type = self.Info.TraitInfo<DeliversExperienceInfo>().Type;
102 				var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredExperienceInfo>();
103 				var targetGainsExperience = target.TraitOrDefault<GainsExperience>();
104 
105 				if (targetGainsExperience == null || targetInfo == null)
106 					return false;
107 
108 				if (targetGainsExperience.Level == targetGainsExperience.MaxLevel)
109 					return false;
110 
111 				return targetInfo.ValidStances.HasStance(target.Owner.Stances[self.Owner])
112 					&& (targetInfo.ValidTypes.Count == 0
113 						|| (!string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type)));
114 			}
115 
CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)116 			public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
117 			{
118 				if (target.Actor == null || target.Actor == self)
119 					return false;
120 
121 				var type = self.Info.TraitInfo<DeliversExperienceInfo>().Type;
122 				var targetInfo = target.Info.TraitInfoOrDefault<AcceptsDeliveredExperienceInfo>();
123 				var targetGainsExperience = target.Actor.TraitOrDefault<GainsExperience>();
124 
125 				if (targetGainsExperience == null || targetInfo == null)
126 					return false;
127 
128 				if (targetGainsExperience.Level == targetGainsExperience.MaxLevel)
129 					return false;
130 
131 				return targetInfo.ValidStances.HasStance(target.Owner.Stances[self.Owner])
132 					&& (targetInfo.ValidTypes.Count == 0
133 						|| (!string.IsNullOrEmpty(type) && targetInfo.ValidTypes.Contains(type)));
134 			}
135 		}
136 	}
137 }
138