Merge pull request #3648 from pchote/frozen-fog-rework
Rework frozen actors to support tooltips and orders
This commit is contained in:
@@ -191,7 +191,7 @@ namespace OpenRA
|
|||||||
if (orderManager.NetFrameNumber == 0)
|
if (orderManager.NetFrameNumber == 0)
|
||||||
orderManager.LastTickTime = Environment.TickCount;
|
orderManager.LastTickTime = Environment.TickCount;
|
||||||
|
|
||||||
world.TickRender(worldRenderer);
|
Sync.CheckSyncUnchanged(world, () => world.TickRender(worldRenderer));
|
||||||
viewport.Tick();
|
viewport.Tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,12 +48,15 @@ namespace OpenRA.GameRules
|
|||||||
[Desc("Whether we should prevent prone response for infantry.")]
|
[Desc("Whether we should prevent prone response for infantry.")]
|
||||||
public readonly bool PreventProne = false;
|
public readonly bool PreventProne = false;
|
||||||
|
|
||||||
public float EffectivenessAgainst(Actor self)
|
public float EffectivenessAgainst(ActorInfo ai)
|
||||||
{
|
{
|
||||||
var health = self.Info.Traits.GetOrDefault<HealthInfo>();
|
var health = ai.Traits.GetOrDefault<HealthInfo>();
|
||||||
if (health == null) return 0f;
|
if (health == null)
|
||||||
var armor = self.Info.Traits.GetOrDefault<ArmorInfo>();
|
return 0f;
|
||||||
if (armor == null || armor.Type == null) return 1;
|
|
||||||
|
var armor = ai.Traits.GetOrDefault<ArmorInfo>();
|
||||||
|
if (armor == null || armor.Type == null)
|
||||||
|
return 1;
|
||||||
|
|
||||||
float versus;
|
float versus;
|
||||||
return Versus.TryGetValue(armor.Type, out versus) ? versus : 1;
|
return Versus.TryGetValue(armor.Type, out versus) ? versus : 1;
|
||||||
@@ -140,20 +143,34 @@ namespace OpenRA.GameRules
|
|||||||
if (targetable == null || !ValidTargets.Intersect(targetable.TargetTypes).Any())
|
if (targetable == null || !ValidTargets.Intersect(targetable.TargetTypes).Any())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Warheads.All(w => w.EffectivenessAgainst(a) <= 0))
|
if (Warheads.All(w => w.EffectivenessAgainst(a.Info) <= 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsValidAgainst(Target target, World world)
|
public bool IsValidAgainst(FrozenActor a)
|
||||||
{
|
{
|
||||||
if (!target.IsValid)
|
var targetable = a.Info.Traits.GetOrDefault<ITargetableInfo>();
|
||||||
|
if (targetable == null || !ValidTargets.Intersect(targetable.GetTargetTypes()).Any())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (target.IsActor)
|
if (Warheads.All(w => w.EffectivenessAgainst(a.Info) <= 0))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsValidAgainst(Target target, World world)
|
||||||
|
{
|
||||||
|
if (target.Type == TargetType.Actor)
|
||||||
return IsValidAgainst(target.Actor);
|
return IsValidAgainst(target.Actor);
|
||||||
else
|
|
||||||
|
if (target.Type == TargetType.FrozenActor)
|
||||||
|
return IsValidAgainst(target.FrozenActor);
|
||||||
|
|
||||||
|
if (target.Type == TargetType.Terrain)
|
||||||
{
|
{
|
||||||
var cell = target.CenterPosition.ToCPos();
|
var cell = target.CenterPosition.ToCPos();
|
||||||
if (ValidTargets.Contains("Ground") && world.GetTerrainType(cell) != "Water")
|
if (ValidTargets.Contains("Ground") && world.GetTerrainType(cell) != "Water")
|
||||||
@@ -164,6 +181,8 @@ namespace OpenRA.GameRules
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,9 +73,15 @@ namespace OpenRA.Graphics
|
|||||||
var bounds = Game.viewport.WorldBounds(world);
|
var bounds = Game.viewport.WorldBounds(world);
|
||||||
var comparer = new RenderableComparer(this);
|
var comparer = new RenderableComparer(this);
|
||||||
|
|
||||||
var actors = world.FindActorsInBox(
|
var tl = bounds.TopLeftAsCPos();
|
||||||
bounds.TopLeftAsCPos(),
|
var br = bounds.BottomRightAsCPos();
|
||||||
bounds.BottomRightAsCPos());
|
var actors = world.FindActorsInBox(tl, br)
|
||||||
|
.Append(world.WorldActor)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Include player actor for the rendered player
|
||||||
|
if (world.RenderPlayer != null)
|
||||||
|
actors.Add(world.RenderPlayer.PlayerActor);
|
||||||
|
|
||||||
var worldRenderables = actors.SelectMany(a => a.Render(this));
|
var worldRenderables = actors.SelectMany(a => a.Render(this));
|
||||||
if (world.OrderGenerator != null)
|
if (world.OrderGenerator != null)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace OpenRA
|
|||||||
TargetString = 0x04,
|
TargetString = 0x04,
|
||||||
Queued = 0x08,
|
Queued = 0x08,
|
||||||
ExtraLocation = 0x10,
|
ExtraLocation = 0x10,
|
||||||
|
ExtraData = 0x20
|
||||||
}
|
}
|
||||||
|
|
||||||
static class OrderFieldsExts
|
static class OrderFieldsExts
|
||||||
@@ -42,12 +43,13 @@ namespace OpenRA
|
|||||||
public CPos TargetLocation;
|
public CPos TargetLocation;
|
||||||
public string TargetString;
|
public string TargetString;
|
||||||
public CPos ExtraLocation;
|
public CPos ExtraLocation;
|
||||||
|
public uint ExtraData;
|
||||||
public bool IsImmediate;
|
public bool IsImmediate;
|
||||||
|
|
||||||
public Player Player { get { return Subject.Owner; } }
|
public Player Player { get { return Subject.Owner; } }
|
||||||
|
|
||||||
Order(string orderString, Actor subject,
|
Order(string orderString, Actor subject,
|
||||||
Actor targetActor, CPos targetLocation, string targetString, bool queued, CPos extraLocation)
|
Actor targetActor, CPos targetLocation, string targetString, bool queued, CPos extraLocation, uint extraData)
|
||||||
{
|
{
|
||||||
this.OrderString = orderString;
|
this.OrderString = orderString;
|
||||||
this.Subject = subject;
|
this.Subject = subject;
|
||||||
@@ -56,18 +58,19 @@ namespace OpenRA
|
|||||||
this.TargetString = targetString;
|
this.TargetString = targetString;
|
||||||
this.Queued = queued;
|
this.Queued = queued;
|
||||||
this.ExtraLocation = extraLocation;
|
this.ExtraLocation = extraLocation;
|
||||||
|
this.ExtraData = extraData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For scripting special powers
|
// For scripting special powers
|
||||||
public Order()
|
public Order()
|
||||||
: this(null, null, null, CPos.Zero, null, false, CPos.Zero) { }
|
: this(null, null, null, CPos.Zero, null, false, CPos.Zero, 0) { }
|
||||||
|
|
||||||
public Order(string orderString, Actor subject, bool queued)
|
public Order(string orderString, Actor subject, bool queued)
|
||||||
: this(orderString, subject, null, CPos.Zero, null, queued, CPos.Zero) { }
|
: this(orderString, subject, null, CPos.Zero, null, queued, CPos.Zero, 0) { }
|
||||||
|
|
||||||
public Order(string orderstring, Order order)
|
public Order(string orderstring, Order order)
|
||||||
: this(orderstring, order.Subject, order.TargetActor, order.TargetLocation,
|
: this(orderstring, order.Subject, order.TargetActor, order.TargetLocation,
|
||||||
order.TargetString, order.Queued, order.ExtraLocation) {}
|
order.TargetString, order.Queued, order.ExtraLocation, order.ExtraData) {}
|
||||||
|
|
||||||
public byte[] Serialize()
|
public byte[] Serialize()
|
||||||
{
|
{
|
||||||
@@ -102,6 +105,7 @@ namespace OpenRA
|
|||||||
if (TargetString != null) fields |= OrderFields.TargetString;
|
if (TargetString != null) fields |= OrderFields.TargetString;
|
||||||
if (Queued) fields |= OrderFields.Queued;
|
if (Queued) fields |= OrderFields.Queued;
|
||||||
if (ExtraLocation != CPos.Zero) fields |= OrderFields.ExtraLocation;
|
if (ExtraLocation != CPos.Zero) fields |= OrderFields.ExtraLocation;
|
||||||
|
if (ExtraData != 0) fields |= OrderFields.ExtraData;
|
||||||
|
|
||||||
w.Write((byte)fields);
|
w.Write((byte)fields);
|
||||||
|
|
||||||
@@ -113,6 +117,8 @@ namespace OpenRA
|
|||||||
w.Write(TargetString);
|
w.Write(TargetString);
|
||||||
if (ExtraLocation != CPos.Zero)
|
if (ExtraLocation != CPos.Zero)
|
||||||
w.Write(ExtraLocation.ToInt2());
|
w.Write(ExtraLocation.ToInt2());
|
||||||
|
if (ExtraData != 0)
|
||||||
|
w.Write(ExtraData);
|
||||||
|
|
||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
@@ -134,12 +140,13 @@ namespace OpenRA
|
|||||||
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
|
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
|
||||||
var queued = flags.HasField(OrderFields.Queued);
|
var queued = flags.HasField(OrderFields.Queued);
|
||||||
var extraLocation = (CPos)(flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero);
|
var extraLocation = (CPos)(flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero);
|
||||||
|
var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0;
|
||||||
|
|
||||||
Actor subject, targetActor;
|
Actor subject, targetActor;
|
||||||
if (!TryGetActorFromUInt(world, subjectId, out subject) || !TryGetActorFromUInt(world, targetActorId, out targetActor))
|
if (!TryGetActorFromUInt(world, subjectId, out subject) || !TryGetActorFromUInt(world, targetActorId, out targetActor))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new Order( order, subject, targetActor, targetLocation, targetString, queued, extraLocation);
|
return new Order(order, subject, targetActor, targetLocation, targetString, queued, extraLocation, extraData);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xfe:
|
case 0xfe:
|
||||||
|
|||||||
@@ -234,6 +234,7 @@
|
|||||||
<Compile Include="Graphics\BeamRenderable.cs" />
|
<Compile Include="Graphics\BeamRenderable.cs" />
|
||||||
<Compile Include="Graphics\ContrailRenderable.cs" />
|
<Compile Include="Graphics\ContrailRenderable.cs" />
|
||||||
<Compile Include="Widgets\ViewportControllerWidget.cs" />
|
<Compile Include="Widgets\ViewportControllerWidget.cs" />
|
||||||
|
<Compile Include="Traits\Player\FrozenActorLayer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||||
|
|||||||
@@ -21,11 +21,23 @@ namespace OpenRA.Orders
|
|||||||
{
|
{
|
||||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||||
.Where(a => a.HasTrait<ITargetable>())
|
.Where(a => a.HasTrait<ITargetable>())
|
||||||
.OrderByDescending(a => a.SelectionPriority())
|
.OrderByDescending(a => a.Info.SelectionPriority())
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
Target target;
|
||||||
|
if (underCursor != null)
|
||||||
|
target = Target.FromActor(underCursor);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var frozen = world.FindFrozenActorsAtMouse(mi.Location)
|
||||||
|
.Where(a => a.Info.Traits.Contains<ITargetableInfo>())
|
||||||
|
.OrderByDescending(a => a.Info.SelectionPriority())
|
||||||
|
.FirstOrDefault();
|
||||||
|
target = frozen != null ? Target.FromFrozenActor(frozen) : Target.FromCell(xy);
|
||||||
|
}
|
||||||
|
|
||||||
var orders = world.Selection.Actors
|
var orders = world.Selection.Actors
|
||||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
.Select(a => OrderForUnit(a, target, mi))
|
||||||
.Where(o => o != null)
|
.Where(o => o != null)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
@@ -51,7 +63,7 @@ namespace OpenRA.Orders
|
|||||||
|
|
||||||
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
var underCursor = world.FindUnitsAtMouse(mi.Location)
|
||||||
.Where(a => a.HasTrait<ITargetable>())
|
.Where(a => a.HasTrait<ITargetable>())
|
||||||
.OrderByDescending(a => a.SelectionPriority())
|
.OrderByDescending(a => a.Info.SelectionPriority())
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
if (underCursor != null && (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()))
|
if (underCursor != null && (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()))
|
||||||
@@ -61,8 +73,20 @@ namespace OpenRA.Orders
|
|||||||
useSelect = true;
|
useSelect = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Target target;
|
||||||
|
if (underCursor != null)
|
||||||
|
target = Target.FromActor(underCursor);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var frozen = world.FindFrozenActorsAtMouse(mi.Location)
|
||||||
|
.Where(a => a.Info.Traits.Contains<ITargetableInfo>())
|
||||||
|
.OrderByDescending(a => a.Info.SelectionPriority())
|
||||||
|
.FirstOrDefault();
|
||||||
|
target = frozen != null ? Target.FromFrozenActor(frozen) : Target.FromCell(xy);
|
||||||
|
}
|
||||||
|
|
||||||
var orders = world.Selection.Actors
|
var orders = world.Selection.Actors
|
||||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
.Select(a => OrderForUnit(a, target, mi))
|
||||||
.Where(o => o != null)
|
.Where(o => o != null)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
@@ -70,12 +94,12 @@ namespace OpenRA.Orders
|
|||||||
return cursorName ?? (useSelect ? "select" : "default");
|
return cursorName ?? (useSelect ? "select" : "default");
|
||||||
}
|
}
|
||||||
|
|
||||||
static UnitOrderResult OrderForUnit(Actor self, CPos xy, MouseInput mi, Actor underCursor)
|
static UnitOrderResult OrderForUnit(Actor self, Target target, MouseInput mi)
|
||||||
{
|
{
|
||||||
if (self.Owner != self.World.LocalPlayer)
|
if (self.Owner != self.World.LocalPlayer)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (self.Destroyed)
|
if (self.Destroyed || target.Type == TargetType.Invalid)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (mi.Button == Game.mouseButtonPreference.Action)
|
if (mi.Button == Game.mouseButtonPreference.Action)
|
||||||
@@ -85,7 +109,7 @@ namespace OpenRA.Orders
|
|||||||
.Select(x => new { Trait = trait, Order = x } ))
|
.Select(x => new { Trait = trait, Order = x } ))
|
||||||
.OrderByDescending(x => x.Order.OrderPriority))
|
.OrderByDescending(x => x.Order.OrderPriority))
|
||||||
{
|
{
|
||||||
var actorsAt = self.World.ActorMap.GetUnitsAt(xy).ToList();
|
var actorsAt = self.World.ActorMap.GetUnitsAt(target.CenterPosition.ToCPos()).ToList();
|
||||||
|
|
||||||
var modifiers = TargetModifiers.None;
|
var modifiers = TargetModifiers.None;
|
||||||
if (mi.Modifiers.HasModifier(Modifiers.Ctrl))
|
if (mi.Modifiers.HasModifier(Modifiers.Ctrl))
|
||||||
@@ -96,11 +120,8 @@ namespace OpenRA.Orders
|
|||||||
modifiers |= TargetModifiers.ForceMove;
|
modifiers |= TargetModifiers.ForceMove;
|
||||||
|
|
||||||
string cursor = null;
|
string cursor = null;
|
||||||
if (underCursor != null)
|
if (o.Order.CanTarget(self, target, actorsAt, modifiers, ref cursor))
|
||||||
if (o.Order.CanTargetActor(self, underCursor, modifiers, ref cursor))
|
return new UnitOrderResult(self, o.Order, o.Trait, cursor, target);
|
||||||
return new UnitOrderResult(self, o.Order, o.Trait, cursor, Target.FromActor(underCursor));
|
|
||||||
if (o.Order.CanTargetLocation(self, xy, actorsAt, modifiers, ref cursor))
|
|
||||||
return new UnitOrderResult(self, o.Order, o.Trait, cursor, Target.FromCell(xy));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,9 +158,9 @@ namespace OpenRA.Orders
|
|||||||
|
|
||||||
public static class SelectableExts
|
public static class SelectableExts
|
||||||
{
|
{
|
||||||
public static int SelectionPriority(this Actor a)
|
public static int SelectionPriority(this ActorInfo a)
|
||||||
{
|
{
|
||||||
var selectableInfo = a.Info.Traits.GetOrDefault<SelectableInfo>();
|
var selectableInfo = a.Traits.GetOrDefault<SelectableInfo>();
|
||||||
return selectableInfo != null ? selectableInfo.Priority : int.MinValue;
|
return selectableInfo != null ? selectableInfo.Priority : int.MinValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,8 +109,10 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
self.World.AddFrameEndTask(w =>
|
self.World.AddFrameEndTask(w =>
|
||||||
{
|
{
|
||||||
if (self.Destroyed) return;
|
if (self.Destroyed)
|
||||||
if (target.IsActor && display)
|
return;
|
||||||
|
|
||||||
|
if (target.Type == TargetType.Actor && display)
|
||||||
w.Add(new FlashTarget(target.Actor));
|
w.Add(new FlashTarget(target.Actor));
|
||||||
|
|
||||||
var line = self.TraitOrDefault<DrawLineToTarget>();
|
var line = self.TraitOrDefault<DrawLineToTarget>();
|
||||||
@@ -118,6 +120,24 @@ namespace OpenRA.Traits
|
|||||||
line.SetTarget(self, target, color, display);
|
line.SetTarget(self, target, color, display);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetTargetLine(this Actor self, FrozenActor target, Color color, bool display)
|
||||||
|
{
|
||||||
|
if (self.Owner != self.World.LocalPlayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
self.World.AddFrameEndTask(w =>
|
||||||
|
{
|
||||||
|
if (self.Destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
target.Flash();
|
||||||
|
|
||||||
|
var line = self.TraitOrDefault<DrawLineToTarget>();
|
||||||
|
if (line != null)
|
||||||
|
line.SetTarget(self, Target.FromPos(target.CenterPosition), color, display);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
173
OpenRA.Game/Traits/Player/FrozenActorLayer.cs
Executable file
173
OpenRA.Game/Traits/Player/FrozenActorLayer.cs
Executable file
@@ -0,0 +1,173 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2013 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.FileFormats;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Traits
|
||||||
|
{
|
||||||
|
public class FrozenActorLayerInfo : ITraitInfo
|
||||||
|
{
|
||||||
|
[Desc("Size of partition bins (screen pixels)")]
|
||||||
|
public readonly int BinSize = 250;
|
||||||
|
|
||||||
|
public object Create(ActorInitializer init) { return new FrozenActorLayer(init.world, this); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FrozenActor
|
||||||
|
{
|
||||||
|
public readonly IEnumerable<CPos> Footprint;
|
||||||
|
public readonly WPos CenterPosition;
|
||||||
|
public readonly Rectangle Bounds;
|
||||||
|
readonly Actor actor;
|
||||||
|
|
||||||
|
public IRenderable[] Renderables { set; private get; }
|
||||||
|
public Player Owner;
|
||||||
|
|
||||||
|
public string TooltipName;
|
||||||
|
public Player TooltipOwner;
|
||||||
|
|
||||||
|
public int HP;
|
||||||
|
public DamageState DamageState;
|
||||||
|
|
||||||
|
public bool Visible;
|
||||||
|
|
||||||
|
public FrozenActor(Actor self, IEnumerable<CPos> footprint)
|
||||||
|
{
|
||||||
|
actor = self;
|
||||||
|
Footprint = footprint;
|
||||||
|
CenterPosition = self.CenterPosition;
|
||||||
|
Bounds = self.Bounds.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint ID { get { return actor.ActorID; } }
|
||||||
|
public bool IsValid { get { return Owner != null; } }
|
||||||
|
public ActorInfo Info { get { return actor.Info; } }
|
||||||
|
public Actor Actor { get { return !actor.IsDead() ? actor : null; } }
|
||||||
|
|
||||||
|
int flashTicks;
|
||||||
|
public void Tick(World world, Shroud shroud)
|
||||||
|
{
|
||||||
|
Visible = !Footprint.Any(c => shroud.IsVisible(c));
|
||||||
|
|
||||||
|
if (flashTicks > 0)
|
||||||
|
flashTicks--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Flash()
|
||||||
|
{
|
||||||
|
flashTicks = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||||
|
{
|
||||||
|
if (Renderables == null)
|
||||||
|
return SpriteRenderable.None;
|
||||||
|
|
||||||
|
if (flashTicks > 0 && flashTicks % 2 == 0)
|
||||||
|
{
|
||||||
|
var highlight = wr.Palette("highlight");
|
||||||
|
return Renderables.Concat(Renderables.Where(r => !r.IsDecoration)
|
||||||
|
.Select(r => r.WithPalette(highlight)));
|
||||||
|
}
|
||||||
|
return Renderables;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FrozenActorLayer : IRender, ITick, ISync
|
||||||
|
{
|
||||||
|
[Sync] public int VisibilityHash;
|
||||||
|
[Sync] public int FrozenHash;
|
||||||
|
|
||||||
|
readonly FrozenActorLayerInfo info;
|
||||||
|
Dictionary<uint, FrozenActor> frozen;
|
||||||
|
List<FrozenActor>[,] bins;
|
||||||
|
|
||||||
|
public FrozenActorLayer(World world, FrozenActorLayerInfo info)
|
||||||
|
{
|
||||||
|
this.info = info;
|
||||||
|
frozen = new Dictionary<uint, FrozenActor>();
|
||||||
|
bins = new List<FrozenActor>[
|
||||||
|
world.Map.MapSize.X * Game.CellSize / info.BinSize,
|
||||||
|
world.Map.MapSize.Y * Game.CellSize / info.BinSize];
|
||||||
|
|
||||||
|
for (var j = 0; j <= bins.GetUpperBound(1); j++)
|
||||||
|
for (var i = 0; i <= bins.GetUpperBound(0); i++)
|
||||||
|
bins[i, j] = new List<FrozenActor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(FrozenActor fa)
|
||||||
|
{
|
||||||
|
frozen.Add(fa.ID, fa);
|
||||||
|
|
||||||
|
var top = (int)Math.Max(0, fa.Bounds.Top / info.BinSize);
|
||||||
|
var left = (int)Math.Max(0, fa.Bounds.Left / info.BinSize);
|
||||||
|
var bottom = (int)Math.Min(bins.GetUpperBound(1), fa.Bounds.Bottom / info.BinSize);
|
||||||
|
var right = (int)Math.Min(bins.GetUpperBound(0), fa.Bounds.Right / info.BinSize);
|
||||||
|
for (var j = top; j <= bottom; j++)
|
||||||
|
for (var i = left; i <= right; i++)
|
||||||
|
bins[i, j].Add(fa);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Tick(Actor self)
|
||||||
|
{
|
||||||
|
var remove = new List<uint>();
|
||||||
|
VisibilityHash = 0;
|
||||||
|
FrozenHash = 0;
|
||||||
|
|
||||||
|
foreach (var kv in frozen)
|
||||||
|
{
|
||||||
|
FrozenHash += (int)kv.Key;
|
||||||
|
|
||||||
|
kv.Value.Tick(self.World, self.Owner.Shroud);
|
||||||
|
if (kv.Value.Visible)
|
||||||
|
VisibilityHash += (int)kv.Key;
|
||||||
|
|
||||||
|
if (!kv.Value.Visible && kv.Value.Actor == null)
|
||||||
|
remove.Add(kv.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var r in remove)
|
||||||
|
{
|
||||||
|
foreach (var bin in bins)
|
||||||
|
bin.Remove(frozen[r]);
|
||||||
|
frozen.Remove(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
|
||||||
|
{
|
||||||
|
return frozen.Values
|
||||||
|
.Where(f => f.Visible)
|
||||||
|
.SelectMany(ff => ff.Render(wr));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<FrozenActor> FrozenActorsAt(int2 pxPos)
|
||||||
|
{
|
||||||
|
var x = (pxPos.X / info.BinSize).Clamp(0, bins.GetUpperBound(0));
|
||||||
|
var y = (pxPos.Y / info.BinSize).Clamp(0, bins.GetUpperBound(1));
|
||||||
|
return bins[x, y].Where(p => p.Bounds.Contains(pxPos) && p.IsValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrozenActor FromID(uint id)
|
||||||
|
{
|
||||||
|
FrozenActor ret;
|
||||||
|
if (!frozen.TryGetValue(id, out ret))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,18 +14,20 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace OpenRA.Traits
|
namespace OpenRA.Traits
|
||||||
{
|
{
|
||||||
|
public enum TargetType { Invalid, Actor, Terrain, FrozenActor }
|
||||||
public struct Target
|
public struct Target
|
||||||
{
|
{
|
||||||
public static readonly Target[] NoTargets = {};
|
public static readonly Target[] None = {};
|
||||||
public static readonly Target None = new Target();
|
public static readonly Target Invalid = new Target { type = TargetType.Invalid };
|
||||||
|
|
||||||
|
TargetType type;
|
||||||
Actor actor;
|
Actor actor;
|
||||||
|
FrozenActor frozen;
|
||||||
WPos pos;
|
WPos pos;
|
||||||
bool valid;
|
|
||||||
int generation;
|
int generation;
|
||||||
|
|
||||||
public static Target FromPos(WPos p) { return new Target { pos = p, valid = true }; }
|
public static Target FromPos(WPos p) { return new Target { pos = p, type = TargetType.Terrain }; }
|
||||||
public static Target FromCell(CPos c) { return new Target { pos = c.CenterPosition, valid = true }; }
|
public static Target FromCell(CPos c) { return new Target { pos = c.CenterPosition, type = TargetType.Terrain }; }
|
||||||
public static Target FromOrder(Order o)
|
public static Target FromOrder(Order o)
|
||||||
{
|
{
|
||||||
return o.TargetActor != null
|
return o.TargetActor != null
|
||||||
@@ -38,26 +40,53 @@ namespace OpenRA.Traits
|
|||||||
return new Target
|
return new Target
|
||||||
{
|
{
|
||||||
actor = a,
|
actor = a,
|
||||||
valid = (a != null),
|
type = a != null ? TargetType.Actor : TargetType.Invalid,
|
||||||
generation = a.Generation,
|
generation = a.Generation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsValid { get { return valid && (actor == null || (actor.IsInWorld && !actor.IsDead() && actor.Generation == generation)); } }
|
public static Target FromFrozenActor(FrozenActor a) { return new Target { frozen = a, type = TargetType.FrozenActor }; }
|
||||||
public Actor Actor { get { return IsActor ? actor : null; } }
|
|
||||||
|
|
||||||
// TODO: This should return true even if the actor is destroyed
|
public bool IsValid { get { return Type != TargetType.Invalid; } }
|
||||||
public bool IsActor { get { return actor != null && !actor.Destroyed; } }
|
public Actor Actor { get { return actor; } }
|
||||||
|
public FrozenActor FrozenActor { get { return frozen; } }
|
||||||
|
|
||||||
|
public TargetType Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (type == TargetType.Actor)
|
||||||
|
{
|
||||||
|
// Actor is no longer in the world
|
||||||
|
if (!actor.IsInWorld || actor.IsDead())
|
||||||
|
return TargetType.Invalid;
|
||||||
|
|
||||||
|
// Actor generation has changed (teleported or captured)
|
||||||
|
if (actor.Generation != generation)
|
||||||
|
return TargetType.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Representative position - see Positions for the full set of targetable positions.
|
// Representative position - see Positions for the full set of targetable positions.
|
||||||
public WPos CenterPosition
|
public WPos CenterPosition
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!IsValid)
|
switch (Type)
|
||||||
|
{
|
||||||
|
case TargetType.Actor:
|
||||||
|
return actor.CenterPosition;
|
||||||
|
case TargetType.FrozenActor:
|
||||||
|
return frozen.CenterPosition;
|
||||||
|
case TargetType.Terrain:
|
||||||
|
return pos;
|
||||||
|
default:
|
||||||
|
case TargetType.Invalid:
|
||||||
throw new InvalidOperationException("Attempting to query the position of an invalid Target");
|
throw new InvalidOperationException("Attempting to query the position of an invalid Target");
|
||||||
|
}
|
||||||
return actor != null ? actor.CenterPosition : pos;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,23 +96,29 @@ namespace OpenRA.Traits
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!IsValid)
|
switch (Type)
|
||||||
return NoPositions;
|
{
|
||||||
|
case TargetType.Actor:
|
||||||
if (actor == null)
|
|
||||||
return new []{pos};
|
|
||||||
|
|
||||||
var targetable = actor.TraitOrDefault<ITargetable>();
|
var targetable = actor.TraitOrDefault<ITargetable>();
|
||||||
if (targetable == null)
|
if (targetable == null)
|
||||||
return new [] { actor.CenterPosition };
|
return new [] { actor.CenterPosition };
|
||||||
|
|
||||||
return targetable.TargetablePositions(actor);
|
var positions = targetable.TargetablePositions(actor);
|
||||||
|
return positions.Any() ? positions : new [] { actor.CenterPosition };
|
||||||
|
case TargetType.FrozenActor:
|
||||||
|
return new [] { frozen.CenterPosition };
|
||||||
|
case TargetType.Terrain:
|
||||||
|
return new [] { pos };
|
||||||
|
default:
|
||||||
|
case TargetType.Invalid:
|
||||||
|
return NoPositions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInRange(WPos origin, WRange range)
|
public bool IsInRange(WPos origin, WRange range)
|
||||||
{
|
{
|
||||||
if (!IsValid)
|
if (Type == TargetType.Invalid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Target ranges are calculated in 2D, so ignore height differences
|
// Target ranges are calculated in 2D, so ignore height differences
|
||||||
|
|||||||
@@ -55,8 +55,7 @@ namespace OpenRA.Traits
|
|||||||
{
|
{
|
||||||
string OrderID { get; }
|
string OrderID { get; }
|
||||||
int OrderPriority { get; }
|
int OrderPriority { get; }
|
||||||
bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor);
|
bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor);
|
||||||
bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor);
|
|
||||||
bool IsQueued { get; }
|
bool IsQueued { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +203,11 @@ namespace OpenRA.Traits
|
|||||||
}
|
}
|
||||||
public interface IBodyOrientationInfo {}
|
public interface IBodyOrientationInfo {}
|
||||||
|
|
||||||
|
public interface ITargetableInfo
|
||||||
|
{
|
||||||
|
string[] GetTargetTypes();
|
||||||
|
}
|
||||||
|
|
||||||
public interface ITargetable
|
public interface ITargetable
|
||||||
{
|
{
|
||||||
string[] TargetTypes { get; }
|
string[] TargetTypes { get; }
|
||||||
|
|||||||
@@ -134,13 +134,7 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public static IEnumerable<CPos> AdjacentCells(Target target)
|
public static IEnumerable<CPos> AdjacentCells(Target target)
|
||||||
{
|
{
|
||||||
var cells = target.IsActor
|
var cells = target.Positions.Select(p => p.ToCPos()).Distinct();
|
||||||
? target.Actor.OccupiesSpace.OccupiedCells().Select(c => c.First).ToArray()
|
|
||||||
: new CPos[] { };
|
|
||||||
|
|
||||||
if (cells.Length == 0)
|
|
||||||
cells = new CPos[] { target.CenterPosition.ToCPos() };
|
|
||||||
|
|
||||||
return Util.ExpandFootprint(cells, true);
|
return Util.ExpandFootprint(cells, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ using System.Linq;
|
|||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.GameRules;
|
using OpenRA.GameRules;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
|
using OpenRA.Orders;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Widgets
|
namespace OpenRA.Widgets
|
||||||
{
|
{
|
||||||
public enum WorldTooltipType { None, Unexplored, Actor }
|
public enum WorldTooltipType { None, Unexplored, Actor, FrozenActor }
|
||||||
|
|
||||||
public class ViewportControllerWidget : Widget
|
public class ViewportControllerWidget : Widget
|
||||||
{
|
{
|
||||||
@@ -28,6 +29,7 @@ namespace OpenRA.Widgets
|
|||||||
|
|
||||||
public WorldTooltipType TooltipType { get; private set; }
|
public WorldTooltipType TooltipType { get; private set; }
|
||||||
public IToolTip ActorTooltip { get; private set; }
|
public IToolTip ActorTooltip { get; private set; }
|
||||||
|
public FrozenActor FrozenActorTooltip { get; private set; }
|
||||||
|
|
||||||
public int EdgeScrollThreshold = 15;
|
public int EdgeScrollThreshold = 15;
|
||||||
public int EdgeCornerScrollThreshold = 35;
|
public int EdgeCornerScrollThreshold = 35;
|
||||||
@@ -101,13 +103,28 @@ namespace OpenRA.Widgets
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var actor = world.FindUnitsAtMouse(Viewport.LastMousePos).FirstOrDefault();
|
var underCursor = world.FindUnitsAtMouse(Viewport.LastMousePos)
|
||||||
if (actor == null)
|
.Where(a => a.HasTrait<IToolTip>())
|
||||||
return;
|
.OrderByDescending(a => a.Info.SelectionPriority())
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
ActorTooltip = actor.TraitsImplementing<IToolTip>().FirstOrDefault();
|
if (underCursor != null)
|
||||||
if (ActorTooltip != null)
|
{
|
||||||
|
ActorTooltip = underCursor.TraitsImplementing<IToolTip>().First();
|
||||||
TooltipType = WorldTooltipType.Actor;
|
TooltipType = WorldTooltipType.Actor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var frozen = world.FindFrozenActorsAtMouse(Viewport.LastMousePos)
|
||||||
|
.Where(a => a.TooltipName != null)
|
||||||
|
.OrderByDescending(a => a.Info.SelectionPriority())
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (frozen != null)
|
||||||
|
{
|
||||||
|
FrozenActorTooltip = frozen;
|
||||||
|
TooltipType = WorldTooltipType.FrozenActor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetScrollCursor(Widget w, ScrollDirection edge, int2 pos)
|
public static string GetScrollCursor(Widget w, ScrollDirection edge, int2 pos)
|
||||||
|
|||||||
@@ -27,6 +27,20 @@ namespace OpenRA
|
|||||||
return FindActorsInBox(world, loc, loc).Where(a => !world.FogObscures(a));
|
return FindActorsInBox(world, loc, loc).Where(a => !world.FogObscures(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly IEnumerable<FrozenActor> NoFrozenActors = new FrozenActor[0].AsEnumerable();
|
||||||
|
public static IEnumerable<FrozenActor> FindFrozenActorsAtMouse(this World world, int2 mouseLocation)
|
||||||
|
{
|
||||||
|
if (world.RenderPlayer == null)
|
||||||
|
return NoFrozenActors;
|
||||||
|
|
||||||
|
var frozenLayer = world.RenderPlayer.PlayerActor.TraitOrDefault<FrozenActorLayer>();
|
||||||
|
if (frozenLayer == null)
|
||||||
|
return NoFrozenActors;
|
||||||
|
|
||||||
|
var loc = Game.viewport.ViewToWorldPx(mouseLocation).ToInt2();
|
||||||
|
return frozenLayer.FrozenActorsAt(loc);
|
||||||
|
}
|
||||||
|
|
||||||
public static IEnumerable<Actor> FindActorsInBox(this World world, CPos tl, CPos br)
|
public static IEnumerable<Actor> FindActorsInBox(this World world, CPos tl, CPos br)
|
||||||
{
|
{
|
||||||
return world.FindActorsInBox(tl.TopLeft, br.BottomRight);
|
return world.FindActorsInBox(tl.TopLeft, br.BottomRight);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
public Attack(Target target, WRange range, bool allowMovement)
|
public Attack(Target target, WRange range, bool allowMovement)
|
||||||
{
|
{
|
||||||
Target = target;
|
Target = target;
|
||||||
if (target.IsActor)
|
if (target.Type == TargetType.Actor)
|
||||||
targetable = target.Actor.TraitOrDefault<ITargetable>();
|
targetable = target.Actor.TraitOrDefault<ITargetable>();
|
||||||
|
|
||||||
Range = range;
|
Range = range;
|
||||||
@@ -53,10 +53,11 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
if (IsCanceled)
|
if (IsCanceled)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
if (!Target.IsValid)
|
var type = Target.Type;
|
||||||
|
if (type != TargetType.Actor && type != TargetType.Terrain)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
if (!self.Owner.HasFogVisibility() && Target.Actor != null && Target.Actor.HasTrait<Mobile>() && !self.Owner.Shroud.IsTargetable(Target.Actor))
|
if (type == TargetType.Actor && !self.Owner.HasFogVisibility() && Target.Actor.HasTrait<Mobile>() && !self.Owner.Shroud.IsTargetable(Target.Actor))
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
if (targetable != null && !targetable.TargetableBy(Target.Actor, self))
|
if (targetable != null && !targetable.TargetableBy(Target.Actor, self))
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (!target.IsValid)
|
if (target.Type != TargetType.Actor)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
var capturable = target.Actor.Trait<Capturable>();
|
var capturable = target.Actor.Trait<Capturable>();
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (IsCanceled || !target.IsValid)
|
if (IsCanceled || target.Type != TargetType.Actor)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () =>
|
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () =>
|
||||||
{
|
{
|
||||||
// Can't demolish an already dead actor
|
// Can't demolish an already dead actor
|
||||||
if (!target.IsValid)
|
if (target.Type != TargetType.Actor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Invulnerable actors can't be demolished
|
// Invulnerable actors can't be demolished
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (IsCanceled || !target.IsValid || !target.IsActor)
|
if (IsCanceled || target.Type != TargetType.Actor)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
var targetActor = target.Actor;
|
var targetActor = target.Actor;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (IsCanceled || !target.IsValid)
|
if (IsCanceled || target.Type != TargetType.Actor)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
if (!Util.AdjacentCells(target).Any(c => c == self.Location))
|
if (!Util.AdjacentCells(target).Any(c => c == self.Location))
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
protected override Activity InnerTick(Actor self, AttackBase attack)
|
protected override Activity InnerTick(Actor self, AttackBase attack)
|
||||||
{
|
{
|
||||||
if (Target.IsActor && Target.Actor.GetDamageState() == DamageState.Undamaged)
|
if (Target.Type == TargetType.Actor && Target.Actor.GetDamageState() == DamageState.Undamaged)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
return base.InnerTick(self, attack);
|
return base.InnerTick(self, attack);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (IsCanceled || !target.IsValid || target.Actor.Owner == self.Owner)
|
if (IsCanceled || target.Type != TargetType.Actor || target.Actor.Owner == self.Owner)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
foreach (var t in target.Actor.TraitsImplementing<IAcceptInfiltrator>())
|
foreach (var t in target.Actor.TraitsImplementing<IAcceptInfiltrator>())
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.Traits;
|
|
||||||
using OpenRA.Mods.RA.Move;
|
|
||||||
using OpenRA.Mods.RA.Buildings;
|
using OpenRA.Mods.RA.Buildings;
|
||||||
|
using OpenRA.Mods.RA.Move;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA.Activities
|
namespace OpenRA.Mods.RA.Activities
|
||||||
{
|
{
|
||||||
@@ -23,31 +23,30 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (IsCanceled)
|
if (IsCanceled || target.Type != TargetType.Actor)
|
||||||
return NextActivity;
|
|
||||||
if (!target.IsValid)
|
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
var b = target.Actor.TraitOrDefault<Building>();
|
var actor = target.Actor;
|
||||||
|
var b = actor.TraitOrDefault<Building>();
|
||||||
if (b != null && b.Locked)
|
if (b != null && b.Locked)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
var capturesInfo = self.Info.Traits.Get<LegacyCapturesInfo>();
|
var capturesInfo = self.Info.Traits.Get<LegacyCapturesInfo>();
|
||||||
var capturableInfo = target.Actor.Info.Traits.Get<LegacyCapturableInfo>();
|
var capturableInfo = actor.Info.Traits.Get<LegacyCapturableInfo>();
|
||||||
|
|
||||||
var health = target.Actor.Trait<Health>();
|
var health = actor.Trait<Health>();
|
||||||
|
|
||||||
self.World.AddFrameEndTask(w =>
|
self.World.AddFrameEndTask(w =>
|
||||||
{
|
{
|
||||||
var lowEnoughHealth = health.HP <= capturableInfo.CaptureThreshold * health.MaxHP;
|
var lowEnoughHealth = health.HP <= capturableInfo.CaptureThreshold * health.MaxHP;
|
||||||
if (!capturesInfo.Sabotage || lowEnoughHealth || target.Actor.Owner.NonCombatant)
|
if (!capturesInfo.Sabotage || lowEnoughHealth || actor.Owner.NonCombatant)
|
||||||
{
|
{
|
||||||
var oldOwner = target.Actor.Owner;
|
var oldOwner = actor.Owner;
|
||||||
|
|
||||||
target.Actor.ChangeOwner(self.Owner);
|
actor.ChangeOwner(self.Owner);
|
||||||
|
|
||||||
foreach (var t in target.Actor.TraitsImplementing<INotifyCapture>())
|
foreach (var t in actor.TraitsImplementing<INotifyCapture>())
|
||||||
t.OnCapture(target.Actor, self, oldOwner, self.Owner);
|
t.OnCapture(actor, self, oldOwner, self.Owner);
|
||||||
|
|
||||||
if (b != null && b.Locked)
|
if (b != null && b.Locked)
|
||||||
b.Unlock();
|
b.Unlock();
|
||||||
@@ -55,7 +54,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var damage = (int)(health.MaxHP * capturesInfo.SabotageHPRemoval);
|
var damage = (int)(health.MaxHP * capturesInfo.SabotageHPRemoval);
|
||||||
target.Actor.InflictDamage(self, damage, null);
|
actor.InflictDamage(self, damage, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Destroy();
|
self.Destroy();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (IsCanceled || !target.IsValid)
|
if (IsCanceled || target.Type != TargetType.Actor)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
var hut = target.Actor.Trait<BridgeHut>();
|
var hut = target.Actor.Trait<BridgeHut>();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (IsCanceled || !target.IsValid)
|
if (IsCanceled || target.Type != TargetType.Actor)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
var health = target.Actor.Trait<Health>();
|
var health = target.Actor.Trait<Health>();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
@@ -44,6 +45,44 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
return stance == Stance.Enemy;
|
return stance == Stance.Enemy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Target ResolveFrozenActorOrder(this Actor self, Order order, Color targetLine)
|
||||||
|
{
|
||||||
|
// Not targeting a frozen actor
|
||||||
|
if (order.ExtraData == 0)
|
||||||
|
return Target.FromOrder(order);
|
||||||
|
|
||||||
|
// Targeted an actor under the fog
|
||||||
|
var frozenLayer = self.Owner.PlayerActor.TraitOrDefault<FrozenActorLayer>();
|
||||||
|
if (frozenLayer == null)
|
||||||
|
return Target.Invalid;
|
||||||
|
|
||||||
|
var frozen = frozenLayer.FromID(order.ExtraData);
|
||||||
|
if (frozen == null)
|
||||||
|
return Target.Invalid;
|
||||||
|
|
||||||
|
// Flashes the frozen proxy
|
||||||
|
self.SetTargetLine(frozen, targetLine, true);
|
||||||
|
|
||||||
|
// Target is still alive - resolve the real order
|
||||||
|
if (frozen.Actor != null && frozen.Actor.IsInWorld)
|
||||||
|
return Target.FromActor(frozen.Actor);
|
||||||
|
|
||||||
|
if (!order.Queued)
|
||||||
|
self.CancelActivity();
|
||||||
|
|
||||||
|
var move = self.TraitOrDefault<IMove>();
|
||||||
|
if (move != null)
|
||||||
|
{
|
||||||
|
// Move within sight range of the frozen actor
|
||||||
|
var sight = self.TraitOrDefault<RevealsShroud>();
|
||||||
|
var range = sight != null ? sight.Range : 2;
|
||||||
|
|
||||||
|
self.QueueActivity(move.MoveWithinRange(Target.FromPos(frozen.CenterPosition), WRange.FromCells(range)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Target.Invalid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new EnterOrderTargeter<Building>("Enter", 5, false, true,
|
yield return new EnterAlliedActorTargeter<Building>("Enter", 5,
|
||||||
target => AircraftCanEnter(target), target => !Reservable.IsReserved(target));
|
target => AircraftCanEnter(target), target => !Reservable.IsReserved(target));
|
||||||
|
|
||||||
yield return new AircraftMoveOrderTargeter();
|
yield return new AircraftMoveOrderTargeter();
|
||||||
@@ -217,15 +217,13 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
public string OrderID { get { return "Move"; } }
|
public string OrderID { get { return "Move"; } }
|
||||||
public int OrderPriority { get { return 4; } }
|
public int OrderPriority { get { return 4; } }
|
||||||
|
|
||||||
public bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
|
if (target.Type != TargetType.Terrain)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
|
||||||
{
|
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||||
cursor = self.World.Map.IsInMap(location) ? "move" : "move-blocked";
|
cursor = self.World.Map.IsInMap(target.CenterPosition.ToCPos()) ? "move" : "move-blocked";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace OpenRA.Mods.RA
|
|||||||
if (self.IsDisabled())
|
if (self.IsDisabled())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (target.IsActor && target.Actor.HasTrait<ITargetable>() &&
|
if (target.Type == TargetType.Actor && target.Actor.HasTrait<ITargetable>() &&
|
||||||
!target.Actor.Trait<ITargetable>().TargetableBy(target.Actor, self))
|
!target.Actor.Trait<ITargetable>().TargetableBy(target.Actor, self))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -76,6 +76,7 @@ namespace OpenRA.Mods.RA
|
|||||||
x.Second();
|
x.Second();
|
||||||
delayedActions[i] = x;
|
delayedActions[i] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
delayedActions.RemoveAll(a => a.First <= 0);
|
delayedActions.RemoveAll(a => a.First <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +105,7 @@ namespace OpenRA.Mods.RA
|
|||||||
if (Armaments.Count() == 0)
|
if (Armaments.Count() == 0)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
var negativeDamage = (Armaments.First().Weapon.Warheads[0].Damage < 0);
|
var negativeDamage = Armaments.First().Weapon.Warheads[0].Damage < 0;
|
||||||
|
|
||||||
yield return new AttackOrderTargeter("Attack", 6, negativeDamage);
|
yield return new AttackOrderTargeter("Attack", 6, negativeDamage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,27 +114,36 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
if (order is AttackOrderTargeter)
|
if (order is AttackOrderTargeter)
|
||||||
{
|
{
|
||||||
if (target.IsActor)
|
switch (target.Type)
|
||||||
|
{
|
||||||
|
case TargetType.Actor:
|
||||||
return new Order("Attack", self, queued) { TargetActor = target.Actor };
|
return new Order("Attack", self, queued) { TargetActor = target.Actor };
|
||||||
else
|
case TargetType.FrozenActor:
|
||||||
|
return new Order("Attack", self, queued) { ExtraData = target.FrozenActor.ID };
|
||||||
|
case TargetType.Terrain:
|
||||||
return new Order("Attack", self, queued) { TargetLocation = target.CenterPosition.ToCPos() };
|
return new Order("Attack", self, queued) { TargetLocation = target.CenterPosition.ToCPos() };
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void ResolveOrder(Actor self, Order order)
|
public virtual void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "Attack" || order.OrderString == "AttackHold")
|
if (order.OrderString == "Attack")
|
||||||
{
|
{
|
||||||
var target = Target.FromOrder(order);
|
var target = self.ResolveFrozenActorOrder(order, Color.Red);
|
||||||
|
if (!target.IsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
self.SetTargetLine(target, Color.Red);
|
self.SetTargetLine(target, Color.Red);
|
||||||
AttackTarget(target, order.Queued, order.OrderString == "Attack");
|
AttackTarget(target, order.Queued, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
return (order.OrderString == "Attack" || order.OrderString == "AttackHold") ? "Attack" : null;
|
return order.OrderString == "Attack" ? "Attack" : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove);
|
public abstract Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove);
|
||||||
@@ -169,16 +178,16 @@ namespace OpenRA.Mods.RA
|
|||||||
public string OrderID { get; private set; }
|
public string OrderID { get; private set; }
|
||||||
public int OrderPriority { get; private set; }
|
public int OrderPriority { get; private set; }
|
||||||
|
|
||||||
public bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
bool CanTargetActor(Actor self, Target target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||||
|
|
||||||
cursor = self.Info.Traits.Get<AttackBaseInfo>().Cursor;
|
cursor = self.Info.Traits.Get<AttackBaseInfo>().Cursor;
|
||||||
|
|
||||||
if (self == target)
|
if (target.Type == TargetType.Actor && target.Actor == self)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!self.Trait<AttackBase>().HasAnyValidWeapons(Target.FromActor(target)))
|
if (!self.Trait<AttackBase>().HasAnyValidWeapons(target))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (modifiers.HasModifier(TargetModifiers.ForceAttack))
|
if (modifiers.HasModifier(TargetModifiers.ForceAttack))
|
||||||
@@ -189,10 +198,11 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
var targetableRelationship = negativeDamage ? Stance.Ally : Stance.Enemy;
|
var targetableRelationship = negativeDamage ? Stance.Ally : Stance.Enemy;
|
||||||
|
|
||||||
return self.Owner.Stances[target.Owner] == targetableRelationship;
|
var owner = target.Type == TargetType.FrozenActor ? target.FrozenActor.Owner : target.Actor.Owner;
|
||||||
|
return self.Owner.Stances[owner] == targetableRelationship;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!self.World.Map.IsInMap(location))
|
if (!self.World.Map.IsInMap(location))
|
||||||
return false;
|
return false;
|
||||||
@@ -214,6 +224,20 @@ namespace OpenRA.Mods.RA
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||||
|
{
|
||||||
|
switch (target.Type)
|
||||||
|
{
|
||||||
|
case TargetType.Actor:
|
||||||
|
case TargetType.FrozenActor:
|
||||||
|
return CanTargetActor(self, target, modifiers, ref cursor);
|
||||||
|
case TargetType.Terrain:
|
||||||
|
return CanTargetLocation(self, target.CenterPosition.ToCPos(), othersAtTarget, modifiers, ref cursor);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsQueued { get; protected set; }
|
public bool IsQueued { get; protected set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public override void DoAttack(Actor self, Target target)
|
public override void DoAttack(Actor self, Target target)
|
||||||
{
|
{
|
||||||
if (!CanAttack(self, target) || !target.IsActor)
|
if (target.Type != TargetType.Actor || !CanAttack(self, target))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var a = ChooseArmamentForTarget(target);
|
var a = ChooseArmamentForTarget(target);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA
|
|||||||
base.ResolveOrder(self, order);
|
base.ResolveOrder(self, order);
|
||||||
|
|
||||||
if (order.OrderString == "Stop")
|
if (order.OrderString == "Stop")
|
||||||
target = Target.None;
|
target = Target.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void BuildingComplete(Actor self) { buildComplete = true; }
|
public virtual void BuildingComplete(Actor self) { buildComplete = true; }
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ namespace OpenRA.Mods.RA
|
|||||||
public UnitStance stance;
|
public UnitStance stance;
|
||||||
[Sync] public int stanceNumber { get { return (int)stance; } }
|
[Sync] public int stanceNumber { get { return (int)stance; } }
|
||||||
public UnitStance predictedStance; /* NOT SYNCED: do not refer to this anywhere other than UI code */
|
public UnitStance predictedStance; /* NOT SYNCED: do not refer to this anywhere other than UI code */
|
||||||
[Sync] public int AggressorID;
|
[Sync] public Actor Aggressor;
|
||||||
|
[Sync] public Actor TargetedActor;
|
||||||
|
|
||||||
public AutoTarget(Actor self, AutoTargetInfo info)
|
public AutoTarget(Actor self, AutoTargetInfo info)
|
||||||
{
|
{
|
||||||
@@ -75,7 +76,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
if (e.Damage < 0) return; // don't retaliate against healers
|
if (e.Damage < 0) return; // don't retaliate against healers
|
||||||
|
|
||||||
AggressorID = (int)e.Attacker.ActorID;
|
Aggressor = e.Attacker;
|
||||||
|
|
||||||
attack.AttackTarget(Target.FromActor(e.Attacker), false, Info.AllowMovement && stance != UnitStance.Defend);
|
attack.AttackTarget(Target.FromActor(e.Attacker), false, Info.AllowMovement && stance != UnitStance.Defend);
|
||||||
}
|
}
|
||||||
@@ -87,6 +88,8 @@ namespace OpenRA.Mods.RA
|
|||||||
var target = ScanForTarget(self, null);
|
var target = ScanForTarget(self, null);
|
||||||
if (target != null)
|
if (target != null)
|
||||||
{
|
{
|
||||||
|
TargetedActor = target;
|
||||||
|
|
||||||
var t = Target.FromActor(target);
|
var t = Target.FromActor(target);
|
||||||
self.SetTargetLine(t, Color.Red, false);
|
self.SetTargetLine(t, Color.Red, false);
|
||||||
attack.AttackTarget(t, false, Info.AllowMovement && stance != UnitStance.Defend);
|
attack.AttackTarget(t, false, Info.AllowMovement && stance != UnitStance.Defend);
|
||||||
@@ -113,8 +116,11 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
var targetActor = ScanForTarget(self, null);
|
var targetActor = ScanForTarget(self, null);
|
||||||
if (targetActor != null)
|
if (targetActor != null)
|
||||||
|
{
|
||||||
|
TargetedActor = targetActor;
|
||||||
attack.AttackTarget(Target.FromActor(targetActor), false, Info.AllowMovement && stance != UnitStance.Defend);
|
attack.AttackTarget(Target.FromActor(targetActor), false, Info.AllowMovement && stance != UnitStance.Defend);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Actor ChooseTarget(Actor self, WRange range)
|
Actor ChooseTarget(Actor self, WRange range)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
class C4Demolition : IIssueOrder, IResolveOrder, IOrderVoice
|
class C4Demolition : IIssueOrder, IResolveOrder, IOrderVoice
|
||||||
{
|
{
|
||||||
readonly C4DemolitionInfo Info;
|
readonly C4DemolitionInfo info;
|
||||||
|
|
||||||
public C4Demolition(C4DemolitionInfo info)
|
public C4Demolition(C4DemolitionInfo info)
|
||||||
{
|
{
|
||||||
Info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IOrderTargeter> Orders
|
public IEnumerable<IOrderTargeter> Orders
|
||||||
@@ -40,26 +40,34 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||||
{
|
{
|
||||||
if (order.OrderID == "C4")
|
if (order.OrderID != "C4")
|
||||||
return new Order("C4", self, queued) { TargetActor = target.Actor };
|
|
||||||
|
|
||||||
return null;
|
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 void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "C4")
|
if (order.OrderString != "C4")
|
||||||
{
|
return;
|
||||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
|
||||||
|
|
||||||
|
var target = self.ResolveFrozenActorOrder(order, Color.Red);
|
||||||
|
if (target.Type != TargetType.Actor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!order.Queued)
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
self.QueueActivity(new Enter(order.TargetActor, new Demolish(order.TargetActor, Info.C4Delay)));
|
|
||||||
}
|
self.SetTargetLine(target, Color.Red);
|
||||||
|
self.QueueActivity(new Enter(target.Actor, new Demolish(target.Actor, info.C4Delay)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
return (order.OrderString == "C4") ? "Attack" : null;
|
return order.OrderString == "C4" ? "Attack" : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,28 @@ namespace OpenRA.Mods.RA
|
|||||||
[Desc("Seconds it takes to change the owner.", "You might want to add a CapturableBar: trait, too.")]
|
[Desc("Seconds it takes to change the owner.", "You might want to add a CapturableBar: trait, too.")]
|
||||||
public readonly int CaptureCompleteTime = 15;
|
public readonly int CaptureCompleteTime = 15;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
public object Create(ActorInitializer init) { return new Capturable(init.self, this); }
|
public object Create(ActorInitializer init) { return new Capturable(init.self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,31 +67,6 @@ namespace OpenRA.Mods.RA
|
|||||||
Info = info;
|
Info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanBeTargetedBy(Actor captor)
|
|
||||||
{
|
|
||||||
var c = captor.TraitOrDefault<Captures>();
|
|
||||||
if (c == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var playerRelationship = self.Owner.Stances[captor.Owner];
|
|
||||||
if (playerRelationship == Stance.Ally && !Info.AllowAllies)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (playerRelationship == Stance.Enemy && !Info.AllowEnemies)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (playerRelationship == Stance.Neutral && !Info.AllowNeutral)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!c.Info.CaptureTypes.Contains(Info.Type))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (CaptureInProgress)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BeginCapture(Actor captor)
|
public void BeginCapture(Actor captor)
|
||||||
{
|
{
|
||||||
var building = self.TraitOrDefault<Building>();
|
var building = self.TraitOrDefault<Building>();
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Mods.RA.Activities;
|
using OpenRA.Mods.RA.Activities;
|
||||||
using OpenRA.Mods.RA.Buildings;
|
using OpenRA.Mods.RA.Buildings;
|
||||||
using OpenRA.Mods.RA.Orders;
|
using OpenRA.Mods.RA.Orders;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
using OpenRA.FileFormats;
|
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
@@ -34,11 +34,9 @@ namespace OpenRA.Mods.RA
|
|||||||
class Captures : IIssueOrder, IResolveOrder, IOrderVoice
|
class Captures : IIssueOrder, IResolveOrder, IOrderVoice
|
||||||
{
|
{
|
||||||
public readonly CapturesInfo Info;
|
public readonly CapturesInfo Info;
|
||||||
readonly Actor self;
|
|
||||||
|
|
||||||
public Captures(Actor self, CapturesInfo info)
|
public Captures(Actor self, CapturesInfo info)
|
||||||
{
|
{
|
||||||
this.self = self;
|
|
||||||
Info = info;
|
Info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,69 +44,89 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new CaptureOrderTargeter(CanCapture);
|
yield return new CaptureOrderTargeter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||||
{
|
{
|
||||||
if (order.OrderID == "CaptureActor")
|
if (order.OrderID != "CaptureActor")
|
||||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
|
||||||
|
|
||||||
return null;
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
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<CapturableInfo>();
|
||||||
|
return ci != null && ci.CanBeTargetedBy(self, frozen.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
var c = order.TargetActor.TraitOrDefault<Capturable>();
|
||||||
|
return c != null && !c.CaptureInProgress && c.Info.CanBeTargetedBy(self, order.TargetActor.Owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
return (order.OrderString == "CaptureActor" && CanCapture(order.TargetActor)) ? "Attack" : null;
|
return order.OrderString == "CaptureActor" && IsValidOrder(self, order)
|
||||||
|
? "Attack" : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "CaptureActor")
|
if (order.OrderString != "CaptureActor" || !IsValidOrder(self, order))
|
||||||
{
|
|
||||||
if (!CanCapture(order.TargetActor))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
var target = self.ResolveFrozenActorOrder(order, Color.Red);
|
||||||
|
if (target.Type != TargetType.Actor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!order.Queued)
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
self.QueueActivity(new CaptureActor(Target.FromOrder(order)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CanCapture(Actor target)
|
self.SetTargetLine(target, Color.Red);
|
||||||
{
|
self.QueueActivity(new CaptureActor(target));
|
||||||
var c = target.TraitOrDefault<Capturable>();
|
|
||||||
return c != null && c.CanBeTargetedBy(self);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CaptureOrderTargeter : UnitOrderTargeter
|
class CaptureOrderTargeter : UnitOrderTargeter
|
||||||
{
|
{
|
||||||
readonly Func<Actor, bool> useCaptureCursor;
|
public CaptureOrderTargeter() : base("CaptureActor", 6, "enter", true, true) { }
|
||||||
|
|
||||||
public CaptureOrderTargeter(Func<Actor, bool> useCaptureCursor)
|
|
||||||
: base("CaptureActor", 6, "enter", true, true)
|
|
||||||
{
|
|
||||||
this.useCaptureCursor = useCaptureCursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!base.CanTargetActor(self, target, modifiers, ref cursor))
|
var c = target.TraitOrDefault<Capturable>();
|
||||||
return false;
|
|
||||||
|
|
||||||
var canTargetActor = useCaptureCursor(target);
|
var canTargetActor = c != null && !c.CaptureInProgress && c.Info.CanBeTargetedBy(self, target.Owner);
|
||||||
cursor = canTargetActor ? "ability" : "move-blocked";
|
cursor = canTargetActor ? "ability" : "move-blocked";
|
||||||
|
return canTargetActor;
|
||||||
|
}
|
||||||
|
|
||||||
if (canTargetActor)
|
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
var c = target.Info.Traits.GetOrDefault<CapturableInfo>();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
var canTargetActor = c != null && c.CanBeTargetedBy(self, target.Owner);
|
||||||
|
cursor = canTargetActor ? "ability" : "move-blocked";
|
||||||
|
return canTargetActor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ namespace OpenRA.Mods.RA
|
|||||||
foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0]))
|
foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0]))
|
||||||
foreach (var unit in world.FindActorsInBox(t, t))
|
foreach (var unit in world.FindActorsInBox(t, t))
|
||||||
unit.InflictDamage(firedBy,
|
unit.InflictDamage(firedBy,
|
||||||
(int)(warhead.Damage * warhead.EffectivenessAgainst(unit)), warhead);
|
(int)(warhead.Damage * warhead.EffectivenessAgainst(unit.Info)), warhead);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +173,7 @@ namespace OpenRA.Mods.RA
|
|||||||
var distance = (int)Math.Max(0, (target.CenterPosition - pos).Length * Game.CellSize / 1024 - health.Radius);
|
var distance = (int)Math.Max(0, (target.CenterPosition - pos).Length * Game.CellSize / 1024 - health.Radius);
|
||||||
var falloff = (float)GetDamageFalloff(distance / warhead.Spread);
|
var falloff = (float)GetDamageFalloff(distance / warhead.Spread);
|
||||||
var rawDamage = (float)(warhead.Damage * modifier * falloff);
|
var rawDamage = (float)(warhead.Damage * modifier * falloff);
|
||||||
var multiplier = (float)warhead.EffectivenessAgainst(target);
|
var multiplier = (float)warhead.EffectivenessAgainst(target.Info);
|
||||||
|
|
||||||
return (float)(rawDamage * multiplier);
|
return (float)(rawDamage * multiplier);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
// Exception when overriding Chronoshift event; removed for now, will look into it.
|
|
||||||
class DemoTruckInfo : TraitInfo<DemoTruck>, Requires<ExplodesInfo> { }
|
class DemoTruckInfo : TraitInfo<DemoTruck>, Requires<ExplodesInfo> { }
|
||||||
|
|
||||||
class DemoTruck : IIssueOrder, IResolveOrder, IOrderVoice
|
class DemoTruck : IIssueOrder, IResolveOrder, IOrderVoice
|
||||||
@@ -41,10 +40,13 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||||
{
|
{
|
||||||
if (order.OrderID == "DemoAttack" || order.OrderID == "DemoDeploy")
|
if (order.OrderID != "DemoAttack" && order.OrderID != "DemoDeploy")
|
||||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
|
||||||
|
|
||||||
return null;
|
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)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
@@ -56,13 +58,18 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
if (order.OrderString == "DemoAttack")
|
if (order.OrderString == "DemoAttack")
|
||||||
{
|
{
|
||||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
var target = self.ResolveFrozenActorOrder(order, Color.Red);
|
||||||
self.World.AddFrameEndTask(w =>
|
if (target.Type != TargetType.Actor)
|
||||||
{
|
return;
|
||||||
self.QueueActivity(new MoveAdjacentTo(Target.FromOrder(order)));
|
|
||||||
|
if (!order.Queued)
|
||||||
|
self.CancelActivity();
|
||||||
|
|
||||||
|
self.SetTargetLine(target, Color.Red);
|
||||||
|
self.QueueActivity(new MoveAdjacentTo(target));
|
||||||
self.QueueActivity(new CallFunc(() => Explode(self)));
|
self.QueueActivity(new CallFunc(() => Explode(self)));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (order.OrderString == "DemoDeploy")
|
if (order.OrderString == "DemoDeploy")
|
||||||
Explode(self);
|
Explode(self);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2013 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.Traits;
|
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA.Effects
|
|
||||||
{
|
|
||||||
public class FrozenActorProxy : IEffect
|
|
||||||
{
|
|
||||||
readonly Actor self;
|
|
||||||
readonly IEnumerable<CPos> footprint;
|
|
||||||
IRenderable[] renderables;
|
|
||||||
|
|
||||||
public FrozenActorProxy(Actor self, IEnumerable<CPos> footprint)
|
|
||||||
{
|
|
||||||
this.self = self;
|
|
||||||
this.footprint = footprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Tick(World world) { }
|
|
||||||
public void SetRenderables(IEnumerable<IRenderable> r)
|
|
||||||
{
|
|
||||||
renderables = r.Select(rr => rr).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
|
||||||
{
|
|
||||||
if (renderables == null)
|
|
||||||
return SpriteRenderable.None;
|
|
||||||
|
|
||||||
if (footprint.Any(c => !wr.world.FogObscures(c)))
|
|
||||||
{
|
|
||||||
if (self.Destroyed)
|
|
||||||
self.World.AddFrameEndTask(w => w.Remove(this));
|
|
||||||
|
|
||||||
return SpriteRenderable.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderables;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,28 +28,58 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||||
{
|
{
|
||||||
if (order.OrderID == "EngineerRepair")
|
if (order.OrderID != "EngineerRepair")
|
||||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
|
||||||
|
|
||||||
return null;
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidOrder(Actor self, Order order)
|
||||||
|
{
|
||||||
|
// Not targeting a frozen 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;
|
||||||
|
|
||||||
|
return frozen.DamageState > DamageState.Undamaged;
|
||||||
|
}
|
||||||
|
|
||||||
|
return order.TargetActor.GetDamageState() > DamageState.Undamaged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
return (order.OrderString == "EngineerRepair" &&
|
return order.OrderString == "EngineerRepair" && IsValidOrder(self, order)
|
||||||
order.TargetActor.GetDamageState() > DamageState.Undamaged) ? "Attack" : null;
|
? "Attack" : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "EngineerRepair" &&
|
if (order.OrderString != "EngineerRepair" || !IsValidOrder(self, order))
|
||||||
order.TargetActor.GetDamageState() > DamageState.Undamaged)
|
return;
|
||||||
{
|
|
||||||
self.SetTargetLine(Target.FromOrder(order), Color.Yellow);
|
|
||||||
|
|
||||||
|
var target = self.ResolveFrozenActorOrder(order, Color.Yellow);
|
||||||
|
if (target.Type != TargetType.Actor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!order.Queued)
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
self.QueueActivity(new Enter(order.TargetActor, new RepairBuilding(order.TargetActor)));
|
|
||||||
}
|
self.SetTargetLine(target, Color.Yellow);
|
||||||
|
self.QueueActivity(new Enter(target.Actor, new RepairBuilding(target.Actor)));
|
||||||
}
|
}
|
||||||
|
|
||||||
class EngineerRepairOrderTargeter : UnitOrderTargeter
|
class EngineerRepairOrderTargeter : UnitOrderTargeter
|
||||||
@@ -59,22 +89,31 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!base.CanTargetActor(self, target, modifiers, ref cursor))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!target.HasTrait<EngineerRepairable>())
|
if (!target.HasTrait<EngineerRepairable>())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (self.Owner.Stances[target.Owner] != Stance.Ally)
|
if (self.Owner.Stances[target.Owner] != Stance.Ally)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
|
||||||
|
|
||||||
if (target.GetDamageState() == DamageState.Undamaged)
|
if (target.GetDamageState() == DamageState.Undamaged)
|
||||||
cursor = "goldwrench-blocked";
|
cursor = "goldwrench-blocked";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||||
|
{
|
||||||
|
if (!target.Info.Traits.Contains<EngineerRepairable>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (self.Owner.Stances[target.Owner] != Stance.Ally)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (target.DamageState == DamageState.Undamaged)
|
||||||
|
cursor = "goldwrench-blocked";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,7 +239,8 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new EnterOrderTargeter<IAcceptOre>("Deliver", 5, false, true, _ => true, proc => !IsEmpty && proc.Trait<IAcceptOre>().AllowDocking);
|
yield return new EnterAlliedActorTargeter<IAcceptOre>("Deliver", 5, _ => true,
|
||||||
|
proc => !IsEmpty && proc.Trait<IAcceptOre>().AllowDocking);
|
||||||
yield return new HarvestOrderTargeter();
|
yield return new HarvestOrderTargeter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -419,16 +420,15 @@ namespace OpenRA.Mods.RA
|
|||||||
public int OrderPriority { get { return 10; } }
|
public int OrderPriority { get { return 10; } }
|
||||||
public bool IsQueued { get; protected set; }
|
public bool IsQueued { get; protected set; }
|
||||||
|
|
||||||
public bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
|
if (target.Type != TargetType.Terrain)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
|
||||||
{
|
|
||||||
if (modifiers.HasModifier(TargetModifiers.ForceMove))
|
if (modifiers.HasModifier(TargetModifiers.ForceMove))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
var location = target.CenterPosition.ToCPos();
|
||||||
// Don't leak info about resources under the shroud
|
// Don't leak info about resources under the shroud
|
||||||
if (!self.Owner.Shroud.IsExplored(location))
|
if (!self.Owner.Shroud.IsExplored(location))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -41,67 +41,96 @@ namespace OpenRA.Mods.RA
|
|||||||
Info = info;
|
Info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IOrderTargeter> Orders
|
public IEnumerable<IOrderTargeter> Orders { get { yield return new InfiltratorOrderTargeter(Info.Types); } }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
yield return new InfiltratorOrderTargeter(CanInfiltrate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||||
{
|
{
|
||||||
if (order.OrderID == "Infiltrate")
|
if (order.OrderID != "Infiltrate")
|
||||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
|
||||||
|
|
||||||
return null;
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ii = frozen.Info.Traits.GetOrDefault<InfiltratableInfo>();
|
||||||
|
return ii != null && Info.Types.Contains(ii.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = order.TargetActor.Info.Traits.GetOrDefault<InfiltratableInfo>();
|
||||||
|
return i != null && Info.Types.Contains(i.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
return (order.OrderString == "Infiltrate" && CanInfiltrate(order.TargetActor)) ? "Attack" : null;
|
return order.OrderString == "Infiltrate" && IsValidOrder(self, order)
|
||||||
|
? "Attack" : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "Infiltrate")
|
if (order.OrderString != "Infiltrate" || !IsValidOrder(self, order))
|
||||||
{
|
|
||||||
if (!CanInfiltrate(order.TargetActor))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
var target = self.ResolveFrozenActorOrder(order, Color.Red);
|
||||||
|
if (target.Type != TargetType.Actor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!order.Queued)
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
self.QueueActivity(new Enter(order.TargetActor, new Infiltrate(order.TargetActor)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CanInfiltrate(Actor target)
|
self.SetTargetLine(target, Color.Red);
|
||||||
{
|
self.QueueActivity(new Enter(target.Actor, new Infiltrate(target.Actor)));
|
||||||
var infiltratable = target.Info.Traits.GetOrDefault<InfiltratableInfo>();
|
|
||||||
return infiltratable != null && Info.Types.Contains(infiltratable.Type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class InfiltratorOrderTargeter : UnitOrderTargeter
|
class InfiltratorOrderTargeter : UnitOrderTargeter
|
||||||
{
|
{
|
||||||
readonly Func<Actor, bool> useEnterCursor;
|
string[] infiltrationTypes;
|
||||||
|
|
||||||
public InfiltratorOrderTargeter(Func<Actor, bool> useEnterCursor)
|
public InfiltratorOrderTargeter(string[] infiltrationTypes)
|
||||||
: base("Infiltrate", 7, "enter", true, false)
|
: base("Infiltrate", 7, "enter", true, false)
|
||||||
{
|
{
|
||||||
ForceAttack = false;
|
ForceAttack = false;
|
||||||
this.useEnterCursor = useEnterCursor;
|
this.infiltrationTypes = infiltrationTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!base.CanTargetActor(self, target, modifiers, ref cursor))
|
var info = target.Info.Traits.GetOrDefault<InfiltratableInfo>();
|
||||||
|
if (info == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!target.HasTrait<IAcceptInfiltrator>())
|
if (!infiltrationTypes.Contains(info.Type))
|
||||||
|
cursor = "enter-blocked";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||||
|
{
|
||||||
|
var info = target.Info.Traits.GetOrDefault<InfiltratableInfo>();
|
||||||
|
if (info == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!useEnterCursor(target))
|
if (!infiltrationTypes.Contains(info.Type))
|
||||||
cursor = "enter-blocked";
|
cursor = "enter-blocked";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using OpenRA.FileFormats;
|
|||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
[Desc("This actor can be captured by a unit with LegacyCaptures: trait.")]
|
[Desc("This actor can be captured by a unit with LegacyCaptures: trait.")]
|
||||||
class LegacyCapturableInfo : ITraitInfo
|
class LegacyCapturableInfo : TraitInfo<LegacyCapturable>
|
||||||
{
|
{
|
||||||
[Desc("Type of actor (the LegacyCaptures: trait defines what Types it can capture).")]
|
[Desc("Type of actor (the LegacyCaptures: trait defines what Types it can capture).")]
|
||||||
public readonly string Type = "building";
|
public readonly string Type = "building";
|
||||||
@@ -25,40 +25,28 @@ namespace OpenRA.Mods.RA
|
|||||||
[Desc("Health percentage the target must be at (or below) before it can be captured.")]
|
[Desc("Health percentage the target must be at (or below) before it can be captured.")]
|
||||||
public readonly float CaptureThreshold = 0.5f;
|
public readonly float CaptureThreshold = 0.5f;
|
||||||
|
|
||||||
public object Create(ActorInitializer init) { return new LegacyCapturable(init.self, this); }
|
public bool CanBeTargetedBy(Actor captor, Player owner)
|
||||||
}
|
|
||||||
|
|
||||||
class LegacyCapturable
|
|
||||||
{
|
|
||||||
[Sync] Actor self;
|
|
||||||
public LegacyCapturableInfo Info;
|
|
||||||
|
|
||||||
public LegacyCapturable(Actor self, LegacyCapturableInfo info)
|
|
||||||
{
|
|
||||||
this.self = self;
|
|
||||||
Info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanBeTargetedBy(Actor captor)
|
|
||||||
{
|
{
|
||||||
var c = captor.TraitOrDefault<LegacyCaptures>();
|
var c = captor.TraitOrDefault<LegacyCaptures>();
|
||||||
if (c == null)
|
if (c == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var playerRelationship = self.Owner.Stances[captor.Owner];
|
var playerRelationship = owner.Stances[captor.Owner];
|
||||||
if (playerRelationship == Stance.Ally && !Info.AllowAllies)
|
if (playerRelationship == Stance.Ally && !AllowAllies)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (playerRelationship == Stance.Enemy && !Info.AllowEnemies)
|
if (playerRelationship == Stance.Enemy && !AllowEnemies)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (playerRelationship == Stance.Neutral && !Info.AllowNeutral)
|
if (playerRelationship == Stance.Neutral && !AllowNeutral)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!c.Info.CaptureTypes.Contains(Info.Type))
|
if (!c.Info.CaptureTypes.Contains(Type))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LegacyCapturable { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Mods.RA.Activities;
|
using OpenRA.Mods.RA.Activities;
|
||||||
using OpenRA.Mods.RA.Buildings;
|
using OpenRA.Mods.RA.Buildings;
|
||||||
using OpenRA.Mods.RA.Orders;
|
using OpenRA.Mods.RA.Orders;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
using OpenRA.FileFormats;
|
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
@@ -36,11 +36,9 @@ namespace OpenRA.Mods.RA
|
|||||||
class LegacyCaptures : IIssueOrder, IResolveOrder, IOrderVoice
|
class LegacyCaptures : IIssueOrder, IResolveOrder, IOrderVoice
|
||||||
{
|
{
|
||||||
public readonly LegacyCapturesInfo Info;
|
public readonly LegacyCapturesInfo Info;
|
||||||
readonly Actor self;
|
|
||||||
|
|
||||||
public LegacyCaptures(Actor self, LegacyCapturesInfo info)
|
public LegacyCaptures(Actor self, LegacyCapturesInfo info)
|
||||||
{
|
{
|
||||||
this.self = self;
|
|
||||||
Info = info;
|
Info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,71 +46,86 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new LegacyCaptureOrderTargeter(CanCapture);
|
yield return new LegacyCaptureOrderTargeter(Info.Sabotage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||||
{
|
{
|
||||||
if (order.OrderID == "LegacyCaptureActor")
|
if (order.OrderID != "LegacyCaptureActor")
|
||||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
|
||||||
|
|
||||||
return null;
|
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)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
return (order.OrderString == "LegacyCaptureActor") ? "Attack" : null;
|
return order.OrderString == "LegacyCaptureActor" ? "Attack" : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "LegacyCaptureActor")
|
if (order.OrderString != "LegacyCaptureActor")
|
||||||
{
|
return;
|
||||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
|
||||||
|
|
||||||
|
var target = self.ResolveFrozenActorOrder(order, Color.Red);
|
||||||
|
if (target.Type != TargetType.Actor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!order.Queued)
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
self.QueueActivity(new Enter(order.TargetActor, new LegacyCaptureActor(Target.FromOrder(order))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CanCapture(Actor target)
|
self.SetTargetLine(target, Color.Red);
|
||||||
{
|
self.QueueActivity(new Enter(target.Actor, new LegacyCaptureActor(target)));
|
||||||
var c = target.TraitOrDefault<LegacyCapturable>();
|
|
||||||
return c != null && c.CanBeTargetedBy(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class LegacyCaptureOrderTargeter : UnitOrderTargeter
|
class LegacyCaptureOrderTargeter : UnitOrderTargeter
|
||||||
{
|
{
|
||||||
readonly Func<Actor, bool> useCaptureCursor;
|
readonly bool sabotage;
|
||||||
|
|
||||||
public LegacyCaptureOrderTargeter(Func<Actor, bool> useCaptureCursor)
|
public LegacyCaptureOrderTargeter(bool sabotage)
|
||||||
: base("LegacyCaptureActor", 6, "enter", true, true)
|
: base("LegacyCaptureActor", 6, "enter", true, true)
|
||||||
{
|
{
|
||||||
this.useCaptureCursor = useCaptureCursor;
|
this.sabotage = sabotage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!base.CanTargetActor(self, target, modifiers, ref cursor)) return false;
|
var c = target.Info.Traits.GetOrDefault<LegacyCapturableInfo>();
|
||||||
|
if (c == null || !c.CanBeTargetedBy(self, target.Owner))
|
||||||
var canTargetActor = useCaptureCursor(target);
|
|
||||||
|
|
||||||
if (canTargetActor)
|
|
||||||
{
|
{
|
||||||
var c = target.Trait<LegacyCapturable>();
|
|
||||||
var health = target.Trait<Health>();
|
|
||||||
var lowEnoughHealth = health.HP <= c.Info.CaptureThreshold * health.MaxHP;
|
|
||||||
|
|
||||||
cursor = lowEnoughHealth ? "enter" : "capture";
|
|
||||||
|
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor = "enter-blocked";
|
cursor = "enter-blocked";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var health = target.Trait<Health>();
|
||||||
|
var lowEnoughHealth = health.HP <= c.CaptureThreshold * health.MaxHP;
|
||||||
|
|
||||||
|
cursor = !sabotage || lowEnoughHealth || target.Owner.NonCombatant
|
||||||
|
? "capture" : "enter";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||||
|
{
|
||||||
|
var c = target.Info.Traits.GetOrDefault<LegacyCapturableInfo>();
|
||||||
|
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
|
||||||
|
? "capture" : "enter";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,21 +156,21 @@ namespace OpenRA.Mods.RA
|
|||||||
public string OrderID { get { return "BeginMinefield"; } }
|
public string OrderID { get { return "BeginMinefield"; } }
|
||||||
public int OrderPriority { get { return 5; } }
|
public int OrderPriority { get { return 5; } }
|
||||||
|
|
||||||
public bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
|
if (target.Type != TargetType.Terrain)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
var location = target.CenterPosition.ToCPos();
|
||||||
{
|
|
||||||
if (!self.World.Map.IsInMap(location))
|
if (!self.World.Map.IsInMap(location))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cursor = "ability";
|
cursor = "ability";
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||||
|
|
||||||
return (actorsAtLocation.Count == 0 && modifiers.HasModifier(TargetModifiers.ForceAttack));
|
return !othersAtTarget.Any() && modifiers.HasModifier(TargetModifiers.ForceAttack);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsQueued { get; protected set; }
|
public bool IsQueued { get; protected set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -457,7 +457,7 @@ namespace OpenRA.Mods.RA.Missions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Allies04HijackableInfo : ITraitInfo
|
class Allies04HijackableInfo : ITraitInfo, Requires<InfiltratableInfo>
|
||||||
{
|
{
|
||||||
public object Create(ActorInitializer init) { return new Allies04Hijackable(init.self); }
|
public object Create(ActorInitializer init) { return new Allies04Hijackable(init.self); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Mods.RA.Buildings;
|
using OpenRA.Mods.RA.Buildings;
|
||||||
using OpenRA.Mods.RA.Effects;
|
using OpenRA.Mods.RA.Effects;
|
||||||
@@ -24,50 +26,97 @@ namespace OpenRA.Mods.RA
|
|||||||
public object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); }
|
public object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FrozenUnderFog : IRenderModifier, IVisibilityModifier, ITickRender
|
public class FrozenUnderFog : IRenderModifier, IVisibilityModifier, ITick, ITickRender, ISync
|
||||||
{
|
{
|
||||||
FrozenActorProxy proxy;
|
[Sync] public int VisibilityHash;
|
||||||
|
|
||||||
|
bool initialized, startsRevealed;
|
||||||
IEnumerable<CPos> footprint;
|
IEnumerable<CPos> footprint;
|
||||||
bool visible, cacheFirstFrame;
|
Lazy<IToolTip> tooltip;
|
||||||
|
Lazy<Health> health;
|
||||||
|
|
||||||
|
Dictionary<Player, bool> visible;
|
||||||
|
Dictionary<Player, FrozenActor> frozen;
|
||||||
|
|
||||||
public FrozenUnderFog(ActorInitializer init, FrozenUnderFogInfo info)
|
public FrozenUnderFog(ActorInitializer init, FrozenUnderFogInfo info)
|
||||||
{
|
{
|
||||||
footprint = FootprintUtils.Tiles(init.self);
|
|
||||||
proxy = new FrozenActorProxy(init.self, footprint);
|
|
||||||
init.world.AddFrameEndTask(w => w.Add(proxy));
|
|
||||||
|
|
||||||
// Spawned actors (e.g. building husks) shouldn't be revealed
|
// Spawned actors (e.g. building husks) shouldn't be revealed
|
||||||
cacheFirstFrame = info.StartsRevealed && !init.Contains<ParentActorInit>();
|
startsRevealed = info.StartsRevealed && !init.Contains<ParentActorInit>();
|
||||||
|
footprint = FootprintUtils.Tiles(init.self);
|
||||||
|
tooltip = Lazy.New(() => init.self.TraitsImplementing<IToolTip>().FirstOrDefault());
|
||||||
|
tooltip = Lazy.New(() => init.self.TraitsImplementing<IToolTip>().FirstOrDefault());
|
||||||
|
health = Lazy.New(() => init.self.TraitOrDefault<Health>());
|
||||||
|
|
||||||
|
frozen = new Dictionary<Player, FrozenActor>();
|
||||||
|
visible = init.world.Players.ToDictionary(p => p, p => false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsVisible(Actor self, Player byPlayer)
|
public bool IsVisible(Actor self, Player byPlayer)
|
||||||
{
|
{
|
||||||
return byPlayer == null || footprint.Any(c => byPlayer.Shroud.IsVisible(c));
|
return byPlayer == null || visible[byPlayer];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TickRender(WorldRenderer wr, Actor self)
|
public void Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (self.Destroyed)
|
if (self.Destroyed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
visible = IsVisible(self, self.World.RenderPlayer);
|
VisibilityHash = 0;
|
||||||
|
foreach (var p in self.World.Players)
|
||||||
if (cacheFirstFrame)
|
|
||||||
{
|
{
|
||||||
visible = true;
|
visible[p] = footprint.Any(c => p.Shroud.IsVisible(c));
|
||||||
cacheFirstFrame = false;
|
if (visible[p])
|
||||||
|
VisibilityHash += p.ClientIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visible)
|
if (!initialized)
|
||||||
{
|
{
|
||||||
var comparer = new RenderableComparer(wr);
|
foreach (var p in self.World.Players)
|
||||||
proxy.SetRenderables(self.Render(wr).OrderBy(r => r, comparer));
|
{
|
||||||
|
visible[p] |= startsRevealed;
|
||||||
|
frozen[p] = new FrozenActor(self, footprint);
|
||||||
|
p.PlayerActor.Trait<FrozenActorLayer>().Add(frozen[p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var player in self.World.Players)
|
||||||
|
{
|
||||||
|
if (!visible[player])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
frozen[player].Owner = self.Owner;
|
||||||
|
|
||||||
|
if (health.Value != null)
|
||||||
|
{
|
||||||
|
frozen[player].HP = health.Value.HP;
|
||||||
|
frozen[player].DamageState = health.Value.DamageState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tooltip.Value != null)
|
||||||
|
{
|
||||||
|
frozen[player].TooltipName = tooltip.Value.Name();
|
||||||
|
frozen[player].TooltipOwner = tooltip.Value.Owner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TickRender(WorldRenderer wr, Actor self)
|
||||||
|
{
|
||||||
|
if (self.Destroyed || !initialized || !visible.Any(v => v.Value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Force a copy of the underlying data
|
||||||
|
var renderables = self.Render(wr).Select(rr => rr).ToArray();
|
||||||
|
foreach (var player in self.World.Players)
|
||||||
|
if (visible[player])
|
||||||
|
frozen[player].Renderables = renderables;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)
|
public IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)
|
||||||
{
|
{
|
||||||
return visible ? r : SpriteRenderable.None;
|
return IsVisible(self, self.World.RenderPlayer) ? r : SpriteRenderable.None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,13 +494,12 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
public int OrderPriority { get { return 4; } }
|
public int OrderPriority { get { return 4; } }
|
||||||
public bool IsQueued { get; protected set; }
|
public bool IsQueued { get; protected set; }
|
||||||
|
|
||||||
public bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
|
if (!target.IsValid)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
var location = target.CenterPosition.ToCPos();
|
||||||
{
|
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||||
cursor = "move";
|
cursor = "move";
|
||||||
|
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
return Enumerable.Reverse(path).Select(c => Target.FromCell(c));
|
return Enumerable.Reverse(path).Select(c => Target.FromCell(c));
|
||||||
if (destination != null)
|
if (destination != null)
|
||||||
return new Target[] { Target.FromCell(destination.Value) };
|
return new Target[] { Target.FromCell(destination.Value) };
|
||||||
return Target.NoTargets;
|
return Target.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class MovePart : Activity
|
abstract class MovePart : Activity
|
||||||
|
|||||||
@@ -282,7 +282,6 @@
|
|||||||
<Compile Include="NullLoadScreen.cs" />
|
<Compile Include="NullLoadScreen.cs" />
|
||||||
<Compile Include="LoadWidgetAtGameStart.cs" />
|
<Compile Include="LoadWidgetAtGameStart.cs" />
|
||||||
<Compile Include="Orders\DeployOrderTargeter.cs" />
|
<Compile Include="Orders\DeployOrderTargeter.cs" />
|
||||||
<Compile Include="Orders\EnterBuildingOrderTargeter.cs" />
|
|
||||||
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
|
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
|
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\RepairOrderGenerator.cs" />
|
<Compile Include="Orders\RepairOrderGenerator.cs" />
|
||||||
@@ -462,10 +461,10 @@
|
|||||||
<Compile Include="World\DomainIndex.cs" />
|
<Compile Include="World\DomainIndex.cs" />
|
||||||
<Compile Include="MPStartUnits.cs" />
|
<Compile Include="MPStartUnits.cs" />
|
||||||
<Compile Include="Orders\SetChronoTankDestination.cs" />
|
<Compile Include="Orders\SetChronoTankDestination.cs" />
|
||||||
<Compile Include="Effects\FrozenActorProxy.cs" />
|
|
||||||
<Compile Include="Widgets\Logic\WorldTooltipLogic.cs" />
|
<Compile Include="Widgets\Logic\WorldTooltipLogic.cs" />
|
||||||
<Compile Include="TeslaZapRenderable.cs" />
|
<Compile Include="TeslaZapRenderable.cs" />
|
||||||
<Compile Include="Buildings\Bib.cs" />
|
<Compile Include="Buildings\Bib.cs" />
|
||||||
|
<Compile Include="Orders\EnterAlliedActorTargeter.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||||
|
|||||||
@@ -35,16 +35,15 @@ namespace OpenRA.Mods.RA.Orders
|
|||||||
public string OrderID { get; private set; }
|
public string OrderID { get; private set; }
|
||||||
public int OrderPriority { get; private set; }
|
public int OrderPriority { get; private set; }
|
||||||
|
|
||||||
public bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
|
if (target.Type != TargetType.Actor)
|
||||||
|
return false;
|
||||||
|
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||||
cursor = useDeployCursor() ? "deploy" : "deploy-blocked";
|
cursor = useDeployCursor() ? "deploy" : "deploy-blocked";
|
||||||
return self == target;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
return self == target.Actor;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsQueued { get; protected set; }
|
public bool IsQueued { get; protected set; }
|
||||||
|
|||||||
@@ -9,18 +9,19 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA.Orders
|
namespace OpenRA.Mods.RA.Orders
|
||||||
{
|
{
|
||||||
public class EnterOrderTargeter<T> : UnitOrderTargeter
|
public class EnterAlliedActorTargeter<T> : UnitOrderTargeter
|
||||||
{
|
{
|
||||||
readonly Func<Actor, bool> canTarget;
|
readonly Func<Actor, bool> canTarget;
|
||||||
readonly Func<Actor, bool> useEnterCursor;
|
readonly Func<Actor, bool> useEnterCursor;
|
||||||
|
|
||||||
public EnterOrderTargeter(string order, int priority, bool targetEnemy, bool targetAlly,
|
public EnterAlliedActorTargeter(string order, int priority,
|
||||||
Func<Actor, bool> canTarget, Func<Actor, bool> useEnterCursor)
|
Func<Actor, bool> canTarget, Func<Actor, bool> useEnterCursor)
|
||||||
: base (order, priority, "enter", targetEnemy, targetAlly)
|
: base (order, priority, "enter", false, true)
|
||||||
{
|
{
|
||||||
this.canTarget = canTarget;
|
this.canTarget = canTarget;
|
||||||
this.useEnterCursor = useEnterCursor;
|
this.useEnterCursor = useEnterCursor;
|
||||||
@@ -28,18 +29,17 @@ namespace OpenRA.Mods.RA.Orders
|
|||||||
|
|
||||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!base.CanTargetActor(self, target, modifiers, ref cursor))
|
if (!target.HasTrait<T>() || !canTarget(target))
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!target.HasTrait<T>())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!canTarget(target))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
cursor = useEnterCursor(target) ? "enter" : "enter-blocked";
|
cursor = useEnterCursor(target) ? "enter" : "enter-blocked";
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||||
|
{
|
||||||
|
// Allied actors are never frozen
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.RA.Orders
|
namespace OpenRA.Mods.RA.Orders
|
||||||
{
|
{
|
||||||
public class UnitOrderTargeter : IOrderTargeter
|
public abstract class UnitOrderTargeter : IOrderTargeter
|
||||||
{
|
{
|
||||||
readonly string cursor;
|
readonly string cursor;
|
||||||
readonly bool targetEnemyUnits, targetAllyUnits;
|
readonly bool targetEnemyUnits, targetAllyUnits;
|
||||||
@@ -33,27 +33,33 @@ namespace OpenRA.Mods.RA.Orders
|
|||||||
public int OrderPriority { get; private set; }
|
public int OrderPriority { get; private set; }
|
||||||
public bool? ForceAttack = null;
|
public bool? ForceAttack = null;
|
||||||
|
|
||||||
public virtual bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public abstract bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor);
|
||||||
|
public abstract bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor);
|
||||||
|
|
||||||
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if( self == null ) throw new ArgumentNullException( "self" );
|
var type = target.Type;
|
||||||
if( target == null ) throw new ArgumentNullException( "target" );
|
if (type != TargetType.Actor && type != TargetType.FrozenActor)
|
||||||
|
return false;
|
||||||
|
|
||||||
cursor = this.cursor;
|
cursor = this.cursor;
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||||
|
|
||||||
if (ForceAttack != null && modifiers.HasModifier(TargetModifiers.ForceAttack) != ForceAttack) return false;
|
if (ForceAttack != null && modifiers.HasModifier(TargetModifiers.ForceAttack) != ForceAttack)
|
||||||
|
|
||||||
var playerRelationship = self.Owner.Stances[target.Owner];
|
|
||||||
|
|
||||||
if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && playerRelationship == Stance.Ally && !targetAllyUnits) return false;
|
|
||||||
if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && playerRelationship == Stance.Enemy && !targetEnemyUnits) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
var owner = type == TargetType.FrozenActor ? target.FrozenActor.Owner : target.Actor.Owner;
|
||||||
|
var playerRelationship = self.Owner.Stances[owner];
|
||||||
|
|
||||||
|
if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && playerRelationship == Stance.Ally && !targetAllyUnits)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && playerRelationship == Stance.Enemy && !targetEnemyUnits)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return type == TargetType.FrozenActor ?
|
||||||
|
CanTargetFrozenActor(self, target.FrozenActor, modifiers, ref cursor) :
|
||||||
|
CanTargetActor(self, target.Actor, modifiers, ref cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool IsQueued { get; protected set; }
|
public virtual bool IsQueued { get; protected set; }
|
||||||
@@ -71,15 +77,12 @@ namespace OpenRA.Mods.RA.Orders
|
|||||||
|
|
||||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!base.CanTargetActor(self, target, modifiers, ref cursor))
|
return target.TraitsImplementing<ITargetable>().Any(t => t.TargetTypes.Contains(targetType));
|
||||||
return false;
|
}
|
||||||
|
|
||||||
if (!target.TraitsImplementing<ITargetable>().Any(t => t.TargetTypes.Contains(targetType)))
|
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||||
return false;
|
{
|
||||||
|
return target.Info.Traits.WithInterface<ITargetableInfo>().Any(t => t.GetTargetTypes().Contains(targetType));
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new EnterOrderTargeter<Cargo>( "EnterTransport", 6, false, true,
|
yield return new EnterAlliedActorTargeter<Cargo>("EnterTransport", 6,
|
||||||
target => IsCorrectCargoType(target), target => CanEnter(target));
|
target => IsCorrectCargoType(target), target => CanEnter(target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,13 +58,12 @@ namespace OpenRA.Mods.RA
|
|||||||
public string OrderID { get { return "SetRallyPoint"; } }
|
public string OrderID { get { return "SetRallyPoint"; } }
|
||||||
public int OrderPriority { get { return 0; } }
|
public int OrderPriority { get { return 0; } }
|
||||||
|
|
||||||
public bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
|
if (target.Type != TargetType.Terrain)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanTargetLocation(Actor self, CPos location, List<Actor> actorsAtLocation, TargetModifiers modifiers, ref string cursor)
|
var location = target.CenterPosition.ToCPos();
|
||||||
{
|
|
||||||
if (self.World.Map.IsInMap(location))
|
if (self.World.Map.IsInMap(location))
|
||||||
{
|
{
|
||||||
cursor = "ability";
|
cursor = "ability";
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public IEnumerable<IOrderTargeter> Orders
|
public IEnumerable<IOrderTargeter> Orders
|
||||||
{
|
{
|
||||||
get { yield return new EnterOrderTargeter<Building>( "Repair", 5, false, true, target => CanRepairAt( target ), _ => CanRepair() ); }
|
get { yield return new EnterAlliedActorTargeter<Building>("Repair", 5,
|
||||||
|
target => CanRepairAt(target), _ => CanRepair()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued )
|
public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued )
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
yield return new EnterOrderTargeter<Building>( "RepairNear", 5, false, true,
|
yield return new EnterAlliedActorTargeter<Building>("RepairNear", 5,
|
||||||
target => CanRepairAt(target), _ => ShouldRepair());
|
target => CanRepairAt(target), _ => ShouldRepair());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,9 +71,6 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!base.CanTargetActor(self, target, modifiers, ref cursor))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var bridge = target.TraitOrDefault<BridgeHut>();
|
var bridge = target.TraitOrDefault<BridgeHut>();
|
||||||
if (bridge == null)
|
if (bridge == null)
|
||||||
return false;
|
return false;
|
||||||
@@ -83,14 +80,18 @@ namespace OpenRA.Mods.RA
|
|||||||
if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && damage != DamageState.Dead)
|
if (!modifiers.HasModifier(TargetModifiers.ForceAttack) && damage != DamageState.Dead)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
|
||||||
|
|
||||||
// Can't repair an undamaged bridge
|
// Can't repair an undamaged bridge
|
||||||
if (damage == DamageState.Undamaged)
|
if (damage == DamageState.Undamaged)
|
||||||
cursor = "goldwrench-blocked";
|
cursor = "goldwrench-blocked";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||||
|
{
|
||||||
|
// TODO: Bridges don't yet support FrozenUnderFog.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Mods.RA.Activities;
|
using OpenRA.Mods.RA.Activities;
|
||||||
using OpenRA.Mods.RA.Buildings;
|
using OpenRA.Mods.RA.Buildings;
|
||||||
using OpenRA.Mods.RA.Orders;
|
using OpenRA.Mods.RA.Orders;
|
||||||
using OpenRA.FileFormats;
|
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
@@ -28,11 +28,11 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
class SupplyTruck : IIssueOrder, IResolveOrder, IOrderVoice
|
class SupplyTruck : IIssueOrder, IResolveOrder, IOrderVoice
|
||||||
{
|
{
|
||||||
SupplyTruckInfo Info;
|
SupplyTruckInfo info;
|
||||||
|
|
||||||
public SupplyTruck(SupplyTruckInfo info)
|
public SupplyTruck(SupplyTruckInfo info)
|
||||||
{
|
{
|
||||||
Info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IOrderTargeter> Orders
|
public IEnumerable<IOrderTargeter> Orders
|
||||||
@@ -42,10 +42,13 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||||
{
|
{
|
||||||
if (order.OrderID == "DeliverSupplies")
|
if (order.OrderID != "DeliverSupplies")
|
||||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
|
||||||
|
|
||||||
return null;
|
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)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
@@ -55,12 +58,18 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "DeliverSupplies")
|
if (order.OrderString != "DeliverSupplies")
|
||||||
{
|
return;
|
||||||
self.SetTargetLine(Target.FromOrder(order), Color.Yellow);
|
|
||||||
|
var target = self.ResolveFrozenActorOrder(order, Color.Yellow);
|
||||||
|
if (target.Type != TargetType.Actor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!order.Queued)
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
self.QueueActivity(new Enter(order.TargetActor, new DonateSupplies(order.TargetActor, Info.Payload)));
|
|
||||||
}
|
self.SetTargetLine(target, Color.Yellow);
|
||||||
|
self.QueueActivity(new Enter(target.Actor, new DonateSupplies(target.Actor, info.Payload)));
|
||||||
}
|
}
|
||||||
|
|
||||||
class SupplyTruckOrderTargeter : UnitOrderTargeter
|
class SupplyTruckOrderTargeter : UnitOrderTargeter
|
||||||
@@ -72,17 +81,12 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (!base.CanTargetActor(self, target, modifiers, ref cursor))
|
return target.HasTrait<AcceptsSupplies>();
|
||||||
return false;
|
}
|
||||||
|
|
||||||
if (target.AppearsHostileTo(self))
|
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||||
return false;
|
{
|
||||||
|
return target.Info.Traits.Contains<AcceptsSuppliesInfo>();
|
||||||
if (!target.HasTrait<AcceptsSupplies>())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
public class TargetableBuildingInfo : ITraitInfo, Requires<BuildingInfo>
|
public class TargetableBuildingInfo : ITraitInfo, ITargetableInfo, Requires<BuildingInfo>
|
||||||
{
|
{
|
||||||
public readonly string[] TargetTypes = { };
|
public readonly string[] TargetTypes = { };
|
||||||
|
|
||||||
|
public string[] GetTargetTypes() { return TargetTypes; }
|
||||||
public object Create(ActorInitializer init) { return new TargetableBuilding(init.self, this); }
|
public object Create(ActorInitializer init) { return new TargetableBuilding(init.self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
public class TargetableUnitInfo : ITraitInfo
|
public class TargetableUnitInfo : ITraitInfo, ITargetableInfo
|
||||||
{
|
{
|
||||||
public readonly string[] TargetTypes = { };
|
public readonly string[] TargetTypes = { };
|
||||||
|
|
||||||
|
public string[] GetTargetTypes() { return TargetTypes; }
|
||||||
public virtual object Create(ActorInitializer init) { return new TargetableUnit(init.self, this); }
|
public virtual object Create(ActorInitializer init) { return new TargetableUnit(init.self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public virtual void ResolveOrder(Actor self, Order order)
|
public virtual void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (info.AlignWhenIdle && order.OrderString != "Attack" && order.OrderString != "AttackHold")
|
if (info.AlignWhenIdle && order.OrderString != "Attack")
|
||||||
desiredFacing = null;
|
desiredFacing = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,16 +41,30 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
if (viewport == null || viewport.TooltipType == WorldTooltipType.None)
|
if (viewport == null || viewport.TooltipType == WorldTooltipType.None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
labelText = viewport.TooltipType == WorldTooltipType.Unexplored ? "Unexplored Terrain" :
|
Player o = null;
|
||||||
viewport.ActorTooltip.Name();
|
switch (viewport.TooltipType)
|
||||||
|
{
|
||||||
|
case WorldTooltipType.Unexplored:
|
||||||
|
labelText = "Unexplored Terrain";
|
||||||
|
break;
|
||||||
|
case WorldTooltipType.Actor:
|
||||||
|
labelText = viewport.ActorTooltip.Name();
|
||||||
|
o = viewport.ActorTooltip.Owner();
|
||||||
|
break;
|
||||||
|
case WorldTooltipType.FrozenActor:
|
||||||
|
labelText = viewport.FrozenActorTooltip.TooltipName;
|
||||||
|
o = viewport.FrozenActorTooltip.TooltipOwner;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
var textWidth = font.Measure(labelText).X;
|
var textWidth = font.Measure(labelText).X;
|
||||||
if (textWidth != cachedWidth)
|
if (textWidth != cachedWidth)
|
||||||
{
|
{
|
||||||
label.Bounds.Width = textWidth;
|
label.Bounds.Width = textWidth;
|
||||||
widget.Bounds.Width = 2*label.Bounds.X + textWidth;
|
widget.Bounds.Width = 2*label.Bounds.X + textWidth;
|
||||||
}
|
}
|
||||||
var o = viewport.ActorTooltip != null ? viewport.ActorTooltip.Owner() : null;
|
|
||||||
showOwner = viewport.TooltipType == WorldTooltipType.Actor && o != null && !o.NonCombatant;
|
showOwner = o != null && !o.NonCombatant;
|
||||||
|
|
||||||
if (showOwner)
|
if (showOwner)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ Player:
|
|||||||
BaseAttackNotifier:
|
BaseAttackNotifier:
|
||||||
Shroud:
|
Shroud:
|
||||||
PlayerStatistics:
|
PlayerStatistics:
|
||||||
|
FrozenActorLayer:
|
||||||
|
|
||||||
World:
|
World:
|
||||||
LoadWidgetAtGameStart:
|
LoadWidgetAtGameStart:
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ Player:
|
|||||||
RemapIndex: 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240
|
RemapIndex: 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240
|
||||||
BaseAttackNotifier:
|
BaseAttackNotifier:
|
||||||
Shroud:
|
Shroud:
|
||||||
Shroud: false
|
FrozenActorLayer:
|
||||||
HarvesterAttackNotifier:
|
HarvesterAttackNotifier:
|
||||||
PlayerStatistics:
|
PlayerStatistics:
|
||||||
|
|
||||||
|
|||||||
@@ -524,6 +524,7 @@ Player:
|
|||||||
RemapIndex: 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
|
RemapIndex: 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
|
||||||
GpsWatcher:
|
GpsWatcher:
|
||||||
Shroud:
|
Shroud:
|
||||||
|
FrozenActorLayer:
|
||||||
BaseAttackNotifier:
|
BaseAttackNotifier:
|
||||||
PlayerStatistics:
|
PlayerStatistics:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user