#region Copyright & License Information /* * Copyright 2007-2015 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.Drawing; using System.Linq; using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.RA.Traits { [Desc("Overrides the default ToolTip when this actor is disguised (aids in deceiving enemy players).")] class DisguiseToolTipInfo : TooltipInfo, Requires { public override object Create(ActorInitializer init) { return new DisguiseToolTip(init.Self, this); } } class DisguiseToolTip : IToolTip { readonly Actor self; readonly Disguise disguise; TooltipInfo info; public DisguiseToolTip(Actor self, TooltipInfo info) { this.self = self; this.info = info; disguise = self.Trait(); } public ITooltipInfo TooltipInfo { get { return disguise.Disguised ? disguise.AsTooltipInfo : info; } } public Player Owner { get { if (disguise.Disguised) return self.Owner == self.World.LocalPlayer ? self.Owner : disguise.AsPlayer; return self.Owner; } } } [Desc("Provides access to the disguise command, which makes the actor appear to be another player's actor.")] class DisguiseInfo : ITraitInfo { [VoiceReference] public readonly string Voice = "Action"; [UpgradeGrantedReference] [Desc("Upgrades to grant when disguised.")] public readonly string[] Upgrades = { "disguise" }; public object Create(ActorInitializer init) { return new Disguise(init.Self, this); } } class Disguise : IEffectiveOwner, IIssueOrder, IResolveOrder, IOrderVoice, IRadarColorModifier, INotifyAttack { public Player AsPlayer { get; private set; } public string AsSprite { get; private set; } public ITooltipInfo AsTooltipInfo { get; private set; } public bool Disguised { get { return AsPlayer != null; } } public Player Owner { get { return AsPlayer; } } readonly Actor self; readonly DisguiseInfo info; readonly Lazy um; public Disguise(Actor self, DisguiseInfo info) { this.self = self; this.info = info; um = Exts.Lazy(() => self.TraitOrDefault()); } public IEnumerable Orders { get { yield return new TargetTypeOrderTargeter(new[] { "Disguise" }, "Disguise", 7, "ability", true, true) { ForceAttack = false }; } } public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) { if (order.OrderID == "Disguise") return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; return null; } public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "Disguise") { var target = order.TargetActor != self && order.TargetActor.IsInWorld ? order.TargetActor : null; DisguiseAs(target); } } public string VoicePhraseForOrder(Actor self, Order order) { return order.OrderString == "Disguise" ? info.Voice : null; } public Color RadarColorOverride(Actor self) { if (!Disguised || self.Owner.IsAlliedWith(self.World.RenderPlayer)) return self.Owner.Color.RGB; return AsPlayer.Color.RGB; } void DisguiseAs(Actor target) { var oldDisguiseSetting = Disguised; var oldEffectiveOwner = AsPlayer; if (target != null) { // Take the image of the target's disguise, if it exist. // E.g., SpyA is disguised as a dog. SpyB then targets SpyA. We should use the dog image. var targetDisguise = target.TraitOrDefault(); if (targetDisguise != null && targetDisguise.Disguised) { AsSprite = targetDisguise.AsSprite; AsPlayer = targetDisguise.AsPlayer; AsTooltipInfo = targetDisguise.AsTooltipInfo; } else { AsSprite = target.Trait().GetImage(target); var tooltip = target.TraitsImplementing().FirstOrDefault(); AsPlayer = tooltip.Owner; AsTooltipInfo = tooltip.TooltipInfo; } } else { AsTooltipInfo = null; AsPlayer = null; AsSprite = null; } foreach (var t in self.TraitsImplementing()) t.OnEffectiveOwnerChanged(self, oldEffectiveOwner, AsPlayer); if (Disguised != oldDisguiseSetting && um.Value != null) { foreach (var u in info.Upgrades) { if (!um.Value.AcknowledgesUpgrade(self, u)) continue; if (Disguised) um.Value.GrantUpgrade(self, u, this); else um.Value.RevokeUpgrade(self, u, this); } } } public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { DisguiseAs(null); } } }