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 OpenRA.Traits; 13 14 namespace OpenRA.Mods.Common.Traits 15 { 16 [Desc("Applies a condition to the actor at when its health is between 2 specific values.")] 17 public class GrantConditionOnHealthInfo : ITraitInfo, IRulesetLoaded, Requires<IHealthInfo> 18 { 19 [FieldLoader.Require] 20 [GrantedConditionReference] 21 [Desc("Condition to grant.")] 22 public readonly string Condition = null; 23 24 [Desc("Play a random sound from this list when enabled.")] 25 public readonly string[] EnabledSounds = { }; 26 27 [Desc("Play a random sound from this list when disabled.")] 28 public readonly string[] DisabledSounds = { }; 29 30 [Desc("Minimum level of health at which to grant the condition.")] 31 public readonly int MinHP = 0; 32 33 [Desc("Maximum level of health at which to grant the condition.", 34 "Non-positive values will make it use Health.HP.")] 35 public readonly int MaxHP = 0; 36 37 [Desc("Is the condition irrevokable once it has been granted?")] 38 public readonly bool GrantPermanently = false; 39 Create(ActorInitializer init)40 public object Create(ActorInitializer init) { return new GrantConditionOnHealth(init.Self, this); } 41 RulesetLoaded(Ruleset rules, ActorInfo ai)42 public void RulesetLoaded(Ruleset rules, ActorInfo ai) 43 { 44 var health = ai.TraitInfo<IHealthInfo>(); 45 if (health.MaxHP < MinHP) 46 throw new YamlException("Minimum HP ({0}) for GrantConditionOnHealth can't be more than actor's Maximum HP ({1})".F(MinHP, health.MaxHP)); 47 } 48 } 49 50 public class GrantConditionOnHealth : INotifyCreated, INotifyDamage 51 { 52 readonly GrantConditionOnHealthInfo info; 53 readonly IHealth health; 54 readonly int maxHP; 55 56 ConditionManager conditionManager; 57 int conditionToken = ConditionManager.InvalidConditionToken; 58 GrantConditionOnHealth(Actor self, GrantConditionOnHealthInfo info)59 public GrantConditionOnHealth(Actor self, GrantConditionOnHealthInfo info) 60 { 61 this.info = info; 62 health = self.Trait<IHealth>(); 63 maxHP = info.MaxHP > 0 ? info.MaxHP : health.MaxHP; 64 } 65 INotifyCreated.Created(Actor self)66 void INotifyCreated.Created(Actor self) 67 { 68 conditionManager = self.Trait<ConditionManager>(); 69 GrantConditionOnValidHealth(self, health.HP); 70 } 71 GrantConditionOnValidHealth(Actor self, int hp)72 void GrantConditionOnValidHealth(Actor self, int hp) 73 { 74 if (info.MinHP > hp || maxHP < hp || conditionToken != ConditionManager.InvalidConditionToken) 75 return; 76 77 conditionToken = conditionManager.GrantCondition(self, info.Condition); 78 79 var sound = info.EnabledSounds.RandomOrDefault(Game.CosmeticRandom); 80 Game.Sound.Play(SoundType.World, sound, self.CenterPosition); 81 } 82 INotifyDamage.Damaged(Actor self, AttackInfo e)83 void INotifyDamage.Damaged(Actor self, AttackInfo e) 84 { 85 var granted = conditionToken != ConditionManager.InvalidConditionToken; 86 if (granted && info.GrantPermanently) 87 return; 88 89 if (!granted) 90 GrantConditionOnValidHealth(self, health.HP); 91 else if (granted && (info.MinHP > health.HP || maxHP < health.HP)) 92 { 93 conditionToken = conditionManager.RevokeCondition(self, conditionToken); 94 95 var sound = info.DisabledSounds.RandomOrDefault(Game.CosmeticRandom); 96 Game.Sound.Play(SoundType.World, sound, self.CenterPosition); 97 } 98 } 99 } 100 } 101