Merge pull request #7282 from penev92/bleed_moveFiles
Move more traits to Mods.Common
This commit is contained in:
@@ -1,79 +0,0 @@
|
||||
#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 OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Mods.RA.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class CaptureActor : Enter
|
||||
{
|
||||
readonly Actor actor;
|
||||
readonly Capturable capturable;
|
||||
readonly CapturesInfo capturesInfo;
|
||||
|
||||
public CaptureActor(Actor self, Actor target)
|
||||
: base(self, target)
|
||||
{
|
||||
actor = target;
|
||||
capturesInfo = self.Info.Traits.Get<CapturesInfo>();
|
||||
capturable = target.Trait<Capturable>();
|
||||
}
|
||||
|
||||
protected override bool CanReserve(Actor self)
|
||||
{
|
||||
return !capturable.BeingCaptured && capturable.Info.CanBeTargetedBy(self, actor.Owner);
|
||||
}
|
||||
|
||||
protected override void OnInside(Actor self)
|
||||
{
|
||||
if (actor.IsDead || capturable.BeingCaptured)
|
||||
return;
|
||||
|
||||
var b = actor.TraitOrDefault<Building>();
|
||||
if (b != null && !b.Lock())
|
||||
return;
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (b != null && b.Locked)
|
||||
b.Unlock();
|
||||
|
||||
if (actor.IsDead || capturable.BeingCaptured)
|
||||
return;
|
||||
|
||||
var health = actor.Trait<Health>();
|
||||
|
||||
var lowEnoughHealth = health.HP <= capturable.Info.CaptureThreshold * health.MaxHP;
|
||||
if (!capturesInfo.Sabotage || lowEnoughHealth || actor.Owner.NonCombatant)
|
||||
{
|
||||
var oldOwner = actor.Owner;
|
||||
|
||||
actor.ChangeOwner(self.Owner);
|
||||
|
||||
foreach (var t in actor.TraitsImplementing<INotifyCapture>())
|
||||
t.OnCapture(actor, self, oldOwner, self.Owner);
|
||||
|
||||
if (b != null && b.Locked)
|
||||
b.Unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
var damage = (int)(health.MaxHP * capturesInfo.SabotageHPRemoval);
|
||||
actor.InflictDamage(self, damage, null);
|
||||
}
|
||||
|
||||
self.Destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#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 OpenRA.Activities;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Mods.RA.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class ExternalCaptureActor : Activity
|
||||
{
|
||||
Target target;
|
||||
|
||||
public ExternalCaptureActor(Target target) { this.target = target; }
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (target.Type != TargetType.Actor)
|
||||
return NextActivity;
|
||||
|
||||
var capturable = target.Actor.Trait<ExternalCapturable>();
|
||||
|
||||
if (IsCanceled || !self.IsInWorld || self.IsDead || !target.IsValidFor(self))
|
||||
{
|
||||
if (capturable.CaptureInProgress)
|
||||
capturable.EndCapture();
|
||||
|
||||
return NextActivity;
|
||||
}
|
||||
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var nearest = target.Actor.OccupiesSpace.NearestCellTo(mobile.ToCell);
|
||||
|
||||
if ((nearest - mobile.ToCell).LengthSquared > 2)
|
||||
return Util.SequenceActivities(new MoveAdjacentTo(self, target), this);
|
||||
|
||||
if (!capturable.CaptureInProgress)
|
||||
capturable.BeginCapture(self);
|
||||
else
|
||||
{
|
||||
if (capturable.Captor != self) return NextActivity;
|
||||
|
||||
if (capturable.CaptureProgressTime % 25 == 0)
|
||||
{
|
||||
self.World.Add(new FlashTarget(target.Actor, self.Owner));
|
||||
self.World.Add(new FlashTarget(self));
|
||||
}
|
||||
|
||||
if (capturable.CaptureProgressTime == capturable.Info.CaptureCompleteTime * 25)
|
||||
{
|
||||
var capturesInfo = self.Info.Traits.Get<ExternalCapturesInfo>();
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (target.Actor.IsDead)
|
||||
return;
|
||||
|
||||
var oldOwner = target.Actor.Owner;
|
||||
|
||||
target.Actor.ChangeOwner(self.Owner);
|
||||
|
||||
foreach (var t in target.Actor.TraitsImplementing<INotifyCapture>())
|
||||
t.OnCapture(target.Actor, self, oldOwner, self.Owner);
|
||||
|
||||
capturable.EndCapture();
|
||||
|
||||
if (capturesInfo != null && capturesInfo.ConsumeActor)
|
||||
self.Destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#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 OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.RA.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class RepairBridge : Enter
|
||||
{
|
||||
readonly BridgeHut hut;
|
||||
|
||||
public RepairBridge(Actor self, Actor target)
|
||||
: base(self, target)
|
||||
{
|
||||
hut = target.Trait<BridgeHut>();
|
||||
}
|
||||
|
||||
protected override bool CanReserve(Actor self)
|
||||
{
|
||||
return hut.BridgeDamageState != DamageState.Undamaged && !hut.Repairing && hut.Bridge.GetHut(0) != null && hut.Bridge.GetHut(1) != null;
|
||||
}
|
||||
|
||||
protected override void OnInside(Actor self)
|
||||
{
|
||||
if (hut.BridgeDamageState == DamageState.Undamaged || hut.Repairing || hut.Bridge.GetHut(0) == null || hut.Bridge.GetHut(1) == null)
|
||||
return;
|
||||
hut.Repair(self);
|
||||
self.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
#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.Linq;
|
||||
using OpenRA.Activities;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class Transform : Activity
|
||||
{
|
||||
public readonly string ToActor;
|
||||
public CVec Offset = CVec.Zero;
|
||||
public int Facing = 96;
|
||||
public string[] Sounds = { };
|
||||
public int ForceHealthPercentage = 0;
|
||||
public bool SkipMakeAnims = false;
|
||||
public string Race = null;
|
||||
|
||||
public Transform(Actor self, string toActor)
|
||||
{
|
||||
ToActor = toActor;
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled)
|
||||
return NextActivity;
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (self.IsDead)
|
||||
return;
|
||||
|
||||
foreach (var nt in self.TraitsImplementing<INotifyTransform>())
|
||||
nt.OnTransform(self);
|
||||
|
||||
var selected = w.Selection.Contains(self);
|
||||
var controlgroup = w.Selection.GetControlGroupForActor(self);
|
||||
|
||||
self.Destroy();
|
||||
foreach (var s in Sounds)
|
||||
Sound.PlayToPlayer(self.Owner, s, self.CenterPosition);
|
||||
|
||||
var init = new TypeDictionary
|
||||
{
|
||||
new LocationInit(self.Location + Offset),
|
||||
new OwnerInit(self.Owner),
|
||||
new FacingInit(Facing),
|
||||
};
|
||||
|
||||
if (SkipMakeAnims)
|
||||
init.Add(new SkipMakeAnimsInit());
|
||||
|
||||
if (Race != null)
|
||||
init.Add(new RaceInit(Race));
|
||||
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if (health != null)
|
||||
{
|
||||
var newHP = (ForceHealthPercentage > 0)
|
||||
? ForceHealthPercentage / 100f
|
||||
: (float)health.HP / health.MaxHP;
|
||||
|
||||
init.Add(new HealthInit(newHP));
|
||||
}
|
||||
|
||||
var cargo = self.TraitOrDefault<Cargo>();
|
||||
if (cargo != null)
|
||||
init.Add(new RuntimeCargoInit(cargo.Passengers.ToArray()));
|
||||
|
||||
var a = w.CreateActor(ToActor, init);
|
||||
foreach (var nt in self.TraitsImplementing<INotifyTransform>())
|
||||
nt.AfterTransform(a);
|
||||
|
||||
if (selected)
|
||||
w.Selection.Add(w, a);
|
||||
if (controlgroup.HasValue)
|
||||
w.Selection.AddToControlGroup(a, controlgroup.Value);
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
#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.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("This actor can be captured by a unit with Captures: trait.")]
|
||||
class CapturableInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Type listed under Types in Captures: trait of actors that can capture this).")]
|
||||
public readonly string Type = "building";
|
||||
public readonly bool AllowAllies = false;
|
||||
public readonly bool AllowNeutral = true;
|
||||
public readonly bool AllowEnemies = true;
|
||||
[Desc("Health percentage the target must be at (or below) before it can be captured.")]
|
||||
public readonly float CaptureThreshold = 0.5f;
|
||||
public readonly bool CancelActivity = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new Capturable(this); }
|
||||
|
||||
public bool CanBeTargetedBy(Actor captor, Player owner)
|
||||
{
|
||||
var c = captor.TraitOrDefault<Captures>();
|
||||
if (c == null)
|
||||
return false;
|
||||
|
||||
var playerRelationship = owner.Stances[captor.Owner];
|
||||
if (playerRelationship == Stance.Ally && !AllowAllies)
|
||||
return false;
|
||||
|
||||
if (playerRelationship == Stance.Enemy && !AllowEnemies)
|
||||
return false;
|
||||
|
||||
if (playerRelationship == Stance.Neutral && !AllowNeutral)
|
||||
return false;
|
||||
|
||||
if (!c.Info.CaptureTypes.Contains(Type))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class Capturable : INotifyCapture
|
||||
{
|
||||
public readonly CapturableInfo Info;
|
||||
public bool BeingCaptured { get; private set; }
|
||||
public Capturable(CapturableInfo info) { Info = info; }
|
||||
|
||||
public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner)
|
||||
{
|
||||
BeingCaptured = true;
|
||||
self.World.AddFrameEndTask(w => BeingCaptured = false);
|
||||
|
||||
if (Info.CancelActivity)
|
||||
{
|
||||
var stop = new Order("Stop", self, false);
|
||||
foreach (var t in self.TraitsImplementing<IResolveOrder>())
|
||||
t.ResolveOrder(self, stop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#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 OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
class CaptureNotificationInfo : ITraitInfo
|
||||
{
|
||||
public readonly string Notification = "BuildingCaptured";
|
||||
public readonly bool NewOwnerVoice = true;
|
||||
|
||||
public object Create(ActorInitializer init) { return new CaptureNotification(this); }
|
||||
}
|
||||
|
||||
class CaptureNotification : INotifyCapture
|
||||
{
|
||||
CaptureNotificationInfo info;
|
||||
public CaptureNotification(CaptureNotificationInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner)
|
||||
{
|
||||
if (captor.World.LocalPlayer != captor.Owner)
|
||||
return;
|
||||
|
||||
var race = info.NewOwnerVoice ? newOwner.Country.Race : oldOwner.Country.Race;
|
||||
Sound.PlayNotification(self.World.Map.Rules, captor.World.LocalPlayer, "Speech", info.Notification, race);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Mods.Common;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("This actor can capture other actors which have the Capturable: trait.")]
|
||||
class CapturesInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Types of actors that it can capture, as long as the type also exists in the Capturable Type: trait.")]
|
||||
public readonly string[] CaptureTypes = { "building" };
|
||||
[Desc("Unit will do damage to the actor instead of capturing it. Unit is destroyed when sabotaging.")]
|
||||
public readonly bool Sabotage = true;
|
||||
[Desc("Only used if Sabotage=true. Sabotage damage expressed as a percentage of enemy health removed.")]
|
||||
public readonly float SabotageHPRemoval = 0.5f;
|
||||
|
||||
public object Create(ActorInitializer init) { return new Captures(init.Self, this); }
|
||||
}
|
||||
|
||||
class Captures : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public readonly CapturesInfo Info;
|
||||
|
||||
public Captures(Actor self, CapturesInfo info)
|
||||
{
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new CaptureOrderTargeter(Info.Sabotage);
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
{
|
||||
if (order.OrderID != "CaptureActor")
|
||||
return null;
|
||||
|
||||
if (target.Type == TargetType.FrozenActor)
|
||||
return new Order(order.OrderID, self, queued) { ExtraData = target.FrozenActor.ID };
|
||||
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return order.OrderString == "CaptureActor" ? "Attack" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "CaptureActor")
|
||||
return;
|
||||
|
||||
var target = self.ResolveFrozenActorOrder(order, Color.Red);
|
||||
if (target.Type != TargetType.Actor)
|
||||
return;
|
||||
|
||||
if (!order.Queued)
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(target, Color.Red);
|
||||
self.QueueActivity(new CaptureActor(self, target.Actor));
|
||||
}
|
||||
|
||||
class CaptureOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
readonly bool sabotage;
|
||||
|
||||
public CaptureOrderTargeter(bool sabotage)
|
||||
: base("CaptureActor", 6, "enter", true, true)
|
||||
{
|
||||
this.sabotage = sabotage;
|
||||
}
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var c = target.Info.Traits.GetOrDefault<CapturableInfo>();
|
||||
if (c == null || !c.CanBeTargetedBy(self, target.Owner))
|
||||
{
|
||||
cursor = "enter-blocked";
|
||||
return false;
|
||||
}
|
||||
|
||||
var health = target.Trait<Health>();
|
||||
var lowEnoughHealth = health.HP <= c.CaptureThreshold * health.MaxHP;
|
||||
|
||||
cursor = !sabotage || lowEnoughHealth || target.Owner.NonCombatant
|
||||
? "enter" : "capture";
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var c = target.Info.Traits.GetOrDefault<CapturableInfo>();
|
||||
if (c == null || !c.CanBeTargetedBy(self, target.Owner))
|
||||
{
|
||||
cursor = "enter-blocked";
|
||||
return false;
|
||||
}
|
||||
|
||||
var health = target.Info.Traits.GetOrDefault<HealthInfo>();
|
||||
var lowEnoughHealth = target.HP <= c.CaptureThreshold * health.HP;
|
||||
|
||||
cursor = !sabotage || lowEnoughHealth || target.Owner.NonCombatant
|
||||
? "enter" : "capture";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.RA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Effects
|
||||
{
|
||||
class RepairIndicator : IEffect
|
||||
{
|
||||
readonly Actor building;
|
||||
readonly string palettePrefix;
|
||||
readonly Animation anim;
|
||||
readonly RepairableBuilding rb;
|
||||
int shownPlayer = 0;
|
||||
|
||||
public RepairIndicator(Actor building, string palettePrefix)
|
||||
{
|
||||
this.building = building;
|
||||
this.palettePrefix = palettePrefix;
|
||||
|
||||
rb = building.TraitOrDefault<RepairableBuilding>();
|
||||
anim = new Animation(building.World, "allyrepair");
|
||||
anim.Paused = () => !rb.RepairActive || rb.IsTraitDisabled;
|
||||
|
||||
CycleRepairer();
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
if (!building.IsInWorld || building.IsDead ||
|
||||
rb == null || !rb.Repairers.Any())
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
|
||||
anim.Tick();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (building.Destroyed || wr.World.FogObscures(building) || rb.Repairers.Count == 0)
|
||||
return SpriteRenderable.None;
|
||||
|
||||
var palette = wr.Palette(palettePrefix + rb.Repairers[shownPlayer % rb.Repairers.Count].InternalName);
|
||||
return anim.Render(building.CenterPosition, palette);
|
||||
}
|
||||
|
||||
void CycleRepairer()
|
||||
{
|
||||
anim.PlayThen("repair", CycleRepairer);
|
||||
|
||||
if (++shownPlayer == rb.Repairers.Count)
|
||||
shownPlayer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#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.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("This actor can be captured by a unit with ExternalCaptures: trait.")]
|
||||
public class ExternalCapturableInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Type of actor (the ExternalCaptures: trait defines what Types it can capture).")]
|
||||
public readonly string Type = "building";
|
||||
public readonly bool AllowAllies = false;
|
||||
public readonly bool AllowNeutral = true;
|
||||
public readonly bool AllowEnemies = true;
|
||||
[Desc("Seconds it takes to change the owner.", "You might want to add a ExternalCapturableBar: trait, too.")]
|
||||
public readonly int CaptureCompleteTime = 15;
|
||||
|
||||
public bool CanBeTargetedBy(Actor captor, Player owner)
|
||||
{
|
||||
var c = captor.TraitOrDefault<ExternalCaptures>();
|
||||
if (c == null)
|
||||
return false;
|
||||
|
||||
var playerRelationship = owner.Stances[captor.Owner];
|
||||
if (playerRelationship == Stance.Ally && !AllowAllies)
|
||||
return false;
|
||||
|
||||
if (playerRelationship == Stance.Enemy && !AllowEnemies)
|
||||
return false;
|
||||
|
||||
if (playerRelationship == Stance.Neutral && !AllowNeutral)
|
||||
return false;
|
||||
|
||||
if (!c.Info.CaptureTypes.Contains(Type))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public object Create(ActorInitializer init) { return new ExternalCapturable(init.Self, this); }
|
||||
}
|
||||
|
||||
public class ExternalCapturable : ITick
|
||||
{
|
||||
[Sync] public int CaptureProgressTime = 0;
|
||||
[Sync] public Actor Captor;
|
||||
private Actor self;
|
||||
public ExternalCapturableInfo Info;
|
||||
public bool CaptureInProgress { get { return Captor != null; } }
|
||||
|
||||
public ExternalCapturable(Actor self, ExternalCapturableInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public void BeginCapture(Actor captor)
|
||||
{
|
||||
var building = self.TraitOrDefault<Building>();
|
||||
if (building != null)
|
||||
building.Lock();
|
||||
|
||||
Captor = captor;
|
||||
}
|
||||
|
||||
public void EndCapture()
|
||||
{
|
||||
var building = self.TraitOrDefault<Building>();
|
||||
if (building != null)
|
||||
building.Unlock();
|
||||
|
||||
Captor = null;
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (Captor != null && (!Captor.IsInWorld || Captor.IsDead))
|
||||
EndCapture();
|
||||
|
||||
if (!CaptureInProgress)
|
||||
CaptureProgressTime = 0;
|
||||
else
|
||||
CaptureProgressTime++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#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.Drawing;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("Visualize the remaining CaptureCompleteTime from ExternalCapturable: trait.")]
|
||||
class ExternalCapturableBarInfo : ITraitInfo, Requires<ExternalCapturableInfo>
|
||||
{
|
||||
public object Create(ActorInitializer init) { return new ExternalCapturableBar(init.Self); }
|
||||
}
|
||||
|
||||
class ExternalCapturableBar : ISelectionBar
|
||||
{
|
||||
ExternalCapturable cap;
|
||||
|
||||
public ExternalCapturableBar(Actor self)
|
||||
{
|
||||
this.cap = self.Trait<ExternalCapturable>();
|
||||
}
|
||||
|
||||
public float GetValue()
|
||||
{
|
||||
// only show when building is being captured
|
||||
if (!cap.CaptureInProgress)
|
||||
return 0f;
|
||||
|
||||
return (float)cap.CaptureProgressTime / (cap.Info.CaptureCompleteTime * 25);
|
||||
}
|
||||
|
||||
public Color GetColor() { return Color.Orange; }
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Mods.Common;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("This actor can capture other actors which have the ExternalCapturable: trait.")]
|
||||
class ExternalCapturesInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Types of actors that it can capture, as long as the type also exists in the ExternalCapturable Type: trait.")]
|
||||
public readonly string[] CaptureTypes = { "building" };
|
||||
[Desc("Destroy the unit after capturing.")]
|
||||
public readonly bool ConsumeActor = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new ExternalCaptures(init.Self, this); }
|
||||
}
|
||||
|
||||
class ExternalCaptures : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public readonly ExternalCapturesInfo Info;
|
||||
|
||||
public ExternalCaptures(Actor self, ExternalCapturesInfo info)
|
||||
{
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new ExternalCaptureOrderTargeter();
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
{
|
||||
if (order.OrderID != "ExternalCaptureActor")
|
||||
return null;
|
||||
|
||||
if (target.Type == TargetType.FrozenActor)
|
||||
return new Order(order.OrderID, self, queued) { ExtraData = target.FrozenActor.ID };
|
||||
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
}
|
||||
|
||||
static bool IsValidOrder(Actor self, Order order)
|
||||
{
|
||||
// Not targeting an actor
|
||||
if (order.ExtraData == 0 && order.TargetActor == null)
|
||||
return false;
|
||||
|
||||
if (order.ExtraData != 0)
|
||||
{
|
||||
// Targeted an actor under the fog
|
||||
var frozenLayer = self.Owner.PlayerActor.TraitOrDefault<FrozenActorLayer>();
|
||||
if (frozenLayer == null)
|
||||
return false;
|
||||
|
||||
var frozen = frozenLayer.FromID(order.ExtraData);
|
||||
if (frozen == null)
|
||||
return false;
|
||||
|
||||
var ci = frozen.Info.Traits.GetOrDefault<ExternalCapturableInfo>();
|
||||
return ci != null && ci.CanBeTargetedBy(self, frozen.Owner);
|
||||
}
|
||||
|
||||
var c = order.TargetActor.TraitOrDefault<ExternalCapturable>();
|
||||
return c != null && !c.CaptureInProgress && c.Info.CanBeTargetedBy(self, order.TargetActor.Owner);
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return order.OrderString == "ExternalCaptureActor" && IsValidOrder(self, order)
|
||||
? "Attack" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "ExternalCaptureActor" || !IsValidOrder(self, order))
|
||||
return;
|
||||
|
||||
var target = self.ResolveFrozenActorOrder(order, Color.Red);
|
||||
if (target.Type != TargetType.Actor)
|
||||
return;
|
||||
|
||||
if (!order.Queued)
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(target, Color.Red);
|
||||
self.QueueActivity(new ExternalCaptureActor(target));
|
||||
}
|
||||
}
|
||||
|
||||
class ExternalCaptureOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
public ExternalCaptureOrderTargeter() : base("ExternalCaptureActor", 6, "enter", true, true) { }
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var c = target.TraitOrDefault<ExternalCapturable>();
|
||||
|
||||
var canTargetActor = c != null && !c.CaptureInProgress && c.Info.CanBeTargetedBy(self, target.Owner);
|
||||
cursor = canTargetActor ? "ability" : "move-blocked";
|
||||
return canTargetActor;
|
||||
}
|
||||
|
||||
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var c = target.Info.Traits.GetOrDefault<ExternalCapturableInfo>();
|
||||
|
||||
var canTargetActor = c != null && c.CanBeTargetedBy(self, target.Owner);
|
||||
cursor = canTargetActor ? "ability" : "move-blocked";
|
||||
return canTargetActor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,14 +78,11 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Activities\CaptureActor.cs" />
|
||||
<Compile Include="AI\AttackOrFleeFuzzy.cs" />
|
||||
<Compile Include="AI\BaseBuilder.cs" />
|
||||
<Compile Include="AI\HackyAI.cs" />
|
||||
<Compile Include="Player\AllyRepair.cs" />
|
||||
<Compile Include="Render\WithIdleOverlay.cs" />
|
||||
<Compile Include="Traits\AcceptsSupplies.cs" />
|
||||
<Compile Include="Activities\ExternalCaptureActor.cs" />
|
||||
<Compile Include="Activities\DeliverResources.cs" />
|
||||
<Compile Include="Activities\Demolish.cs" />
|
||||
<Compile Include="Activities\DonateSupplies.cs" />
|
||||
@@ -95,7 +92,6 @@
|
||||
<Compile Include="Activities\Leap.cs" />
|
||||
<Compile Include="Activities\RAHarvesterDockSequence.cs" />
|
||||
<Compile Include="Activities\Teleport.cs" />
|
||||
<Compile Include="Activities\Transform.cs" />
|
||||
<Compile Include="AI\SupportPowerDecision.cs" />
|
||||
<Compile Include="Effects\GpsSatellite.cs" />
|
||||
<Compile Include="Effects\SatelliteLaunch.cs" />
|
||||
@@ -106,13 +102,8 @@
|
||||
<Compile Include="AI\RushFuzzy.cs" />
|
||||
<Compile Include="AI\StateMachine.cs" />
|
||||
<Compile Include="Traits\Attack\AttackLeap.cs" />
|
||||
<Compile Include="CaptureNotification.cs" />
|
||||
<Compile Include="Scripting\Properties\RepairableBuildingProperties.cs" />
|
||||
<Compile Include="C4Demolition.cs" />
|
||||
<Compile Include="ExternalCapturable.cs" />
|
||||
<Compile Include="ExternalCapturableBar.cs" />
|
||||
<Compile Include="Capturable.cs" />
|
||||
<Compile Include="ExternalCaptures.cs" />
|
||||
<Compile Include="Traits\PaletteEffects\ChronoshiftPaletteEffect.cs" />
|
||||
<Compile Include="Traits\Chronoshiftable.cs" />
|
||||
<Compile Include="CrateSpawner.cs" />
|
||||
@@ -132,10 +123,8 @@
|
||||
<Compile Include="Traits\DemoTruck.cs" />
|
||||
<Compile Include="Effects\GpsDot.cs" />
|
||||
<Compile Include="Effects\Parachute.cs" />
|
||||
<Compile Include="Effects\RepairIndicator.cs" />
|
||||
<Compile Include="EmitInfantryOnSell.cs" />
|
||||
<Compile Include="Invulnerable.cs" />
|
||||
<Compile Include="Captures.cs" />
|
||||
<Compile Include="Lint\CheckActorReferences.cs" />
|
||||
<Compile Include="Lint\CheckSyncAnnotations.cs" />
|
||||
<Compile Include="Lint\CheckTraitPrerequisites.cs" />
|
||||
@@ -145,7 +134,6 @@
|
||||
<Compile Include="Traits\Minelayer.cs" />
|
||||
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
|
||||
<Compile Include="Orders\GlobalButtonOrderGenerator.cs" />
|
||||
<Compile Include="Orders\RepairOrderGenerator.cs" />
|
||||
<Compile Include="ParaDrop.cs" />
|
||||
<Compile Include="Player\ClassicProductionQueue.cs" />
|
||||
<Compile Include="Player\PlaceBuilding.cs" />
|
||||
@@ -155,15 +143,11 @@
|
||||
<Compile Include="Widgets\Logic\TabCompletionLogic.cs" />
|
||||
<Compile Include="Production.cs" />
|
||||
<Compile Include="ProductionBar.cs" />
|
||||
<Compile Include="ProximityCaptor.cs" />
|
||||
<Compile Include="ProximityCapturable.cs" />
|
||||
<Compile Include="Traits\Render\RenderJammerCircle.cs" />
|
||||
<Compile Include="Render\RenderBuildingWarFactory.cs" />
|
||||
<Compile Include="Render\RenderHarvester.cs" />
|
||||
<Compile Include="Render\RenderDisguise.cs" />
|
||||
<Compile Include="Render\RenderLandingCraft.cs" />
|
||||
<Compile Include="Repairable.cs" />
|
||||
<Compile Include="RepairableNear.cs" />
|
||||
<Compile Include="Disguise.cs" />
|
||||
<Compile Include="Traits\SupplyTruck.cs" />
|
||||
<Compile Include="SupportPowers\AirstrikePower.cs" />
|
||||
@@ -175,19 +159,13 @@
|
||||
<Compile Include="SupportPowers\SupportPowerChargeBar.cs" />
|
||||
<Compile Include="SupportPowers\SupportPowerManager.cs" />
|
||||
<Compile Include="TraitsInterfaces.cs" />
|
||||
<Compile Include="Traits\Buildings\Bridge.cs" />
|
||||
<Compile Include="Traits\Buildings\BridgeHut.cs" />
|
||||
<Compile Include="Traits\Buildings\Fake.cs" />
|
||||
<Compile Include="Traits\Buildings\OreRefinery.cs" />
|
||||
<Compile Include="Traits\Buildings\PrimaryBuilding.cs" />
|
||||
<Compile Include="Traits\Buildings\RepairableBuilding.cs" />
|
||||
<Compile Include="Traits\Harvester.cs" />
|
||||
<Compile Include="Traits\HarvesterHuskModifier.cs" />
|
||||
<Compile Include="Traits\LeavesHusk.cs" />
|
||||
<Compile Include="Traits\RepairsBridges.cs" />
|
||||
<Compile Include="Traits\TargetableSubmarine.cs" />
|
||||
<Compile Include="Traits\World\BridgeLayer.cs" />
|
||||
<Compile Include="TransformOnCapture.cs" />
|
||||
<Compile Include="TransformOnPassenger.cs" />
|
||||
<Compile Include="Transforms.cs" />
|
||||
<Compile Include="Widgets\Logic\KickSpectatorsLogic.cs" />
|
||||
@@ -228,7 +206,6 @@
|
||||
<Compile Include="Traits\Infiltration\InfiltrateForSupportPower.cs" />
|
||||
<Compile Include="Traits\Infiltration\Infiltrates.cs" />
|
||||
<Compile Include="Widgets\Logic\ObserverShroudSelectorLogic.cs" />
|
||||
<Compile Include="Activities\RepairBridge.cs" />
|
||||
<Compile Include="Lint\CheckSequences.cs" />
|
||||
<Compile Include="Widgets\Logic\SpawnSelectorTooltipLogic.cs" />
|
||||
<Compile Include="Widgets\Logic\ClientTooltipLogic.cs" />
|
||||
@@ -257,8 +234,6 @@
|
||||
<Compile Include="Scripting\Properties\PlayerProperties.cs" />
|
||||
<Compile Include="Scripting\Properties\TransportProperties.cs" />
|
||||
<Compile Include="Scripting\Properties\ChronosphereProperties.cs" />
|
||||
<Compile Include="Render\WithRepairAnimation.cs" />
|
||||
<Compile Include="Render\WithRepairOverlay.cs" />
|
||||
<Compile Include="Lint\CheckPlayers.cs" />
|
||||
<Compile Include="Lint\CheckActors.cs" />
|
||||
<Compile Include="Lint\CheckMapCordon.cs" />
|
||||
@@ -344,5 +319,4 @@ cd "$(SolutionDir)thirdparty/"
|
||||
copy "FuzzyLogicLibrary.dll" "$(SolutionDir)"
|
||||
cd "$(SolutionDir)"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
@@ -1,64 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common;
|
||||
using OpenRA.Mods.RA.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Orders
|
||||
{
|
||||
public class RepairOrderGenerator : IOrderGenerator
|
||||
{
|
||||
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Right)
|
||||
world.CancelInputMode();
|
||||
|
||||
return OrderInner(world, mi);
|
||||
}
|
||||
|
||||
IEnumerable<Order> OrderInner(World world, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Left)
|
||||
{
|
||||
var underCursor = world.ScreenMap.ActorsAt(mi)
|
||||
.FirstOrDefault(a => !world.FogObscures(a) && a.AppearsFriendlyTo(world.LocalPlayer.PlayerActor)
|
||||
&& a.TraitsImplementing<RepairableBuilding>().Any(t => !t.IsTraitDisabled));
|
||||
|
||||
if (underCursor == null)
|
||||
yield break;
|
||||
|
||||
if (underCursor.Info.Traits.Contains<RepairableBuildingInfo>()
|
||||
&& underCursor.GetDamageState() > DamageState.Undamaged)
|
||||
yield return new Order("RepairBuilding", world.LocalPlayer.PlayerActor, false) { TargetActor = underCursor };
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
if (world.LocalPlayer != null &&
|
||||
world.LocalPlayer.WinState != WinState.Undefined)
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
public IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world) { yield break; }
|
||||
|
||||
public string GetCursor(World world, CPos xy, MouseInput mi)
|
||||
{
|
||||
mi.Button = MouseButton.Left;
|
||||
return OrderInner(world, mi).Any()
|
||||
? "repair" : "repair-blocked";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#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 OpenRA.Mods.Common;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("Attach this to the player actor to allow building repair by team mates.")]
|
||||
class AllyRepairInfo : TraitInfo<AllyRepair> { }
|
||||
|
||||
class AllyRepair : IResolveOrder
|
||||
{
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "RepairBuilding")
|
||||
{
|
||||
var building = order.TargetActor;
|
||||
|
||||
if (building.HasTrait<RepairableBuilding>())
|
||||
if (building.AppearsFriendlyTo(self))
|
||||
building.Trait<RepairableBuilding>().RepairBuilding(building, self.Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#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.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
[Desc("Actor can capture ProximityCapturable actors.")]
|
||||
public class ProximityCaptorInfo : ITraitInfo
|
||||
{
|
||||
public readonly string[] Types = { };
|
||||
public object Create(ActorInitializer init) { return new ProximityCaptor(this); }
|
||||
}
|
||||
|
||||
public class ProximityCaptor
|
||||
{
|
||||
public readonly ProximityCaptorInfo Info;
|
||||
|
||||
public ProximityCaptor(ProximityCaptorInfo info) { Info = info; }
|
||||
|
||||
public bool HasAny(string[] typesList)
|
||||
{
|
||||
return typesList.Any(flag => Info.Types.Contains(flag));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
[Desc("Actor can be captured by units in a specified proximity.")]
|
||||
public class ProximityCapturableInfo : ITraitInfo
|
||||
{
|
||||
public readonly bool Permanent = false;
|
||||
public readonly int Range = 5;
|
||||
public readonly bool MustBeClear = false;
|
||||
public readonly string[] CaptorTypes = { "Vehicle", "Tank", "Infantry" };
|
||||
|
||||
public object Create(ActorInitializer init) { return new ProximityCapturable(init.Self, this); }
|
||||
}
|
||||
|
||||
public class ProximityCapturable : ITick
|
||||
{
|
||||
public readonly Player OriginalOwner;
|
||||
public bool Captured { get { return Self.Owner != OriginalOwner; } }
|
||||
|
||||
public ProximityCapturableInfo Info;
|
||||
public Actor Self;
|
||||
|
||||
public ProximityCapturable(Actor self, ProximityCapturableInfo info)
|
||||
{
|
||||
Info = info;
|
||||
Self = self;
|
||||
OriginalOwner = self.Owner;
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (Captured && Info.Permanent) return; // Permanent capture
|
||||
|
||||
if (!Captured)
|
||||
{
|
||||
var captor = GetInRange(self);
|
||||
|
||||
if (captor != null)
|
||||
if (!Info.MustBeClear || IsClear(self, captor.Owner, OriginalOwner))
|
||||
ChangeOwnership(self, captor);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// if the area must be clear, and there is more than 1 player nearby => return ownership to default
|
||||
if (Info.MustBeClear && !IsClear(self, self.Owner, OriginalOwner))
|
||||
{
|
||||
// Revert Ownership
|
||||
ChangeOwnership(self, OriginalOwner.PlayerActor);
|
||||
return;
|
||||
}
|
||||
|
||||
// See if the 'temporary' owner still is in range
|
||||
if (!IsStillInRange(self))
|
||||
{
|
||||
// no.. So find a new one
|
||||
var captor = GetInRange(self);
|
||||
|
||||
// got one
|
||||
if (captor != null)
|
||||
{
|
||||
ChangeOwnership(self, captor);
|
||||
return;
|
||||
}
|
||||
|
||||
// Revert Ownership otherwise
|
||||
ChangeOwnership(self, OriginalOwner.PlayerActor);
|
||||
}
|
||||
}
|
||||
|
||||
static void ChangeOwnership(Actor self, Actor captor)
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (self.Destroyed || captor.Destroyed) return;
|
||||
|
||||
var previousOwner = self.Owner;
|
||||
|
||||
// momentarily remove from world so the ownership queries don't get confused
|
||||
w.Remove(self);
|
||||
self.Owner = captor.Owner;
|
||||
w.Add(self);
|
||||
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
w.Add(new FlashTarget(self));
|
||||
|
||||
foreach (var t in self.TraitsImplementing<INotifyCapture>())
|
||||
t.OnCapture(self, captor, previousOwner, self.Owner);
|
||||
});
|
||||
}
|
||||
|
||||
bool CanBeCapturedBy(Actor a)
|
||||
{
|
||||
var pc = a.TraitOrDefault<ProximityCaptor>();
|
||||
return pc != null && pc.HasAny(Info.CaptorTypes);
|
||||
}
|
||||
|
||||
IEnumerable<Actor> UnitsInRange()
|
||||
{
|
||||
return Self.World.FindActorsInCircle(Self.CenterPosition, WRange.FromCells(Info.Range))
|
||||
.Where(a => a.IsInWorld && a != Self && !a.Destroyed && !a.Owner.NonCombatant);
|
||||
}
|
||||
|
||||
bool IsClear(Actor self, Player currentOwner, Player originalOwner)
|
||||
{
|
||||
return UnitsInRange()
|
||||
.All(a => a.Owner == originalOwner || a.Owner == currentOwner ||
|
||||
WorldUtils.AreMutualAllies(a.Owner, currentOwner) || !CanBeCapturedBy(a));
|
||||
}
|
||||
|
||||
// TODO exclude other NeutralActor that arent permanent
|
||||
bool IsStillInRange(Actor self)
|
||||
{
|
||||
return UnitsInRange().Any(a => a.Owner == self.Owner && CanBeCapturedBy(a));
|
||||
}
|
||||
|
||||
IEnumerable<Actor> CaptorsInRange(Actor self)
|
||||
{
|
||||
return UnitsInRange()
|
||||
.Where(a => a.Owner != OriginalOwner && CanBeCapturedBy(a));
|
||||
}
|
||||
|
||||
// TODO exclude other NeutralActor that arent permanent
|
||||
Actor GetInRange(Actor self)
|
||||
{
|
||||
return CaptorsInRange(self).ClosestTo(self);
|
||||
}
|
||||
|
||||
int CountPlayersNear(Actor self, Player ignoreMe)
|
||||
{
|
||||
return CaptorsInRange(self).Select(a => a.Owner).Where(p => p != ignoreMe)
|
||||
.Distinct().Count();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("Replaces the building animation when it repairs a unit.")]
|
||||
public class WithRepairAnimationInfo : ITraitInfo, Requires<RenderBuildingInfo>
|
||||
{
|
||||
[Desc("Sequence name to use")]
|
||||
public readonly string Sequence = "active";
|
||||
|
||||
public readonly bool PauseOnLowPower = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new WithRepairAnimation(init.Self, this); }
|
||||
}
|
||||
|
||||
public class WithRepairAnimation : INotifyRepair
|
||||
{
|
||||
IEnumerable<IDisable> disabled;
|
||||
WithRepairAnimationInfo info;
|
||||
|
||||
public WithRepairAnimation(Actor self, WithRepairAnimationInfo info)
|
||||
{
|
||||
disabled = self.TraitsImplementing<IDisable>();
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void Repairing(Actor self, Actor host)
|
||||
{
|
||||
var building = host.TraitOrDefault<RenderBuilding>();
|
||||
if (building != null && !(info.PauseOnLowPower && disabled.Any(d => d.Disabled)))
|
||||
building.PlayCustomAnim(host, info.Sequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
#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.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("Displays an overlay when the building is being repaired by the player.")]
|
||||
public class WithRepairOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<IBodyOrientationInfo>
|
||||
{
|
||||
[Desc("Sequence name to use")]
|
||||
public readonly string Sequence = "active";
|
||||
|
||||
[Desc("Position relative to body")]
|
||||
public readonly WVec Offset = WVec.Zero;
|
||||
|
||||
[Desc("Custom palette name")]
|
||||
public readonly string Palette = null;
|
||||
|
||||
[Desc("Custom palette is a player palette BaseName")]
|
||||
public readonly bool IsPlayerPalette = false;
|
||||
|
||||
public readonly bool PauseOnLowPower = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new WithRepairOverlay(init.Self, this); }
|
||||
}
|
||||
|
||||
public class WithRepairOverlay : INotifyDamageStateChanged, INotifyBuildComplete, INotifySold, INotifyRepair
|
||||
{
|
||||
Animation overlay;
|
||||
bool buildComplete;
|
||||
|
||||
public WithRepairOverlay(Actor self, WithRepairOverlayInfo info)
|
||||
{
|
||||
var rs = self.Trait<RenderSprites>();
|
||||
var body = self.Trait<IBodyOrientation>();
|
||||
var disabled = self.TraitsImplementing<IDisable>();
|
||||
|
||||
buildComplete = !self.HasTrait<Building>(); // always render instantly for units
|
||||
overlay = new Animation(self.World, rs.GetImage(self));
|
||||
overlay.Play(info.Sequence);
|
||||
rs.Add("repair_{0}".F(info.Sequence),
|
||||
new AnimationWithOffset(overlay,
|
||||
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
|
||||
() => !buildComplete,
|
||||
() => info.PauseOnLowPower && disabled.Any(d => d.Disabled),
|
||||
p => WithTurret.ZOffsetFromCenter(self, p, 1)),
|
||||
info.Palette, info.IsPlayerPalette);
|
||||
}
|
||||
|
||||
public void BuildingComplete(Actor self)
|
||||
{
|
||||
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(120, () =>
|
||||
buildComplete = true)));
|
||||
}
|
||||
|
||||
public void Sold(Actor self) { }
|
||||
public void Selling(Actor self)
|
||||
{
|
||||
buildComplete = false;
|
||||
}
|
||||
|
||||
public void DamageStateChanged(Actor self, AttackInfo e)
|
||||
{
|
||||
overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name));
|
||||
}
|
||||
|
||||
public void Repairing(Actor self, Actor host)
|
||||
{
|
||||
overlay.Play(overlay.CurrentSequence.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Activities;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("This actor can be sent to a structure for repairs.")]
|
||||
class RepairableInfo : ITraitInfo, Requires<HealthInfo>
|
||||
{
|
||||
public readonly string[] RepairBuildings = { "fix" };
|
||||
public virtual object Create(ActorInitializer init) { return new Repairable(init.Self); }
|
||||
}
|
||||
|
||||
class Repairable : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly Health health;
|
||||
|
||||
public Repairable(Actor self)
|
||||
{
|
||||
this.self = self;
|
||||
health = self.Trait<Health>();
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new EnterAlliedActorTargeter<Building>("Repair", 5,
|
||||
target => CanRepairAt(target), _ => CanRepair());
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
{
|
||||
if (order.OrderID == "Repair")
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool CanRepairAt(Actor target)
|
||||
{
|
||||
return self.Info.Traits.Get<RepairableInfo>().RepairBuildings.Contains(target.Info.Name);
|
||||
}
|
||||
|
||||
bool CanRepair()
|
||||
{
|
||||
var li = self.TraitOrDefault<LimitedAmmo>();
|
||||
return health.DamageState > DamageState.Undamaged || (li != null && !li.FullAmmo());
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "Repair" && CanRepair()) ? "Move" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Repair")
|
||||
{
|
||||
if (!CanRepairAt(order.TargetActor) || !CanRepair())
|
||||
return;
|
||||
|
||||
var movement = self.Trait<IMove>();
|
||||
var target = Target.FromOrder(self.World, order);
|
||||
self.SetTargetLine(target, Color.Green);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new MoveAdjacentTo(self, target));
|
||||
self.QueueActivity(movement.MoveTo(self.World.Map.CellContaining(order.TargetActor.CenterPosition), order.TargetActor));
|
||||
self.QueueActivity(new Rearm(self));
|
||||
self.QueueActivity(new Repair(order.TargetActor));
|
||||
|
||||
var rp = order.TargetActor.TraitOrDefault<RallyPoint>();
|
||||
if (rp != null)
|
||||
self.QueueActivity(new CallFunc(() =>
|
||||
{
|
||||
self.SetTargetLine(Target.FromCell(self.World, rp.Location), Color.Green);
|
||||
self.QueueActivity(movement.MoveTo(rp.Location, order.TargetActor));
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
class RepairableNearInfo : ITraitInfo, Requires<HealthInfo>
|
||||
{
|
||||
[ActorReference] public readonly string[] Buildings = { "spen", "syrd" };
|
||||
public readonly int CloseEnough = 4; /* cells */
|
||||
|
||||
public object Create(ActorInitializer init) { return new RepairableNear(init.Self, this); }
|
||||
}
|
||||
|
||||
class RepairableNear : IIssueOrder, IResolveOrder
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly RepairableNearInfo info;
|
||||
|
||||
public RepairableNear(Actor self, RepairableNearInfo info) { this.self = self; this.info = info; }
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new EnterAlliedActorTargeter<Building>("RepairNear", 5,
|
||||
target => CanRepairAt(target), _ => ShouldRepair());
|
||||
}
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
{
|
||||
if (order.OrderID == "RepairNear")
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool CanRepairAt(Actor target)
|
||||
{
|
||||
return info.Buildings.Contains(target.Info.Name);
|
||||
}
|
||||
|
||||
bool ShouldRepair()
|
||||
{
|
||||
return self.GetDamageState() > DamageState.Undamaged;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "RepairNear" && CanRepairAt(order.TargetActor) && ShouldRepair())
|
||||
{
|
||||
var movement = self.Trait<IMove>();
|
||||
var target = Target.FromOrder(self.World, order);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(movement.MoveWithinRange(target, new WRange(1024 * info.CloseEnough)));
|
||||
self.QueueActivity(new Repair(order.TargetActor));
|
||||
|
||||
self.SetTargetLine(target, Color.Green, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Mods.RA.Traits;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Scripting;
|
||||
using OpenRA.Traits;
|
||||
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
#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.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
class BridgeInfo : ITraitInfo, Requires<HealthInfo>, Requires<BuildingInfo>
|
||||
{
|
||||
public readonly bool Long = false;
|
||||
|
||||
[Desc("Delay (in ticks) between repairing adjacent spans in long bridges")]
|
||||
public readonly int RepairPropagationDelay = 20;
|
||||
|
||||
public readonly ushort Template = 0;
|
||||
public readonly ushort DamagedTemplate = 0;
|
||||
public readonly ushort DestroyedTemplate = 0;
|
||||
|
||||
// For long bridges
|
||||
public readonly ushort DestroyedPlusNorthTemplate = 0;
|
||||
public readonly ushort DestroyedPlusSouthTemplate = 0;
|
||||
public readonly ushort DestroyedPlusBothTemplate = 0;
|
||||
|
||||
public readonly string[] ShorePieces = { "br1", "br2" };
|
||||
public readonly int[] NorthOffset = null;
|
||||
public readonly int[] SouthOffset = null;
|
||||
|
||||
[Desc("The name of the weapon to use when demolishing the bridge")]
|
||||
public readonly string DemolishWeapon = "Demolish";
|
||||
|
||||
public object Create(ActorInitializer init) { return new Bridge(init.Self, this); }
|
||||
|
||||
public IEnumerable<Pair<ushort, float>> Templates
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Template != 0)
|
||||
yield return Pair.New(Template, 1f);
|
||||
|
||||
if (DamagedTemplate != 0)
|
||||
yield return Pair.New(DamagedTemplate, .5f);
|
||||
|
||||
if (DestroyedTemplate != 0)
|
||||
yield return Pair.New(DestroyedTemplate, 0f);
|
||||
|
||||
if (DestroyedPlusNorthTemplate != 0)
|
||||
yield return Pair.New(DestroyedPlusNorthTemplate, 0f);
|
||||
|
||||
if (DestroyedPlusSouthTemplate != 0)
|
||||
yield return Pair.New(DestroyedPlusSouthTemplate, 0f);
|
||||
|
||||
if (DestroyedPlusBothTemplate != 0)
|
||||
yield return Pair.New(DestroyedPlusBothTemplate, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Bridge : IRender, INotifyDamageStateChanged
|
||||
{
|
||||
readonly Building building;
|
||||
readonly Bridge[] neighbours = new Bridge[2];
|
||||
readonly BridgeHut[] huts = new BridgeHut[2]; // Huts before this / first & after this / last
|
||||
readonly Health health;
|
||||
readonly Actor self;
|
||||
readonly BridgeInfo info;
|
||||
readonly string type;
|
||||
|
||||
readonly Lazy<bool> isDangling;
|
||||
ushort template;
|
||||
Dictionary<CPos, byte> footprint;
|
||||
|
||||
public BridgeHut Hut { get; private set; }
|
||||
public bool IsDangling { get { return isDangling.Value; } }
|
||||
|
||||
public Bridge(Actor self, BridgeInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
health = self.Trait<Health>();
|
||||
health.RemoveOnDeath = false;
|
||||
this.info = info;
|
||||
type = self.Info.Name;
|
||||
isDangling = new Lazy<bool>(() => huts[0] == huts[1] && (neighbours[0] == null || neighbours[1] == null));
|
||||
building = self.Trait<Building>();
|
||||
}
|
||||
|
||||
public Bridge Neighbour(int direction) { return neighbours[direction]; }
|
||||
public IEnumerable<Bridge> Enumerate(int direction, bool includeSelf = false)
|
||||
{
|
||||
for (var b = includeSelf ? this : neighbours[direction]; b != null; b = b.neighbours[direction])
|
||||
yield return b;
|
||||
}
|
||||
|
||||
public void Do(Action<Bridge, int> action)
|
||||
{
|
||||
action(this, -1);
|
||||
for (var d = 0; d <= 1; d++)
|
||||
if (neighbours[d] != null)
|
||||
action(neighbours[d], d);
|
||||
}
|
||||
|
||||
public void Create(ushort template, Dictionary<CPos, byte> footprint)
|
||||
{
|
||||
this.template = template;
|
||||
this.footprint = footprint;
|
||||
|
||||
// Set the initial custom terrain types
|
||||
foreach (var c in footprint.Keys)
|
||||
self.World.Map.CustomTerrain[c] = GetTerrainType(c);
|
||||
}
|
||||
|
||||
byte GetTerrainType(CPos cell)
|
||||
{
|
||||
var dx = cell - self.Location;
|
||||
var index = dx.X + self.World.TileSet.Templates[template].Size.X * dx.Y;
|
||||
return self.World.TileSet.GetTerrainIndex(new TerrainTile(template, (byte)index));
|
||||
}
|
||||
|
||||
public void LinkNeighbouringBridges(World world, BridgeLayer bridges)
|
||||
{
|
||||
for (var d = 0; d <= 1; d++)
|
||||
{
|
||||
if (neighbours[d] != null)
|
||||
continue; // Already linked by reverse lookup
|
||||
|
||||
var offset = d == 0 ? info.NorthOffset : info.SouthOffset;
|
||||
if (offset == null)
|
||||
continue; // End piece type
|
||||
|
||||
neighbours[d] = GetNeighbor(offset, bridges);
|
||||
if (neighbours[d] != null)
|
||||
neighbours[d].neighbours[1 - d] = this; // Save reverse lookup
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddHut(BridgeHut hut)
|
||||
{
|
||||
if (huts[0] == huts[1])
|
||||
huts[1] = hut;
|
||||
if (Hut == null)
|
||||
{
|
||||
Hut = hut; // Assume only one until called again
|
||||
if (huts[0] == null)
|
||||
huts[0] = hut; // Set only first time
|
||||
for (var d = 0; d <= 1; d++)
|
||||
for (var b = neighbours[d]; b != null; b = b.Hut == null ? b.neighbours[d] : null)
|
||||
b.huts[1 - d] = hut;
|
||||
}
|
||||
else
|
||||
Hut = null;
|
||||
}
|
||||
|
||||
public BridgeHut GetHut(int index) { return huts[index]; }
|
||||
public Bridge GetNeighbor(int[] offset, BridgeLayer bridges)
|
||||
{
|
||||
if (offset == null)
|
||||
return null;
|
||||
|
||||
return bridges.GetBridge(self.Location + new CVec(offset[0], offset[1]));
|
||||
}
|
||||
|
||||
IRenderable[] TemplateRenderables(WorldRenderer wr, PaletteReference palette, ushort template)
|
||||
{
|
||||
var offset = FootprintUtils.CenterOffset(self.World, building.Info).Y + 1024;
|
||||
|
||||
return footprint.Select(c => (IRenderable)(new SpriteRenderable(
|
||||
wr.Theater.TileSprite(new TerrainTile(template, c.Value)),
|
||||
wr.World.Map.CenterOfCell(c.Key), WVec.Zero, -offset, palette, 1f, true))).ToArray();
|
||||
}
|
||||
|
||||
bool initialized;
|
||||
Dictionary<ushort, IRenderable[]> renderables;
|
||||
public IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
var palette = wr.Palette("terrain");
|
||||
renderables = new Dictionary<ushort, IRenderable[]>();
|
||||
foreach (var t in info.Templates)
|
||||
renderables.Add(t.First, TemplateRenderables(wr, palette, t.First));
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return renderables[template];
|
||||
}
|
||||
|
||||
void KillUnitsOnBridge()
|
||||
{
|
||||
foreach (var c in footprint.Keys)
|
||||
foreach (var a in self.World.ActorMap.GetUnitsAt(c))
|
||||
if (a.HasTrait<IPositionable>() && !a.Trait<IPositionable>().CanEnterCell(c))
|
||||
a.Kill(self);
|
||||
}
|
||||
|
||||
bool NeighbourIsDeadShore(Bridge neighbour)
|
||||
{
|
||||
return neighbour != null && info.ShorePieces.Contains(neighbour.type) && neighbour.health.IsDead;
|
||||
}
|
||||
|
||||
bool LongBridgeSegmentIsDead()
|
||||
{
|
||||
// The long bridge artwork requires a hack to display correctly
|
||||
// if the adjacent shore piece is dead
|
||||
if (!info.Long)
|
||||
return health.IsDead;
|
||||
|
||||
if (NeighbourIsDeadShore(neighbours[0]) || NeighbourIsDeadShore(neighbours[1]))
|
||||
return true;
|
||||
|
||||
return health.IsDead;
|
||||
}
|
||||
|
||||
ushort ChooseTemplate()
|
||||
{
|
||||
if (info.Long && LongBridgeSegmentIsDead())
|
||||
{
|
||||
// Long bridges have custom art for multiple segments being destroyed
|
||||
var previousIsDead = neighbours[0] != null && neighbours[0].LongBridgeSegmentIsDead();
|
||||
var nextIsDead = neighbours[1] != null && neighbours[1].LongBridgeSegmentIsDead();
|
||||
if (previousIsDead && nextIsDead)
|
||||
return info.DestroyedPlusBothTemplate;
|
||||
if (previousIsDead)
|
||||
return info.DestroyedPlusNorthTemplate;
|
||||
if (nextIsDead)
|
||||
return info.DestroyedPlusSouthTemplate;
|
||||
|
||||
return info.DestroyedTemplate;
|
||||
}
|
||||
|
||||
var ds = health.DamageState;
|
||||
return (ds == DamageState.Dead && info.DestroyedTemplate > 0) ? info.DestroyedTemplate :
|
||||
(ds >= DamageState.Heavy && info.DamagedTemplate > 0) ? info.DamagedTemplate : info.Template;
|
||||
}
|
||||
|
||||
bool killedUnits = false;
|
||||
void UpdateState()
|
||||
{
|
||||
var oldTemplate = template;
|
||||
|
||||
template = ChooseTemplate();
|
||||
if (template == oldTemplate)
|
||||
return;
|
||||
|
||||
// Update map
|
||||
foreach (var c in footprint.Keys)
|
||||
self.World.Map.CustomTerrain[c] = GetTerrainType(c);
|
||||
|
||||
// If this bridge repair operation connects two pathfinding domains,
|
||||
// update the domain index.
|
||||
var domainIndex = self.World.WorldActor.TraitOrDefault<DomainIndex>();
|
||||
if (domainIndex != null)
|
||||
domainIndex.UpdateCells(self.World, footprint.Keys);
|
||||
|
||||
if (LongBridgeSegmentIsDead() && !killedUnits)
|
||||
{
|
||||
killedUnits = true;
|
||||
KillUnitsOnBridge();
|
||||
}
|
||||
}
|
||||
|
||||
public void Repair(Actor repairer, int direction, Action onComplete)
|
||||
{
|
||||
// Repair self
|
||||
var initialDamage = health.DamageState;
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (health.IsDead)
|
||||
{
|
||||
health.Resurrect(self, repairer);
|
||||
killedUnits = false;
|
||||
KillUnitsOnBridge();
|
||||
}
|
||||
else
|
||||
health.InflictDamage(self, repairer, -health.MaxHP, null, true);
|
||||
if (direction < 0 ? neighbours[0] == null && neighbours[1] == null : Hut != null || neighbours[direction] == null)
|
||||
onComplete(); // Done if single or reached other hut
|
||||
});
|
||||
|
||||
// Repair adjacent spans onto next hut or end
|
||||
if (direction >= 0 && Hut == null && neighbours[direction] != null)
|
||||
{
|
||||
var delay = initialDamage == DamageState.Undamaged || NeighbourIsDeadShore(neighbours[direction]) ?
|
||||
0 : info.RepairPropagationDelay;
|
||||
|
||||
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () =>
|
||||
neighbours[direction].Repair(repairer, direction, onComplete))));
|
||||
}
|
||||
}
|
||||
|
||||
public void DamageStateChanged(Actor self, AttackInfo e)
|
||||
{
|
||||
Do((b, d) => b.UpdateState());
|
||||
|
||||
// Need to update the neighbours neighbour to correctly
|
||||
// display the broken shore hack
|
||||
if (info.ShorePieces.Contains(type))
|
||||
for (var d = 0; d <= 1; d++)
|
||||
if (neighbours[d] != null && neighbours[d].neighbours[d] != null)
|
||||
neighbours[d].neighbours[d].UpdateState();
|
||||
}
|
||||
|
||||
void AggregateDamageState(Bridge b, int d, ref DamageState damage)
|
||||
{
|
||||
if (b.health.DamageState > damage)
|
||||
damage = b.health.DamageState;
|
||||
if (b.Hut == null && d >= 0 && b.neighbours[d] != null)
|
||||
AggregateDamageState(b.neighbours[d], d, ref damage);
|
||||
}
|
||||
|
||||
// Find the worst span damage before other hut
|
||||
public DamageState AggregateDamageState()
|
||||
{
|
||||
var damage = health.DamageState;
|
||||
Do((b, d) => AggregateDamageState(b, d, ref damage));
|
||||
return damage;
|
||||
}
|
||||
|
||||
public void Demolish(Actor saboteur, int direction)
|
||||
{
|
||||
var initialDamage = health.DamageState;
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
var weapon = saboteur.World.Map.Rules.Weapons[info.DemolishWeapon.ToLowerInvariant()];
|
||||
|
||||
// Use .FromPos since this actor is killed. Cannot use Target.FromActor
|
||||
weapon.Impact(Target.FromPos(self.CenterPosition), saboteur, Enumerable.Empty<int>());
|
||||
|
||||
self.World.WorldActor.Trait<ScreenShaker>().AddEffect(15, self.CenterPosition, 6);
|
||||
self.Kill(saboteur);
|
||||
});
|
||||
|
||||
// Destroy adjacent spans between (including) huts
|
||||
if (direction >= 0 && Hut == null && neighbours[direction] != null)
|
||||
{
|
||||
var delay = initialDamage == DamageState.Dead || NeighbourIsDeadShore(neighbours[direction]) ?
|
||||
0 : info.RepairPropagationDelay;
|
||||
|
||||
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () =>
|
||||
neighbours[direction].Demolish(saboteur, direction))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
#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.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("Allows bridges to be targeted for demolition and repair.")]
|
||||
class BridgeHutInfo : IDemolishableInfo, ITraitInfo
|
||||
{
|
||||
public bool IsValidTarget(ActorInfo actorInfo, Actor saboteur) { return false; } // TODO: bridges don't support frozen under fog
|
||||
|
||||
public object Create(ActorInitializer init) { return new BridgeHut(init); }
|
||||
}
|
||||
|
||||
class BridgeHut : IDemolishable
|
||||
{
|
||||
public readonly Bridge FirstBridge;
|
||||
public readonly Bridge Bridge;
|
||||
public DamageState BridgeDamageState { get { return Bridge.AggregateDamageState(); } }
|
||||
public bool Repairing { get { return repairDirections > 0; } }
|
||||
int repairDirections = 0;
|
||||
|
||||
public BridgeHut(ActorInitializer init)
|
||||
{
|
||||
Bridge = init.Get<ParentActorInit>().ActorValue.Trait<Bridge>();
|
||||
Bridge.AddHut(this);
|
||||
FirstBridge = Bridge.Enumerate(0, true).Last();
|
||||
}
|
||||
|
||||
public void Repair(Actor repairer)
|
||||
{
|
||||
repairDirections = Bridge.GetHut(0) != this && Bridge.GetHut(1) != this ? 2 : 1;
|
||||
Bridge.Do((b, d) => b.Repair(repairer, d, () => repairDirections--));
|
||||
}
|
||||
|
||||
public void Demolish(Actor self, Actor saboteur)
|
||||
{
|
||||
Bridge.Do((b, d) => b.Demolish(saboteur, d));
|
||||
}
|
||||
|
||||
public bool IsValidTarget(Actor self, Actor saboteur)
|
||||
{
|
||||
return BridgeDamageState != DamageState.Dead;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
#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.Mods.Common;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Mods.RA.Effects;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("Building can be repaired by the repair button.")]
|
||||
public class RepairableBuildingInfo : UpgradableTraitInfo, ITraitInfo, Requires<HealthInfo>
|
||||
{
|
||||
public readonly int RepairPercent = 20;
|
||||
public readonly int RepairInterval = 24;
|
||||
public readonly int RepairStep = 7;
|
||||
public readonly int[] RepairBonuses = { 100, 150, 175, 200, 220, 240, 260, 280, 300 };
|
||||
public readonly bool CancelWhenDisabled = false;
|
||||
|
||||
public readonly string IndicatorPalettePrefix = "player";
|
||||
|
||||
public object Create(ActorInitializer init) { return new RepairableBuilding(init.Self, this); }
|
||||
}
|
||||
|
||||
public class RepairableBuilding : UpgradableTrait<RepairableBuildingInfo>, ITick
|
||||
{
|
||||
[Sync]
|
||||
public int RepairersHash { get { return Repairers.Aggregate(0, (code, player) => code ^ Sync.HashPlayer(player)); } }
|
||||
public List<Player> Repairers = new List<Player>();
|
||||
|
||||
readonly Health health;
|
||||
public bool RepairActive = false;
|
||||
|
||||
public RepairableBuilding(Actor self, RepairableBuildingInfo info)
|
||||
: base(info)
|
||||
{
|
||||
health = self.Trait<Health>();
|
||||
}
|
||||
|
||||
public void RepairBuilding(Actor self, Player player)
|
||||
{
|
||||
if (!IsTraitDisabled && self.AppearsFriendlyTo(player.PlayerActor))
|
||||
{
|
||||
// If the player won't affect the repair, we won't add him
|
||||
if (!Repairers.Remove(player) && Repairers.Count < Info.RepairBonuses.Length)
|
||||
{
|
||||
Repairers.Add(player);
|
||||
Sound.PlayNotification(self.World.Map.Rules, player, "Speech", "Repairing", player.Country.Race);
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (!self.IsDead)
|
||||
w.Add(new RepairIndicator(self, Info.IndicatorPalettePrefix));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int remainingTicks;
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (IsTraitDisabled)
|
||||
{
|
||||
if (RepairActive && Info.CancelWhenDisabled)
|
||||
{
|
||||
Repairers.Clear();
|
||||
RepairActive = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (remainingTicks == 0)
|
||||
{
|
||||
Repairers = Repairers.Where(player => player.WinState == WinState.Undefined
|
||||
&& player.Stances[self.Owner] == Stance.Ally).ToList();
|
||||
|
||||
// If after the previous operation there's no repairers left, stop
|
||||
if (!Repairers.Any()) return;
|
||||
var buildingValue = self.GetSellValue();
|
||||
|
||||
// The cost is the same regardless of the amount of people repairing
|
||||
var hpToRepair = Math.Min(Info.RepairStep, health.MaxHP - health.HP);
|
||||
var cost = Math.Max(1, (hpToRepair * Info.RepairPercent * buildingValue) / (health.MaxHP * 100));
|
||||
|
||||
// TakeCash will return false if the player can't pay, and will stop him from contributing this Tick
|
||||
var activePlayers = Repairers.Count(player => player.PlayerActor.Trait<PlayerResources>().TakeCash(cost));
|
||||
|
||||
RepairActive = activePlayers > 0;
|
||||
|
||||
if (!RepairActive)
|
||||
{
|
||||
remainingTicks = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Bonus is applied after finding players who can pay
|
||||
|
||||
// activePlayers won't cause IndexOutOfRange because we capped the max amount of players
|
||||
// to the length of the array
|
||||
self.InflictDamage(self, -(hpToRepair * Info.RepairBonuses[activePlayers - 1] / 100), null);
|
||||
|
||||
if (health.DamageState == DamageState.Undamaged)
|
||||
{
|
||||
Repairers.Clear();
|
||||
RepairActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
remainingTicks = Info.RepairInterval;
|
||||
}
|
||||
else
|
||||
--remainingTicks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
[Desc("Can enter a BridgeHut to trigger a repair.")]
|
||||
class RepairsBridgesInfo : TraitInfo<RepairsBridges> { }
|
||||
|
||||
class RepairsBridges : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get { yield return new RepairBridgeOrderTargeter(); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
{
|
||||
if (order.OrderID == "RepairBridge")
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "RepairBridge")
|
||||
return null;
|
||||
|
||||
var hut = order.TargetActor.TraitOrDefault<BridgeHut>();
|
||||
if (hut == null)
|
||||
return null;
|
||||
|
||||
return hut.BridgeDamageState == DamageState.Undamaged || hut.Repairing || hut.Bridge.IsDangling ? null : "Attack";
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "RepairBridge")
|
||||
{
|
||||
var hut = order.TargetActor.TraitOrDefault<BridgeHut>();
|
||||
if (hut == null)
|
||||
return;
|
||||
|
||||
if (hut.BridgeDamageState == DamageState.Undamaged || hut.Repairing || hut.Bridge.IsDangling)
|
||||
return;
|
||||
|
||||
self.SetTargetLine(Target.FromOrder(self.World, order), Color.Yellow);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new RepairBridge(self, order.TargetActor));
|
||||
}
|
||||
}
|
||||
|
||||
class RepairBridgeOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
public RepairBridgeOrderTargeter()
|
||||
: base("RepairBridge", 6, "goldwrench", true, true) { }
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var hut = target.TraitOrDefault<BridgeHut>();
|
||||
if (hut == null)
|
||||
return false;
|
||||
|
||||
// Require force attack to heal partially damaged bridges to avoid unnecessary cursor noise
|
||||
var damage = hut.BridgeDamageState;
|
||||
if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && damage != DamageState.Dead)
|
||||
return false;
|
||||
|
||||
// Obey force moving onto bridges
|
||||
if (modifiers.HasModifier(TargetModifiers.ForceMove))
|
||||
return false;
|
||||
|
||||
// Can't repair a bridge that is undamaged, already under repair, or dangling
|
||||
if (damage == DamageState.Undamaged || hut.Repairing || hut.Bridge.IsDangling)
|
||||
cursor = "goldwrench-blocked";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
// TODO: Bridges don't yet support FrozenUnderFog.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Traits
|
||||
{
|
||||
class BridgeLayerInfo : ITraitInfo
|
||||
{
|
||||
[ActorReference]
|
||||
public readonly string[] Bridges = { "bridge1", "bridge2" };
|
||||
|
||||
public object Create(ActorInitializer init) { return new BridgeLayer(init.Self, this); }
|
||||
}
|
||||
|
||||
class BridgeLayer : IWorldLoaded
|
||||
{
|
||||
readonly BridgeLayerInfo info;
|
||||
readonly World world;
|
||||
Dictionary<ushort, Pair<string, float>> bridgeTypes = new Dictionary<ushort, Pair<string, float>>();
|
||||
CellLayer<Bridge> bridges;
|
||||
|
||||
public BridgeLayer(Actor self, BridgeLayerInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
this.world = self.World;
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w, WorldRenderer wr)
|
||||
{
|
||||
bridges = new CellLayer<Bridge>(w.Map);
|
||||
|
||||
// Build a list of templates that should be overlayed with bridges
|
||||
foreach (var bridge in info.Bridges)
|
||||
{
|
||||
var bi = w.Map.Rules.Actors[bridge].Traits.Get<BridgeInfo>();
|
||||
foreach (var template in bi.Templates)
|
||||
bridgeTypes.Add(template.First, Pair.New(bridge, template.Second));
|
||||
}
|
||||
|
||||
// Loop through the map looking for templates to overlay
|
||||
for (var i = w.Map.Bounds.Left; i < w.Map.Bounds.Right; i++)
|
||||
{
|
||||
for (var j = w.Map.Bounds.Top; j < w.Map.Bounds.Bottom; j++)
|
||||
{
|
||||
var cell = new CPos(i, j);
|
||||
if (bridgeTypes.ContainsKey(w.Map.MapTiles.Value[cell].Type))
|
||||
ConvertBridgeToActor(w, cell);
|
||||
}
|
||||
}
|
||||
|
||||
// Link adjacent (long)-bridges so that artwork is updated correctly
|
||||
foreach (var b in w.Actors.SelectMany(a => a.TraitsImplementing<Bridge>()))
|
||||
b.LinkNeighbouringBridges(w, this);
|
||||
}
|
||||
|
||||
void ConvertBridgeToActor(World w, CPos cell)
|
||||
{
|
||||
// This cell already has a bridge overlaying it from a previous iteration
|
||||
if (bridges[cell] != null)
|
||||
return;
|
||||
|
||||
// Correlate the tile "image" aka subtile with its position to find the template origin
|
||||
var tile = w.Map.MapTiles.Value[cell].Type;
|
||||
var index = w.Map.MapTiles.Value[cell].Index;
|
||||
var template = w.TileSet.Templates[tile];
|
||||
var ni = cell.X - index % template.Size.X;
|
||||
var nj = cell.Y - index / template.Size.X;
|
||||
|
||||
// Create a new actor for this bridge and keep track of which subtiles this bridge includes
|
||||
var bridge = w.CreateActor(bridgeTypes[tile].First, new TypeDictionary
|
||||
{
|
||||
new LocationInit(new CPos(ni, nj)),
|
||||
new OwnerInit(w.WorldActor.Owner),
|
||||
new HealthInit(bridgeTypes[tile].Second),
|
||||
}).Trait<Bridge>();
|
||||
|
||||
var subTiles = new Dictionary<CPos, byte>();
|
||||
|
||||
// For each subtile in the template
|
||||
for (byte ind = 0; ind < template.Size.X * template.Size.Y; ind++)
|
||||
{
|
||||
// Where do we expect to find the subtile
|
||||
var subtile = new CPos(ni + ind % template.Size.X, nj + ind / template.Size.X);
|
||||
|
||||
// This isn't the bridge you're looking for
|
||||
if (!w.Map.Contains(subtile) || w.Map.MapTiles.Value[subtile].Type != tile ||
|
||||
w.Map.MapTiles.Value[subtile].Index != ind)
|
||||
continue;
|
||||
|
||||
subTiles.Add(subtile, ind);
|
||||
bridges[subtile] = bridge;
|
||||
}
|
||||
|
||||
bridge.Create(tile, subTiles);
|
||||
}
|
||||
|
||||
// Used to check for neighbouring bridges
|
||||
public Bridge GetBridge(CPos cell)
|
||||
{
|
||||
if (!world.Map.Contains(cell))
|
||||
return null;
|
||||
|
||||
return bridges[cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#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 OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class TransformOnCaptureInfo : ITraitInfo
|
||||
{
|
||||
[ActorReference] public readonly string IntoActor = null;
|
||||
public readonly int ForceHealthPercentage = 0;
|
||||
public readonly bool SkipMakeAnims = true;
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new TransformOnCapture(this); }
|
||||
}
|
||||
|
||||
class TransformOnCapture : INotifyCapture
|
||||
{
|
||||
readonly TransformOnCaptureInfo info;
|
||||
|
||||
public TransformOnCapture(TransformOnCaptureInfo info) { this.info = info; }
|
||||
|
||||
public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner)
|
||||
{
|
||||
var facing = self.TraitOrDefault<IFacing>();
|
||||
var transform = new Transform(self, info.IntoActor) { ForceHealthPercentage = info.ForceHealthPercentage };
|
||||
if (facing != null) transform.Facing = facing.Facing;
|
||||
transform.SkipMakeAnims = info.SkipMakeAnims;
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Mods.Common.Widgets;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
Reference in New Issue
Block a user