Compare commits
92 Commits
playtest-2
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3deaf6c7bb | ||
|
|
8bbf43f45d | ||
|
|
5cd674445c | ||
|
|
27f1c37eca | ||
|
|
258259af4a | ||
|
|
276b1a9509 | ||
|
|
5b19dbe20c | ||
|
|
40424814a4 | ||
|
|
c0ea92850b | ||
|
|
dc1f11f412 | ||
|
|
e4602f8db2 | ||
|
|
b4b4412664 | ||
|
|
a23634897a | ||
|
|
082efe1b08 | ||
|
|
c6c05802d2 | ||
|
|
c091d7dc67 | ||
|
|
ac1d95c863 | ||
|
|
f15bb98f4a | ||
|
|
1353ad38a0 | ||
|
|
508f74822c | ||
|
|
4b5ae12536 | ||
|
|
4ad4e143b7 | ||
|
|
94aa310612 | ||
|
|
06d5826a0b | ||
|
|
a64f0eb0f5 | ||
|
|
814878126b | ||
|
|
3438dd3f74 | ||
|
|
e6b9bc07e9 | ||
|
|
cee511f59d | ||
|
|
992559d317 | ||
|
|
f27440d67e | ||
|
|
6b1aac4d98 | ||
|
|
96b95c8980 | ||
|
|
088288fee1 | ||
|
|
a93fbc3219 | ||
|
|
58273c532c | ||
|
|
4498f52723 | ||
|
|
28ede7ad8f | ||
|
|
fd663cc3f3 | ||
|
|
75d6495003 | ||
|
|
eb4ba7e793 | ||
|
|
4532cf9b55 | ||
|
|
2fba47151c | ||
|
|
d4f1ea54e7 | ||
|
|
4a6efc99ee | ||
|
|
c150ed373c | ||
|
|
d99b22db51 | ||
|
|
51ad7e6b59 | ||
|
|
493294c61e | ||
|
|
ea7d00df8d | ||
|
|
3218249a2d | ||
|
|
2be9200ce7 | ||
|
|
90ca7cedc2 | ||
|
|
4f884f9835 | ||
|
|
1f8aa67593 | ||
|
|
44af88bb49 | ||
|
|
522ee22845 | ||
|
|
9d98276c7d | ||
|
|
7ecc653183 | ||
|
|
de330daf85 | ||
|
|
e2a74f21b7 | ||
|
|
7bb594e11b | ||
|
|
4055952be3 | ||
|
|
77daea61bb | ||
|
|
fec1e244f3 | ||
|
|
1e26672b70 | ||
|
|
aead03d9b3 | ||
|
|
a9d44d4e44 | ||
|
|
7047ba3a31 | ||
|
|
e169368cf4 | ||
|
|
90f3788187 | ||
|
|
96b65aa969 | ||
|
|
0771a42749 | ||
|
|
8afa1d8dde | ||
|
|
79f6a51deb | ||
|
|
4bb4897ba3 | ||
|
|
f82aa58d2b | ||
|
|
30ee546fb3 | ||
|
|
2dad293328 | ||
|
|
14c4e2978f | ||
|
|
cb75a85341 | ||
|
|
dbbbb2c782 | ||
|
|
bf432df830 | ||
|
|
c42e2db542 | ||
|
|
bc55717b6b | ||
|
|
19551063a8 | ||
|
|
6d0f3a0008 | ||
|
|
88d11b4c66 | ||
|
|
9f7c3d6bac | ||
|
|
55ba6b9e26 | ||
|
|
79627d036e | ||
|
|
2438ee487a |
@@ -3,7 +3,7 @@
|
||||
|
||||
dist: xenial
|
||||
language: csharp
|
||||
mono: 5.20.1
|
||||
mono: 6.4.0
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
||||
2
Makefile
2
Makefile
@@ -151,7 +151,7 @@ test: core
|
||||
all: dependencies core
|
||||
|
||||
core:
|
||||
@command -v $(MSBUILD) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.4."; exit 1)
|
||||
@command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.4."; exit 1)
|
||||
ifeq ($(WIN32), $(filter $(WIN32),true yes y on 1))
|
||||
@$(MSBUILD) -t:build -p:Configuration="Release-x86"
|
||||
else
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace OpenRA
|
||||
readonly INotifyIdle[] tickIdles;
|
||||
readonly ITargetablePositions[] targetablePositions;
|
||||
WPos[] staticTargetablePositions;
|
||||
bool created;
|
||||
|
||||
internal Actor(World world, string name, TypeDictionary initDict)
|
||||
{
|
||||
@@ -138,6 +139,35 @@ namespace OpenRA
|
||||
SyncHashes = TraitsImplementing<ISync>().Select(sync => new SyncHash(sync)).ToArray();
|
||||
}
|
||||
|
||||
internal void Created()
|
||||
{
|
||||
created = true;
|
||||
|
||||
foreach (var t in TraitsImplementing<INotifyCreated>())
|
||||
t.Created(this);
|
||||
|
||||
// The initial activity should run before any activities queued by INotifyCreated.Created
|
||||
// However, we need to know which traits are enabled (via conditions), so wait for after the calls and insert the activity as the first
|
||||
ICreationActivity creationActivity = null;
|
||||
foreach (var ica in TraitsImplementing<ICreationActivity>())
|
||||
{
|
||||
if (!ica.IsTraitEnabled())
|
||||
continue;
|
||||
|
||||
if (creationActivity != null)
|
||||
throw new InvalidOperationException("More than one enabled ICreationActivity trait: {0} and {1}".F(creationActivity.GetType().Name, ica.GetType().Name));
|
||||
|
||||
var activity = ica.GetCreationActivity();
|
||||
if (activity == null)
|
||||
continue;
|
||||
|
||||
creationActivity = ica;
|
||||
|
||||
activity.Queue(CurrentActivity);
|
||||
CurrentActivity = activity;
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
var wasIdle = IsIdle;
|
||||
@@ -214,11 +244,15 @@ namespace OpenRA
|
||||
{
|
||||
if (!queued)
|
||||
CancelActivity();
|
||||
|
||||
QueueActivity(nextActivity);
|
||||
}
|
||||
|
||||
public void QueueActivity(Activity nextActivity)
|
||||
{
|
||||
if (!created)
|
||||
throw new InvalidOperationException("An activity was queued before the actor was created. Queue it inside the INotifyCreated.Created callback instead.");
|
||||
|
||||
if (CurrentActivity == null)
|
||||
CurrentActivity = nextActivity;
|
||||
else
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace OpenRA
|
||||
public static ICursor Cursor;
|
||||
public static bool HideCursor;
|
||||
static WorldRenderer worldRenderer;
|
||||
static string modLaunchWrapper;
|
||||
|
||||
internal static OrderManager OrderManager;
|
||||
static Server.Server server;
|
||||
@@ -351,6 +352,8 @@ namespace OpenRA
|
||||
foreach (var mod in Mods)
|
||||
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Metadata.Title, mod.Value.Metadata.Version);
|
||||
|
||||
modLaunchWrapper = args.GetValue("Engine.LaunchWrapper", null);
|
||||
|
||||
ExternalMods = new ExternalMods();
|
||||
|
||||
Manifest currentMod;
|
||||
@@ -509,8 +512,15 @@ namespace OpenRA
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = mod.LaunchPath;
|
||||
var args = launchArguments != null ? mod.LaunchArgs.Append(launchArguments) : mod.LaunchArgs;
|
||||
var p = Process.Start(mod.LaunchPath, args.Select(a => "\"" + a + "\"").JoinWith(" "));
|
||||
if (modLaunchWrapper != null)
|
||||
{
|
||||
path = modLaunchWrapper;
|
||||
args = new[] { mod.LaunchPath }.Concat(args);
|
||||
}
|
||||
|
||||
var p = Process.Start(path, args.Select(a => "\"" + a + "\"").JoinWith(" "));
|
||||
if (p == null || p.HasExited)
|
||||
onFailed();
|
||||
else
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace OpenRA
|
||||
public readonly Hotkey Default = Hotkey.Invalid;
|
||||
public readonly string Description = "";
|
||||
public readonly HashSet<string> Types = new HashSet<string>();
|
||||
public bool HasDuplicates { get; internal set; }
|
||||
|
||||
public HotkeyDefinition(string name, MiniYaml node)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,9 @@ namespace OpenRA
|
||||
if (definitions.ContainsKey(kv.Key))
|
||||
keys[kv.Key] = kv.Value;
|
||||
}
|
||||
|
||||
foreach (var hd in definitions)
|
||||
hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null;
|
||||
}
|
||||
|
||||
internal Func<Hotkey> GetHotkeyReference(string name)
|
||||
@@ -65,6 +68,20 @@ namespace OpenRA
|
||||
settings[name] = value;
|
||||
else
|
||||
settings.Remove(name);
|
||||
|
||||
var hadDuplicates = definition.HasDuplicates;
|
||||
definition.HasDuplicates = GetFirstDuplicate(definition.Name, this[definition.Name].GetValue(), definition) != null;
|
||||
|
||||
if (hadDuplicates || definition.HasDuplicates)
|
||||
{
|
||||
foreach (var hd in definitions)
|
||||
{
|
||||
if (hd.Value == definition)
|
||||
continue;
|
||||
|
||||
hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HotkeyDefinition GetFirstDuplicate(string name, Hotkey value, HotkeyDefinition definition)
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace OpenRA
|
||||
public MouseScrollType MiddleMouseScroll = MouseScrollType.Standard;
|
||||
public MouseScrollType RightMouseScroll = MouseScrollType.Disabled;
|
||||
public MouseButtonPreference MouseButtonPreference = new MouseButtonPreference();
|
||||
public float ViewportEdgeScrollStep = 10f;
|
||||
public float ViewportEdgeScrollStep = 30f;
|
||||
public float UIScrollSpeed = 50f;
|
||||
public int SelectionDeadzone = 24;
|
||||
public int MouseScrollDeadzone = 8;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using OpenRA.Activities;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Network;
|
||||
@@ -260,6 +261,7 @@ namespace OpenRA.Traits
|
||||
WDist LargestActorRadius { get; }
|
||||
WDist LargestBlockingActorRadius { get; }
|
||||
|
||||
void UpdateOccupiedCells(IOccupySpace ios);
|
||||
event Action<CPos> CellUpdated;
|
||||
}
|
||||
|
||||
@@ -312,7 +314,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public interface IPositionableInfo : IOccupySpaceInfo
|
||||
{
|
||||
bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true);
|
||||
bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, bool checkTransientActors = true);
|
||||
}
|
||||
|
||||
public interface IPositionable : IOccupySpace
|
||||
@@ -527,4 +529,7 @@ namespace OpenRA.Traits
|
||||
|
||||
[RequireExplicitImplementation]
|
||||
public interface IUnlocksRenderPlayer { bool RenderPlayerUnlocked { get; } }
|
||||
|
||||
[RequireExplicitImplementation]
|
||||
public interface ICreationActivity { Activity GetCreationActivity(); }
|
||||
}
|
||||
|
||||
@@ -329,10 +329,10 @@ namespace OpenRA
|
||||
public Actor CreateActor(bool addToWorld, string name, TypeDictionary initDict)
|
||||
{
|
||||
var a = new Actor(this, name, initDict);
|
||||
foreach (var t in a.TraitsImplementing<INotifyCreated>())
|
||||
t.Created(a);
|
||||
a.Created();
|
||||
if (addToWorld)
|
||||
Add(a);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,12 +47,9 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
bool IOccupySpaceInfo.SharesCell { get { return false; } }
|
||||
|
||||
// Used to determine if actor can spawn
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = false)
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, bool checkTransientActors = false)
|
||||
{
|
||||
if (!world.Map.Contains(cell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return world.Map.Contains(cell);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +188,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; }
|
||||
public Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange,
|
||||
WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; }
|
||||
public Activity MoveIntoWorld(Actor self, int delay = 0) { return null; }
|
||||
public Activity ReturnToCell(Actor self) { return null; }
|
||||
public Activity MoveToTarget(Actor self, Target target,
|
||||
WPos? initialTargetPosition = null, Color? targetLineColor = null) { return null; }
|
||||
public Activity MoveIntoTarget(Actor self, Target target) { return null; }
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
if (aircraft.Info.CanHover && !skipHeightAdjustment && dat != aircraft.Info.CruiseAltitude)
|
||||
{
|
||||
if (dat <= aircraft.LandAltitude)
|
||||
QueueChild(new TakeOff(self, target));
|
||||
QueueChild(new TakeOff(self));
|
||||
else
|
||||
VerticalTakeOffOrLandTick(self, aircraft, aircraft.Facing, aircraft.Info.CruiseAltitude);
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
}
|
||||
else if (dat <= aircraft.LandAltitude)
|
||||
{
|
||||
QueueChild(new TakeOff(self, target));
|
||||
QueueChild(new TakeOff(self));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,17 @@ namespace OpenRA.Mods.Common.Activities
|
||||
lastVisibleTargetTypes = target.Actor.GetEnabledTargetTypes();
|
||||
}
|
||||
|
||||
// The target may become hidden in the same tick the FlyAttack constructor is called,
|
||||
// causing lastVisible* to remain uninitialized.
|
||||
// Fix the fallback values based on the frozen actor properties
|
||||
else if (target.Type == TargetType.FrozenActor && !lastVisibleTarget.IsValidFor(self))
|
||||
{
|
||||
lastVisibleTarget = Target.FromTargetPositions(target);
|
||||
lastVisibleMaximumRange = attackAircraft.GetMaximumRangeVersusTarget(target);
|
||||
lastVisibleOwner = target.FrozenActor.Owner;
|
||||
lastVisibleTargetTypes = target.FrozenActor.TargetTypes;
|
||||
}
|
||||
|
||||
useLastVisibleTarget = targetIsHiddenActor || !target.IsValidFor(self);
|
||||
|
||||
// Target is hidden or dead, and we don't have a fallback position to move towards
|
||||
|
||||
@@ -21,19 +21,13 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
readonly Aircraft aircraft;
|
||||
readonly IMove move;
|
||||
Target fallbackTarget;
|
||||
bool movedToTarget = false;
|
||||
|
||||
public TakeOff(Actor self, Target fallbackTarget)
|
||||
public TakeOff(Actor self)
|
||||
{
|
||||
aircraft = self.Trait<Aircraft>();
|
||||
move = self.Trait<IMove>();
|
||||
this.fallbackTarget = fallbackTarget;
|
||||
}
|
||||
|
||||
public TakeOff(Actor self)
|
||||
: this(self, Target.Invalid) { }
|
||||
|
||||
protected override void OnFirstRun(Actor self)
|
||||
{
|
||||
if (aircraft.ForceLanding)
|
||||
@@ -42,8 +36,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
if (self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition).Length >= aircraft.Info.MinAirborneAltitude)
|
||||
return;
|
||||
|
||||
// We are taking off, so remove reservation and influence in ground cells.
|
||||
aircraft.UnReserve();
|
||||
// We are taking off, so remove influence in ground cells.
|
||||
aircraft.RemoveInfluence();
|
||||
|
||||
if (aircraft.Info.TakeoffSounds.Length > 0)
|
||||
@@ -73,24 +66,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only move to the fallback target if we don't have anything better to do
|
||||
if (NextActivity == null && fallbackTarget.IsValidFor(self) && !movedToTarget)
|
||||
{
|
||||
QueueChild(new AttackMoveActivity(self, () => move.MoveToTarget(self, fallbackTarget, targetLineColor: Color.OrangeRed)));
|
||||
movedToTarget = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)
|
||||
{
|
||||
if (ChildActivity != null)
|
||||
foreach (var n in ChildActivity.TargetLineNodes(self))
|
||||
yield return n;
|
||||
else
|
||||
yield return new TargetLineNode(fallbackTarget, Color.OrangeRed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
case EnterState.Exiting:
|
||||
{
|
||||
QueueChild(move.MoveIntoWorld(self));
|
||||
QueueChild(move.ReturnToCell(self));
|
||||
lastState = EnterState.Finished;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
if (b != WVec.Zero && c != WVec.Zero)
|
||||
{
|
||||
var cosA = (int)(1024 * (b.LengthSquared + c.LengthSquared - a.LengthSquared) / (2 * b.Length * c.Length));
|
||||
var cosA = (int)(512 * (b.LengthSquared + c.LengthSquared - a.LengthSquared) / b.Length / c.Length);
|
||||
|
||||
// Cost modifier varies between 0 and ResourceRefineryDirectionPenalty
|
||||
return Math.Abs(harvInfo.ResourceRefineryDirectionPenalty / 2) + harvInfo.ResourceRefineryDirectionPenalty * cosA / 2048;
|
||||
|
||||
@@ -208,6 +208,13 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
var nextCell = path[path.Count - 1];
|
||||
|
||||
// Something else might have moved us, so the path is no longer valid.
|
||||
if (!Util.AreAdjacentCells(mobile.ToCell, nextCell))
|
||||
{
|
||||
path = EvalPath();
|
||||
return null;
|
||||
}
|
||||
|
||||
var containsTemporaryBlocker = WorldUtils.ContainsTemporaryBlocker(self.World, nextCell, self);
|
||||
|
||||
// Next cell in the move is blocked by another actor
|
||||
@@ -331,9 +338,6 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
public override bool Tick(Actor self)
|
||||
{
|
||||
if (Move.mobile.IsTraitDisabled)
|
||||
return false;
|
||||
|
||||
var ret = InnerTick(self, Move.mobile);
|
||||
|
||||
if (moveFraction > MoveFractionTotal)
|
||||
@@ -412,7 +416,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
var nextCell = parent.PopPath(self);
|
||||
if (nextCell != null)
|
||||
{
|
||||
if (IsTurn(mobile, nextCell.Value.First))
|
||||
if (!mobile.IsTraitPaused && !mobile.IsTraitDisabled && IsTurn(mobile, nextCell.Value.First))
|
||||
{
|
||||
var nextSubcellOffset = map.Grid.OffsetOfSubCell(nextCell.Value.Second);
|
||||
var ret = new MoveFirstHalf(
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Activities;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
@@ -20,20 +21,18 @@ namespace OpenRA.Mods.Common.Activities
|
||||
public class PickupUnit : Activity
|
||||
{
|
||||
readonly Actor cargo;
|
||||
readonly IMove movement;
|
||||
|
||||
readonly Carryall carryall;
|
||||
readonly IFacing carryallFacing;
|
||||
|
||||
readonly Carryable carryable;
|
||||
readonly IFacing carryableFacing;
|
||||
readonly BodyOrientation carryableBody;
|
||||
|
||||
readonly int delay;
|
||||
|
||||
enum PickupState { Intercept, LockCarryable, Pickup }
|
||||
// TODO: Expose this to yaml
|
||||
readonly WDist targetLockRange = WDist.FromCells(4);
|
||||
|
||||
PickupState state;
|
||||
enum PickupState { Intercept, LockCarryable, Pickup }
|
||||
PickupState state = PickupState.Intercept;
|
||||
|
||||
public PickupUnit(Actor self, Actor cargo, int delay)
|
||||
{
|
||||
@@ -43,16 +42,20 @@ namespace OpenRA.Mods.Common.Activities
|
||||
carryableFacing = cargo.Trait<IFacing>();
|
||||
carryableBody = cargo.Trait<BodyOrientation>();
|
||||
|
||||
movement = self.Trait<IMove>();
|
||||
carryall = self.Trait<Carryall>();
|
||||
carryallFacing = self.Trait<IFacing>();
|
||||
|
||||
state = PickupState.Intercept;
|
||||
ChildHasPriority = false;
|
||||
}
|
||||
|
||||
protected override void OnFirstRun(Actor self)
|
||||
{
|
||||
carryall.ReserveCarryable(self, cargo);
|
||||
if (carryall.ReserveCarryable(self, cargo))
|
||||
{
|
||||
// Fly to the target and wait for it to be locked for pickup
|
||||
// These activities will be cancelled and replaced by Land once the target has been locked
|
||||
QueueChild(new Fly(self, Target.FromActor(cargo)));
|
||||
QueueChild(new FlyCircle(self));
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Tick(Actor self)
|
||||
@@ -74,26 +77,21 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return true;
|
||||
}
|
||||
|
||||
if (carryall.State != Carryall.CarryallState.Reserved)
|
||||
return true;
|
||||
// Wait until we are near the target before we try to lock it
|
||||
var distSq = (cargo.CenterPosition - self.CenterPosition).HorizontalLengthSquared;
|
||||
if (state == PickupState.Intercept && distSq <= targetLockRange.LengthSquared)
|
||||
state = PickupState.LockCarryable;
|
||||
|
||||
switch (state)
|
||||
if (state == PickupState.LockCarryable)
|
||||
{
|
||||
case PickupState.Intercept:
|
||||
QueueChild(movement.MoveWithinRange(Target.FromActor(cargo), WDist.FromCells(4)));
|
||||
state = PickupState.LockCarryable;
|
||||
return false;
|
||||
|
||||
case PickupState.LockCarryable:
|
||||
if (!carryable.LockForPickup(cargo, self))
|
||||
Cancel(self);
|
||||
|
||||
state = PickupState.Pickup;
|
||||
return false;
|
||||
|
||||
case PickupState.Pickup:
|
||||
var lockResponse = carryable.LockForPickup(cargo, self);
|
||||
if (lockResponse == LockResponse.Failed)
|
||||
Cancel(self);
|
||||
else if (lockResponse == LockResponse.Success)
|
||||
{
|
||||
// Land at the target location
|
||||
// Pickup position and facing are now known - swap the fly/wait activity with Land
|
||||
ChildActivity.Cancel(self);
|
||||
|
||||
var localOffset = carryall.OffsetForCarryable(self, cargo).Rotate(carryableBody.QuantizeOrientation(self, cargo.Orientation));
|
||||
QueueChild(new Land(self, Target.FromActor(cargo), -carryableBody.LocalToWorld(localOffset), carryableFacing.Facing));
|
||||
|
||||
@@ -104,11 +102,13 @@ namespace OpenRA.Mods.Common.Activities
|
||||
// Remove our carryable from world
|
||||
QueueChild(new AttachUnit(self, cargo));
|
||||
QueueChild(new TakeOff(self));
|
||||
return false;
|
||||
|
||||
state = PickupState.Pickup;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
// Return once we are in the pickup state and the pickup activities have completed
|
||||
return TickChild(self) && state == PickupState.Pickup;
|
||||
}
|
||||
|
||||
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)
|
||||
|
||||
@@ -187,10 +187,12 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
if (wasRepaired || isHostInvalid || (!stayOnResupplier && aircraft.Info.TakeOffOnResupply))
|
||||
{
|
||||
if (rp != null)
|
||||
QueueChild(move.MoveTo(rp.Location, repairableNear != null ? null : host.Actor));
|
||||
if (self.CurrentActivity.NextActivity == null && rp != null)
|
||||
QueueChild(move.MoveTo(rp.Location, repairableNear != null ? null : host.Actor, targetLineColor: Color.Green));
|
||||
else
|
||||
QueueChild(new TakeOff(self));
|
||||
|
||||
aircraft.UnReserve();
|
||||
}
|
||||
|
||||
// Aircraft without TakeOffOnResupply remain on the resupplier until something else needs it
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (self.IsDead)
|
||||
return;
|
||||
|
||||
// Make sure the target hasn't changed while entering
|
||||
// OnEnterComplete is only called if targetActor is alive
|
||||
if (targetActor != enterActor)
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
var move = actor.Trait<IMove>();
|
||||
var pos = actor.Trait<IPositionable>();
|
||||
|
||||
pos.SetPosition(self, exitSubCell.Value.First, exitSubCell.Value.Second);
|
||||
pos.SetPosition(actor, exitSubCell.Value.First, exitSubCell.Value.Second);
|
||||
pos.SetVisualPosition(actor, spawn);
|
||||
|
||||
actor.CancelActivity();
|
||||
|
||||
@@ -24,13 +24,13 @@ namespace OpenRA.Mods.Common
|
||||
public int Value(World world) { return value; }
|
||||
}
|
||||
|
||||
public class MoveIntoWorldDelayInit : IActorInit<int>
|
||||
public class CreationActivityDelayInit : IActorInit<int>
|
||||
{
|
||||
[FieldFromYamlKey]
|
||||
readonly int value = 0;
|
||||
|
||||
public MoveIntoWorldDelayInit() { }
|
||||
public MoveIntoWorldDelayInit(int init) { value = init; }
|
||||
public CreationActivityDelayInit() { }
|
||||
public CreationActivityDelayInit(int init) { value = init; }
|
||||
public int Value(World world) { return value; }
|
||||
}
|
||||
|
||||
|
||||
@@ -47,9 +47,11 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
|
||||
if (entryLocation.HasValue)
|
||||
{
|
||||
var pi = ai.TraitInfoOrDefault<AircraftInfo>();
|
||||
initDict.Add(new CenterPositionInit(owner.World.Map.CenterOfCell(entryLocation.Value) + new WVec(0, 0, pi != null ? pi.CruiseAltitude.Length : 0)));
|
||||
initDict.Add(new LocationInit(entryLocation.Value));
|
||||
|
||||
var pi = ai.TraitInfoOrDefault<AircraftInfo>();
|
||||
if (pi != null)
|
||||
initDict.Add(new CenterPositionInit(owner.World.Map.CenterOfCell(entryLocation.Value) + new WVec(0, 0, pi.CruiseAltitude.Length)));
|
||||
}
|
||||
|
||||
if (entryLocation.HasValue && nextLocation.HasValue)
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
var pos = Self.CenterPosition;
|
||||
mobile.SetPosition(Self, cell);
|
||||
mobile.SetVisualPosition(Self, pos);
|
||||
Self.QueueActivity(mobile.MoveIntoWorld(Self));
|
||||
Self.QueueActivity(mobile.ReturnToCell(Self));
|
||||
}
|
||||
|
||||
[ScriptActorPropertyActivity]
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using Eluant;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Scripting;
|
||||
@@ -35,7 +36,13 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public int PassengerCount { get { return cargo.Passengers.Count(); } }
|
||||
|
||||
[Desc("Teleport an existing actor inside this transport.")]
|
||||
public void LoadPassenger(Actor a) { cargo.Load(Self, a); }
|
||||
public void LoadPassenger(Actor a)
|
||||
{
|
||||
if (!a.IsIdle)
|
||||
throw new LuaException("LoadPassenger requires the passenger to be idle.");
|
||||
|
||||
cargo.Load(Self, a);
|
||||
}
|
||||
|
||||
[Desc("Remove the first actor from the transport. This actor is not added to the world.")]
|
||||
public Actor UnloadPassenger() { return cargo.Unload(Self); }
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
bool IOccupySpaceInfo.SharesCell { get { return false; } }
|
||||
|
||||
// Used to determine if an aircraft can spawn landed
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
{
|
||||
if (!world.Map.Contains(cell))
|
||||
return false;
|
||||
@@ -173,6 +173,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!checkTransientActors)
|
||||
return true;
|
||||
|
||||
// Since aircraft don't share cells, we don't pass the subCell parameter
|
||||
return !world.ActorMap.GetActorsAt(cell).Any(x => x != ignoreActor);
|
||||
}
|
||||
|
||||
@@ -190,7 +191,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public class Aircraft : ITick, ISync, IFacing, IPositionable, IMove, IIssueOrder, IResolveOrder, IOrderVoice, IDeathActorInitModifier,
|
||||
INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, INotifyBecomingIdle,
|
||||
IActorPreviewInitModifier, IIssueDeployOrder, IObservesVariables
|
||||
IActorPreviewInitModifier, IIssueDeployOrder, IObservesVariables, ICreationActivity
|
||||
{
|
||||
static readonly Pair<CPos, SubCell>[] NoCells = { };
|
||||
|
||||
@@ -220,7 +221,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
IEnumerable<CPos> landingCells = Enumerable.Empty<CPos>();
|
||||
bool requireForceMove;
|
||||
int moveIntoWorldDelay;
|
||||
int creationActivityDelay;
|
||||
|
||||
public static WPos GroundPosition(Actor self)
|
||||
{
|
||||
@@ -251,7 +252,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
SetPosition(self, init.Get<CenterPositionInit, WPos>());
|
||||
|
||||
Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : Info.InitialFacing;
|
||||
moveIntoWorldDelay = init.Contains<MoveIntoWorldDelayInit>() ? init.Get<MoveIntoWorldDelayInit, int>() : 0;
|
||||
|
||||
if (init.Contains<CreationActivityDelayInit>())
|
||||
creationActivityDelay = init.Get<CreationActivityDelayInit, int>();
|
||||
}
|
||||
|
||||
public WDist LandAltitude
|
||||
@@ -309,8 +312,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
notifyMoving = self.TraitsImplementing<INotifyMoving>().ToArray();
|
||||
positionOffsets = self.TraitsImplementing<IAircraftCenterPositionOffset>().ToArray();
|
||||
overrideAircraftLanding = self.TraitOrDefault<IOverrideAircraftLanding>();
|
||||
|
||||
self.QueueActivity(MoveIntoWorld(self, moveIntoWorldDelay));
|
||||
}
|
||||
|
||||
void INotifyAddedToWorld.AddedToWorld(Actor self)
|
||||
@@ -506,26 +507,15 @@ namespace OpenRA.Mods.Common.Traits
|
||||
MayYieldReservation = true;
|
||||
}
|
||||
|
||||
public void UnReserve(bool takeOff = false)
|
||||
public void UnReserve()
|
||||
{
|
||||
if (reservation == null)
|
||||
return;
|
||||
|
||||
// Move to the host's rally point if it has one
|
||||
var rp = ReservedActor != null ? ReservedActor.TraitOrDefault<RallyPoint>() : null;
|
||||
|
||||
reservation.Dispose();
|
||||
reservation = null;
|
||||
ReservedActor = null;
|
||||
MayYieldReservation = false;
|
||||
|
||||
if (takeOff && self.World.Map.DistanceAboveTerrain(CenterPosition).Length <= LandAltitude.Length)
|
||||
{
|
||||
if (rp != null)
|
||||
self.QueueActivity(new TakeOff(self, Target.FromCell(self.World, rp.Location)));
|
||||
else
|
||||
self.QueueActivity(new TakeOff(self));
|
||||
}
|
||||
}
|
||||
|
||||
bool AircraftCanEnter(Actor a, TargetModifiers modifiers)
|
||||
@@ -858,18 +848,15 @@ namespace OpenRA.Mods.Common.Traits
|
||||
initialTargetPosition, targetLineColor);
|
||||
}
|
||||
|
||||
public Activity MoveIntoWorld(Actor self, int delay = 0)
|
||||
{
|
||||
return new MoveIntoWorldActivity(self, delay);
|
||||
}
|
||||
public Activity ReturnToCell(Actor self) { return null; }
|
||||
|
||||
class MoveIntoWorldActivity : Activity
|
||||
class AssociateWithAirfieldActivity : Activity
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly Aircraft aircraft;
|
||||
readonly int delay;
|
||||
|
||||
public MoveIntoWorldActivity(Actor self, int delay = 0)
|
||||
public AssociateWithAirfieldActivity(Actor self, int delay = 0)
|
||||
{
|
||||
this.self = self;
|
||||
aircraft = self.Trait<Aircraft>();
|
||||
@@ -1179,6 +1166,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
inits.Add(new DynamicFacingInit(() => Facing));
|
||||
}
|
||||
|
||||
Activity ICreationActivity.GetCreationActivity()
|
||||
{
|
||||
return new AssociateWithAirfieldActivity(self, creationActivityDelay);
|
||||
}
|
||||
|
||||
public class AircraftMoveOrderTargeter : IOrderTargeter
|
||||
{
|
||||
readonly Aircraft aircraft;
|
||||
|
||||
@@ -42,18 +42,24 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public class FallsToEarth : IEffectiveOwner
|
||||
public class FallsToEarth : IEffectiveOwner, INotifyCreated
|
||||
{
|
||||
readonly FallsToEarthInfo info;
|
||||
readonly Player effectiveOwner;
|
||||
|
||||
public FallsToEarth(ActorInitializer init, FallsToEarthInfo info)
|
||||
{
|
||||
init.Self.QueueActivity(false, new FallToEarth(init.Self, info));
|
||||
this.info = info;
|
||||
effectiveOwner = init.Contains<EffectiveOwnerInit>() ? init.Get<EffectiveOwnerInit, Player>() : init.Self.Owner;
|
||||
}
|
||||
|
||||
// We return init.Self.Owner if there's no effective owner
|
||||
bool IEffectiveOwner.Disguised { get { return true; } }
|
||||
Player IEffectiveOwner.Owner { get { return effectiveOwner; } }
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
self.QueueActivity(false, new FallToEarth(self, info));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,6 +293,17 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
// The target may become hidden in the same tick the AttackActivity constructor is called,
|
||||
// causing lastVisible* to remain uninitialized.
|
||||
// Fix the fallback values based on the frozen actor properties
|
||||
else if (target.Type == TargetType.FrozenActor && !lastVisibleTarget.IsValidFor(self))
|
||||
{
|
||||
lastVisibleTarget = Target.FromTargetPositions(target);
|
||||
lastVisibleMaximumRange = attack.GetMaximumRangeVersusTarget(target);
|
||||
lastVisibleOwner = target.FrozenActor.Owner;
|
||||
lastVisibleTargetTypes = target.FrozenActor.TargetTypes;
|
||||
}
|
||||
|
||||
var maxRange = lastVisibleMaximumRange;
|
||||
var minRange = lastVisibleMinimumRange;
|
||||
useLastVisibleTarget = targetIsHiddenActor || !target.IsValidFor(self);
|
||||
|
||||
@@ -102,10 +102,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
// Prepare for transport pickup
|
||||
public override bool LockForPickup(Actor self, Actor carrier)
|
||||
public override LockResponse LockForPickup(Actor self, Actor carrier)
|
||||
{
|
||||
if (state == State.Locked || !WantsTransport)
|
||||
return false;
|
||||
if ((state == State.Locked && Carrier != carrier) || !WantsTransport)
|
||||
return LockResponse.Failed;
|
||||
|
||||
// Last chance to change our mind...
|
||||
var delta = self.World.Map.CenterOfCell(Destination.Value) - self.CenterPosition;
|
||||
@@ -113,7 +113,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
// Cancel pickup
|
||||
MovementCancelled(self);
|
||||
return false;
|
||||
return LockResponse.Failed;
|
||||
}
|
||||
|
||||
return base.LockForPickup(self, carrier);
|
||||
|
||||
@@ -229,7 +229,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return new List<MiniYamlNode>()
|
||||
{
|
||||
new MiniYamlNode("InitialBaseCenter", FieldSaver.FormatValue(initialBaseCenter)),
|
||||
new MiniYamlNode("ActiveMCVs", FieldSaver.FormatValue(activeMCVs.Select(a => a.ActorID).ToArray()))
|
||||
new MiniYamlNode("ActiveMCVs", FieldSaver.FormatValue(activeMCVs
|
||||
.Where(a => !unitCannotBeOrdered(a))
|
||||
.Select(a => a.ActorID)
|
||||
.ToArray()))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -247,7 +250,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
activeMCVs.Clear();
|
||||
activeMCVs.AddRange(FieldLoader.GetValue<uint[]>("ActiveMCVs", activeMCVsNode.Value.Value)
|
||||
.Select(a => world.GetActorById(a)));
|
||||
.Select(a => world.GetActorById(a)).Where(a => a != null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,8 +357,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
new MiniYamlNode("Squads", "", Squads.Select(s => new MiniYamlNode("Squad", s.Serialize())).ToList()),
|
||||
new MiniYamlNode("InitialBaseCenter", FieldSaver.FormatValue(initialBaseCenter)),
|
||||
new MiniYamlNode("UnitsHangingAroundTheBase", FieldSaver.FormatValue(unitsHangingAroundTheBase.Select(a => a.ActorID).ToArray())),
|
||||
new MiniYamlNode("ActiveUnits", FieldSaver.FormatValue(activeUnits.Select(a => a.ActorID).ToArray())),
|
||||
new MiniYamlNode("UnitsHangingAroundTheBase", FieldSaver.FormatValue(unitsHangingAroundTheBase
|
||||
.Where(a => !unitCannotBeOrdered(a))
|
||||
.Select(a => a.ActorID)
|
||||
.ToArray())),
|
||||
new MiniYamlNode("ActiveUnits", FieldSaver.FormatValue(activeUnits
|
||||
.Where(a => !unitCannotBeOrdered(a))
|
||||
.Select(a => a.ActorID)
|
||||
.ToArray())),
|
||||
new MiniYamlNode("RushTicks", FieldSaver.FormatValue(rushTicks)),
|
||||
new MiniYamlNode("AssignRolesTicks", FieldSaver.FormatValue(assignRolesTicks)),
|
||||
new MiniYamlNode("AttackForceTicks", FieldSaver.FormatValue(attackForceTicks)),
|
||||
@@ -380,7 +386,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
unitsHangingAroundTheBase.Clear();
|
||||
unitsHangingAroundTheBase.AddRange(FieldLoader.GetValue<uint[]>("UnitsHangingAroundTheBase", unitsHangingAroundTheBaseNode.Value.Value)
|
||||
.Select(a => self.World.GetActorById(a)));
|
||||
.Select(a => self.World.GetActorById(a)).Where(a => a != null));
|
||||
}
|
||||
|
||||
var activeUnitsNode = data.FirstOrDefault(n => n.Key == "ActiveUnits");
|
||||
@@ -388,7 +394,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
activeUnits.Clear();
|
||||
activeUnits.AddRange(FieldLoader.GetValue<uint[]>("ActiveUnits", activeUnitsNode.Value.Value)
|
||||
.Select(a => self.World.GetActorById(a)));
|
||||
.Select(a => self.World.GetActorById(a)).Where(a => a != null));
|
||||
}
|
||||
|
||||
var rushTicksNode = data.FirstOrDefault(n => n.Key == "RushTicks");
|
||||
|
||||
@@ -40,9 +40,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
readonly World world;
|
||||
readonly Player player;
|
||||
readonly Dictionary<SupportPowerInstance, int> waitingPowers = new Dictionary<SupportPowerInstance, int>();
|
||||
readonly Dictionary<string, SupportPowerDecision> powerDecisions = new Dictionary<string, SupportPowerDecision>();
|
||||
readonly List<SupportPowerInstance> stalePowers = new List<SupportPowerInstance>();
|
||||
SupportPowerManager supportPowerManager;
|
||||
Dictionary<SupportPowerInstance, int> waitingPowers = new Dictionary<SupportPowerInstance, int>();
|
||||
Dictionary<string, SupportPowerDecision> powerDecisions = new Dictionary<string, SupportPowerDecision>();
|
||||
|
||||
public SupportPowerBotModule(Actor self, SupportPowerBotModuleInfo info)
|
||||
: base(info)
|
||||
@@ -108,6 +109,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
bot.QueueOrder(new Order(sp.Key, supportPowerManager.Self, Target.FromCell(world, attackLocation.Value), false) { SuppressVisualFeedback = true });
|
||||
}
|
||||
}
|
||||
|
||||
// Remove stale powers
|
||||
stalePowers.AddRange(waitingPowers.Keys.Where(wp => !supportPowerManager.Powers.ContainsKey(wp.Key)));
|
||||
foreach (var p in stalePowers)
|
||||
waitingPowers.Remove(p);
|
||||
|
||||
stalePowers.Clear();
|
||||
}
|
||||
|
||||
/// <summary>Scans the map in chunks, evaluating all actors in each.</summary>
|
||||
@@ -208,8 +216,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
var waitingPowersNode = data.FirstOrDefault(n => n.Key == "WaitingPowers");
|
||||
if (waitingPowersNode != null)
|
||||
{
|
||||
foreach (var n in waitingPowersNode.Value.Nodes)
|
||||
waitingPowers[supportPowerManager.Powers[n.Key]] = FieldLoader.GetValue<int>("WaitingPowers", n.Value.Value);
|
||||
{
|
||||
SupportPowerInstance instance;
|
||||
if (supportPowerManager.Powers.TryGetValue(n.Key, out instance))
|
||||
waitingPowers[instance] = FieldLoader.GetValue<int>("WaitingPowers", n.Value.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
readonly List<string> queuedBuildRequests = new List<string>();
|
||||
|
||||
IBotRequestPauseUnitProduction[] requestPause;
|
||||
|
||||
List<Actor> idleUnits = new List<Actor>();
|
||||
int idleUnitCount;
|
||||
|
||||
int ticks;
|
||||
|
||||
@@ -68,7 +67,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
void IBotNotifyIdleBaseUnits.UpdatedIdleBaseUnits(List<Actor> idleUnits)
|
||||
{
|
||||
this.idleUnits = idleUnits;
|
||||
idleUnitCount = idleUnits.Count;
|
||||
}
|
||||
|
||||
void IBotTick.BotTick(IBot bot)
|
||||
@@ -88,7 +87,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
foreach (var q in Info.UnitQueues)
|
||||
BuildUnit(bot, q, idleUnits.Count < Info.IdleBaseUnitsMaximum);
|
||||
BuildUnit(bot, q, idleUnitCount < Info.IdleBaseUnitsMaximum);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +217,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return new List<MiniYamlNode>()
|
||||
{
|
||||
new MiniYamlNode("QueuedBuildRequests", FieldSaver.FormatValue(queuedBuildRequests.ToArray())),
|
||||
new MiniYamlNode("IdleUnits", FieldSaver.FormatValue(idleUnits.Select(a => a.ActorID).ToArray()))
|
||||
new MiniYamlNode("IdleUnitCount", FieldSaver.FormatValue(idleUnitCount))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -234,13 +233,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
queuedBuildRequests.AddRange(FieldLoader.GetValue<string[]>("QueuedBuildRequests", queuedBuildRequestsNode.Value.Value));
|
||||
}
|
||||
|
||||
var idleUnitsNode = data.FirstOrDefault(n => n.Key == "IdleUnits");
|
||||
if (idleUnitsNode != null)
|
||||
{
|
||||
idleUnits.Clear();
|
||||
idleUnits.AddRange(FieldLoader.GetValue<uint[]>("IdleUnits", idleUnitsNode.Value.Value)
|
||||
.Select(a => world.GetActorById(a)));
|
||||
}
|
||||
var idleUnitCountNode = data.FirstOrDefault(n => n.Key == "IdleUnitCount");
|
||||
if (idleUnitCountNode != null)
|
||||
idleUnitCount = FieldLoader.GetValue<int>("IdleUnitCount", idleUnitCountNode.Value.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -18,10 +19,16 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Reserve landing places for aircraft.")]
|
||||
class ReservableInfo : TraitInfo<Reservable> { }
|
||||
|
||||
public class Reservable : ITick, INotifyOwnerChanged, INotifySold, INotifyActorDisposing
|
||||
public class Reservable : ITick, INotifyOwnerChanged, INotifySold, INotifyActorDisposing, INotifyCreated
|
||||
{
|
||||
Actor reservedFor;
|
||||
Aircraft reservedForAircraft;
|
||||
RallyPoint rallyPoint;
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
rallyPoint = self.TraitOrDefault<RallyPoint>();
|
||||
}
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
{
|
||||
@@ -41,7 +48,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public IDisposable Reserve(Actor self, Actor forActor, Aircraft forAircraft)
|
||||
{
|
||||
if (reservedForAircraft != null && reservedForAircraft.MayYieldReservation)
|
||||
reservedForAircraft.UnReserve(true);
|
||||
UnReserve(self);
|
||||
|
||||
reservedFor = forActor;
|
||||
reservedForAircraft = forAircraft;
|
||||
@@ -71,17 +78,27 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return res == null || res.reservedForAircraft == null || res.reservedForAircraft.MayYieldReservation || res.reservedFor == forActor;
|
||||
}
|
||||
|
||||
private void UnReserve()
|
||||
void UnReserve(Actor self)
|
||||
{
|
||||
if (reservedForAircraft != null)
|
||||
reservedForAircraft.UnReserve(true);
|
||||
{
|
||||
if (reservedForAircraft.GetActorBelow() == self)
|
||||
{
|
||||
if (rallyPoint != null)
|
||||
reservedFor.QueueActivity(reservedForAircraft.MoveTo(rallyPoint.Location, null, targetLineColor: Color.Green));
|
||||
else
|
||||
reservedFor.QueueActivity(new TakeOff(reservedFor));
|
||||
}
|
||||
|
||||
reservedForAircraft.UnReserve();
|
||||
}
|
||||
}
|
||||
|
||||
void INotifyActorDisposing.Disposing(Actor self) { UnReserve(); }
|
||||
void INotifyActorDisposing.Disposing(Actor self) { UnReserve(self); }
|
||||
|
||||
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) { UnReserve(); }
|
||||
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) { UnReserve(self); }
|
||||
|
||||
void INotifySold.Selling(Actor self) { UnReserve(); }
|
||||
void INotifySold.Sold(Actor self) { UnReserve(); }
|
||||
void INotifySold.Selling(Actor self) { UnReserve(self); }
|
||||
void INotifySold.Sold(Actor self) { UnReserve(self); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +221,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (captures == null)
|
||||
return false;
|
||||
|
||||
// HACK: Make sure the target is not moving and at its normal position with respect to the cell grid
|
||||
var enterMobile = target.TraitOrDefault<Mobile>();
|
||||
if (enterMobile != null && enterMobile.IsMovingBetweenCells)
|
||||
return false;
|
||||
|
||||
if (progressWatchers.Any() || targetManager.progressWatchers.Any())
|
||||
{
|
||||
currentTargetTotal = captures.Info.CaptureDelay;
|
||||
|
||||
@@ -229,7 +229,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
return !IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location, blockedByMobile: false))
|
||||
&& CurrentAdjacentCells != null && CurrentAdjacentCells.Any(c => Passengers.Any(p => p.Trait<IPositionable>().CanEnterCell(c, null, immediate)));
|
||||
&& CurrentAdjacentCells != null && CurrentAdjacentCells.Any(c => Passengers.Any(p => !p.IsDead && p.Trait<IPositionable>().CanEnterCell(c, null, immediate)));
|
||||
}
|
||||
|
||||
public bool CanLoad(Actor self, Actor a)
|
||||
@@ -258,7 +258,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
internal void UnreserveSpace(Actor a)
|
||||
{
|
||||
if (!reserves.Contains(a))
|
||||
if (!reserves.Contains(a) || self.IsDead)
|
||||
return;
|
||||
|
||||
reservedWeight -= GetWeight(a);
|
||||
@@ -409,11 +409,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// If not initialized then this will be notified in the first tick
|
||||
if (initialized)
|
||||
{
|
||||
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
|
||||
npe.OnPassengerEntered(self, a);
|
||||
|
||||
foreach (var nec in a.TraitsImplementing<INotifyEnteredCargo>())
|
||||
nec.OnEnteredCargo(a, self);
|
||||
|
||||
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
|
||||
npe.OnPassengerEntered(self, a);
|
||||
}
|
||||
|
||||
var p = a.Trait<Passenger>();
|
||||
@@ -510,11 +510,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
c.Trait<Passenger>().Transport = self;
|
||||
|
||||
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
|
||||
npe.OnPassengerEntered(self, c);
|
||||
|
||||
foreach (var nec in c.TraitsImplementing<INotifyEnteredCargo>())
|
||||
nec.OnEnteredCargo(c, self);
|
||||
|
||||
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
|
||||
npe.OnPassengerEntered(self, c);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -35,6 +35,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public override object Create(ActorInitializer init) { return new Carryable(init.Self, this); }
|
||||
}
|
||||
|
||||
public enum LockResponse { Success, Pending, Failed }
|
||||
|
||||
public interface IDelayCarryallPickup
|
||||
{
|
||||
bool TryLockForPickup(Actor self, Actor carrier);
|
||||
}
|
||||
|
||||
public class Carryable : ConditionalTrait<CarryableInfo>
|
||||
{
|
||||
ConditionManager conditionManager;
|
||||
@@ -42,6 +49,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
int carriedToken = ConditionManager.InvalidConditionToken;
|
||||
int lockedToken = ConditionManager.InvalidConditionToken;
|
||||
|
||||
Mobile mobile;
|
||||
IDelayCarryallPickup[] delayPickups;
|
||||
|
||||
public Actor Carrier { get; private set; }
|
||||
public bool Reserved { get { return state != State.Free; } }
|
||||
public CPos? Destination { get; protected set; }
|
||||
@@ -57,6 +67,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
protected override void Created(Actor self)
|
||||
{
|
||||
conditionManager = self.Trait<ConditionManager>();
|
||||
mobile = self.TraitOrDefault<Mobile>();
|
||||
delayPickups = self.TraitsImplementing<IDelayCarryallPickup>().ToArray();
|
||||
|
||||
base.Created(self);
|
||||
}
|
||||
@@ -111,18 +123,28 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
// Prepare for transport pickup
|
||||
public virtual bool LockForPickup(Actor self, Actor carrier)
|
||||
public virtual LockResponse LockForPickup(Actor self, Actor carrier)
|
||||
{
|
||||
if (state == State.Locked)
|
||||
return false;
|
||||
if (state == State.Locked && Carrier != carrier)
|
||||
return LockResponse.Failed;
|
||||
|
||||
state = State.Locked;
|
||||
Carrier = carrier;
|
||||
if (delayPickups.Any(d => d.IsTraitEnabled() && !d.TryLockForPickup(self, carrier)))
|
||||
return LockResponse.Pending;
|
||||
|
||||
if (lockedToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.LockedCondition))
|
||||
lockedToken = conditionManager.GrantCondition(self, Info.LockedCondition);
|
||||
if (state != State.Locked)
|
||||
{
|
||||
state = State.Locked;
|
||||
Carrier = carrier;
|
||||
|
||||
return true;
|
||||
if (lockedToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.LockedCondition))
|
||||
lockedToken = conditionManager.GrantCondition(self, Info.LockedCondition);
|
||||
}
|
||||
|
||||
// Make sure we are not moving and at our normal position with respect to the cell grid
|
||||
if (mobile != null && mobile.IsMovingBetweenCells)
|
||||
return LockResponse.Pending;
|
||||
|
||||
return LockResponse.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Undeploy before the actor tries to move?")]
|
||||
public readonly bool UndeployOnMove = false;
|
||||
|
||||
[Desc("Undeploy before the actor is picked up by a Carryall?")]
|
||||
public readonly bool UndeployOnPickup = false;
|
||||
|
||||
[VoiceReference]
|
||||
public readonly string Voice = "Action";
|
||||
|
||||
@@ -67,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public enum DeployState { Undeployed, Deploying, Deployed, Undeploying }
|
||||
|
||||
public class GrantConditionOnDeploy : PausableConditionalTrait<GrantConditionOnDeployInfo>, IResolveOrder, IIssueOrder,
|
||||
INotifyDeployComplete, IIssueDeployOrder, IOrderVoice, IWrapMove
|
||||
INotifyDeployComplete, IIssueDeployOrder, IOrderVoice, IWrapMove, IDelayCarryallPickup
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly bool checkTerrainType;
|
||||
@@ -137,6 +140,17 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return activity;
|
||||
}
|
||||
|
||||
bool IDelayCarryallPickup.TryLockForPickup(Actor self, Actor carrier)
|
||||
{
|
||||
if (!Info.UndeployOnPickup || deployState == DeployState.Undeployed || IsTraitDisabled)
|
||||
return true;
|
||||
|
||||
if (deployState == DeployState.Deployed && !IsTraitPaused)
|
||||
Undeploy();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IEnumerable<IOrderTargeter> IIssueOrder.Orders
|
||||
{
|
||||
get
|
||||
|
||||
@@ -40,8 +40,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
bool IOccupySpaceInfo.SharesCell { get { return false; } }
|
||||
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
{
|
||||
// Since crates don't share cells and GetAvailableSubCell only returns SubCell.Full or SubCell.Invalid, we ignore the subCell parameter
|
||||
return GetAvailableSubCell(world, cell, ignoreActor, checkTransientActors) != SubCell.Invalid;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,12 +90,12 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
protected override void TraitEnabled(Actor self)
|
||||
{
|
||||
self.World.ActorMap.UpdatePosition(self, self.OccupiesSpace);
|
||||
self.World.ActorMap.UpdateOccupiedCells(self.OccupiesSpace);
|
||||
}
|
||||
|
||||
protected override void TraitDisabled(Actor self)
|
||||
{
|
||||
self.World.ActorMap.UpdatePosition(self, self.OccupiesSpace);
|
||||
self.World.ActorMap.UpdateOccupiedCells(self.OccupiesSpace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void GiveLevels(int numLevels, bool silent = false)
|
||||
{
|
||||
if (MaxLevel == 0)
|
||||
return;
|
||||
|
||||
var newLevel = Math.Min(Level + numLevels, MaxLevel);
|
||||
GiveExperience(nextLevel[newLevel - 1].First - experience, silent);
|
||||
}
|
||||
@@ -105,6 +108,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (amount < 0)
|
||||
throw new ArgumentException("Revoking experience is not implemented.", "amount");
|
||||
|
||||
if (MaxLevel == 0)
|
||||
return;
|
||||
|
||||
experience = (experience + amount).Clamp(0, nextLevel[MaxLevel - 1].First);
|
||||
|
||||
while (Level < MaxLevel && experience >= nextLevel[Level].First)
|
||||
|
||||
@@ -130,8 +130,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
mobile = self.Trait<Mobile>();
|
||||
resLayer = self.World.WorldActor.Trait<ResourceLayer>();
|
||||
claimLayer = self.World.WorldActor.Trait<ResourceClaimLayer>();
|
||||
|
||||
self.QueueActivity(new CallFunc(() => ChooseNewProc(self, null)));
|
||||
}
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
@@ -141,6 +139,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
conditionManager = self.TraitOrDefault<ConditionManager>();
|
||||
UpdateCondition(self);
|
||||
|
||||
self.QueueActivity(new CallFunc(() => ChooseNewProc(self, null)));
|
||||
|
||||
// Note: This is queued in a FrameEndTask because otherwise the activity is dropped/overridden while moving out of a factory.
|
||||
if (Info.SearchOnCreation)
|
||||
self.World.AddFrameEndTask(w => self.QueueActivity(new FindAndDeliverResources(self)));
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
bool IOccupySpaceInfo.SharesCell { get { return false; } }
|
||||
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
{
|
||||
// IPositionable*Info*.CanEnterCell is only ever used for things like exiting production facilities,
|
||||
// all places relevant for husks check IPositionable.CanEnterCell instead, so we can safely set this to true.
|
||||
|
||||
@@ -82,7 +82,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// initialized and used by CanEnterCell
|
||||
Locomotor locomotor;
|
||||
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
/// <summary>
|
||||
/// Note: If the target <paramref name="cell"/> has any free subcell, the value of <paramref name="subCell"/> is ignored.
|
||||
/// </summary>
|
||||
public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
{
|
||||
// PERF: Avoid repeated trait queries on the hot path
|
||||
if (locomotor == null)
|
||||
@@ -93,7 +96,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return false;
|
||||
|
||||
var check = checkTransientActors ? CellConditions.All : CellConditions.BlockedByMovers;
|
||||
return locomotor.CanMoveFreelyInto(self, cell, ignoreActor, check);
|
||||
return locomotor.CanMoveFreelyInto(self, cell, subCell, ignoreActor, check);
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any)
|
||||
@@ -139,12 +142,15 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public class Mobile : PausableConditionalTrait<MobileInfo>, IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove, ITick,
|
||||
public class Mobile : PausableConditionalTrait<MobileInfo>, IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove, ITick, ICreationActivity,
|
||||
IFacing, IDeathActorInitModifier, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyBlockingMove, IActorPreviewInitModifier, INotifyBecomingIdle
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly Lazy<IEnumerable<int>> speedModifiers;
|
||||
readonly int moveIntoWorldDelay;
|
||||
|
||||
readonly bool returnToCellOnCreation;
|
||||
readonly bool returnToCellOnCreationRecalculateSubCell = true;
|
||||
readonly int creationActivityDelay;
|
||||
|
||||
#region IMove CurrentMovementTypes
|
||||
MovementType movementTypes;
|
||||
@@ -160,8 +166,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
var oldValue = movementTypes;
|
||||
movementTypes = value;
|
||||
if (value != oldValue)
|
||||
{
|
||||
self.World.ActorMap.UpdateOccupiedCells(self.OccupiesSpace);
|
||||
foreach (var n in notifyMoving)
|
||||
n.MovementTypeChanged(self, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -177,6 +186,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
IWrapMove[] moveWrappers;
|
||||
bool requireForceMove;
|
||||
|
||||
public bool IsMovingBetweenCells
|
||||
{
|
||||
get { return FromCell != ToCell; }
|
||||
}
|
||||
|
||||
#region IFacing
|
||||
[Sync]
|
||||
public int Facing
|
||||
@@ -210,8 +224,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
if (FromCell == ToCell)
|
||||
return new[] { Pair.New(FromCell, FromSubCell) };
|
||||
if (CanEnterCell(ToCell))
|
||||
return new[] { Pair.New(ToCell, ToSubCell) };
|
||||
|
||||
return new[] { Pair.New(FromCell, FromSubCell), Pair.New(ToCell, ToSubCell) };
|
||||
}
|
||||
@@ -226,7 +238,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
ToSubCell = FromSubCell = info.LocomotorInfo.SharesCell ? init.World.Map.Grid.DefaultSubCell : SubCell.FullCell;
|
||||
if (init.Contains<SubCellInit>())
|
||||
{
|
||||
FromSubCell = ToSubCell = init.Get<SubCellInit, SubCell>();
|
||||
returnToCellOnCreationRecalculateSubCell = false;
|
||||
}
|
||||
|
||||
if (init.Contains<LocationInit>())
|
||||
{
|
||||
@@ -234,14 +249,19 @@ namespace OpenRA.Mods.Common.Traits
|
||||
SetVisualPosition(self, init.World.Map.CenterOfSubCell(FromCell, FromSubCell));
|
||||
}
|
||||
|
||||
Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
|
||||
Facing = oldFacing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
|
||||
|
||||
// Sets the visual position to WPos accuracy
|
||||
// Use LocationInit if you want to insert the actor into the ActorMap!
|
||||
// Sets the initial visual position
|
||||
// Unit will move into the cell grid (defined by LocationInit) as its initial activity
|
||||
if (init.Contains<CenterPositionInit>())
|
||||
SetVisualPosition(self, init.Get<CenterPositionInit, WPos>());
|
||||
{
|
||||
oldPos = init.Get<CenterPositionInit, WPos>();
|
||||
SetVisualPosition(self, oldPos);
|
||||
returnToCellOnCreation = true;
|
||||
}
|
||||
|
||||
moveIntoWorldDelay = init.Contains<MoveIntoWorldDelayInit>() ? init.Get<MoveIntoWorldDelayInit, int>() : 0;
|
||||
if (init.Contains<CreationActivityDelayInit>())
|
||||
creationActivityDelay = init.Get<CreationActivityDelayInit, int>();
|
||||
}
|
||||
|
||||
protected override void Created(Actor self)
|
||||
@@ -254,7 +274,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
Locomotor = self.World.WorldActor.TraitsImplementing<Locomotor>()
|
||||
.Single(l => l.Info.Name == Info.Locomotor);
|
||||
|
||||
self.QueueActivity(MoveIntoWorld(self, moveIntoWorldDelay));
|
||||
base.Created(self);
|
||||
}
|
||||
|
||||
@@ -295,7 +314,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void Nudge(Actor self, Actor nudger, bool force)
|
||||
{
|
||||
if (IsTraitDisabled || IsTraitPaused)
|
||||
if (IsTraitDisabled || IsTraitPaused || requireForceMove)
|
||||
return;
|
||||
|
||||
// Initial fairly braindead implementation.
|
||||
@@ -455,7 +474,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public bool CanEnterCell(CPos cell, Actor ignoreActor = null, bool checkTransientActors = true)
|
||||
{
|
||||
return Info.CanEnterCell(self.World, self, cell, ignoreActor, checkTransientActors);
|
||||
return Info.CanEnterCell(self.World, self, cell, ToSubCell, ignoreActor, checkTransientActors);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -567,27 +586,27 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return WrapMove(new Follow(self, target, minRange, maxRange, initialTargetPosition, targetLineColor));
|
||||
}
|
||||
|
||||
public Activity MoveIntoWorld(Actor self, int delay = 0)
|
||||
public Activity ReturnToCell(Actor self)
|
||||
{
|
||||
return new MoveIntoWorldActivity(self, delay);
|
||||
return new ReturnToCellActivity(self);
|
||||
}
|
||||
|
||||
class MoveIntoWorldActivity : Activity
|
||||
class ReturnToCellActivity : Activity
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly Mobile mobile;
|
||||
readonly bool recalculateSubCell;
|
||||
|
||||
CPos cell;
|
||||
SubCell subCell;
|
||||
WPos pos;
|
||||
int delay;
|
||||
|
||||
public MoveIntoWorldActivity(Actor self, int delay = 0)
|
||||
public ReturnToCellActivity(Actor self, int delay = 0, bool recalculateSubCell = false)
|
||||
{
|
||||
this.self = self;
|
||||
mobile = self.Trait<Mobile>();
|
||||
IsInterruptible = false;
|
||||
this.delay = delay;
|
||||
this.recalculateSubCell = recalculateSubCell;
|
||||
}
|
||||
|
||||
protected override void OnFirstRun(Actor self)
|
||||
@@ -603,7 +622,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
cell = mobile.ToCell;
|
||||
subCell = mobile.ToSubCell;
|
||||
|
||||
if (subCell == SubCell.Any)
|
||||
if (recalculateSubCell)
|
||||
subCell = mobile.Info.LocomotorInfo.SharesCell ? self.World.ActorMap.FreeSubCell(cell, subCell) : SubCell.FullCell;
|
||||
|
||||
// TODO: solve/reduce cell is full problem
|
||||
@@ -890,6 +909,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
Activity ICreationActivity.GetCreationActivity()
|
||||
{
|
||||
return returnToCellOnCreation ? new ReturnToCellActivity(self, creationActivityDelay, returnToCellOnCreationRecalculateSubCell) : null;
|
||||
}
|
||||
|
||||
class MoveOrderTargeter : IOrderTargeter
|
||||
{
|
||||
readonly Mobile mobile;
|
||||
|
||||
@@ -131,6 +131,16 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (specificCargoToken == ConditionManager.InvalidConditionToken && Info.CargoConditions.TryGetValue(cargo.Info.Name, out specificCargoCondition))
|
||||
specificCargoToken = conditionManager.GrantCondition(self, specificCargoCondition);
|
||||
}
|
||||
|
||||
// Allow scripted / initial actors to move from the unload point back into the cell grid on unload
|
||||
// This is handled by the RideTransport activity for player-loaded cargo
|
||||
if (self.IsIdle)
|
||||
{
|
||||
// IMove is not used anywhere else in this trait, there is no benefit to caching it from Created.
|
||||
var move = self.TraitOrDefault<IMove>();
|
||||
if (move != null)
|
||||
self.QueueActivity(move.ReturnToCell(self));
|
||||
}
|
||||
}
|
||||
|
||||
void INotifyExitedCargo.OnExitedCargo(Actor self, Actor cargo)
|
||||
|
||||
@@ -28,14 +28,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public int OrderCount;
|
||||
|
||||
public int EarnedThisMinute
|
||||
{
|
||||
get
|
||||
{
|
||||
return resources != null ? resources.Earned - earnedAtBeginningOfMinute : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int Experience
|
||||
{
|
||||
get
|
||||
@@ -44,10 +36,12 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public Queue<int> EarnedSamples = new Queue<int>(100);
|
||||
int earnedAtBeginningOfMinute;
|
||||
// Low resolution (every 30 seconds) record of earnings, covering the entire game
|
||||
public List<int> IncomeSamples = new List<int>(100);
|
||||
public int Income;
|
||||
public int DisplayIncome;
|
||||
|
||||
public Queue<int> ArmySamples = new Queue<int>(100);
|
||||
public List<int> ArmySamples = new List<int>(100);
|
||||
|
||||
public int KillsCost;
|
||||
public int DeathsCost;
|
||||
@@ -59,40 +53,63 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public int BuildingsDead;
|
||||
|
||||
public int ArmyValue;
|
||||
|
||||
// High resolution (every second) record of earnings, limited to the last minute
|
||||
readonly Queue<int> earnedSeconds = new Queue<int>(60);
|
||||
|
||||
int lastIncome;
|
||||
int lastIncomeTick;
|
||||
int ticks;
|
||||
int replayTimestep;
|
||||
|
||||
bool armyGraphDisabled;
|
||||
bool incomeGraphDisabled;
|
||||
|
||||
public PlayerStatistics(Actor self) { }
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
resources = self.TraitOrDefault<PlayerResources>();
|
||||
experience = self.TraitOrDefault<PlayerExperience>();
|
||||
}
|
||||
|
||||
void UpdateEarnedThisMinute()
|
||||
{
|
||||
EarnedSamples.Enqueue(EarnedThisMinute);
|
||||
earnedAtBeginningOfMinute = resources != null ? resources.Earned : 0;
|
||||
if (EarnedSamples.Count > 100)
|
||||
EarnedSamples.Dequeue();
|
||||
}
|
||||
|
||||
void UpdateArmyThisMinute()
|
||||
{
|
||||
ArmySamples.Enqueue(ArmyValue);
|
||||
if (ArmySamples.Count > 100)
|
||||
ArmySamples.Dequeue();
|
||||
incomeGraphDisabled = resources == null;
|
||||
}
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
{
|
||||
var timestep = self.World.IsReplay ? replayTimestep : self.World.Timestep;
|
||||
ticks++;
|
||||
|
||||
if (timestep * self.World.WorldTick % 60000 == 0)
|
||||
var timestep = self.World.IsReplay ? replayTimestep : self.World.Timestep;
|
||||
if (ticks * timestep >= 30000)
|
||||
{
|
||||
UpdateEarnedThisMinute();
|
||||
UpdateArmyThisMinute();
|
||||
ticks = 0;
|
||||
|
||||
if (!armyGraphDisabled && (ArmyValue != 0 || self.Owner.WinState == WinState.Undefined))
|
||||
ArmySamples.Add(ArmyValue);
|
||||
else
|
||||
armyGraphDisabled = true;
|
||||
|
||||
if (!incomeGraphDisabled && (Income != 0 || self.Owner.WinState == WinState.Undefined))
|
||||
IncomeSamples.Add(Income);
|
||||
else
|
||||
incomeGraphDisabled = true;
|
||||
}
|
||||
|
||||
if (resources == null)
|
||||
return;
|
||||
|
||||
var tickDelta = self.World.WorldTick - lastIncomeTick;
|
||||
if (tickDelta * timestep >= 1000)
|
||||
{
|
||||
lastIncomeTick = self.World.WorldTick;
|
||||
|
||||
var lastEarned = earnedSeconds.Count > 59 ? earnedSeconds.Dequeue() : 0;
|
||||
lastIncome = DisplayIncome = Income;
|
||||
Income = resources.Earned - lastEarned;
|
||||
earnedSeconds.Enqueue(resources.Earned);
|
||||
}
|
||||
else
|
||||
DisplayIncome = int2.Lerp(lastIncome, Income, tickDelta * timestep, 1000);
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
@@ -126,8 +143,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (w.IsReplay)
|
||||
replayTimestep = w.WorldActor.Trait<MapOptions>().GameSpeed.Timestep;
|
||||
|
||||
UpdateEarnedThisMinute();
|
||||
UpdateArmyThisMinute();
|
||||
if (!armyGraphDisabled)
|
||||
ArmySamples.Add(ArmyValue);
|
||||
|
||||
if (!incomeGraphDisabled)
|
||||
IncomeSamples.Add(Income);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
td.Add(new CenterPositionInit(spawn));
|
||||
td.Add(new FacingInit(initialFacing));
|
||||
if (exitinfo != null)
|
||||
td.Add(new MoveIntoWorldDelayInit(exitinfo.ExitDelay));
|
||||
td.Add(new CreationActivityDelayInit(exitinfo.ExitDelay));
|
||||
}
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
@@ -130,7 +130,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
self.NotifyBlocker(self.Location + s.ExitCell);
|
||||
|
||||
return mobileInfo == null ||
|
||||
mobileInfo.CanEnterCell(self.World, self, self.Location + s.ExitCell, self);
|
||||
mobileInfo.CanEnterCell(self.World, self, self.Location + s.ExitCell, ignoreActor: self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
td.Add(new LocationInit(exit));
|
||||
td.Add(new CenterPositionInit(spawn));
|
||||
td.Add(new FacingInit(initialFacing));
|
||||
td.Add(new MoveIntoWorldDelayInit(exitinfo.ExitDelay));
|
||||
td.Add(new CreationActivityDelayInit(exitinfo.ExitDelay));
|
||||
}
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
|
||||
@@ -93,6 +93,7 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
protected override void Created(Actor self)
|
||||
{
|
||||
rsm = self.TraitOrDefault<IRenderInfantrySequenceModifier>();
|
||||
idleDelay = self.World.SharedRandom.Next(Info.MinIdleDelay, Info.MaxIdleDelay);
|
||||
|
||||
base.Created(self);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
|
||||
{
|
||||
if (!activated)
|
||||
if (!activated && world.Map.Contains(cell))
|
||||
{
|
||||
targetCell = cell;
|
||||
targetLocation = mi.Location;
|
||||
@@ -119,7 +119,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
IEnumerable<IRenderable> IOrderGenerator.RenderAboveShroud(WorldRenderer wr, World world) { yield break; }
|
||||
|
||||
string IOrderGenerator.GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) { return cursor; }
|
||||
string IOrderGenerator.GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
return world.Map.Contains(cell) ? cursor : "generic-blocked";
|
||||
}
|
||||
|
||||
bool IOrderGenerator.HandleKeyPress(KeyInput e) { return false; }
|
||||
|
||||
|
||||
20
OpenRA.Mods.Common/Traits/UpdatesDerrickCount.cs
Normal file
20
OpenRA.Mods.Common/Traits/UpdatesDerrickCount.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2019 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, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Tag trait for updating the 'Oil Derrick' count economy statistic.")]
|
||||
public class UpdatesDerrickCountInfo : TraitInfo<UpdatesDerrickCount> { }
|
||||
|
||||
public class UpdatesDerrickCount { }
|
||||
}
|
||||
@@ -410,6 +410,15 @@ namespace OpenRA.Mods.Common.Traits
|
||||
influenceNode = influenceNode.Next;
|
||||
}
|
||||
|
||||
public void UpdateOccupiedCells(IOccupySpace ios)
|
||||
{
|
||||
if (CellUpdated == null)
|
||||
return;
|
||||
|
||||
foreach (var c in ios.OccupiedCells())
|
||||
CellUpdated(c.First);
|
||||
}
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
{
|
||||
// Position updates are done in one pass
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// TODO: This won't make sense for MP saves
|
||||
var localPlayer = worldRenderer.World.LocalPlayer;
|
||||
if ((localPlayer != null && localPlayer.PlayerActor != self) ||
|
||||
self.Owner != self.World.Players.FirstOrDefault(p => p.IsBot))
|
||||
(localPlayer == null && self.Owner != self.World.Players.FirstOrDefault(p => p.IsBot)))
|
||||
return null;
|
||||
|
||||
var nodes = new List<MiniYamlNode>()
|
||||
|
||||
@@ -220,6 +220,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
CellLayer<short> cellsCost;
|
||||
CellLayer<CellCache> blockingCache;
|
||||
|
||||
readonly Dictionary<byte, CellLayer<short>> customLayerCellsCost = new Dictionary<byte, CellLayer<short>>();
|
||||
readonly Dictionary<byte, CellLayer<CellCache>> customLayerBlockingCache = new Dictionary<byte, CellLayer<CellCache>>();
|
||||
|
||||
LocomotorInfo.TerrainInfo[] terrainInfos;
|
||||
World world;
|
||||
readonly HashSet<CPos> dirtyCells = new HashSet<CPos>();
|
||||
@@ -238,7 +241,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!world.Map.Contains(cell))
|
||||
return short.MaxValue;
|
||||
|
||||
return cellsCost[cell];
|
||||
return cell.Layer == 0 ? cellsCost[cell] : customLayerCellsCost[cell.Layer][cell];
|
||||
}
|
||||
|
||||
public short MovementCostToEnterCell(Actor actor, CPos destNode, Actor ignoreActor, CellConditions check)
|
||||
@@ -246,7 +249,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!world.Map.Contains(destNode))
|
||||
return short.MaxValue;
|
||||
|
||||
var cellCost = cellsCost[destNode];
|
||||
var cellCost = destNode.Layer == 0 ? cellsCost[destNode] : customLayerCellsCost[destNode.Layer][destNode];
|
||||
|
||||
if (cellCost == short.MaxValue ||
|
||||
!CanMoveFreelyInto(actor, destNode, ignoreActor, check))
|
||||
@@ -257,6 +260,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
// Determines whether the actor is blocked by other Actors
|
||||
public bool CanMoveFreelyInto(Actor actor, CPos cell, Actor ignoreActor, CellConditions check)
|
||||
{
|
||||
return CanMoveFreelyInto(actor, cell, SubCell.FullCell, ignoreActor, check);
|
||||
}
|
||||
|
||||
public bool CanMoveFreelyInto(Actor actor, CPos cell, SubCell subCell, Actor ignoreActor, CellConditions check)
|
||||
{
|
||||
var cellCache = GetCache(cell);
|
||||
var cellFlag = cellCache.CellFlag;
|
||||
@@ -289,7 +297,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var otherActor in world.ActorMap.GetActorsAt(cell))
|
||||
var otherActors = subCell == SubCell.FullCell ? world.ActorMap.GetActorsAt(cell) : world.ActorMap.GetActorsAt(cell, subCell);
|
||||
foreach (var otherActor in otherActors)
|
||||
if (IsBlockedBy(actor, otherActor, ignoreActor, check, cellFlag))
|
||||
return false;
|
||||
|
||||
@@ -298,8 +307,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public SubCell GetAvailableSubCell(Actor self, CPos cell, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, CellConditions check = CellConditions.All)
|
||||
{
|
||||
var cost = cellsCost[cell];
|
||||
if (cost == short.MaxValue)
|
||||
if (MovementCostForCell(cell) == short.MaxValue)
|
||||
return SubCell.Invalid;
|
||||
|
||||
if (check.HasCellCondition(CellConditions.TransientActors))
|
||||
@@ -377,16 +385,40 @@ namespace OpenRA.Mods.Common.Traits
|
||||
var map = w.Map;
|
||||
actorMap = w.ActorMap;
|
||||
actorMap.CellUpdated += CellUpdated;
|
||||
terrainInfos = Info.TilesetTerrainInfo[map.Rules.TileSet];
|
||||
|
||||
blockingCache = new CellLayer<CellCache>(map);
|
||||
cellsCost = new CellLayer<short>(map);
|
||||
|
||||
terrainInfos = Info.TilesetTerrainInfo[map.Rules.TileSet];
|
||||
|
||||
foreach (var cell in map.AllCells)
|
||||
UpdateCellCost(cell);
|
||||
|
||||
map.CustomTerrain.CellEntryChanged += UpdateCellCost;
|
||||
map.Tiles.CellEntryChanged += UpdateCellCost;
|
||||
|
||||
// This section needs to run after WorldLoaded() because we need to be sure that all types of ICustomMovementLayer have been initialized.
|
||||
w.AddFrameEndTask(_ =>
|
||||
{
|
||||
var customMovementLayers = w.WorldActor.TraitsImplementing<ICustomMovementLayer>();
|
||||
foreach (var cml in customMovementLayers)
|
||||
{
|
||||
var cellLayer = new CellLayer<short>(map);
|
||||
customLayerCellsCost[cml.Index] = cellLayer;
|
||||
customLayerBlockingCache[cml.Index] = new CellLayer<CellCache>(map);
|
||||
|
||||
foreach (var cell in map.AllCells)
|
||||
{
|
||||
var index = cml.GetTerrainIndex(cell);
|
||||
|
||||
var cost = short.MaxValue;
|
||||
|
||||
if (index != byte.MaxValue)
|
||||
cost = terrainInfos[index].Cost;
|
||||
|
||||
cellLayer[cell] = cost;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CellCache GetCache(CPos cell)
|
||||
@@ -397,7 +429,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
dirtyCells.Remove(cell);
|
||||
}
|
||||
|
||||
return blockingCache[cell];
|
||||
var cache = cell.Layer == 0 ? blockingCache : customLayerBlockingCache[cell.Layer];
|
||||
|
||||
return cache[cell];
|
||||
}
|
||||
|
||||
void CellUpdated(CPos cell)
|
||||
@@ -416,24 +450,28 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (index != byte.MaxValue)
|
||||
cost = terrainInfos[index].Cost;
|
||||
|
||||
cellsCost[cell] = cost;
|
||||
var cache = cell.Layer == 0 ? cellsCost : customLayerCellsCost[cell.Layer];
|
||||
|
||||
cache[cell] = cost;
|
||||
}
|
||||
|
||||
void UpdateCellBlocking(CPos cell)
|
||||
{
|
||||
using (new PerfSample("locomotor_cache"))
|
||||
{
|
||||
var cache = cell.Layer == 0 ? blockingCache : customLayerBlockingCache[cell.Layer];
|
||||
|
||||
var actors = actorMap.GetActorsAt(cell);
|
||||
|
||||
if (!actors.Any())
|
||||
{
|
||||
blockingCache[cell] = new CellCache(default(LongBitSet<PlayerBitMask>), CellFlag.HasFreeSpace);
|
||||
cache[cell] = new CellCache(default(LongBitSet<PlayerBitMask>), CellFlag.HasFreeSpace);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sharesCell && actorMap.HasFreeSubCell(cell))
|
||||
{
|
||||
blockingCache[cell] = new CellCache(default(LongBitSet<PlayerBitMask>), CellFlag.HasFreeSpace);
|
||||
cache[cell] = new CellCache(default(LongBitSet<PlayerBitMask>), CellFlag.HasFreeSpace);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -444,6 +482,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var actor in actors)
|
||||
{
|
||||
var actorBlocksPlayers = world.AllPlayersMask;
|
||||
var actorCrushablePlayers = world.NoPlayersMask;
|
||||
|
||||
var crushables = actor.TraitsImplementing<ICrushable>();
|
||||
var mobile = actor.OccupiesSpace as Mobile;
|
||||
var isMoving = mobile != null && mobile.CurrentMovementTypes.HasMovementType(MovementType.Horizontal);
|
||||
@@ -452,10 +492,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
cellFlag |= CellFlag.HasCrushableActor;
|
||||
foreach (var crushable in crushables)
|
||||
cellCrushablePlayers = cellCrushablePlayers.Intersect(crushable.CrushableBy(actor, Info.Crushes));
|
||||
actorCrushablePlayers = actorCrushablePlayers.Union(crushable.CrushableBy(actor, Info.Crushes));
|
||||
}
|
||||
else
|
||||
cellCrushablePlayers = world.NoPlayersMask;
|
||||
|
||||
if (isMoving)
|
||||
{
|
||||
@@ -471,10 +509,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
cellFlag |= CellFlag.HasTemporaryBlocker;
|
||||
}
|
||||
|
||||
cellCrushablePlayers = cellCrushablePlayers.Intersect(actorCrushablePlayers);
|
||||
cellBlockedPlayers = cellBlockedPlayers.Union(actorBlocksPlayers);
|
||||
}
|
||||
|
||||
blockingCache[cell] = new CellCache(cellBlockedPlayers, cellFlag, cellCrushablePlayers);
|
||||
cache[cell] = new CellCache(cellBlockedPlayers, cellFlag, cellCrushablePlayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
WPos? initialTargetPosition = null, Color? targetLineColor = null);
|
||||
Activity MoveToTarget(Actor self, Target target,
|
||||
WPos? initialTargetPosition = null, Color? targetLineColor = null);
|
||||
Activity MoveIntoWorld(Actor self, int delay = 0);
|
||||
Activity ReturnToCell(Actor self);
|
||||
Activity MoveIntoTarget(Actor self, Target target);
|
||||
Activity VisualMove(Actor self, WPos fromPos, WPos toPos);
|
||||
int EstimatedMoveDuration(Actor self, WPos fromPos, WPos toPos);
|
||||
|
||||
@@ -129,10 +129,12 @@ namespace OpenRA.Mods.Common.UpdateRules
|
||||
new RemovePlaceBuildingPalettes(),
|
||||
new RenameHoversOffsetModifier(),
|
||||
new AddAirAttackTypes(),
|
||||
new MoveAbortOnResupply(),
|
||||
new RenameCarryallDelays(),
|
||||
new AddCanSlide(),
|
||||
new AddAircraftIdleBehavior(),
|
||||
new RenameSearchRadius(),
|
||||
new RenameChronoshiftFootprint(),
|
||||
new RemoveMoveIntoWorldFromExit(),
|
||||
})
|
||||
};
|
||||
|
||||
@@ -141,6 +141,12 @@ namespace OpenRA.Mods.Common
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AreAdjacentCells(CPos a, CPos b)
|
||||
{
|
||||
var offset = b - a;
|
||||
return Math.Abs(offset.X) < 2 && Math.Abs(offset.Y) < 2;
|
||||
}
|
||||
|
||||
public static IEnumerable<CPos> ExpandFootprint(IEnumerable<CPos> cells, bool allowDiagonal)
|
||||
{
|
||||
return cells.SelectMany(c => Neighbours(c, allowDiagonal)).Distinct();
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var textSize = font.Measure(text).Y;
|
||||
var offset = font.TopOffset;
|
||||
|
||||
if (chatPos.Y < pos.Y)
|
||||
if (chatPos.Y - font.TopOffset < pos.Y)
|
||||
break;
|
||||
|
||||
var textLineHeight = lineHeight;
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
public string YAxisValueFormat = "{0}";
|
||||
public int XAxisSize = 10;
|
||||
public int YAxisSize = 10;
|
||||
public int XAxisTicksPerLabel = 1;
|
||||
public string XAxisLabel = "";
|
||||
public string YAxisLabel = "";
|
||||
public bool DisplayFirstYAxisValue = false;
|
||||
@@ -77,6 +78,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
YAxisValueFormat = other.YAxisValueFormat;
|
||||
XAxisSize = other.XAxisSize;
|
||||
YAxisSize = other.YAxisSize;
|
||||
XAxisTicksPerLabel = other.XAxisTicksPerLabel;
|
||||
XAxisLabel = other.XAxisLabel;
|
||||
YAxisLabel = other.YAxisLabel;
|
||||
DisplayFirstYAxisValue = other.DisplayFirstYAxisValue;
|
||||
@@ -89,14 +91,21 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
if (GetSeries == null || !GetSeries().Any()
|
||||
|| GetLabelFont == null || GetLabelFont() == null)
|
||||
if (GetSeries == null || GetLabelFont == null)
|
||||
return;
|
||||
|
||||
var series = GetSeries();
|
||||
if (!series.Any())
|
||||
return;
|
||||
|
||||
var font = GetLabelFont();
|
||||
if (font == null)
|
||||
return;
|
||||
|
||||
var cr = Game.Renderer.RgbaColorRenderer;
|
||||
var rect = RenderBounds;
|
||||
|
||||
var labelFont = Game.Renderer.Fonts[GetLabelFont()];
|
||||
var labelFont = Game.Renderer.Fonts[font];
|
||||
var axisFont = Game.Renderer.Fonts[GetAxisFont()];
|
||||
|
||||
var xAxisSize = GetXAxisSize();
|
||||
@@ -110,8 +119,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var graphBottomOffset = Padding * 2 + xAxisLabelSize.Y + xAxisPointLabelHeight;
|
||||
var height = rect.Height - (graphBottomOffset + Padding);
|
||||
|
||||
var maxValue = GetSeries().Select(p => p.Points).SelectMany(d => d).Concat(new[] { 0f }).Max();
|
||||
var longestName = GetSeries().Select(s => s.Key).OrderByDescending(s => s.Length).FirstOrDefault() ?? "";
|
||||
var maxValue = series.Select(p => p.Points).SelectMany(d => d).Concat(new[] { 0f }).Max();
|
||||
var longestName = series.Select(s => s.Key).OrderByDescending(s => s.Length).FirstOrDefault() ?? "";
|
||||
|
||||
var scale = 200 / Math.Max(5000, (float)Math.Ceiling(maxValue / 1000) * 1000);
|
||||
|
||||
@@ -127,7 +136,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var xStep = width / xAxisSize;
|
||||
var yStep = height / yAxisSize;
|
||||
|
||||
var pointCount = GetSeries().First().Points.Count();
|
||||
var pointCount = series.Max(s => s.Points.Count());
|
||||
var pointStart = Math.Max(0, pointCount - xAxisSize);
|
||||
var pointEnd = Math.Max(pointCount, xAxisSize);
|
||||
|
||||
@@ -136,11 +145,11 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var origin = new float2(rect.Left, rect.Bottom);
|
||||
|
||||
var keyOffset = 0;
|
||||
foreach (var series in GetSeries())
|
||||
foreach (var s in series)
|
||||
{
|
||||
var key = series.Key;
|
||||
var color = series.Color;
|
||||
var points = series.Points;
|
||||
var key = s.Key;
|
||||
var color = s.Color;
|
||||
var points = s.Points;
|
||||
if (points.Any())
|
||||
{
|
||||
points = points.Reverse().Take(xAxisSize).Reverse();
|
||||
@@ -171,7 +180,10 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
for (int n = pointStart, x = 0; n <= pointEnd; n++, x += xStep)
|
||||
{
|
||||
cr.DrawLine(graphOrigin + new float2(x, 0), graphOrigin + new float2(x, -5), 1, Color.White);
|
||||
var xAxisText = GetXAxisValueFormat().F(n);
|
||||
if (n % XAxisTicksPerLabel != 0)
|
||||
continue;
|
||||
|
||||
var xAxisText = GetXAxisValueFormat().F(n / XAxisTicksPerLabel);
|
||||
var xAxisTickTextWidth = labelFont.Measure(xAxisText).X;
|
||||
var xLocation = x - (xAxisTickTextWidth / 2);
|
||||
labelFont.DrawTextWithShadow(xAxisText, graphOrigin + new float2(xLocation, 2), Color.White, BackgroundColorDark, BackgroundColorLight, 1);
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
}
|
||||
|
||||
if (Directory.Exists(baseSavePath))
|
||||
LoadGames(gameTemplate, newTemplate);
|
||||
LoadGames(gameTemplate, newTemplate, world);
|
||||
|
||||
var renameButton = panel.Get<ButtonWidget>("RENAME_BUTTON");
|
||||
renameButton.IsDisabled = () => selectedSave == null;
|
||||
@@ -171,7 +171,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
SelectFirstVisible();
|
||||
}
|
||||
|
||||
void LoadGames(ScrollItemWidget gameTemplate, ScrollItemWidget newTemplate)
|
||||
void LoadGames(ScrollItemWidget gameTemplate, ScrollItemWidget newTemplate, World world)
|
||||
{
|
||||
gameList.RemoveChildren();
|
||||
if (isSavePanel)
|
||||
@@ -198,7 +198,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
item.IsVisible = () => true;
|
||||
item.IsSelected = () => selectedSave == item.ItemKey;
|
||||
item.OnClick = () => Select(item.ItemKey);
|
||||
item.OnDoubleClick = Load;
|
||||
|
||||
if (isSavePanel)
|
||||
item.OnDoubleClick = () => Save(world);
|
||||
else
|
||||
item.OnDoubleClick = Load;
|
||||
|
||||
var title = Path.GetFileNameWithoutExtension(savePath);
|
||||
var label = item.Get<LabelWithTooltipWidget>("TITLE");
|
||||
|
||||
@@ -38,10 +38,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
readonly ScrollItemWidget productionPlayerTemplate;
|
||||
readonly ScrollItemWidget supportPowersPlayerTemplate;
|
||||
readonly ScrollItemWidget combatPlayerTemplate;
|
||||
readonly ContainerWidget earnedThisMinuteGraphContainer;
|
||||
readonly ContainerWidget armyThisMinuteGraphContainer;
|
||||
readonly LineGraphWidget earnedThisMinuteGraph;
|
||||
readonly LineGraphWidget armyThisMinuteGraph;
|
||||
readonly ContainerWidget incomeGraphContainer;
|
||||
readonly ContainerWidget armyValueGraphContainer;
|
||||
readonly LineGraphWidget incomeGraph;
|
||||
readonly LineGraphWidget armyValueGraph;
|
||||
readonly ScrollItemWidget teamTemplate;
|
||||
readonly IEnumerable<Player> players;
|
||||
readonly IOrderedEnumerable<IGrouping<int, Player>> teams;
|
||||
@@ -95,11 +95,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
supportPowersPlayerTemplate = playerStatsPanel.Get<ScrollItemWidget>("SUPPORT_POWERS_PLAYER_TEMPLATE");
|
||||
combatPlayerTemplate = playerStatsPanel.Get<ScrollItemWidget>("COMBAT_PLAYER_TEMPLATE");
|
||||
|
||||
earnedThisMinuteGraphContainer = widget.Get<ContainerWidget>("EARNED_THIS_MIN_GRAPH_CONTAINER");
|
||||
earnedThisMinuteGraph = earnedThisMinuteGraphContainer.Get<LineGraphWidget>("EARNED_THIS_MIN_GRAPH");
|
||||
incomeGraphContainer = widget.Get<ContainerWidget>("INCOME_GRAPH_CONTAINER");
|
||||
incomeGraph = incomeGraphContainer.Get<LineGraphWidget>("INCOME_GRAPH");
|
||||
|
||||
armyThisMinuteGraphContainer = widget.Get<ContainerWidget>("ARMY_THIS_MIN_GRAPH_CONTAINER");
|
||||
armyThisMinuteGraph = armyThisMinuteGraphContainer.Get<LineGraphWidget>("ARMY_THIS_MIN_GRAPH");
|
||||
armyValueGraphContainer = widget.Get<ContainerWidget>("ARMY_VALUE_GRAPH_CONTAINER");
|
||||
armyValueGraph = armyValueGraphContainer.Get<LineGraphWidget>("ARMY_VALUE_GRAPH");
|
||||
|
||||
teamTemplate = playerStatsPanel.Get<ScrollItemWidget>("TEAM_TEMPLATE");
|
||||
|
||||
@@ -144,8 +144,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
createStatsOption("Production", ObserverStatsPanel.Production, productionPlayerTemplate, () => DisplayStats(ProductionStats)),
|
||||
createStatsOption("Support Powers", ObserverStatsPanel.SupportPowers, supportPowersPlayerTemplate, () => DisplayStats(SupportPowerStats)),
|
||||
createStatsOption("Combat", ObserverStatsPanel.Combat, combatPlayerTemplate, () => DisplayStats(CombatStats)),
|
||||
createStatsOption("Earnings (graph)", ObserverStatsPanel.Graph, null, () => EarnedThisMinuteGraph()),
|
||||
createStatsOption("Army (graph)", ObserverStatsPanel.ArmyGraph, null, () => ArmyThisMinuteGraph()),
|
||||
createStatsOption("Earnings (graph)", ObserverStatsPanel.Graph, null, () => IncomeGraph()),
|
||||
createStatsOption("Army (graph)", ObserverStatsPanel.ArmyGraph, null, () => ArmyValueGraph()),
|
||||
};
|
||||
|
||||
Func<StatsDropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) =>
|
||||
@@ -192,31 +192,31 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
supportPowerStatsHeaders.Visible = false;
|
||||
combatStatsHeaders.Visible = false;
|
||||
|
||||
earnedThisMinuteGraphContainer.Visible = false;
|
||||
armyThisMinuteGraphContainer.Visible = false;
|
||||
incomeGraphContainer.Visible = false;
|
||||
armyValueGraphContainer.Visible = false;
|
||||
|
||||
earnedThisMinuteGraph.GetSeries = null;
|
||||
armyThisMinuteGraph.GetSeries = null;
|
||||
incomeGraph.GetSeries = null;
|
||||
armyValueGraph.GetSeries = null;
|
||||
}
|
||||
|
||||
void EarnedThisMinuteGraph()
|
||||
void IncomeGraph()
|
||||
{
|
||||
playerStatsPanel.Visible = false;
|
||||
earnedThisMinuteGraphContainer.Visible = true;
|
||||
incomeGraphContainer.Visible = true;
|
||||
|
||||
earnedThisMinuteGraph.GetSeries = () =>
|
||||
incomeGraph.GetSeries = () =>
|
||||
players.Select(p => new LineGraphSeries(
|
||||
p.PlayerName,
|
||||
p.Color,
|
||||
(p.PlayerActor.TraitOrDefault<PlayerStatistics>() ?? new PlayerStatistics(p.PlayerActor)).EarnedSamples.Select(s => (float)s)));
|
||||
(p.PlayerActor.TraitOrDefault<PlayerStatistics>() ?? new PlayerStatistics(p.PlayerActor)).IncomeSamples.Select(s => (float)s)));
|
||||
}
|
||||
|
||||
void ArmyThisMinuteGraph()
|
||||
void ArmyValueGraph()
|
||||
{
|
||||
playerStatsPanel.Visible = false;
|
||||
armyThisMinuteGraphContainer.Visible = true;
|
||||
armyValueGraphContainer.Visible = true;
|
||||
|
||||
armyThisMinuteGraph.GetSeries = () =>
|
||||
armyValueGraph.GetSeries = () =>
|
||||
players.Select(p => new LineGraphSeries(
|
||||
p.PlayerName,
|
||||
p.Color,
|
||||
@@ -233,7 +233,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
tt.IgnoreMouseOver = true;
|
||||
|
||||
var teamLabel = tt.Get<LabelWidget>("TEAM");
|
||||
teamLabel.GetText = () => team.Key == 0 ? "No Team" : "Team " + team.Key;
|
||||
var teamText = team.Key == 0 ? "No Team" : "Team " + team.Key;
|
||||
teamLabel.GetText = () => teamText;
|
||||
tt.Bounds.Width = teamLabel.Bounds.Width = Game.Renderer.Fonts[tt.Font].Measure(tt.Get<LabelWidget>("TEAM").GetText()).X;
|
||||
|
||||
var colorBlockWidget = tt.Get<ColorBlockWidget>("TEAM_COLOR");
|
||||
@@ -273,14 +274,29 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
SetupPlayerColor(player, template, playerColor, playerGradient);
|
||||
|
||||
var stats = player.PlayerActor.TraitOrDefault<PlayerStatistics>();
|
||||
if (stats == null) return template;
|
||||
template.Get<LabelWidget>("ASSETS_DESTROYED").GetText = () => "$" + stats.KillsCost;
|
||||
template.Get<LabelWidget>("ASSETS_LOST").GetText = () => "$" + stats.DeathsCost;
|
||||
template.Get<LabelWidget>("UNITS_KILLED").GetText = () => stats.UnitsKilled.ToString();
|
||||
template.Get<LabelWidget>("UNITS_DEAD").GetText = () => stats.UnitsDead.ToString();
|
||||
template.Get<LabelWidget>("BUILDINGS_KILLED").GetText = () => stats.BuildingsKilled.ToString();
|
||||
template.Get<LabelWidget>("BUILDINGS_DEAD").GetText = () => stats.BuildingsDead.ToString();
|
||||
template.Get<LabelWidget>("ARMY_VALUE").GetText = () => "$" + stats.ArmyValue.ToString();
|
||||
if (stats == null)
|
||||
return template;
|
||||
|
||||
var destroyedText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("ASSETS_DESTROYED").GetText = () => destroyedText.Update(stats.KillsCost);
|
||||
|
||||
var lostText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("ASSETS_LOST").GetText = () => lostText.Update(stats.DeathsCost);
|
||||
|
||||
var unitsKilledText = new CachedTransform<int, string>(i => i.ToString());
|
||||
template.Get<LabelWidget>("UNITS_KILLED").GetText = () => unitsKilledText.Update(stats.UnitsKilled);
|
||||
|
||||
var unitsDeadText = new CachedTransform<int, string>(i => i.ToString());
|
||||
template.Get<LabelWidget>("UNITS_DEAD").GetText = () => unitsDeadText.Update(stats.UnitsDead);
|
||||
|
||||
var buildingsKilledText = new CachedTransform<int, string>(i => i.ToString());
|
||||
template.Get<LabelWidget>("BUILDINGS_KILLED").GetText = () => buildingsKilledText.Update(stats.BuildingsKilled);
|
||||
|
||||
var buildingsDeadText = new CachedTransform<int, string>(i => i.ToString());
|
||||
template.Get<LabelWidget>("BUILDINGS_DEAD").GetText = () => buildingsDeadText.Update(stats.BuildingsDead);
|
||||
|
||||
var armyText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("ARMY_VALUE").GetText = () => armyText.Update(stats.ArmyValue);
|
||||
|
||||
return template;
|
||||
}
|
||||
@@ -344,22 +360,34 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
var res = player.PlayerActor.Trait<PlayerResources>();
|
||||
var stats = player.PlayerActor.TraitOrDefault<PlayerStatistics>();
|
||||
if (stats == null) return template;
|
||||
if (stats == null)
|
||||
return template;
|
||||
|
||||
template.Get<LabelWidget>("CASH").GetText = () => "$" + (res.Cash + res.Resources);
|
||||
template.Get<LabelWidget>("EARNED_MIN").GetText = () => AverageEarnedPerMinute(res.Earned);
|
||||
template.Get<LabelWidget>("EARNED_THIS_MIN").GetText = () => "$" + stats.EarnedThisMinute;
|
||||
template.Get<LabelWidget>("EARNED").GetText = () => "$" + res.Earned;
|
||||
template.Get<LabelWidget>("SPENT").GetText = () => "$" + res.Spent;
|
||||
var cashText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("CASH").GetText = () => cashText.Update(res.Cash + res.Resources);
|
||||
|
||||
var incomeText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("INCOME").GetText = () => incomeText.Update(stats.DisplayIncome);
|
||||
|
||||
var earnedText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("EARNED").GetText = () => earnedText.Update(res.Earned);
|
||||
|
||||
var spentText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("SPENT").GetText = () => spentText.Update(res.Spent);
|
||||
|
||||
var assetsText = new CachedTransform<int, string>(i => "$" + i);
|
||||
var assets = template.Get<LabelWidget>("ASSETS");
|
||||
assets.GetText = () => "$" + world.ActorsHavingTrait<Valued>()
|
||||
assets.GetText = () => assetsText.Update(world.ActorsHavingTrait<Valued>()
|
||||
.Where(a => a.Owner == player && !a.IsDead)
|
||||
.Sum(a => a.Info.TraitInfos<ValuedInfo>().First().Cost);
|
||||
.Sum(a => a.Info.TraitInfos<ValuedInfo>().First().Cost));
|
||||
|
||||
var harvesters = template.Get<LabelWidget>("HARVESTERS");
|
||||
harvesters.GetText = () => world.ActorsHavingTrait<Harvester>().Count(a => a.Owner == player && !a.IsDead).ToString();
|
||||
|
||||
var derricks = template.GetOrNull<LabelWidget>("DERRICKS");
|
||||
if (derricks != null)
|
||||
derricks.GetText = () => world.ActorsHavingTrait<UpdatesDerrickCount>().Count(a => a.Owner == player && !a.IsDead).ToString();
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
@@ -379,25 +407,39 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
SetupPlayerColor(player, template, playerColor, playerGradient);
|
||||
|
||||
var res = player.PlayerActor.Trait<PlayerResources>();
|
||||
template.Get<LabelWidget>("CASH").GetText = () => "$" + (res.Cash + res.Resources);
|
||||
template.Get<LabelWidget>("EARNED_MIN").GetText = () => AverageEarnedPerMinute(res.Earned);
|
||||
var cashText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("CASH").GetText = () => cashText.Update(res.Cash + res.Resources);
|
||||
|
||||
var powerRes = player.PlayerActor.TraitOrDefault<PowerManager>();
|
||||
if (powerRes != null)
|
||||
{
|
||||
var power = template.Get<LabelWidget>("POWER");
|
||||
power.GetText = () => powerRes.PowerDrained + "/" + powerRes.PowerProvided;
|
||||
var powerText = new CachedTransform<Pair<int, int>, string>(p => p.First + "/" + p.Second);
|
||||
power.GetText = () => powerText.Update(new Pair<int, int>(powerRes.PowerDrained, powerRes.PowerProvided));
|
||||
power.GetColor = () => GetPowerColor(powerRes.PowerState);
|
||||
}
|
||||
|
||||
var stats = player.PlayerActor.TraitOrDefault<PlayerStatistics>();
|
||||
if (stats == null) return template;
|
||||
template.Get<LabelWidget>("KILLS").GetText = () => (stats.UnitsKilled + stats.BuildingsKilled).ToString();
|
||||
template.Get<LabelWidget>("DEATHS").GetText = () => (stats.UnitsDead + stats.BuildingsDead).ToString();
|
||||
template.Get<LabelWidget>("ASSETS_DESTROYED").GetText = () => "$" + stats.KillsCost;
|
||||
template.Get<LabelWidget>("ASSETS_LOST").GetText = () => "$" + stats.DeathsCost;
|
||||
template.Get<LabelWidget>("EXPERIENCE").GetText = () => stats.Experience.ToString();
|
||||
template.Get<LabelWidget>("ACTIONS_MIN").GetText = () => AverageOrdersPerMinute(stats.OrderCount);
|
||||
if (stats == null)
|
||||
return template;
|
||||
|
||||
var killsText = new CachedTransform<int, string>(i => i.ToString());
|
||||
template.Get<LabelWidget>("KILLS").GetText = () => killsText.Update(stats.UnitsKilled + stats.BuildingsKilled);
|
||||
|
||||
var deathsText = new CachedTransform<int, string>(i => i.ToString());
|
||||
template.Get<LabelWidget>("DEATHS").GetText = () => deathsText.Update(stats.UnitsDead + stats.BuildingsDead);
|
||||
|
||||
var destroyedText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("ASSETS_DESTROYED").GetText = () => destroyedText.Update(stats.KillsCost);
|
||||
|
||||
var lostText = new CachedTransform<int, string>(i => "$" + i);
|
||||
template.Get<LabelWidget>("ASSETS_LOST").GetText = () => lostText.Update(stats.DeathsCost);
|
||||
|
||||
var experienceText = new CachedTransform<int, string>(i => i.ToString());
|
||||
template.Get<LabelWidget>("EXPERIENCE").GetText = () => experienceText.Update(stats.Experience);
|
||||
|
||||
var actionsText = new CachedTransform<double, string>(d => AverageOrdersPerMinute(d));
|
||||
template.Get<LabelWidget>("ACTIONS_MIN").GetText = () => actionsText.Update(stats.OrderCount);
|
||||
|
||||
return template;
|
||||
}
|
||||
@@ -446,9 +488,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
headerTemplate.Get<GradientColorBlockWidget>("HEADER_GRADIENT").Bounds.X += offset;
|
||||
|
||||
foreach (var headerLabel in headerTemplate.Children.OfType<LabelWidget>())
|
||||
{
|
||||
headerLabel.Bounds.X += offset;
|
||||
}
|
||||
}
|
||||
|
||||
static void AddPlayerFlagAndName(ScrollItemWidget template, Player player)
|
||||
@@ -482,15 +522,14 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
return (world.WorldTick == 0 ? 0 : orders / (world.WorldTick / 1500.0)).ToString("F1");
|
||||
}
|
||||
|
||||
string AverageEarnedPerMinute(double earned)
|
||||
{
|
||||
return "$" + (world.WorldTick == 0 ? 0 : earned / (world.WorldTick / 1500.0)).ToString("F0");
|
||||
}
|
||||
|
||||
static Color GetPowerColor(PowerState state)
|
||||
{
|
||||
if (state == PowerState.Critical) return Color.Red;
|
||||
if (state == PowerState.Low) return Color.Orange;
|
||||
if (state == PowerState.Critical)
|
||||
return Color.Red;
|
||||
|
||||
if (state == PowerState.Low)
|
||||
return Color.Orange;
|
||||
|
||||
return Color.LimeGreen;
|
||||
}
|
||||
|
||||
|
||||
@@ -149,9 +149,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
remapButton.GetColor = () =>
|
||||
{
|
||||
return modData.Hotkeys.GetFirstDuplicate(hd.Name, modData.Hotkeys[hd.Name].GetValue(), hd) != null ?
|
||||
hotkeyInvalidColor :
|
||||
hotkeyValidColor;
|
||||
return hd.HasDuplicates ? hotkeyInvalidColor : hotkeyValidColor;
|
||||
};
|
||||
|
||||
if (selectedHotkeyDefinition == hd)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<dllmap dll="freetype6" os="linux" target="libfreetype.so.6" />
|
||||
<dllmap dll="freetype6" os="!windows" target="libfreetype.so.6" />
|
||||
<dllmap dll="freetype6" os="openbsd" target="libfreetype.so" />
|
||||
<dllmap dll="freetype6" os="osx" target="libfreetype.6.dylib" />
|
||||
<dllmap dll="freetype6" os="freebsd" target="libfreetype.so.6" />
|
||||
</configuration>
|
||||
|
||||
@@ -268,7 +268,7 @@ Container@OBSERVER_WIDGETS:
|
||||
StatisticsArmyGraphKey: StatisticsArmyGraph
|
||||
X: 5
|
||||
Y: 5
|
||||
Width: 765
|
||||
Width: 730
|
||||
Height: 240
|
||||
Children:
|
||||
DropDownButton@STATS_DROPDOWN:
|
||||
@@ -288,7 +288,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@BASIC_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 765
|
||||
Width: 705
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -322,17 +322,8 @@ Container@OBSERVER_WIDGETS:
|
||||
Text: Cash
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN_HEADER:
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: $/min
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@POWER_HEADER:
|
||||
X: 300
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -341,7 +332,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Center
|
||||
Shadow: True
|
||||
Label@KILLS_HEADER:
|
||||
X: 380
|
||||
X: 320
|
||||
Y: 0
|
||||
Width: 40
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -350,7 +341,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DEATHS_HEADER:
|
||||
X: 420
|
||||
X: 360
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -359,7 +350,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_DESTROYED_HEADER:
|
||||
X: 480
|
||||
X: 420
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -368,7 +359,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST_HEADER:
|
||||
X: 560
|
||||
X: 500
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -377,7 +368,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EXPERIENCE_HEADER:
|
||||
X: 640
|
||||
X: 580
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -386,7 +377,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ACTIONS_MIN_HEADER:
|
||||
X: 700
|
||||
X: 640
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -397,7 +388,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@ECONOMY_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 745
|
||||
Width: 730
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -428,24 +419,16 @@ Container@OBSERVER_WIDGETS:
|
||||
Text: Cash
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN_HEADER:
|
||||
Label@INCOME_HEADER:
|
||||
X: 240
|
||||
Width: 60
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: $/min
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_THIS_MIN_HEADER:
|
||||
X: 300
|
||||
Width: 120
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Earned this min
|
||||
Text: Income
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_HEADER:
|
||||
X: 420
|
||||
X: 320
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -453,7 +436,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_HEADER:
|
||||
X: 500
|
||||
X: 400
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -461,7 +444,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@SPENT_HEADER:
|
||||
X: 580
|
||||
X: 480
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -469,13 +452,21 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@HARVESTERS_HEADER:
|
||||
X: 660
|
||||
X: 560
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Harvesters
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DERRICKS_HEADER:
|
||||
X: 650
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Oil Derricks
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Container@PRODUCTION_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
@@ -551,7 +542,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@COMBAT_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 775
|
||||
Width: 730
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -579,32 +570,32 @@ Container@OBSERVER_WIDGETS:
|
||||
Label@ASSETS_DESTROYED_HEADER:
|
||||
X: 160
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Destroyed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST_HEADER:
|
||||
X: 240
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Lost
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_KILLED_HEADER:
|
||||
X: 320
|
||||
X: 310
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Units Killed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_DEAD_HEADER:
|
||||
X: 420
|
||||
X: 400
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -613,27 +604,27 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_KILLED_HEADER:
|
||||
X: 500
|
||||
X: 480
|
||||
Y: 0
|
||||
Width: 90
|
||||
Width: 85
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Bldg Killed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_DEAD_HEADER:
|
||||
X: 590
|
||||
X: 565
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Bldg Lost
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ARMY_VALUE_HEADER:
|
||||
X: 670
|
||||
X: 640
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 85
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Army Value
|
||||
@@ -679,7 +670,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@BASIC_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 765
|
||||
Width: 705
|
||||
Height: 24
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -714,57 +705,50 @@ Container@OBSERVER_WIDGETS:
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN:
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@POWER:
|
||||
X: 300
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Center
|
||||
Shadow: True
|
||||
Label@KILLS:
|
||||
X: 380
|
||||
X: 320
|
||||
Y: 0
|
||||
Width: 40
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DEATHS:
|
||||
X: 420
|
||||
X: 360
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_DESTROYED:
|
||||
X: 480
|
||||
X: 420
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST:
|
||||
X: 560
|
||||
X: 500
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EXPERIENCE:
|
||||
X: 640
|
||||
X: 580
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ACTIONS_MIN:
|
||||
X: 700
|
||||
X: 640
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -773,7 +757,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@ECONOMY_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 745
|
||||
Width: 730
|
||||
Height: 24
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -808,48 +792,48 @@ Container@OBSERVER_WIDGETS:
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN:
|
||||
Label@INCOME:
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_THIS_MIN:
|
||||
X: 300
|
||||
Y: 0
|
||||
Width: 120
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS:
|
||||
X: 420
|
||||
X: 320
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED:
|
||||
X: 500
|
||||
X: 400
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@SPENT:
|
||||
X: 580
|
||||
X: 480
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@HARVESTERS:
|
||||
X: 660
|
||||
X: 560
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DERRICKS:
|
||||
X: 650
|
||||
Y: 0
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
ScrollItem@PRODUCTION_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
@@ -927,7 +911,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@COMBAT_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 775
|
||||
Width: 730
|
||||
Height: 24
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -958,53 +942,53 @@ Container@OBSERVER_WIDGETS:
|
||||
Label@ASSETS_DESTROYED:
|
||||
X: 160
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST:
|
||||
X: 240
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_KILLED:
|
||||
X: 320
|
||||
X: 310
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_DEAD:
|
||||
X: 420
|
||||
X: 400
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_KILLED:
|
||||
X: 500
|
||||
X: 480
|
||||
Y: 0
|
||||
Width: 90
|
||||
Width: 85
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_DEAD:
|
||||
X: 590
|
||||
X: 565
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ARMY_VALUE:
|
||||
X: 670
|
||||
X: 640
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 85
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Container@EARNED_THIS_MIN_GRAPH_CONTAINER:
|
||||
Container@INCOME_GRAPH_CONTAINER:
|
||||
X: 0
|
||||
Y: 30
|
||||
Width: PARENT_RIGHT
|
||||
@@ -1017,21 +1001,20 @@ Container@OBSERVER_WIDGETS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Color: 00000090
|
||||
LineGraph@EARNED_THIS_MIN_GRAPH:
|
||||
LineGraph@INCOME_GRAPH:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: PARENT_RIGHT
|
||||
Width: PARENT_RIGHT - 5
|
||||
Height: PARENT_BOTTOM
|
||||
ValueFormat: ${0}
|
||||
XAxisValueFormat: {0}
|
||||
YAxisValueFormat: ${0:F0}
|
||||
XAxisSize: 20
|
||||
YAxisSize: 10
|
||||
XAxisSize: 40
|
||||
XAxisTicksPerLabel: 2
|
||||
XAxisLabel: Game Minute
|
||||
YAxisLabel: Earnings
|
||||
LabelFont: TinyBold
|
||||
AxisFont: TinyBold
|
||||
Container@ARMY_THIS_MIN_GRAPH_CONTAINER:
|
||||
Container@ARMY_VALUE_GRAPH_CONTAINER:
|
||||
X: 0
|
||||
Y: 30
|
||||
Width: PARENT_RIGHT
|
||||
@@ -1044,16 +1027,15 @@ Container@OBSERVER_WIDGETS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Color: 00000090
|
||||
LineGraph@ARMY_THIS_MIN_GRAPH:
|
||||
LineGraph@ARMY_VALUE_GRAPH:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: PARENT_RIGHT
|
||||
Width: PARENT_RIGHT - 5
|
||||
Height: PARENT_BOTTOM
|
||||
ValueFormat: ${0}
|
||||
XAxisValueFormat: {0}
|
||||
YAxisValueFormat: ${0:F0}
|
||||
XAxisSize: 20
|
||||
YAxisSize: 10
|
||||
XAxisSize: 40
|
||||
XAxisTicksPerLabel: 2
|
||||
XAxisLabel: Game Minute
|
||||
YAxisLabel: Army Value
|
||||
LabelFont: TinyBold
|
||||
|
||||
@@ -72,8 +72,6 @@ RMBO:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromHarvesterRadius: 24
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ HARV:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
Harvester:
|
||||
SearchFromProcRadius: 24
|
||||
SearchFromHarvesterRadius: 24
|
||||
|
||||
FTNK:
|
||||
|
||||
@@ -67,6 +67,7 @@ E6:
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromProcRadius: 45
|
||||
SearchFromHarvesterRadius: 45
|
||||
|
||||
HTNK:
|
||||
|
||||
@@ -63,6 +63,7 @@ E5:
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromProcRadius: 45
|
||||
SearchFromHarvesterRadius: 45
|
||||
|
||||
MTNK:
|
||||
|
||||
@@ -70,6 +70,7 @@ E5:
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromProcRadius: 30
|
||||
SearchFromHarvesterRadius: 30
|
||||
|
||||
HTNK:
|
||||
|
||||
@@ -78,10 +78,6 @@ E5:
|
||||
E6:
|
||||
-RepairsBridges:
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromHarvesterRadius: 30
|
||||
|
||||
MTNK:
|
||||
Buildable:
|
||||
Prerequisites: ~weap
|
||||
|
||||
@@ -97,6 +97,7 @@ E6:
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromProcRadius: 30
|
||||
SearchFromHarvesterRadius: 30
|
||||
|
||||
MTNK:
|
||||
|
||||
@@ -83,10 +83,6 @@ E5:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromHarvesterRadius: 45
|
||||
|
||||
HTNK:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
@@ -18,6 +18,7 @@ V19:
|
||||
ValidStances: Neutral, Enemy
|
||||
SpawnActorOnDeath:
|
||||
Actor: V19.Husk
|
||||
UpdatesDerrickCount:
|
||||
|
||||
V19.Husk:
|
||||
Inherits: ^CivBuildingHusk
|
||||
|
||||
@@ -172,7 +172,7 @@ Container@OBSERVER_WIDGETS:
|
||||
StatisticsArmyGraphKey: StatisticsArmyGraph
|
||||
X: 5
|
||||
Y: 5
|
||||
Width: 765
|
||||
Width: 760
|
||||
Height: 250
|
||||
Children:
|
||||
DropDownButton@STATS_DROPDOWN:
|
||||
@@ -192,7 +192,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@BASIC_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 760
|
||||
Width: 700
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -226,17 +226,8 @@ Container@OBSERVER_WIDGETS:
|
||||
Text: Cash
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN_HEADER:
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: $/min
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@POWER_HEADER:
|
||||
X: 295
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -245,7 +236,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Center
|
||||
Shadow: True
|
||||
Label@KILLS_HEADER:
|
||||
X: 375
|
||||
X: 315
|
||||
Y: 0
|
||||
Width: 40
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -254,7 +245,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DEATHS_HEADER:
|
||||
X: 415
|
||||
X: 355
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -263,7 +254,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_DESTROYED_HEADER:
|
||||
X: 475
|
||||
X: 415
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -272,7 +263,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST_HEADER:
|
||||
X: 555
|
||||
X: 495
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -281,7 +272,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EXPERIENCE_HEADER:
|
||||
X: 635
|
||||
X: 575
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -290,7 +281,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ACTIONS_MIN_HEADER:
|
||||
X: 695
|
||||
X: 635
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -301,7 +292,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@ECONOMY_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 740
|
||||
Width: 640
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -332,24 +323,16 @@ Container@OBSERVER_WIDGETS:
|
||||
Text: Cash
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN_HEADER:
|
||||
Label@INCOME_HEADER:
|
||||
X: 235
|
||||
Width: 60
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: $/min
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_THIS_MIN_HEADER:
|
||||
X: 295
|
||||
Width: 120
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Earned this min
|
||||
Text: Income
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_HEADER:
|
||||
X: 415
|
||||
X: 315
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -357,7 +340,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_HEADER:
|
||||
X: 495
|
||||
X: 395
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -365,7 +348,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@SPENT_HEADER:
|
||||
X: 575
|
||||
X: 475
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -373,7 +356,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@HARVESTERS_HEADER:
|
||||
X: 655
|
||||
X: 555
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -455,7 +438,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@COMBAT_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 770
|
||||
Width: 735
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -483,32 +466,32 @@ Container@OBSERVER_WIDGETS:
|
||||
Label@ASSETS_DESTROYED_HEADER:
|
||||
X: 155
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Destroyed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST_HEADER:
|
||||
X: 235
|
||||
X: 230
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Lost
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_KILLED_HEADER:
|
||||
X: 315
|
||||
X: 305
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Units Killed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_DEAD_HEADER:
|
||||
X: 415
|
||||
X: 395
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -517,16 +500,16 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_KILLED_HEADER:
|
||||
X: 495
|
||||
X: 475
|
||||
Y: 0
|
||||
Width: 90
|
||||
Width: 85
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Bldg Killed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_DEAD_HEADER:
|
||||
X: 585
|
||||
X: 560
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -535,9 +518,9 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ARMY_VALUE_HEADER:
|
||||
X: 665
|
||||
X: 640
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Army Value
|
||||
@@ -583,7 +566,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@BASIC_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 760
|
||||
Width: 700
|
||||
Height: 25
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -616,57 +599,50 @@ Container@OBSERVER_WIDGETS:
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN:
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@POWER:
|
||||
X: 295
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Center
|
||||
Shadow: True
|
||||
Label@KILLS:
|
||||
X: 375
|
||||
X: 315
|
||||
Y: 0
|
||||
Width: 40
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DEATHS:
|
||||
X: 415
|
||||
X: 355
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_DESTROYED:
|
||||
X: 475
|
||||
X: 415
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST:
|
||||
X: 555
|
||||
X: 495
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EXPERIENCE:
|
||||
X: 635
|
||||
X: 575
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ACTIONS_MIN:
|
||||
X: 695
|
||||
X: 635
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -675,7 +651,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@ECONOMY_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 740
|
||||
Width: 640
|
||||
Height: 25
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -708,43 +684,36 @@ Container@OBSERVER_WIDGETS:
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN:
|
||||
Label@INCOME:
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_THIS_MIN:
|
||||
X: 295
|
||||
Y: 0
|
||||
Width: 120
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS:
|
||||
X: 415
|
||||
X: 315
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED:
|
||||
X: 495
|
||||
X: 395
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@SPENT:
|
||||
X: 575
|
||||
X: 475
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@HARVESTERS:
|
||||
X: 655
|
||||
X: 555
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -823,7 +792,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@COMBAT_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 770
|
||||
Width: 735
|
||||
Height: 25
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -852,53 +821,53 @@ Container@OBSERVER_WIDGETS:
|
||||
Label@ASSETS_DESTROYED:
|
||||
X: 155
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST:
|
||||
X: 235
|
||||
X: 230
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_KILLED:
|
||||
X: 315
|
||||
X: 305
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_DEAD:
|
||||
X: 415
|
||||
X: 395
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_KILLED:
|
||||
X: 495
|
||||
X: 475
|
||||
Y: 0
|
||||
Width: 90
|
||||
Width: 85
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_DEAD:
|
||||
X: 585
|
||||
X: 560
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ARMY_VALUE:
|
||||
X: 665
|
||||
X: 640
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Container@EARNED_THIS_MIN_GRAPH_CONTAINER:
|
||||
Container@INCOME_GRAPH_CONTAINER:
|
||||
X: 0
|
||||
Y: 30
|
||||
Width: PARENT_RIGHT
|
||||
@@ -911,21 +880,20 @@ Container@OBSERVER_WIDGETS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Color: 00000090
|
||||
LineGraph@EARNED_THIS_MIN_GRAPH:
|
||||
LineGraph@INCOME_GRAPH:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: PARENT_RIGHT
|
||||
Width: PARENT_RIGHT - 5
|
||||
Height: PARENT_BOTTOM
|
||||
ValueFormat: ${0}
|
||||
XAxisValueFormat: {0}
|
||||
YAxisValueFormat: ${0:F0}
|
||||
XAxisSize: 20
|
||||
YAxisSize: 10
|
||||
XAxisSize: 40
|
||||
XAxisTicksPerLabel: 2
|
||||
XAxisLabel: Game Minute
|
||||
YAxisLabel: Earnings
|
||||
LabelFont: TinyBold
|
||||
AxisFont: TinyBold
|
||||
Container@ARMY_THIS_MIN_GRAPH_CONTAINER:
|
||||
Container@ARMY_VALUE_GRAPH_CONTAINER:
|
||||
X: 0
|
||||
Y: 30
|
||||
Width: PARENT_RIGHT
|
||||
@@ -938,16 +906,15 @@ Container@OBSERVER_WIDGETS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Color: 00000090
|
||||
LineGraph@ARMY_THIS_MIN_GRAPH:
|
||||
LineGraph@ARMY_VALUE_GRAPH:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: PARENT_RIGHT
|
||||
Width: PARENT_RIGHT - 5
|
||||
Height: PARENT_BOTTOM
|
||||
ValueFormat: ${0}
|
||||
XAxisValueFormat: {0}
|
||||
YAxisValueFormat: ${0:F0}
|
||||
XAxisSize: 20
|
||||
YAxisSize: 10
|
||||
XAxisSize: 40
|
||||
XAxisTicksPerLabel: 2
|
||||
XAxisLabel: Game Minute
|
||||
YAxisLabel: Army Value
|
||||
LabelFont: TinyBold
|
||||
|
||||
@@ -73,8 +73,8 @@ harvester:
|
||||
HarvestFacings: 8
|
||||
Resources: Spice
|
||||
BaleUnloadDelay: 5
|
||||
SearchFromProcRadius: 15
|
||||
SearchFromHarvesterRadius: 8
|
||||
SearchFromProcRadius: 30
|
||||
SearchFromHarvesterRadius: 15
|
||||
CarryableHarvester:
|
||||
Health:
|
||||
HP: 45000
|
||||
|
||||
Binary file not shown.
@@ -202,7 +202,7 @@ Container@OBSERVER_WIDGETS:
|
||||
StatsDropDownPanelTemplate: SPECTATOR_LABEL_DROPDOWN_TEMPLATE
|
||||
X: 5
|
||||
Y: 5
|
||||
Width: 765
|
||||
Width: 760
|
||||
Height: 240
|
||||
Children:
|
||||
DropDownButton@STATS_DROPDOWN:
|
||||
@@ -224,7 +224,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@BASIC_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 765
|
||||
Width: 705
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -258,17 +258,8 @@ Container@OBSERVER_WIDGETS:
|
||||
Text: Cash
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN_HEADER:
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: $/min
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@POWER_HEADER:
|
||||
X: 300
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -277,7 +268,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Center
|
||||
Shadow: True
|
||||
Label@KILLS_HEADER:
|
||||
X: 380
|
||||
X: 320
|
||||
Y: 0
|
||||
Width: 40
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -286,7 +277,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DEATHS_HEADER:
|
||||
X: 420
|
||||
X: 360
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -295,7 +286,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_DESTROYED_HEADER:
|
||||
X: 480
|
||||
X: 420
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -304,7 +295,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST_HEADER:
|
||||
X: 560
|
||||
X: 500
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -313,7 +304,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EXPERIENCE_HEADER:
|
||||
X: 640
|
||||
X: 580
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -322,7 +313,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ACTIONS_MIN_HEADER:
|
||||
X: 700
|
||||
X: 640
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -333,7 +324,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@ECONOMY_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 745
|
||||
Width: 735
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -364,24 +355,16 @@ Container@OBSERVER_WIDGETS:
|
||||
Text: Cash
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN_HEADER:
|
||||
Label@INCOME_HEADER:
|
||||
X: 240
|
||||
Width: 60
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: $/min
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_THIS_MIN_HEADER:
|
||||
X: 300
|
||||
Width: 120
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Earned this min
|
||||
Text: Income
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_HEADER:
|
||||
X: 420
|
||||
X: 320
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -389,7 +372,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_HEADER:
|
||||
X: 500
|
||||
X: 400
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -397,7 +380,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@SPENT_HEADER:
|
||||
X: 580
|
||||
X: 480
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
@@ -405,13 +388,21 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@HARVESTERS_HEADER:
|
||||
X: 660
|
||||
X: 560
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Harvesters
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DERRICKS_HEADER:
|
||||
X: 650
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Oil Derricks
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Container@PRODUCTION_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
@@ -487,7 +478,7 @@ Container@OBSERVER_WIDGETS:
|
||||
Container@COMBAT_STATS_HEADERS:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 775
|
||||
Width: 740
|
||||
Height: PARENT_BOTTOM
|
||||
Children:
|
||||
ColorBlock@HEADER_COLOR:
|
||||
@@ -515,32 +506,32 @@ Container@OBSERVER_WIDGETS:
|
||||
Label@ASSETS_DESTROYED_HEADER:
|
||||
X: 160
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Destroyed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST_HEADER:
|
||||
X: 240
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Lost
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_KILLED_HEADER:
|
||||
X: 320
|
||||
X: 310
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Units Killed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_DEAD_HEADER:
|
||||
X: 420
|
||||
X: 400
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -549,16 +540,16 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_KILLED_HEADER:
|
||||
X: 500
|
||||
X: 480
|
||||
Y: 0
|
||||
Width: 90
|
||||
Width: 85
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Bldg Killed
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_DEAD_HEADER:
|
||||
X: 590
|
||||
X: 565
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -567,9 +558,9 @@ Container@OBSERVER_WIDGETS:
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ARMY_VALUE_HEADER:
|
||||
X: 670
|
||||
X: 645
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Font: Bold
|
||||
Text: Army Value
|
||||
@@ -591,7 +582,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@TEAM_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 650 #PARENT_RIGHT - 35
|
||||
Width: 650
|
||||
Height: 24
|
||||
Children:
|
||||
ColorBlock@TEAM_COLOR:
|
||||
@@ -617,7 +608,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@BASIC_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 765
|
||||
Width: 705
|
||||
Height: 24
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -652,57 +643,50 @@ Container@OBSERVER_WIDGETS:
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN:
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@POWER:
|
||||
X: 300
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Center
|
||||
Shadow: True
|
||||
Label@KILLS:
|
||||
X: 380
|
||||
X: 320
|
||||
Y: 0
|
||||
Width: 40
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DEATHS:
|
||||
X: 420
|
||||
X: 360
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_DESTROYED:
|
||||
X: 480
|
||||
X: 420
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST:
|
||||
X: 560
|
||||
X: 500
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EXPERIENCE:
|
||||
X: 640
|
||||
X: 580
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ACTIONS_MIN:
|
||||
X: 700
|
||||
X: 640
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -711,7 +695,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@ECONOMY_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 745
|
||||
Width: 735
|
||||
Height: 24
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -746,43 +730,43 @@ Container@OBSERVER_WIDGETS:
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_MIN:
|
||||
Label@INCOME:
|
||||
X: 240
|
||||
Y: 0
|
||||
Width: 60
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED_THIS_MIN:
|
||||
X: 300
|
||||
Y: 0
|
||||
Width: 120
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS:
|
||||
X: 420
|
||||
X: 320
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@EARNED:
|
||||
X: 500
|
||||
X: 400
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@SPENT:
|
||||
X: 580
|
||||
X: 480
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@HARVESTERS:
|
||||
X: 660
|
||||
X: 560
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@DERRICKS:
|
||||
X: 650
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
@@ -865,7 +849,7 @@ Container@OBSERVER_WIDGETS:
|
||||
ScrollItem@COMBAT_PLAYER_TEMPLATE:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 775
|
||||
Width: 740
|
||||
Height: 24
|
||||
BaseName: scrollitem-nohover
|
||||
Children:
|
||||
@@ -896,53 +880,53 @@ Container@OBSERVER_WIDGETS:
|
||||
Label@ASSETS_DESTROYED:
|
||||
X: 160
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ASSETS_LOST:
|
||||
X: 240
|
||||
X: 235
|
||||
Y: 0
|
||||
Width: 80
|
||||
Width: 75
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_KILLED:
|
||||
X: 320
|
||||
X: 310
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@UNITS_DEAD:
|
||||
X: 420
|
||||
X: 400
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_KILLED:
|
||||
X: 500
|
||||
X: 480
|
||||
Y: 0
|
||||
Width: 90
|
||||
Width: 85
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@BUILDINGS_DEAD:
|
||||
X: 590
|
||||
X: 565
|
||||
Y: 0
|
||||
Width: 80
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Label@ARMY_VALUE:
|
||||
X: 670
|
||||
X: 645
|
||||
Y: 0
|
||||
Width: 100
|
||||
Width: 90
|
||||
Height: PARENT_BOTTOM
|
||||
Align: Right
|
||||
Shadow: True
|
||||
Container@EARNED_THIS_MIN_GRAPH_CONTAINER:
|
||||
Container@INCOME_GRAPH_CONTAINER:
|
||||
X: 0
|
||||
Y: 30
|
||||
Width: PARENT_RIGHT
|
||||
@@ -955,21 +939,20 @@ Container@OBSERVER_WIDGETS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Color: 00000090
|
||||
LineGraph@EARNED_THIS_MIN_GRAPH:
|
||||
LineGraph@INCOME_GRAPH:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: PARENT_RIGHT
|
||||
Width: PARENT_RIGHT - 5
|
||||
Height: PARENT_BOTTOM
|
||||
ValueFormat: ${0}
|
||||
XAxisValueFormat: {0}
|
||||
YAxisValueFormat: ${0:F0}
|
||||
XAxisSize: 20
|
||||
YAxisSize: 10
|
||||
XAxisSize: 40
|
||||
XAxisTicksPerLabel: 2
|
||||
XAxisLabel: Game Minute
|
||||
YAxisLabel: Earnings
|
||||
LabelFont: TinyBold
|
||||
AxisFont: TinyBold
|
||||
Container@ARMY_THIS_MIN_GRAPH_CONTAINER:
|
||||
Container@ARMY_VALUE_GRAPH_CONTAINER:
|
||||
X: 0
|
||||
Y: 30
|
||||
Width: PARENT_RIGHT
|
||||
@@ -982,16 +965,15 @@ Container@OBSERVER_WIDGETS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Color: 00000090
|
||||
LineGraph@ARMY_THIS_MIN_GRAPH:
|
||||
LineGraph@ARMY_VALUE_GRAPH:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: PARENT_RIGHT
|
||||
Width: PARENT_RIGHT - 5
|
||||
Height: PARENT_BOTTOM
|
||||
ValueFormat: ${0}
|
||||
XAxisValueFormat: {0}
|
||||
YAxisValueFormat: ${0:F0}
|
||||
XAxisSize: 20
|
||||
YAxisSize: 10
|
||||
XAxisSize: 40
|
||||
XAxisTicksPerLabel: 2
|
||||
XAxisLabel: Game Minute
|
||||
YAxisLabel: Army Value
|
||||
LabelFont: TinyBold
|
||||
|
||||
@@ -189,8 +189,8 @@ InitTriggers = function()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
Trigger.OnAllRemovedFromWorld(FirstUSSRBase, function()
|
||||
if baseCamera then
|
||||
Trigger.OnAllKilledOrCaptured(FirstUSSRBase, function()
|
||||
if baseCamera and baseCamera.IsInWorld then
|
||||
baseCamera.Destroy()
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -252,8 +252,8 @@ InitTriggers = function()
|
||||
AlertFirstBase()
|
||||
end)
|
||||
end)
|
||||
Trigger.OnAllRemovedFromWorld(FirstUSSRBase, function()
|
||||
if baseCamera then
|
||||
Trigger.OnAllKilledOrCaptured(FirstUSSRBase, function()
|
||||
if baseCamera and baseCamera.IsInWorld then
|
||||
baseCamera.Destroy()
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -245,6 +245,10 @@ ProduceAircraft = function()
|
||||
end
|
||||
|
||||
TargetAndAttack = function(yak, target)
|
||||
if yak.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if not target or target.IsDead or (not target.IsInWorld) then
|
||||
local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == player and self.HasProperty("Health") and yak.CanTarget(self) end)
|
||||
|
||||
@@ -260,7 +264,11 @@ TargetAndAttack = function(yak, target)
|
||||
end
|
||||
|
||||
yak.CallFunc(function()
|
||||
TargetAndAttack(yak, target)
|
||||
-- TODO: Replace this with an idle trigger once that works for aircraft
|
||||
-- Add a delay of one tick to fix an endless recursive call
|
||||
Trigger.AfterDelay(1, function()
|
||||
TargetAndAttack(yak, target)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -264,6 +264,10 @@ ProduceAircraft = function()
|
||||
end
|
||||
|
||||
TargetAndAttack = function(yak, target)
|
||||
if yak.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if not target or target.IsDead or (not target.IsInWorld) then
|
||||
local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == greece and self.HasProperty("Health") and yak.CanTarget(self) end)
|
||||
if #enemies > 0 then
|
||||
@@ -278,7 +282,11 @@ TargetAndAttack = function(yak, target)
|
||||
end
|
||||
|
||||
yak.CallFunc(function()
|
||||
TargetAndAttack(yak, target)
|
||||
-- TODO: Replace this with an idle trigger once that works for aircraft
|
||||
-- Add a delay of one tick to fix an endless recursive call
|
||||
Trigger.AfterDelay(1, function()
|
||||
TargetAndAttack(yak, target)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -159,6 +159,10 @@ ProduceAircraft = function()
|
||||
end
|
||||
|
||||
TargetAndAttack = function(yak, target)
|
||||
if yak.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if not target or target.IsDead or (not target.IsInWorld) then
|
||||
local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == player and self.HasProperty("Health") and yak.CanTarget(self) end)
|
||||
if #enemies > 0 then
|
||||
@@ -173,7 +177,11 @@ TargetAndAttack = function(yak, target)
|
||||
end
|
||||
|
||||
yak.CallFunc(function()
|
||||
TargetAndAttack(yak, target)
|
||||
-- TODO: Replace this with an idle trigger once that works for aircraft
|
||||
-- Add a delay of one tick to fix an endless recursive call
|
||||
Trigger.AfterDelay(1, function()
|
||||
TargetAndAttack(yak, target)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -171,6 +171,10 @@ ProduceAircraft = function()
|
||||
end
|
||||
|
||||
TargetAndAttack = function(yak, target)
|
||||
if yak.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if not target or target.IsDead or (not target.IsInWorld) then
|
||||
local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == player and self.HasProperty("Health") and yak.CanTarget(self) end)
|
||||
if #enemies > 0 then
|
||||
@@ -185,7 +189,11 @@ TargetAndAttack = function(yak, target)
|
||||
end
|
||||
|
||||
yak.CallFunc(function()
|
||||
TargetAndAttack(yak, target)
|
||||
-- TODO: Replace this with an idle trigger once that works for aircraft
|
||||
-- Add a delay of one tick to fix an endless recursive call
|
||||
Trigger.AfterDelay(1, function()
|
||||
TargetAndAttack(yak, target)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ WorldLoaded = function()
|
||||
|
||||
Camera.Position = DefaultCameraPosition.CenterPosition
|
||||
|
||||
if Map.LobbyOption("difficulty") ~= "hard" then
|
||||
if Map.LobbyOption("difficulty") == "easy" then
|
||||
Trigger.OnEnteredProximityTrigger(SovietDefenseCam.CenterPosition, WDist.New(1024 * 7), function(a, id)
|
||||
if a.Owner == player then
|
||||
Trigger.RemoveProximityTrigger(id)
|
||||
@@ -220,15 +220,19 @@ WorldLoaded = function()
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if Map.LobbyOption("difficulty") == "easy" then
|
||||
Trigger.OnKilled(DefBrl1, function(a, b)
|
||||
if Map.LobbyOption("difficulty") ~= "hard" then
|
||||
Trigger.OnKilled(DefBrl1, function(a, b)
|
||||
if not DefenseFlame1.IsDead then
|
||||
DefenseFlame1.Kill()
|
||||
end)
|
||||
Trigger.OnKilled(DefBrl2, function(a, b)
|
||||
end
|
||||
end)
|
||||
Trigger.OnKilled(DefBrl2, function(a, b)
|
||||
if not DefenseFlame2.IsDead then
|
||||
DefenseFlame2.Kill()
|
||||
end)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Utils.Do(BadGuys, function(a)
|
||||
|
||||
@@ -134,6 +134,10 @@ ProduceAircraft = function()
|
||||
end
|
||||
|
||||
TargetAndAttack = function(yak, target)
|
||||
if yak.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if not target or target.IsDead or (not target.IsInWorld) then
|
||||
local enemies = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == greece and self.HasProperty("Health") and yak.CanTarget(self) end)
|
||||
if #enemies > 0 then
|
||||
@@ -148,7 +152,11 @@ TargetAndAttack = function(yak, target)
|
||||
end
|
||||
|
||||
yak.CallFunc(function()
|
||||
TargetAndAttack(yak, target)
|
||||
-- TODO: Replace this with an idle trigger once that works for aircraft
|
||||
-- Add a delay of one tick to fix an endless recursive call
|
||||
Trigger.AfterDelay(1, function()
|
||||
TargetAndAttack(yak, target)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ BaseRaids = function()
|
||||
if Map.LobbyOption("difficulty") == "easy" then
|
||||
return
|
||||
else
|
||||
Trigger.AfterDelay(Utils.RandomInteger(BaseRaidDelay1[1], BaseRaidDelay1[2]), function()
|
||||
Trigger.AfterDelay(Utils.RandomInteger(BaseRaidDelay1[1], BaseRaidDelay1[2]), function()
|
||||
local raiders = Reinforcements.ReinforceWithTransport(ussr, "lst", RaidingParty, RaidOnePath, { RaidOneEntry.Location })[2]
|
||||
Utils.Do(raiders, function(a)
|
||||
Trigger.OnAddedToWorld(a, function()
|
||||
@@ -95,7 +95,7 @@ BaseRaids = function()
|
||||
end)
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(Utils.RandomInteger(BaseRaidDelay2[1], BaseRaidDelay2[2]), function()
|
||||
Trigger.AfterDelay(Utils.RandomInteger(BaseRaidDelay2[1], BaseRaidDelay2[2]), function()
|
||||
local raiders = Reinforcements.ReinforceWithTransport(ussr, "lst", RaidingParty, RaidTwoPath, { RaidTwoEntry.Location })[2]
|
||||
Utils.Do(raiders, function(a)
|
||||
Trigger.OnAddedToWorld(a, function()
|
||||
@@ -126,7 +126,7 @@ FinishTimer = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(6), function() UserInterface.SetMissionText("") end)
|
||||
end
|
||||
|
||||
BattalionWays =
|
||||
BattalionWays =
|
||||
{
|
||||
{ HardEntry1.Location, HardLanding1.Location },
|
||||
{ HardEntry2.Location, HardLanding2.Location },
|
||||
@@ -138,7 +138,7 @@ BattalionWays =
|
||||
|
||||
SendArmoredBattalion = function()
|
||||
Media.PlaySpeechNotification(greece, "EnemyUnitsApproaching")
|
||||
Utils.Do(BattalionWays, function(way)
|
||||
Utils.Do(BattalionWays, function(way)
|
||||
local units = { "3tnk", "3tnk", "3tnk", "4tnk", "4tnk" }
|
||||
local armor = Reinforcements.ReinforceWithTransport(ussr, "lst", units , way, { way[2], way[1] })[2]
|
||||
Utils.Do(armor, function(a)
|
||||
@@ -146,7 +146,7 @@ SendArmoredBattalion = function()
|
||||
a.AttackMove(PlayerBase.Location)
|
||||
IdleHunt(a)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -217,6 +217,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(ActivateAIDelay, ActivateAI)
|
||||
Trigger.AfterDelay(StartTimerDelay, StartTimerFunction)
|
||||
|
||||
Trigger.OnAllRemovedFromWorld(DestroySubPensTriggerActivator, DestroySubPensCompleted)
|
||||
Trigger.OnAllKilledOrCaptured(DestroySubPensTriggerActivator, DestroySubPensCompleted)
|
||||
Trigger.OnAllRemovedFromWorld(ClearSubActivityTriggerActivator, ClearSubActivityCompleted)
|
||||
end
|
||||
|
||||
@@ -130,9 +130,13 @@ ProduceAircraft = function()
|
||||
end
|
||||
|
||||
TargetAndAttack = function(mig, target)
|
||||
if mig.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if not target or target.IsDead or (not target.IsInWorld) then
|
||||
local enemies = Utils.Where(greece.GetActors(), function(actor)
|
||||
return actor.HasProperty("Health") and actor.Type ~= "brik"
|
||||
return actor.HasProperty("Health") and actor.Type ~= "brik" and mig.CanTarget(target)
|
||||
end)
|
||||
if #enemies > 0 then
|
||||
target = Utils.Random(enemies)
|
||||
@@ -146,7 +150,11 @@ TargetAndAttack = function(mig, target)
|
||||
end
|
||||
|
||||
mig.CallFunc(function()
|
||||
TargetAndAttack(mig, target)
|
||||
-- TODO: Replace this with an idle trigger once that works for aircraft
|
||||
-- Add a delay of one tick to fix an endless recursive call
|
||||
Trigger.AfterDelay(1, function()
|
||||
TargetAndAttack(mig, target)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -129,9 +129,13 @@ ProduceAircraft = function()
|
||||
end
|
||||
|
||||
TargetAndAttack = function(mig, target)
|
||||
if mig.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
if not target or target.IsDead or (not target.IsInWorld) then
|
||||
local enemies = Utils.Where(greece.GetActors(), function(actor)
|
||||
return actor.HasProperty("Health") and actor.Type ~= "brik"
|
||||
return actor.HasProperty("Health") and actor.Type ~= "brik" and mig.CanTarget(target)
|
||||
end)
|
||||
if #enemies > 0 then
|
||||
target = Utils.Random(enemies)
|
||||
@@ -145,7 +149,11 @@ TargetAndAttack = function(mig, target)
|
||||
end
|
||||
|
||||
mig.CallFunc(function()
|
||||
TargetAndAttack(mig, target)
|
||||
-- TODO: Replace this with an idle trigger once that works for aircraft
|
||||
-- Add a delay of one tick to fix an endless recursive call
|
||||
Trigger.AfterDelay(1, function()
|
||||
TargetAndAttack(mig, target)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
BIN
mods/ra/maps/climax-rev15.oramap
Normal file
BIN
mods/ra/maps/climax-rev15.oramap
Normal file
Binary file not shown.
@@ -222,6 +222,7 @@ end
|
||||
|
||||
StopHunt = function(unit)
|
||||
if not unit.IsDead then
|
||||
unit.Stop()
|
||||
Trigger.Clear(unit, "OnIdle")
|
||||
end
|
||||
end
|
||||
@@ -282,12 +283,10 @@ end
|
||||
|
||||
SovietBaseMaintenanceSetup = function()
|
||||
local sovietbuildings = Utils.Where(Map.NamedActors, function(a)
|
||||
return a.Owner == soviets
|
||||
and a.HasProperty("StartBuildingRepairs") and a.HasProperty("Sell")
|
||||
return a.Owner == soviets and a.HasProperty("StartBuildingRepairs")
|
||||
end)
|
||||
|
||||
-- This includes killed, captured (actor is temporarily removed) and sold.
|
||||
Trigger.OnAllRemovedFromWorld(sovietbuildings, function()
|
||||
Trigger.OnAllKilledOrCaptured(sovietbuildings, function()
|
||||
Utils.Do(humans, function(player)
|
||||
player.MarkCompletedObjective(destroyBase)
|
||||
end)
|
||||
@@ -295,15 +294,9 @@ SovietBaseMaintenanceSetup = function()
|
||||
|
||||
Utils.Do(sovietbuildings, function(sovietbuilding)
|
||||
Trigger.OnDamaged(sovietbuilding, function(building)
|
||||
if building.Owner ~= soviets then
|
||||
return
|
||||
end
|
||||
if building.Health < building.MaxHealth * 3/4 then
|
||||
if building.Owner == soviets and building.Health < building.MaxHealth * 3/4 then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
if building.Health < building.MaxHealth * 1/4 then
|
||||
building.Sell()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -104,6 +104,11 @@ TRUK.Hijackable:
|
||||
Voiced:
|
||||
VoiceSet: SpyVoice
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromProcRadius: 25
|
||||
SearchFromHarvesterRadius: 25
|
||||
|
||||
E7:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
@@ -35,10 +35,10 @@ end
|
||||
|
||||
Village = { FarmHouse1, FarmHouse2, FarmHouse3, FarmHouse4, FarmHouse5, FarmHouse6, FarmHouse7, FarmHouse8, FarmHouse9, Church }
|
||||
VillageRaidInterval = DateTime.Minutes(3)
|
||||
VillageRaidAircraft = { "mig", "mig" }
|
||||
VillageRaidAircraft = { "mig.scripted", "mig.scripted" }
|
||||
VillageRaidWpts = { VillageRaidEntrypoint.Location, VillageRaidWpt1.Location, VillageRaidWpt2.Location }
|
||||
|
||||
BaseRaidAircraft = { "mig", "mig" }
|
||||
BaseRaidAircraft = { "mig.scripted", "mig.scripted" }
|
||||
BaseRaidWpts = { BaseRaidEntrypoint.Location, UboatPatrolWpt1.Location, BaseRaidWpt2.Location }
|
||||
|
||||
BaseFrontAttackUnits = { "e3", "e3", "e1", "e1", "e1", "3tnk", "3tnk", "apc" }
|
||||
@@ -77,7 +77,7 @@ ParadropSovietUnits = function()
|
||||
powerproxy.Destroy()
|
||||
end
|
||||
|
||||
AirRaid = function(planeTypes, ingress, egress, target)
|
||||
AirRaid = function(planeTypes, ingress, target)
|
||||
if target == nil then
|
||||
return
|
||||
end
|
||||
@@ -89,8 +89,6 @@ AirRaid = function(planeTypes, ingress, egress, target)
|
||||
|
||||
Utils.Do(ingress, function(wpt) plane.Move(wpt) end)
|
||||
plane.Attack(target)
|
||||
Utils.Do(egress, function(wpt) plane.Move(wpt) end)
|
||||
plane.Destroy()
|
||||
end)
|
||||
end
|
||||
end
|
||||
@@ -106,7 +104,7 @@ BaseRaid = function()
|
||||
|
||||
local target = Utils.Random(targets)
|
||||
|
||||
AirRaid(BaseRaidAircraft, BaseRaidWpts, { VillageRaidEntrypoint.Location }, target)
|
||||
AirRaid(BaseRaidAircraft, BaseRaidWpts, target)
|
||||
|
||||
Trigger.AfterDelay(BaseRaidInterval, BaseRaid)
|
||||
end
|
||||
@@ -124,7 +122,7 @@ VillageRaid = function()
|
||||
return
|
||||
end
|
||||
|
||||
AirRaid(VillageRaidAircraft, VillageRaidWpts, { BaseRaidEntrypoint.Location }, target)
|
||||
AirRaid(VillageRaidAircraft, VillageRaidWpts, target)
|
||||
|
||||
Trigger.AfterDelay(VillageRaidInterval, VillageRaid)
|
||||
end
|
||||
|
||||
@@ -71,11 +71,16 @@ GIVEFIX:
|
||||
Tooltip:
|
||||
Name: Weapons Factory or Helipad
|
||||
|
||||
MIG:
|
||||
MIG.SCRIPTED:
|
||||
Inherits: MIG
|
||||
Buildable:
|
||||
Prerequisites: ~afld
|
||||
Prerequisites: ~disabled
|
||||
RenderSprites:
|
||||
Image: mig
|
||||
AmmoPool:
|
||||
Ammo: 2
|
||||
Aircraft:
|
||||
IdleBehavior: LeaveMap
|
||||
|
||||
HELI:
|
||||
Buildable:
|
||||
|
||||
@@ -41,30 +41,6 @@ SetupTriggers = function()
|
||||
Trigger.OnAllKilled(ConvoyTrucks, function()
|
||||
greece.MarkCompletedObjective(objDestroyAllTrucks)
|
||||
end)
|
||||
|
||||
Trigger.OnEnteredFootprint({ TruckEscapeCenter.Location }, function(actor, triggerlose1)
|
||||
if actor.Owner == ussr and actor.Type == "truk" then
|
||||
Trigger.RemoveProximityTrigger(triggerlose1)
|
||||
actor.Destroy()
|
||||
greece.MarkFailedObjective(objDestroyAllTrucks)
|
||||
end
|
||||
end)
|
||||
|
||||
Trigger.OnEnteredFootprint({ EscapeNorth10.Location }, function(actor, triggerlose2)
|
||||
if actor.Owner == ussr and actor.Type == "truk" then
|
||||
Trigger.RemoveProximityTrigger(triggerlose2)
|
||||
actor.Destroy()
|
||||
greece.MarkFailedObjective(objDestroyAllTrucks)
|
||||
end
|
||||
end)
|
||||
|
||||
Trigger.OnEnteredFootprint({ EscapeSouth5.Location }, function(actor, triggerlose3)
|
||||
if actor.Owner == ussr and actor.Type == "truk" then
|
||||
Trigger.RemoveProximityTrigger(triggerlose3)
|
||||
actor.Destroy()
|
||||
greece.MarkFailedObjective(objDestroyAllTrucks)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
MissionStart = function()
|
||||
@@ -123,26 +99,23 @@ SendPatrol = function(mammoth)
|
||||
end
|
||||
end
|
||||
|
||||
MoveTruckNorth = function(truck)
|
||||
MoveTruckEscapeRoute = function(truck, route)
|
||||
if truck.IsDead then
|
||||
return
|
||||
else
|
||||
Media.DisplayMessage("Convoy truck attempting to escape!")
|
||||
Media.PlaySoundNotification(greece, "AlertBleep")
|
||||
Utils.Do(TruckEscapeNorth, function(waypoint)
|
||||
Utils.Do(route, function(waypoint)
|
||||
truck.Move(waypoint.Location)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
MoveTruckSouth = function(truck)
|
||||
if truck.IsDead then
|
||||
return
|
||||
else
|
||||
Media.DisplayMessage("Convoy truck attempting to escape!")
|
||||
Media.PlaySoundNotification(greece, "AlertBleep")
|
||||
Utils.Do(TruckEscapeSouth, function(waypoint)
|
||||
truck.Move(waypoint.Location)
|
||||
|
||||
Trigger.OnIdle(truck, function()
|
||||
if truck.Location == route[#route].Location then
|
||||
truck.Destroy()
|
||||
greece.MarkFailedObjective(objDestroyAllTrucks)
|
||||
else
|
||||
truck.Move(route[#route].Location)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
@@ -195,10 +168,10 @@ WorldLoaded = function()
|
||||
Camera.Position = DefaultCameraPosition.CenterPosition
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(5), function() SendPatrol(PatrolMammoth) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(5), function() MoveTruckNorth(Truck1) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(9), function() MoveTruckNorth(Truck2) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(12), function() MoveTruckSouth(Truck3) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(15), function() MoveTruckNorth(Truck4) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(17), function() MoveTruckSouth(Truck5) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(18), function() MoveTruckSouth(IntroTruck2) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(5), function() MoveTruckEscapeRoute(Truck1, TruckEscapeNorth) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(9), function() MoveTruckEscapeRoute(Truck2, TruckEscapeNorth) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(12), function() MoveTruckEscapeRoute(Truck3, TruckEscapeSouth) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(15), function() MoveTruckEscapeRoute(Truck4, TruckEscapeNorth) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(17), function() MoveTruckEscapeRoute(Truck5, TruckEscapeSouth) end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(18), function() MoveTruckEscapeRoute(IntroTruck2, TruckEscapeSouth) end)
|
||||
end
|
||||
|
||||
@@ -477,10 +477,6 @@ Actors:
|
||||
Location: 58,89
|
||||
Facing: 60
|
||||
TurretFacing: 60
|
||||
Helper: proc
|
||||
Owner: Greece
|
||||
Location: 42,42
|
||||
FreeActor: False
|
||||
Actor181: mine
|
||||
Owner: Neutral
|
||||
Location: 63,65
|
||||
|
||||
@@ -22,6 +22,10 @@ World:
|
||||
hard: Hard
|
||||
Default: easy
|
||||
|
||||
HARV:
|
||||
Harvester:
|
||||
SearchFromProcRadius: 44
|
||||
|
||||
MCV.CAM:
|
||||
Inherits: CAMERA
|
||||
RevealsShroud:
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
the License, or (at your option) any later version. For more
|
||||
information, see COPYING.
|
||||
]]
|
||||
|
||||
CheckForBase = function()
|
||||
baseBuildings = Map.ActorsInBox(Map.TopLeft, CFBPoint.CenterPosition, function(actor)
|
||||
return actor.Type == "fact" or actor.Type == "powr"
|
||||
@@ -36,7 +37,6 @@ RunInitialActivities = function()
|
||||
|
||||
Trigger.AfterDelay(1, function()
|
||||
Harvester.FindResources()
|
||||
Helper.Destroy()
|
||||
IdlingUnits()
|
||||
Media.PlaySpeechNotification(player, "ReinforcementsArrived")
|
||||
|
||||
@@ -75,32 +75,29 @@ RunInitialActivities = function()
|
||||
end
|
||||
|
||||
Expand = function()
|
||||
if ExpansionCheck then
|
||||
return
|
||||
elseif mcvtransport.IsDead then
|
||||
return
|
||||
elseif mcvGG.IsDead then
|
||||
if ExpansionCheck or mcvtransport.IsDead or mcvGG.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
mcvGG.Move(mcvGGLoadPoint.Location)
|
||||
mcvtransport.Move(lstBeachPoint.Location)
|
||||
ExpansionCheck = true
|
||||
Trigger.ClearAll(mcvGG)
|
||||
Trigger.ClearAll(mcvtransport)
|
||||
Media.DisplayMessage("Allied MCV detected moving to the island.")
|
||||
|
||||
Reinforcements.Reinforce(GoodGuy, { "dd", "dd" }, ShipArrivePath, 0, function(ddsquad)
|
||||
ddsquad.AttackMove(NearExpPoint.Location) end)
|
||||
|
||||
ExpansionCheck = true
|
||||
Trigger.ClearAll(mcvGG)
|
||||
Trigger.ClearAll(mcvtransport)
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
if mcvtransport.IsDead then
|
||||
return
|
||||
elseif mcvGG.IsDead then
|
||||
|
||||
mcvtransport.Move(lstBeachPoint.Location)
|
||||
|
||||
mcvGG.Move(mcvGGLoadPoint.Location)
|
||||
mcvGG.EnterTransport(mcvtransport)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Seconds(5), function()
|
||||
if mcvtransport.IsDead or mcvGG.IsDead then
|
||||
return
|
||||
end
|
||||
|
||||
mcvGG.EnterTransport(mcvtransport)
|
||||
mcvtransport.Move(GGUnloadPoint.Location)
|
||||
mcvtransport.UnloadPassengers()
|
||||
Trigger.AfterDelay(DateTime.Seconds(12), function()
|
||||
|
||||
@@ -8,7 +8,7 @@ BADR:
|
||||
Aircraft:
|
||||
CruiseAltitude: 2560
|
||||
TurnSpeed: 5
|
||||
Speed: 149
|
||||
Speed: 180
|
||||
Repulsable: False
|
||||
MaximumPitch: 56
|
||||
Cargo:
|
||||
@@ -47,11 +47,11 @@ BADR.Bomber:
|
||||
Aircraft:
|
||||
CruiseAltitude: 2560
|
||||
TurnSpeed: 5
|
||||
Speed: 149
|
||||
Speed: 180
|
||||
Repulsable: False
|
||||
MaximumPitch: 56
|
||||
AmmoPool:
|
||||
Ammo: 7
|
||||
Ammo: 5
|
||||
-Selectable:
|
||||
SelectionDecorations:
|
||||
RenderSelectionBars: False
|
||||
@@ -111,6 +111,7 @@ MIG:
|
||||
AttackAircraft:
|
||||
FacingTolerance: 20
|
||||
PersistentTargeting: false
|
||||
AttackTurnDelay: 30
|
||||
Aircraft:
|
||||
CruiseAltitude: 2560
|
||||
InitialFacing: 192
|
||||
|
||||
@@ -504,6 +504,7 @@ OILB:
|
||||
AppearsOnMapPreview:
|
||||
GivesCashOnCapture:
|
||||
Amount: 100
|
||||
UpdatesDerrickCount:
|
||||
|
||||
BR1:
|
||||
Inherits: ^Bridge
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
InvalidTargets: NoAutoTarget, WaterStructure
|
||||
AutoTargetPriority@ATTACKANYTHING:
|
||||
RequiresCondition: stance-attackanything
|
||||
ValidTargets: Infantry, Vehicle, Water, Underwater, Structure, Defense
|
||||
ValidTargets: Infantry, Vehicle, Water, Underwater, Structure, Defense, Mine
|
||||
InvalidTargets: NoAutoTarget
|
||||
|
||||
^AutoTargetGroundAssaultMove:
|
||||
@@ -542,7 +542,6 @@
|
||||
|
||||
^NeutralPlane:
|
||||
Inherits@1: ^ExistsInWorld
|
||||
Inherits@3: ^IronCurtainable
|
||||
Inherits@4: ^SpriteActor
|
||||
Inherits@bounty: ^GlobalBounty
|
||||
Inherits@SELECTION_MODE: ^FlatSelectionMode
|
||||
|
||||
@@ -65,8 +65,6 @@ TENF:
|
||||
HitShape:
|
||||
UseTargetableCellsOffsets: false
|
||||
TargetableOffsets: 0,0,0, 630,-512,0, 355,512,0, -281,-512,0, -630,512,0
|
||||
Selectable:
|
||||
Bounds: 48,48
|
||||
|
||||
SYRF:
|
||||
Inherits: ^FakeBuilding
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user