Compare commits
105 Commits
devtest-20
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4239fd16e | ||
|
|
13e74f7836 | ||
|
|
5179a95572 | ||
|
|
e6d4f1fdc3 | ||
|
|
3124a0024a | ||
|
|
0f7016cb6e | ||
|
|
dc02686a17 | ||
|
|
5a86c8fff6 | ||
|
|
c67aef47aa | ||
|
|
87e5dfad9f | ||
|
|
2dda81b2db | ||
|
|
4243d42a63 | ||
|
|
4dec9258be | ||
|
|
b2e3ce8edf | ||
|
|
dbd48831b7 | ||
|
|
d11875b091 | ||
|
|
838a3f83c6 | ||
|
|
8512cdb8bb | ||
|
|
0b78f93178 | ||
|
|
59fd3184ca | ||
|
|
ffa7db01a0 | ||
|
|
0eb1e2307d | ||
|
|
bbf60a3697 | ||
|
|
a8fa37d84b | ||
|
|
0176c1a217 | ||
|
|
43abbbecb1 | ||
|
|
d063b28728 | ||
|
|
50c4f19523 | ||
|
|
a93435ccc4 | ||
|
|
ffed6c0a4a | ||
|
|
52934818e9 | ||
|
|
8ddfcd705b | ||
|
|
578313c3a5 | ||
|
|
01fdd67ef0 | ||
|
|
ac9b641240 | ||
|
|
18604cf905 | ||
|
|
dc2fca9df8 | ||
|
|
e8d95a1d57 | ||
|
|
d6aab1bd7a | ||
|
|
a293e162b2 | ||
|
|
60752b115f | ||
|
|
b4f02440d9 | ||
|
|
bd951d8fb0 | ||
|
|
f520b375e4 | ||
|
|
cadf6956a9 | ||
|
|
db317eb226 | ||
|
|
b36ca98a83 | ||
|
|
1b5261e58a | ||
|
|
5654736086 | ||
|
|
3038f15f00 | ||
|
|
187dd5a071 | ||
|
|
740f04801b | ||
|
|
619d433e8b | ||
|
|
4ca87c1e05 | ||
|
|
0b97003d83 | ||
|
|
6ba02da2eb | ||
|
|
4496cffa4a | ||
|
|
c3f1f617e0 | ||
|
|
dbab122594 | ||
|
|
521236398d | ||
|
|
4b7f8c6c82 | ||
|
|
2e60e41764 | ||
|
|
e8f552bf68 | ||
|
|
8743f13caa | ||
|
|
963a8e6ea9 | ||
|
|
c8f1ce0d42 | ||
|
|
13e0e927fe | ||
|
|
d3c130e8ae | ||
|
|
8ff1762eac | ||
|
|
ef418403c5 | ||
|
|
74da4065fc | ||
|
|
b3e4fc807e | ||
|
|
893ee6eb2c | ||
|
|
a5df442499 | ||
|
|
a87df0f81e | ||
|
|
75130c47ff | ||
|
|
fd73556685 | ||
|
|
958cfcd378 | ||
|
|
08be5d3907 | ||
|
|
4adee762d9 | ||
|
|
bf0b139398 | ||
|
|
65fedd1eb1 | ||
|
|
117b229cb6 | ||
|
|
76f52abd3d | ||
|
|
a7212d52fb | ||
|
|
5e0a789dac | ||
|
|
17b4158a56 | ||
|
|
09d9cf7da6 | ||
|
|
63ee481f01 | ||
|
|
818fc9d173 | ||
|
|
fed3b5f565 | ||
|
|
1d2dc1c232 | ||
|
|
722ea75cab | ||
|
|
e81b9e9467 | ||
|
|
509dc09aa6 | ||
|
|
d71c377e93 | ||
|
|
c6baf16fa7 | ||
|
|
0529a16298 | ||
|
|
53adc2bec7 | ||
|
|
e97617d618 | ||
|
|
4d47dd6ad7 | ||
|
|
7ad95ed0b0 | ||
|
|
1d6732f24f | ||
|
|
85931d5f0b | ||
|
|
6f68b4fb3e |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -62,6 +62,7 @@ OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
|
||||
|
||||
# auto-generated documentation
|
||||
DOCUMENTATION.md
|
||||
WEAPONS.md
|
||||
Lua-API.md
|
||||
*.html
|
||||
openra.6
|
||||
@@ -80,3 +81,5 @@ StyleCopViolations.xml
|
||||
|
||||
# Support directory
|
||||
/Support
|
||||
/da/Microsoft.Build.Utilities.v3.5.resources.dll
|
||||
/da
|
||||
|
||||
14
Makefile
14
Makefile
@@ -14,9 +14,6 @@
|
||||
# to check the official mod dlls for StyleCop violations, run:
|
||||
# make check
|
||||
#
|
||||
# to generate documentation aimed at modders, run:
|
||||
# make docs
|
||||
#
|
||||
# to install, run:
|
||||
# make [prefix=/foo] [bindir=/bar/bin] install
|
||||
#
|
||||
@@ -414,7 +411,13 @@ install-linux-mime:
|
||||
|
||||
install-linux-appdata:
|
||||
@$(INSTALL_DIR) "$(DESTDIR)$(datadir)/appdata/"
|
||||
@$(INSTALL_DATA) packaging/linux/openra.appdata.xml "$(DESTDIR)$(datadir)/appdata/"
|
||||
@sed 's/{MOD}/ra/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Red Alert/g' | sed 's/{SCREENSHOT_RA}/ type="default"/g' | sed 's/{SCREENSHOT_CNC}//g' | sed 's/{SCREENSHOT_D2K}//g'> packaging/linux/openra-ra.appdata.xml
|
||||
@$(INSTALL_DATA) packaging/linux/openra-ra.appdata.xml "$(DESTDIR)$(datadir)/appdata/"
|
||||
@sed 's/{MOD}/cnc/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Tiberian Dawn/g' | sed 's/{SCREENSHOT_RA}//g' | sed 's/{SCREENSHOT_CNC}/ type="default"/g' | sed 's/{SCREENSHOT_D2K}//g'> packaging/linux/openra-cnc.appdata.xml
|
||||
@$(INSTALL_DATA) packaging/linux/openra-cnc.appdata.xml "$(DESTDIR)$(datadir)/appdata/"
|
||||
@sed 's/{MOD}/d2k/g' packaging/linux/openra.appdata.xml.in | sed 's/{MOD_NAME}/Dune 2000/g' | sed 's/{SCREENSHOT_RA}//g' | sed 's/{SCREENSHOT_CNC}//g' | sed 's/{SCREENSHOT_D2K}/ type="default"/g'> packaging/linux/openra-d2k.appdata.xml
|
||||
@$(INSTALL_DATA) packaging/linux/openra-d2k.appdata.xml "$(DESTDIR)$(datadir)/appdata/"
|
||||
@-$(RM) packaging/linux/openra-ra.appdata.xml packaging/linux/openra-cnc.appdata.xml packaging/linux/openra-d2k.appdata.xml
|
||||
|
||||
install-man-page: man-page
|
||||
@$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man6/"
|
||||
@@ -495,9 +498,6 @@ help:
|
||||
@echo 'to check the official mods for erroneous yaml files, run:'
|
||||
@echo ' make test'
|
||||
@echo
|
||||
@echo 'to generate documentation aimed at modders, run:'
|
||||
@echo ' make docs'
|
||||
@echo
|
||||
@echo 'to install, run:'
|
||||
@echo ' make [prefix=/foo] [bindir=/bar/bin] install'
|
||||
@echo
|
||||
|
||||
@@ -152,7 +152,6 @@ namespace OpenRA.Activities
|
||||
set { NextActivity = value; }
|
||||
}
|
||||
|
||||
public bool IsIdle { get; protected set; }
|
||||
public bool IsInterruptible { get; protected set; }
|
||||
public bool IsCanceled { get { return State == ActivityState.Canceled; } }
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace OpenRA
|
||||
public IOccupySpace OccupiesSpace { get; private set; }
|
||||
public ITargetable[] Targetables { get; private set; }
|
||||
|
||||
public bool IsIdle { get { return CurrentActivity == null || CurrentActivity.IsIdle; } }
|
||||
public bool IsIdle { get { return CurrentActivity == null; } }
|
||||
public bool IsDead { get { return Disposed || (health != null && health.IsDead); } }
|
||||
|
||||
public CPos Location { get { return OccupiesSpace.TopLeft; } }
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace OpenRA
|
||||
{
|
||||
public static readonly MapPreview UnknownMap = new MapPreview(null, null, MapGridType.Rectangular, null);
|
||||
public readonly IReadOnlyDictionary<IReadOnlyPackage, MapClassification> MapLocations;
|
||||
readonly Dictionary<IReadOnlyPackage, MapClassification> mapLocations = new Dictionary<IReadOnlyPackage, MapClassification>();
|
||||
|
||||
readonly Cache<string, MapPreview> previews;
|
||||
readonly ModData modData;
|
||||
@@ -45,8 +46,16 @@ namespace OpenRA
|
||||
previews = new Cache<string, MapPreview>(uid => new MapPreview(modData, uid, gridType.Value, this));
|
||||
sheetBuilder = new SheetBuilder(SheetType.BGRA);
|
||||
|
||||
MapLocations = new ReadOnlyDictionary<IReadOnlyPackage, MapClassification>(mapLocations);
|
||||
}
|
||||
|
||||
public void LoadMaps()
|
||||
{
|
||||
// Utility mod that does not support maps
|
||||
if (!modData.Manifest.Contains<MapGrid>())
|
||||
return;
|
||||
|
||||
// Enumerate map directories
|
||||
var mapLocations = new Dictionary<IReadOnlyPackage, MapClassification>();
|
||||
foreach (var kv in modData.Manifest.MapFolders)
|
||||
{
|
||||
var name = kv.Key;
|
||||
@@ -82,15 +91,6 @@ namespace OpenRA
|
||||
mapLocations.Add(package, classification);
|
||||
}
|
||||
|
||||
MapLocations = new ReadOnlyDictionary<IReadOnlyPackage, MapClassification>(mapLocations);
|
||||
}
|
||||
|
||||
public void LoadMaps()
|
||||
{
|
||||
// Utility mod that does not support maps
|
||||
if (!modData.Manifest.Contains<MapGrid>())
|
||||
return;
|
||||
|
||||
var mapGrid = modData.Manifest.Get<MapGrid>();
|
||||
foreach (var kv in MapLocations)
|
||||
{
|
||||
|
||||
@@ -157,6 +157,8 @@ namespace OpenRA
|
||||
public string Platform = "Default";
|
||||
|
||||
public bool ViewportEdgeScroll = true;
|
||||
public int ViewportEdgeScrollMargin = 5;
|
||||
|
||||
public bool LockMouseWindow = false;
|
||||
public MouseScrollType MiddleMouseScroll = MouseScrollType.Standard;
|
||||
public MouseScrollType RightMouseScroll = MouseScrollType.Disabled;
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
}
|
||||
}
|
||||
|
||||
class MadTank : IIssueOrder, IResolveOrder, IOrderVoice, ITick, IPreventsTeleport
|
||||
class MadTank : IIssueOrder, IResolveOrder, IOrderVoice, ITick, IPreventsTeleport, IIssueDeployOrder
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly MadTankInfo info;
|
||||
@@ -116,6 +116,11 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
}
|
||||
|
||||
Order IIssueDeployOrder.IssueDeployOrder(Actor self)
|
||||
{
|
||||
return new Order("Detonate", self, false);
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return info.Voice;
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Cnc.Activities;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Cnc.Traits
|
||||
@@ -28,18 +30,25 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
|
||||
public readonly WDist MinefieldDepth = new WDist(1536);
|
||||
|
||||
public object Create(ActorInitializer init) { return new Minelayer(init.Self); }
|
||||
[Desc("Voice to use when ordered to lay a minefield.")]
|
||||
[VoiceReference] public readonly string Voice = "Action";
|
||||
|
||||
public object Create(ActorInitializer init) { return new Minelayer(init.Self, this); }
|
||||
}
|
||||
|
||||
public class Minelayer : IIssueOrder, IResolveOrder, IRenderAboveShroudWhenSelected, ISync
|
||||
public class Minelayer : IIssueOrder, IResolveOrder, IRenderAboveShroudWhenSelected, ISync, IIssueDeployOrder, IOrderVoice
|
||||
{
|
||||
readonly MinelayerInfo info;
|
||||
|
||||
/* TODO: [Sync] when sync can cope with arrays! */
|
||||
public CPos[] Minefield = null;
|
||||
readonly Sprite tile;
|
||||
[Sync] CPos minefieldStart;
|
||||
|
||||
public Minelayer(Actor self)
|
||||
public Minelayer(Actor self, MinelayerInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
|
||||
var tileset = self.World.Map.Tileset.ToLowerInvariant();
|
||||
tile = self.World.Map.Rules.Sequences.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0);
|
||||
}
|
||||
@@ -72,6 +81,11 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
}
|
||||
}
|
||||
|
||||
Order IIssueDeployOrder.IssueDeployOrder(Actor self)
|
||||
{
|
||||
return new Order("PlaceMine", self, false) { TargetLocation = self.Location };
|
||||
}
|
||||
|
||||
void IResolveOrder.ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "BeginMinefield")
|
||||
@@ -89,15 +103,25 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
{
|
||||
var movement = self.Trait<IPositionable>();
|
||||
|
||||
Minefield = GetMinefieldCells(minefieldStart, order.TargetLocation,
|
||||
self.Info.TraitInfo<MinelayerInfo>().MinefieldDepth)
|
||||
Minefield = GetMinefieldCells(minefieldStart, order.TargetLocation, info.MinefieldDepth)
|
||||
.Where(p => movement.CanEnterCell(p, null, false)).ToArray();
|
||||
|
||||
if (Minefield.Length == 1 && Minefield[0] != self.Location)
|
||||
self.SetTargetLine(Target.FromCell(self.World, Minefield[0]), Color.Red);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new LayMines(self));
|
||||
}
|
||||
}
|
||||
|
||||
string IOrderVoice.VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "PlaceMine" || order.OrderString == "PlaceMinefield")
|
||||
return info.Voice;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static IEnumerable<CPos> GetMinefieldCells(CPos start, CPos end, WDist depth)
|
||||
{
|
||||
var mins = new CPos(Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
|
||||
@@ -122,6 +146,10 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
if (self.Owner != self.World.LocalPlayer || Minefield == null)
|
||||
yield break;
|
||||
|
||||
// Single-cell mine fields use a target line instead
|
||||
if (Minefield.Length == 1)
|
||||
yield break;
|
||||
|
||||
var pal = wr.Palette(TileSet.TerrainPaletteInternalName);
|
||||
foreach (var c in Minefield)
|
||||
yield return new SpriteRenderable(tile, self.World.Map.CenterOfCell(c),
|
||||
@@ -178,7 +206,6 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
CPos lastMousePos;
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
public IEnumerable<IRenderable> RenderAboveShroud(WorldRenderer wr, World world)
|
||||
{
|
||||
@@ -187,6 +214,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
yield break;
|
||||
|
||||
// We get the biggest depth so we cover all cells that mines could be placed on.
|
||||
var lastMousePos = wr.Viewport.ViewToWorld(Viewport.LastMousePos);
|
||||
var minefield = GetMinefieldCells(minefieldStart, lastMousePos,
|
||||
minelayers.Max(m => m.Info.TraitInfo<MinelayerInfo>().MinefieldDepth));
|
||||
|
||||
@@ -202,7 +230,7 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
|
||||
public string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
lastMousePos = cell; return "ability"; /* TODO */
|
||||
return "ability";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return NextActivity;
|
||||
|
||||
// TODO: This should fire each weapon at its maximum range
|
||||
if (attackPlane != null && target.IsInRange(self.CenterPosition, attackPlane.Armaments.Select(a => a.Weapon.MinRange).Min()))
|
||||
if (attackPlane != null && target.IsInRange(self.CenterPosition, attackPlane.Armaments.Where(Exts.IsTraitEnabled).Select(a => a.Weapon.MinRange).Min()))
|
||||
ChildActivity = ActivityUtils.SequenceActivities(new FlyTimed(ticksUntilTurn, self), new Fly(self, target), new FlyTimed(ticksUntilTurn, self));
|
||||
else
|
||||
ChildActivity = ActivityUtils.SequenceActivities(new Fly(self, target), new FlyTimed(ticksUntilTurn, self));
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
public FlyCircle(Actor self)
|
||||
{
|
||||
IsIdle = true;
|
||||
plane = self.Trait<Aircraft>();
|
||||
cruiseAltitude = plane.Info.CruiseAltitude;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace OpenRA.Mods.Common.Activities
|
||||
public HeliFlyCircle(Actor self)
|
||||
{
|
||||
helicopter = self.Trait<Aircraft>();
|
||||
IsIdle = true;
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
public class Move : Activity
|
||||
{
|
||||
const int AverageTicksBeforePathing = 5;
|
||||
const int SpreadTicksBeforePathing = 5;
|
||||
static readonly List<CPos> NoPath = new List<CPos>();
|
||||
|
||||
readonly Mobile mobile;
|
||||
@@ -41,7 +39,6 @@ namespace OpenRA.Mods.Common.Activities
|
||||
int waitTicksRemaining;
|
||||
|
||||
// To work around queued activity issues while minimizing changes to legacy behaviour
|
||||
int ticksBeforePathing;
|
||||
bool evaluateNearestMovableCell;
|
||||
|
||||
// Scriptable move order
|
||||
@@ -140,9 +137,6 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
protected override void OnFirstRun(Actor self)
|
||||
{
|
||||
ticksBeforePathing = AverageTicksBeforePathing +
|
||||
self.World.SharedRandom.Next(-SpreadTicksBeforePathing, SpreadTicksBeforePathing);
|
||||
|
||||
if (evaluateNearestMovableCell && destination.HasValue)
|
||||
{
|
||||
var movableDestination = mobile.NearestMoveableCell(destination.Value);
|
||||
@@ -165,9 +159,9 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
if (path == null)
|
||||
{
|
||||
if (ticksBeforePathing > 0)
|
||||
if (mobile.TicksBeforePathing > 0)
|
||||
{
|
||||
--ticksBeforePathing;
|
||||
--mobile.TicksBeforePathing;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -264,9 +258,9 @@ namespace OpenRA.Mods.Common.Activities
|
||||
if (--waitTicksRemaining >= 0)
|
||||
return null;
|
||||
|
||||
if (ticksBeforePathing > 0)
|
||||
if (mobile.TicksBeforePathing > 0)
|
||||
{
|
||||
--ticksBeforePathing;
|
||||
--mobile.TicksBeforePathing;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
nt.BeforeTransform(self);
|
||||
|
||||
var makeAnimation = self.TraitOrDefault<WithMakeAnimation>();
|
||||
if (makeAnimation != null)
|
||||
if (!SkipMakeAnims && makeAnimation != null)
|
||||
{
|
||||
// Once the make animation starts the activity must not be stopped anymore.
|
||||
IsInterruptible = false;
|
||||
|
||||
@@ -21,9 +21,6 @@ namespace OpenRA.Mods.Common
|
||||
{
|
||||
public static bool IsAtGroundLevel(this Actor self)
|
||||
{
|
||||
if (self.IsDead)
|
||||
return false;
|
||||
|
||||
if (self.OccupiesSpace == null)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -26,8 +26,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly EditorActorLayer editorLayer;
|
||||
readonly EditorViewportControllerWidget editorWidget;
|
||||
readonly ActorPreviewWidget preview;
|
||||
readonly CVec locationOffset;
|
||||
readonly WVec previewOffset;
|
||||
readonly WVec centerOffset;
|
||||
readonly PlayerReference owner;
|
||||
readonly CVec[] footprint;
|
||||
|
||||
@@ -49,10 +48,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
var buildingInfo = actor.TraitInfoOrDefault<BuildingInfo>();
|
||||
if (buildingInfo != null)
|
||||
{
|
||||
locationOffset = -buildingInfo.LocationOffset();
|
||||
previewOffset = buildingInfo.CenterOffset(world);
|
||||
}
|
||||
centerOffset = buildingInfo.CenterOffset(world);
|
||||
|
||||
var td = new TypeDictionary();
|
||||
td.Add(new FacingInit(facing));
|
||||
@@ -91,17 +87,16 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
return false;
|
||||
}
|
||||
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location - worldRenderer.ScreenPxOffset(centerOffset));
|
||||
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
|
||||
{
|
||||
// Check the actor is inside the map
|
||||
if (!footprint.All(c => world.Map.Tiles.Contains(cell + locationOffset + c)))
|
||||
if (!footprint.All(c => world.Map.Tiles.Contains(cell + c)))
|
||||
return true;
|
||||
|
||||
var newActorReference = new ActorReference(Actor.Name);
|
||||
newActorReference.Add(new OwnerInit(owner.Name));
|
||||
|
||||
cell += locationOffset;
|
||||
newActorReference.Add(new LocationInit(cell));
|
||||
|
||||
var ios = Actor.TraitInfoOrDefault<IOccupySpaceInfo>();
|
||||
@@ -128,8 +123,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
|
||||
var pos = world.Map.CenterOfCell(cell + locationOffset) + previewOffset;
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos - worldRenderer.ScreenPxOffset(centerOffset));
|
||||
var pos = world.Map.CenterOfCell(cell) + centerOffset;
|
||||
|
||||
var origin = worldRenderer.Viewport.WorldToViewPx(worldRenderer.ScreenPxPosition(pos));
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
<HintPath>..\thirdparty\download\FuzzyLogicLibrary.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="rix0rrr.BeaconLib, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Reference Include="rix0rrr.BeaconLib">
|
||||
<HintPath>..\thirdparty\download\rix0rrr.BeaconLib.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
@@ -549,6 +549,7 @@
|
||||
<Compile Include="UtilityCommands\ExtractSettingsDocsCommand.cs" />
|
||||
<Compile Include="UtilityCommands\ExtractZeroBraneStudioLuaAPI.cs" />
|
||||
<Compile Include="UtilityCommands\ExtractTraitDocsCommand.cs" />
|
||||
<Compile Include="UtilityCommands\ExtractWeaponDocsCommand.cs" />
|
||||
<Compile Include="Widgets\Logic\Ingame\MusicControllerLogic.cs" />
|
||||
<Compile Include="Widgets\UnitCommandWidget.cs" />
|
||||
<Compile Include="WorldExtensions.cs" />
|
||||
|
||||
@@ -33,14 +33,18 @@ namespace OpenRA.Mods.Common.Orders
|
||||
readonly string faction;
|
||||
readonly Sprite buildOk;
|
||||
readonly Sprite buildBlocked;
|
||||
readonly Viewport viewport;
|
||||
readonly WVec centerOffset;
|
||||
readonly int2 topLeftScreenOffset;
|
||||
IActorPreview[] preview;
|
||||
|
||||
bool initialized;
|
||||
|
||||
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name)
|
||||
public PlaceBuildingOrderGenerator(ProductionQueue queue, string name, WorldRenderer worldRenderer)
|
||||
{
|
||||
var world = queue.Actor.World;
|
||||
this.queue = queue;
|
||||
viewport = worldRenderer.Viewport;
|
||||
placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo<PlaceBuildingInfo>();
|
||||
building = name;
|
||||
|
||||
@@ -53,6 +57,8 @@ namespace OpenRA.Mods.Common.Orders
|
||||
|
||||
var info = map.Rules.Actors[building];
|
||||
buildingInfo = info.TraitInfo<BuildingInfo>();
|
||||
centerOffset = buildingInfo.CenterOffset(world);
|
||||
topLeftScreenOffset = -worldRenderer.ScreenPxOffset(centerOffset);
|
||||
|
||||
var buildableInfo = info.TraitInfo<BuildableInfo>();
|
||||
var mostLikelyProducer = queue.MostLikelyProducer();
|
||||
@@ -99,7 +105,7 @@ namespace OpenRA.Mods.Common.Orders
|
||||
if (mi.Button == MouseButton.Left)
|
||||
{
|
||||
var orderType = "PlaceBuilding";
|
||||
var topLeft = cell - buildingInfo.LocationOffset();
|
||||
var topLeft = viewport.ViewToWorld(Viewport.LastMousePos + topLeftScreenOffset);
|
||||
|
||||
var plugInfo = world.Map.Rules.Actors[building].TraitInfoOrDefault<PlugInfo>();
|
||||
if (plugInfo != null)
|
||||
@@ -162,14 +168,13 @@ namespace OpenRA.Mods.Common.Orders
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
public IEnumerable<IRenderable> RenderAboveShroud(WorldRenderer wr, World world)
|
||||
{
|
||||
var xy = wr.Viewport.ViewToWorld(Viewport.LastMousePos);
|
||||
var topLeft = xy - buildingInfo.LocationOffset();
|
||||
var offset = world.Map.CenterOfCell(topLeft) + buildingInfo.CenterOffset(world);
|
||||
var topLeft = viewport.ViewToWorld(Viewport.LastMousePos + topLeftScreenOffset);
|
||||
var centerPosition = world.Map.CenterOfCell(topLeft) + centerOffset;
|
||||
var rules = world.Map.Rules;
|
||||
|
||||
var actorInfo = rules.Actors[building];
|
||||
foreach (var dec in actorInfo.TraitInfos<IPlaceBuildingDecorationInfo>())
|
||||
foreach (var r in dec.Render(wr, world, actorInfo, offset))
|
||||
foreach (var r in dec.Render(wr, world, actorInfo, centerPosition))
|
||||
yield return r;
|
||||
|
||||
var cells = new Dictionary<CPos, CellType>();
|
||||
@@ -219,7 +224,7 @@ namespace OpenRA.Mods.Common.Orders
|
||||
}
|
||||
|
||||
var previewRenderables = preview
|
||||
.SelectMany(p => p.Render(wr, offset))
|
||||
.SelectMany(p => p.Render(wr, centerPosition))
|
||||
.OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey);
|
||||
|
||||
foreach (var r in previewRenderables)
|
||||
|
||||
@@ -210,7 +210,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var armament in Armaments)
|
||||
{
|
||||
var checkIsValid = checkForCenterTargetingWeapons ? armament.Weapon.TargetActorCenter : !armament.OutOfAmmo;
|
||||
if (checkIsValid && armament.Weapon.IsValidAgainst(t, self.World, self))
|
||||
if (checkIsValid && !armament.IsTraitDisabled && armament.Weapon.IsValidAgainst(t, self.World, self))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
foreach (var a in Armaments)
|
||||
{
|
||||
if (a.IsTraitDisabled)
|
||||
continue;
|
||||
|
||||
var port = SelectFirePort(self, targetYaw);
|
||||
if (port == null)
|
||||
return;
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
@@ -20,10 +23,18 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[VoiceReference] public readonly string Voice = "Action";
|
||||
|
||||
[GrantedConditionReference]
|
||||
[Desc("The condition to grant to self while scanning for targets during an attack-move.")]
|
||||
public readonly string AttackMoveScanCondition = null;
|
||||
|
||||
[GrantedConditionReference]
|
||||
[Desc("The condition to grant to self while scanning for targets during an assault-move.")]
|
||||
public readonly string AssaultMoveScanCondition = null;
|
||||
|
||||
public object Create(ActorInitializer init) { return new AttackMove(init.Self, this); }
|
||||
}
|
||||
|
||||
class AttackMove : IResolveOrder, IOrderVoice, INotifyIdle, ISync
|
||||
class AttackMove : INotifyCreated, ITick, IResolveOrder, IOrderVoice, INotifyIdle, ISync
|
||||
{
|
||||
[Sync] public CPos _targetLocation { get { return TargetLocation.HasValue ? TargetLocation.Value : CPos.Zero; } }
|
||||
public CPos? TargetLocation = null;
|
||||
@@ -31,23 +42,54 @@ namespace OpenRA.Mods.Common.Traits
|
||||
readonly IMove move;
|
||||
readonly AttackMoveInfo info;
|
||||
|
||||
ConditionManager conditionManager;
|
||||
int attackMoveToken = ConditionManager.InvalidConditionToken;
|
||||
int assaultMoveToken = ConditionManager.InvalidConditionToken;
|
||||
bool assaultMoving = false;
|
||||
|
||||
public AttackMove(Actor self, AttackMoveInfo info)
|
||||
{
|
||||
move = self.Trait<IMove>();
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
conditionManager = self.TraitOrDefault<ConditionManager>();
|
||||
}
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
{
|
||||
if (conditionManager == null)
|
||||
return;
|
||||
|
||||
var activity = self.CurrentActivity as AttackMoveActivity;
|
||||
var attackActive = activity != null && !assaultMoving;
|
||||
var assaultActive = activity != null && assaultMoving;
|
||||
|
||||
if (attackActive && attackMoveToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(info.AttackMoveScanCondition))
|
||||
attackMoveToken = conditionManager.GrantCondition(self, info.AttackMoveScanCondition);
|
||||
else if (!attackActive && attackMoveToken != ConditionManager.InvalidConditionToken)
|
||||
attackMoveToken = conditionManager.RevokeCondition(self, attackMoveToken);
|
||||
|
||||
if (assaultActive && assaultMoveToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(info.AssaultMoveScanCondition))
|
||||
assaultMoveToken = conditionManager.GrantCondition(self, info.AssaultMoveScanCondition);
|
||||
else if (!assaultActive && assaultMoveToken != ConditionManager.InvalidConditionToken)
|
||||
assaultMoveToken = conditionManager.RevokeCondition(self, assaultMoveToken);
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "AttackMove")
|
||||
if (order.OrderString == "AttackMove" || order.OrderString == "AssaultMove")
|
||||
return info.Voice;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void Activate(Actor self)
|
||||
void Activate(Actor self, bool assaultMove)
|
||||
{
|
||||
self.CancelActivity();
|
||||
assaultMoving = assaultMove;
|
||||
self.QueueActivity(new AttackMoveActivity(self, move.MoveTo(TargetLocation.Value, 1)));
|
||||
}
|
||||
|
||||
@@ -55,19 +97,71 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
// This might cause the actor to be stuck if the target location is unreachable
|
||||
if (TargetLocation.HasValue && self.Location != TargetLocation.Value)
|
||||
Activate(self);
|
||||
Activate(self, assaultMoving);
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
TargetLocation = null;
|
||||
|
||||
if (order.OrderString == "AttackMove")
|
||||
if (order.OrderString == "AttackMove" || order.OrderString == "AssaultMove")
|
||||
{
|
||||
TargetLocation = move.NearestMoveableCell(order.TargetLocation);
|
||||
self.SetTargetLine(Target.FromCell(self.World, TargetLocation.Value), Color.Red);
|
||||
Activate(self);
|
||||
Activate(self, order.OrderString == "AssaultMove");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AttackMoveOrderGenerator : UnitOrderGenerator
|
||||
{
|
||||
readonly TraitPair<AttackMove>[] subjects;
|
||||
readonly MouseButton expectedButton;
|
||||
|
||||
public AttackMoveOrderGenerator(IEnumerable<Actor> subjects, MouseButton button)
|
||||
{
|
||||
expectedButton = button;
|
||||
|
||||
this.subjects = subjects.Where(a => !a.IsDead)
|
||||
.SelectMany(a => a.TraitsImplementing<AttackMove>()
|
||||
.Select(am => new TraitPair<AttackMove>(a, am)))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public override IEnumerable<Order> Order(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
if (mi.Button != expectedButton)
|
||||
world.CancelInputMode();
|
||||
|
||||
return OrderInner(world, cell, mi);
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<Order> OrderInner(World world, CPos cell, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == expectedButton)
|
||||
{
|
||||
world.CancelInputMode();
|
||||
|
||||
var queued = mi.Modifiers.HasModifier(Modifiers.Shift);
|
||||
var orderName = mi.Modifiers.HasModifier(Modifiers.Ctrl) ? "AssaultMove" : "AttackMove";
|
||||
|
||||
// Cells outside the playable area should be clamped to the edge for consistency with move orders
|
||||
cell = world.Map.Clamp(cell);
|
||||
foreach (var s in subjects)
|
||||
yield return new Order(orderName, s.Actor, queued) { TargetLocation = cell };
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
var prefix = mi.Modifiers.HasModifier(Modifiers.Ctrl) ? "assaultmove" : "attackmove";
|
||||
return world.Map.Contains(cell) ? prefix : prefix + "-blocked";
|
||||
}
|
||||
|
||||
public override bool InputOverridesSelection(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
// Custom order generators always override selection
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,10 +60,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Ticks to wait until next AutoTarget: attempt.")]
|
||||
public readonly int MaximumScanTimeInterval = 8;
|
||||
|
||||
public readonly bool TargetWhenIdle = true;
|
||||
|
||||
public readonly bool TargetWhenDamaged = true;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new AutoTarget(init, this); }
|
||||
|
||||
public override void RulesetLoaded(Ruleset rules, ActorInfo info)
|
||||
@@ -157,17 +153,18 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void Damaged(Actor self, AttackInfo e)
|
||||
{
|
||||
if (IsTraitDisabled)
|
||||
if (IsTraitDisabled || !self.IsIdle || Stance < UnitStance.ReturnFire)
|
||||
return;
|
||||
|
||||
if (!self.IsIdle || !Info.TargetWhenDamaged)
|
||||
// Don't retaliate against healers
|
||||
if (e.Damage.Value < 0)
|
||||
return;
|
||||
|
||||
var attacker = e.Attacker;
|
||||
if (attacker.Disposed || Stance < UnitStance.ReturnFire)
|
||||
if (attacker.Disposed)
|
||||
return;
|
||||
|
||||
if (!attacker.IsInWorld && !attacker.Disposed)
|
||||
if (!attacker.IsInWorld)
|
||||
{
|
||||
// If the aggressor is in a transport, then attack the transport instead
|
||||
var passenger = attacker.TraitOrDefault<Passenger>();
|
||||
@@ -175,19 +172,15 @@ namespace OpenRA.Mods.Common.Traits
|
||||
attacker = passenger.Transport;
|
||||
}
|
||||
|
||||
// not a lot we can do about things we can't hurt... although maybe we should automatically run away?
|
||||
// Not a lot we can do about things we can't hurt... although maybe we should automatically run away?
|
||||
var attackerAsTarget = Target.FromActor(attacker);
|
||||
if (!activeAttackBases.Any(a => a.HasAnyValidWeapons(attackerAsTarget)))
|
||||
return;
|
||||
|
||||
// don't retaliate against own units force-firing on us. It's usually not what the player wanted.
|
||||
// Don't retaliate against own units force-firing on us. It's usually not what the player wanted.
|
||||
if (attacker.AppearsFriendlyTo(self))
|
||||
return;
|
||||
|
||||
// don't retaliate against healers
|
||||
if (e.Damage.Value < 0)
|
||||
return;
|
||||
|
||||
Aggressor = attacker;
|
||||
|
||||
bool allowMove;
|
||||
@@ -197,10 +190,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void TickIdle(Actor self)
|
||||
{
|
||||
if (IsTraitDisabled)
|
||||
return;
|
||||
|
||||
if (Stance < UnitStance.Defend || !Info.TargetWhenIdle)
|
||||
if (IsTraitDisabled || Stance < UnitStance.Defend)
|
||||
return;
|
||||
|
||||
bool allowMove;
|
||||
|
||||
@@ -47,7 +47,18 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public object Create(ActorInitializer init) { return new Bridge(init.Self, this); }
|
||||
|
||||
public void RulesetLoaded(Ruleset rules, ActorInfo ai) { DemolishWeaponInfo = rules.Weapons[DemolishWeapon.ToLowerInvariant()]; }
|
||||
public void RulesetLoaded(Ruleset rules, ActorInfo ai)
|
||||
{
|
||||
if (string.IsNullOrEmpty(DemolishWeapon))
|
||||
throw new YamlException("A value for DemolishWeapon of a Bridge trait is missing.");
|
||||
|
||||
WeaponInfo weapon;
|
||||
var weaponToLower = DemolishWeapon.ToLowerInvariant();
|
||||
if (!rules.Weapons.TryGetValue(weaponToLower, out weapon))
|
||||
throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower));
|
||||
|
||||
DemolishWeaponInfo = weapon;
|
||||
}
|
||||
|
||||
public IEnumerable<Pair<ushort, int>> Templates
|
||||
{
|
||||
|
||||
@@ -144,11 +144,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
yield return t;
|
||||
}
|
||||
|
||||
public CVec LocationOffset()
|
||||
{
|
||||
return new CVec(Dimensions.X / 2, Dimensions.Y > 1 ? (Dimensions.Y + 1) / 2 : 0);
|
||||
}
|
||||
|
||||
public WVec CenterOffset(World w)
|
||||
{
|
||||
var off = (w.Map.CenterOfCell(new CPos(Dimensions.X, Dimensions.Y)) - w.Map.CenterOfCell(new CPos(1, 1))) / 2;
|
||||
|
||||
@@ -139,12 +139,12 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
if (!preventDock)
|
||||
{
|
||||
harv.QueueActivity(new CallFunc(() => dockedHarv = harv, false));
|
||||
harv.QueueActivity(DockSequence(harv, self));
|
||||
harv.QueueActivity(new CallFunc(() => dockedHarv = null, false));
|
||||
dockOrder.Queue(new CallFunc(() => dockedHarv = harv, false));
|
||||
dockOrder.Queue(DockSequence(harv, self));
|
||||
dockOrder.Queue(new CallFunc(() => dockedHarv = null, false));
|
||||
}
|
||||
|
||||
harv.QueueActivity(new CallFunc(() => harv.Trait<Harvester>().ContinueHarvesting(harv)));
|
||||
dockOrder.Queue(new CallFunc(() => harv.Trait<Harvester>().ContinueHarvesting(harv)));
|
||||
}
|
||||
|
||||
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
|
||||
|
||||
@@ -117,6 +117,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
foreach (var a in attack.Armaments)
|
||||
{
|
||||
if (a.IsTraitDisabled)
|
||||
continue;
|
||||
|
||||
foreach (var b in a.Barrels)
|
||||
{
|
||||
var muzzle = self.CenterPosition + a.MuzzleOffset(self, b);
|
||||
|
||||
@@ -55,6 +55,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Can this actor undeploy?")]
|
||||
public readonly bool CanUndeploy = true;
|
||||
|
||||
[Desc("Skip make/deploy animation?")]
|
||||
public readonly bool SkipMakeAnimation = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new GrantConditionOnDeploy(init, this); }
|
||||
}
|
||||
|
||||
@@ -223,7 +226,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
OnDeployCompleted();
|
||||
else
|
||||
foreach (var n in notify)
|
||||
n.Deploy(self);
|
||||
n.Deploy(self, Info.SkipMakeAnimation);
|
||||
}
|
||||
|
||||
/// <summary>Play undeploy sound and animation and after that revoke the condition.</summary>
|
||||
@@ -246,7 +249,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
OnUndeployCompleted();
|
||||
else
|
||||
foreach (var n in notify)
|
||||
n.Undeploy(self);
|
||||
n.Undeploy(self, Info.SkipMakeAnimation);
|
||||
}
|
||||
|
||||
void OnDeployStarted()
|
||||
|
||||
@@ -392,6 +392,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public class Mobile : ConditionalTrait<MobileInfo>, INotifyCreated, IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove,
|
||||
IFacing, IDeathActorInitModifier, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyBlockingMove, IActorPreviewInitModifier, INotifyBecomingIdle
|
||||
{
|
||||
const int AverageTicksBeforePathing = 5;
|
||||
const int SpreadTicksBeforePathing = 5;
|
||||
internal int TicksBeforePathing = 0;
|
||||
|
||||
readonly Actor self;
|
||||
readonly Lazy<IEnumerable<int>> speedModifiers;
|
||||
public bool IsMoving { get; set; }
|
||||
@@ -629,14 +633,18 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
if (order.OrderString == "Move")
|
||||
{
|
||||
if (!Info.MoveIntoShroud && !self.Owner.Shroud.IsExplored(order.TargetLocation))
|
||||
var loc = self.World.Map.Clamp(order.TargetLocation);
|
||||
|
||||
if (!Info.MoveIntoShroud && !self.Owner.Shroud.IsExplored(loc))
|
||||
return;
|
||||
|
||||
if (!order.Queued)
|
||||
self.CancelActivity();
|
||||
|
||||
self.SetTargetLine(Target.FromCell(self.World, order.TargetLocation), Color.Green);
|
||||
self.QueueActivity(order.Queued, new Move(self, order.TargetLocation, WDist.FromCells(8), null, true));
|
||||
TicksBeforePathing = AverageTicksBeforePathing + self.World.SharedRandom.Next(-SpreadTicksBeforePathing, SpreadTicksBeforePathing);
|
||||
|
||||
self.SetTargetLine(Target.FromCell(self.World, loc), Color.Green);
|
||||
self.QueueActivity(order.Queued, new Move(self, loc, WDist.FromCells(8), null, true));
|
||||
}
|
||||
|
||||
if (order.OrderString == "Stop")
|
||||
|
||||
@@ -116,16 +116,24 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
}
|
||||
|
||||
// TODO: Make this use Forward instead
|
||||
void INotifyDeployTriggered.Deploy(Actor self)
|
||||
void INotifyDeployTriggered.Deploy(Actor self, bool skipMakeAnim)
|
||||
{
|
||||
var notified = false;
|
||||
var notify = self.TraitsImplementing<INotifyDeployComplete>();
|
||||
|
||||
if (skipMakeAnim)
|
||||
{
|
||||
foreach (var n in notify)
|
||||
n.FinishedDeploy(self);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var wsb in wsbs)
|
||||
{
|
||||
if (wsb.IsTraitDisabled)
|
||||
continue;
|
||||
|
||||
var notify = self.TraitsImplementing<INotifyDeployComplete>();
|
||||
wsb.PlayCustomAnimation(self, info.Sequence, () =>
|
||||
{
|
||||
if (notified)
|
||||
@@ -141,16 +149,24 @@ namespace OpenRA.Mods.Common.Traits.Render
|
||||
}
|
||||
|
||||
// TODO: Make this use Reverse instead
|
||||
void INotifyDeployTriggered.Undeploy(Actor self)
|
||||
void INotifyDeployTriggered.Undeploy(Actor self, bool skipMakeAnim)
|
||||
{
|
||||
var notified = false;
|
||||
var notify = self.TraitsImplementing<INotifyDeployComplete>();
|
||||
|
||||
if (skipMakeAnim)
|
||||
{
|
||||
foreach (var n in notify)
|
||||
n.FinishedUndeploy(self);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var wsb in wsbs)
|
||||
{
|
||||
if (wsb.IsTraitDisabled)
|
||||
continue;
|
||||
|
||||
var notify = self.TraitsImplementing<INotifyDeployComplete>();
|
||||
wsb.PlayCustomAnimationBackwards(self, info.Sequence, () =>
|
||||
{
|
||||
if (notified)
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public readonly int RefundPercent = 50;
|
||||
public readonly string[] SellSounds = { };
|
||||
|
||||
[Desc("Skip playing (reversed) make animation.")]
|
||||
public readonly bool SkipMakeAnimation = false;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new Sellable(init.Self, this); }
|
||||
}
|
||||
|
||||
@@ -63,11 +66,17 @@ namespace OpenRA.Mods.Common.Traits
|
||||
foreach (var ns in self.TraitsImplementing<INotifySold>())
|
||||
ns.Selling(self);
|
||||
|
||||
var makeAnimation = self.TraitOrDefault<WithMakeAnimation>();
|
||||
if (makeAnimation != null)
|
||||
makeAnimation.Reverse(self, new Sell(self), false);
|
||||
else
|
||||
self.QueueActivity(false, new Sell(self));
|
||||
if (!info.SkipMakeAnimation)
|
||||
{
|
||||
var makeAnimation = self.TraitOrDefault<WithMakeAnimation>();
|
||||
if (makeAnimation != null)
|
||||
{
|
||||
makeAnimation.Reverse(self, new Sell(self), false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.QueueActivity(false, new Sell(self));
|
||||
}
|
||||
|
||||
public bool IsTooltipVisible(Player forPlayer)
|
||||
|
||||
@@ -53,11 +53,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public override object Create(ActorInitializer init) { return new SpawnActorOnDeath(init, this); }
|
||||
}
|
||||
|
||||
public class SpawnActorOnDeath : ConditionalTrait<SpawnActorOnDeathInfo>, INotifyKilled
|
||||
public class SpawnActorOnDeath : ConditionalTrait<SpawnActorOnDeathInfo>, INotifyKilled, INotifyRemovedFromWorld
|
||||
{
|
||||
readonly string faction;
|
||||
readonly bool enabled;
|
||||
|
||||
Player attackingPlayer;
|
||||
|
||||
public SpawnActorOnDeath(ActorInitializer init, SpawnActorOnDeathInfo info)
|
||||
: base(info)
|
||||
{
|
||||
@@ -65,7 +67,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
faction = init.Contains<FactionInit>() ? init.Get<FactionInit, string>() : init.Self.Owner.Faction.InternalName;
|
||||
}
|
||||
|
||||
public void Killed(Actor self, AttackInfo e)
|
||||
void INotifyKilled.Killed(Actor self, AttackInfo e)
|
||||
{
|
||||
if (!enabled || IsTraitDisabled)
|
||||
return;
|
||||
@@ -79,39 +81,41 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (Info.DeathType != null && !e.Damage.DamageTypes.Contains(Info.DeathType))
|
||||
return;
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
attackingPlayer = e.Attacker.Owner;
|
||||
}
|
||||
|
||||
// Don't add the new actor to the world before all RemovedFromWorld callbacks have run
|
||||
void INotifyRemovedFromWorld.RemovedFromWorld(Actor self)
|
||||
{
|
||||
if (attackingPlayer == null)
|
||||
return;
|
||||
|
||||
var td = new TypeDictionary
|
||||
{
|
||||
// Actor has been disposed by something else before its death (for example `Enter`).
|
||||
if (self.Disposed)
|
||||
return;
|
||||
new ParentActorInit(self),
|
||||
new LocationInit(self.Location + Info.Offset),
|
||||
new CenterPositionInit(self.CenterPosition),
|
||||
new FactionInit(faction)
|
||||
};
|
||||
|
||||
var td = new TypeDictionary
|
||||
{
|
||||
new ParentActorInit(self),
|
||||
new LocationInit(self.Location + Info.Offset),
|
||||
new CenterPositionInit(self.CenterPosition),
|
||||
new FactionInit(faction)
|
||||
};
|
||||
if (Info.OwnerType == OwnerType.Victim)
|
||||
td.Add(new OwnerInit(self.Owner));
|
||||
else if (Info.OwnerType == OwnerType.Killer)
|
||||
td.Add(new OwnerInit(attackingPlayer));
|
||||
else
|
||||
td.Add(new OwnerInit(self.World.Players.First(p => p.InternalName == Info.InternalOwner)));
|
||||
|
||||
if (Info.OwnerType == OwnerType.Victim)
|
||||
td.Add(new OwnerInit(self.Owner));
|
||||
else if (Info.OwnerType == OwnerType.Killer)
|
||||
td.Add(new OwnerInit(e.Attacker.Owner));
|
||||
else
|
||||
td.Add(new OwnerInit(self.World.Players.First(p => p.InternalName == Info.InternalOwner)));
|
||||
if (Info.SkipMakeAnimations)
|
||||
td.Add(new SkipMakeAnimsInit());
|
||||
|
||||
if (Info.SkipMakeAnimations)
|
||||
td.Add(new SkipMakeAnimsInit());
|
||||
foreach (var modifier in self.TraitsImplementing<IDeathActorInitModifier>())
|
||||
modifier.ModifyDeathActorInit(self, td);
|
||||
|
||||
foreach (var modifier in self.TraitsImplementing<IDeathActorInitModifier>())
|
||||
modifier.ModifyDeathActorInit(self, td);
|
||||
var huskActor = self.TraitsImplementing<IHuskModifier>()
|
||||
.Select(ihm => ihm.HuskActor(self))
|
||||
.FirstOrDefault(a => a != null);
|
||||
|
||||
var huskActor = self.TraitsImplementing<IHuskModifier>()
|
||||
.Select(ihm => ihm.HuskActor(self))
|
||||
.FirstOrDefault(a => a != null);
|
||||
|
||||
w.CreateActor(huskActor ?? Info.Actor, td);
|
||||
});
|
||||
self.World.AddFrameEndTask(w => w.CreateActor(huskActor ?? Info.Actor, td));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
var location = self.World.Map.CenterOfCell(order.TargetLocation);
|
||||
|
||||
PlayLaunchSounds();
|
||||
Game.Sound.Play(SoundType.World, info.DeploySound, location);
|
||||
|
||||
if (!string.IsNullOrEmpty(info.EffectSequence) && !string.IsNullOrEmpty(info.EffectPalette))
|
||||
|
||||
@@ -160,13 +160,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public int RemainingTime;
|
||||
public int TotalTime;
|
||||
public bool Active { get; private set; }
|
||||
public bool Disabled { get { return (!prereqsAvailable && !manager.DevMode.AllTech) || !instancesEnabled; } }
|
||||
public bool Disabled { get { return (!prereqsAvailable && !manager.DevMode.AllTech) || !instancesEnabled || oneShotFired; } }
|
||||
|
||||
public SupportPowerInfo Info { get { return Instances.Select(i => i.Info).FirstOrDefault(); } }
|
||||
public bool Ready { get { return Active && RemainingTime == 0; } }
|
||||
|
||||
bool instancesEnabled;
|
||||
bool prereqsAvailable = true;
|
||||
bool oneShotFired;
|
||||
|
||||
public SupportPowerInstance(string key, SupportPowerManager manager)
|
||||
{
|
||||
@@ -249,7 +250,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
notifiedCharging = notifiedReady = false;
|
||||
|
||||
if (Info.OneShot)
|
||||
{
|
||||
PrerequisitesAvailable(false);
|
||||
oneShotFired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -175,8 +175,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public interface INotifyDeployTriggered
|
||||
{
|
||||
void Deploy(Actor self);
|
||||
void Undeploy(Actor self);
|
||||
void Deploy(Actor self, bool skipMakeAnim);
|
||||
void Undeploy(Actor self, bool skipMakeAnim);
|
||||
}
|
||||
|
||||
public interface IAcceptResourcesInfo : ITraitInfo { }
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
@@ -189,5 +191,64 @@ namespace OpenRA.Mods.Common
|
||||
return rules.Actors.Where(a => a.Value.HasTraitInfo<IBlocksProjectilesInfo>())
|
||||
.SelectMany(a => a.Value.TraitInfos<HitShapeInfo>()).Max(h => h.Type.OuterRadius);
|
||||
}
|
||||
|
||||
public static string FriendlyTypeName(Type t)
|
||||
{
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(HashSet<>))
|
||||
return "Set of {0}".F(t.GetGenericArguments().Select(FriendlyTypeName).ToArray());
|
||||
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
return "Mapping of {0} to {1}".F(t.GetGenericArguments().Select(FriendlyTypeName).ToArray());
|
||||
|
||||
if (t.IsSubclassOf(typeof(Array)))
|
||||
return "Collection of {0}".F(FriendlyTypeName(t.GetElementType()));
|
||||
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition().GetInterfaces().Any(e => e.IsGenericType && e.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
|
||||
return "Collection of {0}".F(FriendlyTypeName(t.GetGenericArguments().First()));
|
||||
|
||||
if (t == typeof(int) || t == typeof(uint))
|
||||
return "Integer";
|
||||
|
||||
if (t == typeof(int2))
|
||||
return "2D Integer";
|
||||
|
||||
if (t == typeof(float) || t == typeof(decimal))
|
||||
return "Real Number";
|
||||
|
||||
if (t == typeof(float2))
|
||||
return "2D Real Number";
|
||||
|
||||
if (t == typeof(CPos))
|
||||
return "2D Cell Position";
|
||||
|
||||
if (t == typeof(CVec))
|
||||
return "2D Cell Vector";
|
||||
|
||||
if (t == typeof(WAngle))
|
||||
return "1D World Angle";
|
||||
|
||||
if (t == typeof(WRot))
|
||||
return "3D World Rotation";
|
||||
|
||||
if (t == typeof(WPos))
|
||||
return "3D World Position";
|
||||
|
||||
if (t == typeof(WDist))
|
||||
return "1D World Distance";
|
||||
|
||||
if (t == typeof(WVec))
|
||||
return "3D World Vector";
|
||||
|
||||
if (t == typeof(HSLColor) || t == typeof(Color))
|
||||
return "Color (RRGGBB[AA] notation)";
|
||||
|
||||
if (t == typeof(IProjectileInfo))
|
||||
return "Projectile";
|
||||
|
||||
if (t == typeof(IWarhead))
|
||||
return "Warhead";
|
||||
|
||||
return t.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.UtilityCommands
|
||||
@@ -57,7 +56,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
|
||||
var traitName = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name;
|
||||
toc.AppendLine(" * [{0}](#{1})".F(traitName, traitName.ToLowerInvariant()));
|
||||
toc.AppendLine(" * [{0}](#{1})".F(traitName, traitName.ToLowerInvariant()));
|
||||
var traitDescLines = t.GetCustomAttributes<DescAttribute>(false).SelectMany(d => d.Lines);
|
||||
doc.AppendLine();
|
||||
doc.AppendLine("### {0}".F(traitName));
|
||||
@@ -92,7 +91,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
foreach (var info in infos)
|
||||
{
|
||||
var fieldDescLines = info.Field.GetCustomAttributes<DescAttribute>(true).SelectMany(d => d.Lines);
|
||||
var fieldType = FriendlyTypeName(info.Field.FieldType);
|
||||
var fieldType = Util.FriendlyTypeName(info.Field.FieldType);
|
||||
var loadInfo = info.Field.GetCustomAttributes<FieldLoader.SerializeAttribute>(true).FirstOrDefault();
|
||||
var defaultValue = loadInfo != null && loadInfo.Required ? "<em>(required)</em>" : FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value;
|
||||
doc.Append("<tr><td>{0}</td><td>{1}</td><td>{2}</td>".F(info.YamlName, defaultValue, fieldType));
|
||||
@@ -118,58 +117,5 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
.OrderBy(i => i.Name)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
static string FriendlyTypeName(Type t)
|
||||
{
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(HashSet<>))
|
||||
return "Set of {0}".F(t.GetGenericArguments().Select(FriendlyTypeName).ToArray());
|
||||
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
return "Dictionary<{0},{1}>".F(t.GetGenericArguments().Select(FriendlyTypeName).ToArray());
|
||||
|
||||
if (t.IsSubclassOf(typeof(Array)))
|
||||
return "Multiple {0}".F(FriendlyTypeName(t.GetElementType()));
|
||||
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Primitives.Cache<,>))
|
||||
return "Cached<{0},{1}>".F(t.GetGenericArguments().Select(FriendlyTypeName).ToArray());
|
||||
|
||||
if (t == typeof(int) || t == typeof(uint))
|
||||
return "Integer";
|
||||
|
||||
if (t == typeof(int2))
|
||||
return "2D Integer";
|
||||
|
||||
if (t == typeof(float) || t == typeof(decimal))
|
||||
return "Real Number";
|
||||
|
||||
if (t == typeof(float2))
|
||||
return "2D Real Number";
|
||||
|
||||
if (t == typeof(CPos))
|
||||
return "2D Cell Position";
|
||||
|
||||
if (t == typeof(CVec))
|
||||
return "2D Cell Vector";
|
||||
|
||||
if (t == typeof(WAngle))
|
||||
return "1D World Angle";
|
||||
|
||||
if (t == typeof(WRot))
|
||||
return "3D World Rotation";
|
||||
|
||||
if (t == typeof(WPos))
|
||||
return "3D World Position";
|
||||
|
||||
if (t == typeof(WDist))
|
||||
return "1D World Distance";
|
||||
|
||||
if (t == typeof(WVec))
|
||||
return "3D World Vector";
|
||||
|
||||
if (t == typeof(HSLColor))
|
||||
return "Color";
|
||||
|
||||
return t.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
106
OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs
Normal file
106
OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2017 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.UtilityCommands
|
||||
{
|
||||
class ExtractWeaponDocsCommand : IUtilityCommand
|
||||
{
|
||||
string IUtilityCommand.Name { get { return "--weapon-docs"; } }
|
||||
|
||||
bool IUtilityCommand.ValidateArguments(string[] args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
[Desc("Generate weaponry documentation in MarkDown format.")]
|
||||
void IUtilityCommand.Run(Utility utility, string[] args)
|
||||
{
|
||||
// HACK: The engine code assumes that Game.modData is set.
|
||||
Game.ModData = utility.ModData;
|
||||
|
||||
Console.WriteLine(
|
||||
"This documentation is aimed at modders. It displays a template for weapon definitions " +
|
||||
"as well as its contained types (warheads and projectiles) with default values and developer commentary. " +
|
||||
"Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " +
|
||||
"automatically generated for version {0} of OpenRA.", utility.ModData.Manifest.Metadata.Version);
|
||||
Console.WriteLine();
|
||||
|
||||
var toc = new StringBuilder();
|
||||
var doc = new StringBuilder();
|
||||
|
||||
var currentNamespace = "";
|
||||
|
||||
var objectCreator = utility.ModData.ObjectCreator;
|
||||
var weaponInfo = objectCreator.GetTypesImplementing<WeaponInfo>();
|
||||
var warheads = objectCreator.GetTypesImplementing<IWarhead>().OrderBy(t => t.Namespace);
|
||||
var projectiles = objectCreator.GetTypesImplementing<IProjectileInfo>().OrderBy(t => t.Namespace);
|
||||
|
||||
var weaponTypes = Enumerable.Concat(weaponInfo, Enumerable.Concat(projectiles, warheads));
|
||||
foreach (var t in weaponTypes)
|
||||
{
|
||||
// skip helpers like TraitInfo<T>
|
||||
if (t.ContainsGenericParameters || t.IsAbstract)
|
||||
continue;
|
||||
|
||||
if (currentNamespace != t.Namespace)
|
||||
{
|
||||
currentNamespace = t.Namespace;
|
||||
doc.AppendLine();
|
||||
doc.AppendLine("## {0}".F(currentNamespace));
|
||||
toc.AppendLine("* [{0}](#{1})".F(currentNamespace, currentNamespace.Replace(".", "").ToLowerInvariant()));
|
||||
}
|
||||
|
||||
var traitName = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name;
|
||||
toc.AppendLine(" * [{0}](#{1})".F(traitName, traitName.ToLowerInvariant()));
|
||||
doc.AppendLine();
|
||||
doc.AppendLine("### {0}".F(traitName));
|
||||
|
||||
var traitDescLines = t.GetCustomAttributes<DescAttribute>(false).SelectMany(d => d.Lines);
|
||||
foreach (var line in traitDescLines)
|
||||
doc.AppendLine(line);
|
||||
|
||||
var infos = FieldLoader.GetTypeLoadInfo(t);
|
||||
if (!infos.Any())
|
||||
continue;
|
||||
|
||||
doc.AppendLine("<table>");
|
||||
doc.AppendLine("<tr><th>Property</th><th>Default Value</th><th>Type</th><th>Description</th></tr>");
|
||||
|
||||
var liveTraitInfo = t == typeof(WeaponInfo) ? null : objectCreator.CreateBasic(t);
|
||||
foreach (var info in infos)
|
||||
{
|
||||
var fieldDescLines = info.Field.GetCustomAttributes<DescAttribute>(true).SelectMany(d => d.Lines);
|
||||
var fieldType = Util.FriendlyTypeName(info.Field.FieldType);
|
||||
var defaultValue = liveTraitInfo == null ? "" : FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value;
|
||||
doc.Append("<tr><td>{0}</td><td>{1}</td><td>{2}</td>".F(info.YamlName, defaultValue, fieldType));
|
||||
doc.Append("<td>");
|
||||
|
||||
foreach (var line in fieldDescLines)
|
||||
doc.Append(line + " ");
|
||||
|
||||
doc.AppendLine("</td></tr>");
|
||||
}
|
||||
|
||||
doc.AppendLine("</table>");
|
||||
}
|
||||
|
||||
Console.Write(toc.ToString());
|
||||
Console.Write(doc.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -845,6 +845,82 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
}
|
||||
}
|
||||
|
||||
// TargetWhenIdle and TargetWhenDamaged were removed from AutoTarget
|
||||
if (engineVersion < 20170722)
|
||||
{
|
||||
if (node.Key.StartsWith("AutoTarget", StringComparison.Ordinal))
|
||||
{
|
||||
var valueNodes = node.Value.Nodes;
|
||||
var targetIdle = valueNodes.FirstOrDefault(n => n.Key == "TargetWhenIdle");
|
||||
var targetDamaged = valueNodes.FirstOrDefault(n => n.Key == "TargetWhenDamaged");
|
||||
var hasInitialStance = valueNodes.FirstOrDefault(n => n.Key == "InitialStance") != null;
|
||||
var enableStances = valueNodes.FirstOrDefault(n => n.Key == "EnableStances");
|
||||
|
||||
if (targetDamaged == null)
|
||||
{
|
||||
if (targetIdle != null)
|
||||
{
|
||||
if (hasInitialStance)
|
||||
Console.WriteLine("'TargetWhenIdle' was removed from 'AutoTarget'. 'InitialStance' might need to be adjusted.");
|
||||
else
|
||||
{
|
||||
valueNodes.Add(new MiniYamlNode("InitialStance", targetIdle.Value.Value.ToLower() == "true" ? "Defend" : "ReturnFire"));
|
||||
|
||||
if (enableStances != null)
|
||||
enableStances.Value.Value = "false";
|
||||
else
|
||||
valueNodes.Add(new MiniYamlNode("EnableStances", "false"));
|
||||
}
|
||||
|
||||
valueNodes.Remove(targetIdle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targetIdle == null)
|
||||
{
|
||||
if (hasInitialStance)
|
||||
Console.WriteLine("'TargetWhenDamaged' was removed from 'AutoTarget'. 'InitialStance' might need to be adjusted.");
|
||||
else
|
||||
{
|
||||
// In this case the default for "TargetWhenIdle" (true) takes effect, i.e. use the "Defend" stance
|
||||
valueNodes.Add(new MiniYamlNode("InitialStance", "Defend"));
|
||||
|
||||
if (enableStances != null)
|
||||
enableStances.Value.Value = "false";
|
||||
else
|
||||
valueNodes.Add(new MiniYamlNode("EnableStances", "false"));
|
||||
}
|
||||
|
||||
valueNodes.Remove(targetDamaged);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasInitialStance)
|
||||
Console.WriteLine("'TargetWhenDamaged' and 'TargetWhenIdle' were removed from 'AutoTarget'. 'InitialStance' might need to be adjusted.");
|
||||
else
|
||||
{
|
||||
var idle = targetIdle.Value.Value.ToLower() == "true";
|
||||
var damaged = targetDamaged.Value.Value.ToLower() == "true";
|
||||
|
||||
if (idle)
|
||||
valueNodes.Add(new MiniYamlNode("InitialStance", "Defend"));
|
||||
else
|
||||
valueNodes.Add(new MiniYamlNode("InitialStance", damaged ? "ReturnFire" : "HoldFire"));
|
||||
|
||||
if (enableStances != null)
|
||||
enableStances.Value.Value = "false";
|
||||
else
|
||||
valueNodes.Add(new MiniYamlNode("EnableStances", "false"));
|
||||
}
|
||||
|
||||
valueNodes.Remove(targetIdle);
|
||||
valueNodes.Remove(targetDamaged);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
}
|
||||
|
||||
public bool DisableKeyRepeat = false;
|
||||
public bool DisableKeySound = false;
|
||||
|
||||
[Translate] public string Text = "";
|
||||
public string Background = "button";
|
||||
@@ -141,9 +142,10 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
if (!IsDisabled())
|
||||
{
|
||||
OnKeyPress(e);
|
||||
Game.Sound.PlayNotification(ModRules, null, "Sounds", "ClickSound", null);
|
||||
if (!DisableKeySound)
|
||||
Game.Sound.PlayNotification(ModRules, null, "Sounds", "ClickSound", null);
|
||||
}
|
||||
else
|
||||
else if (!DisableKeySound)
|
||||
Game.Sound.PlayNotification(ModRules, null, "Sounds", "ClickDisabledSound", null);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public override bool HandleMouseInput(MouseInput mi)
|
||||
{
|
||||
if (mi.Event != MouseInputEvent.Down && mi.Event != MouseInputEvent.Up)
|
||||
if (mi.Event == MouseInputEvent.Move)
|
||||
return false;
|
||||
|
||||
if (mi.Event == MouseInputEvent.Down)
|
||||
|
||||
@@ -165,6 +165,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
InitializeActorPreviews();
|
||||
};
|
||||
|
||||
searchTextField.OnEscKey = () =>
|
||||
{
|
||||
searchTextField.Text = "";
|
||||
searchTextField.YieldKeyboardFocus();
|
||||
return true;
|
||||
};
|
||||
|
||||
var actorCategorySelector = widget.Get<DropDownButtonWidget>("CATEGORIES_DROPDOWN");
|
||||
actorCategorySelector.GetText = () =>
|
||||
{
|
||||
|
||||
@@ -73,6 +73,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
InitializeTilePreview();
|
||||
};
|
||||
|
||||
searchTextField.OnEscKey = () =>
|
||||
{
|
||||
searchTextField.Text = "";
|
||||
searchTextField.YieldKeyboardFocus();
|
||||
return true;
|
||||
};
|
||||
|
||||
Func<string, string> categoryTitle = s => s != null ? s : "Search Results";
|
||||
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) =>
|
||||
{
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var color = message.Type == ChatMessageType.Notification ? ChromeMetrics.Get<Color>("GlobalChatNotificationColor")
|
||||
: ChromeMetrics.Get<Color>("GlobalChatPlayerNameColor");
|
||||
var template = (ContainerWidget)chatTemplate.Clone();
|
||||
LobbyUtils.SetupChatLine(template, color, from, message.Message);
|
||||
LobbyUtils.SetupChatLine(template, color, message.Time, from, message.Message);
|
||||
|
||||
template.Id = message.UID;
|
||||
return template;
|
||||
|
||||
@@ -10,13 +10,10 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Orders;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
@@ -55,17 +52,21 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
attackMoveButton.GetKey = _ => ks.AttackMoveKey;
|
||||
attackMoveButton.IsDisabled = () => { UpdateStateIfNecessary(); return attackMoveDisabled; };
|
||||
attackMoveButton.IsHighlighted = () => world.OrderGenerator is GenericSelectTarget
|
||||
&& ((GenericSelectTarget)world.OrderGenerator).OrderName == "AttackMove";
|
||||
attackMoveButton.IsHighlighted = () => world.OrderGenerator is AttackMoveOrderGenerator;
|
||||
|
||||
attackMoveButton.OnClick = () =>
|
||||
Action<bool> toggle = allowCancel =>
|
||||
{
|
||||
if (attackMoveButton.IsHighlighted())
|
||||
world.CancelInputMode();
|
||||
{
|
||||
if (allowCancel)
|
||||
world.CancelInputMode();
|
||||
}
|
||||
else
|
||||
world.OrderGenerator = new GenericSelectTarget(selectedActors,
|
||||
"AttackMove", "attackmove", Game.Settings.Game.MouseButtonPreference.Action);
|
||||
world.OrderGenerator = new AttackMoveOrderGenerator(selectedActors, Game.Settings.Game.MouseButtonPreference.Action);
|
||||
};
|
||||
|
||||
attackMoveButton.OnClick = () => toggle(true);
|
||||
attackMoveButton.OnKeyPress = _ => toggle(false);
|
||||
}
|
||||
|
||||
var forceMoveButton = widget.GetOrNull<ButtonWidget>("FORCE_MOVE");
|
||||
@@ -90,7 +91,9 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
BindButtonIcon(forceAttackButton);
|
||||
|
||||
forceAttackButton.IsDisabled = () => { UpdateStateIfNecessary(); return forceAttackDisabled; };
|
||||
forceAttackButton.IsHighlighted = () => !forceAttackButton.IsDisabled() && IsForceModifiersActive(Modifiers.Ctrl);
|
||||
forceAttackButton.IsHighlighted = () => !forceAttackButton.IsDisabled() && IsForceModifiersActive(Modifiers.Ctrl)
|
||||
&& !(world.OrderGenerator is AttackMoveOrderGenerator);
|
||||
|
||||
forceAttackButton.OnClick = () =>
|
||||
{
|
||||
if (forceAttackButton.IsHighlighted())
|
||||
@@ -110,14 +113,20 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
guardButton.IsHighlighted = () => world.OrderGenerator is GenericSelectTarget
|
||||
&& ((GenericSelectTarget)world.OrderGenerator).OrderName == "Guard";
|
||||
|
||||
guardButton.OnClick = () =>
|
||||
Action<bool> toggle = allowCancel =>
|
||||
{
|
||||
if (guardButton.IsHighlighted())
|
||||
world.CancelInputMode();
|
||||
{
|
||||
if (allowCancel)
|
||||
world.CancelInputMode();
|
||||
}
|
||||
else
|
||||
world.OrderGenerator = new GuardOrderGenerator(selectedActors,
|
||||
"Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action);
|
||||
};
|
||||
|
||||
guardButton.OnClick = () => toggle(true);
|
||||
guardButton.OnKeyPress = _ => toggle(false);
|
||||
}
|
||||
|
||||
var scatterButton = widget.GetOrNull<ButtonWidget>("SCATTER");
|
||||
@@ -171,6 +180,23 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Shift, false);
|
||||
};
|
||||
}
|
||||
|
||||
var keyOverrides = widget.GetOrNull<LogicKeyListenerWidget>("MODIFIER_OVERRIDES");
|
||||
if (keyOverrides != null)
|
||||
{
|
||||
keyOverrides.OnKeyPress = ki =>
|
||||
{
|
||||
// HACK: enable attack move to be triggered if the ctrl key is pressed
|
||||
var modified = new Hotkey(ki.Key, ki.Modifiers & ~Modifiers.Ctrl);
|
||||
if (!attackMoveDisabled && attackMoveButton.Key == modified)
|
||||
{
|
||||
attackMoveButton.OnKeyPress(ki);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override void Tick()
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var keyhandler = shroudSelector.Get<LogicKeyListenerWidget>("SHROUD_KEYHANDLER");
|
||||
keyhandler.OnKeyPress = HandleKeyPress;
|
||||
|
||||
selected = limitViews ? groups.First().Value.First() : disableShroud;
|
||||
selected = limitViews ? groups.First().Value.First() : world.WorldActor.Owner.Shroud.ExploreMapEnabled ? combined : disableShroud;
|
||||
selected.OnClick();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
widget.IsVisible = () => (orderManager.LobbyInfo.ClientWithIndex(clientIndex) != null);
|
||||
tooltipContainer.BeforeRender = () =>
|
||||
{
|
||||
if (!widget.IsVisible())
|
||||
return;
|
||||
|
||||
var latencyPrefixSize = latencyPrefix == null ? 0 : latencyPrefix.Bounds.X + latencyPrefixFont.Measure(latencyPrefix.GetText() + " ").X;
|
||||
var locationWidth = locationFont.Measure(location.GetText()).X;
|
||||
var adminWidth = adminFont.Measure(admin.GetText()).X;
|
||||
|
||||
@@ -567,7 +567,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
lobbyChatUnreadMessages += 1;
|
||||
|
||||
var template = (ContainerWidget)chatTemplate.Clone();
|
||||
LobbyUtils.SetupChatLine(template, c, from, text);
|
||||
LobbyUtils.SetupChatLine(template, c, DateTime.Now, from, text);
|
||||
|
||||
var scrolledToBottom = lobbyChatPanel.ScrolledToBottom;
|
||||
lobbyChatPanel.AddChild(template);
|
||||
|
||||
@@ -542,7 +542,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
return address;
|
||||
}
|
||||
|
||||
public static void SetupChatLine(ContainerWidget template, Color c, string from, string text)
|
||||
public static void SetupChatLine(ContainerWidget template, Color c, DateTime time, string from, string text)
|
||||
{
|
||||
var nameLabel = template.Get<LabelWidget>("NAME");
|
||||
var timeLabel = template.Get<LabelWidget>("TIME");
|
||||
@@ -552,7 +552,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var font = Game.Renderer.Fonts[nameLabel.Font];
|
||||
var nameSize = font.Measure(from);
|
||||
|
||||
var time = DateTime.Now;
|
||||
timeLabel.GetText = () => "{0:D2}:{1:D2}".F(time.Hour, time.Minute);
|
||||
|
||||
nameLabel.GetColor = () => c;
|
||||
|
||||
@@ -13,6 +13,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@@ -37,7 +38,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
static bool fetchedNews;
|
||||
|
||||
// Increment the version number when adding new stats
|
||||
const int SystemInformationVersion = 2;
|
||||
const int SystemInformationVersion = 3;
|
||||
Dictionary<string, Pair<string, string>> GetSystemInformation()
|
||||
{
|
||||
var lang = System.Globalization.CultureInfo.InstalledUICulture.TwoLetterISOLanguageName;
|
||||
@@ -47,10 +48,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{ "platform", Pair.New("OS Type", Platform.CurrentPlatform.ToString()) },
|
||||
{ "os", Pair.New("OS Version", Environment.OSVersion.ToString()) },
|
||||
{ "x64", Pair.New("OS is 64 bit", Environment.Is64BitOperatingSystem.ToString()) },
|
||||
{ "x64process", Pair.New("Process is 64 bit", Environment.Is64BitProcess.ToString()) },
|
||||
{ "runtime", Pair.New(".NET Runtime", Platform.RuntimeVersion) },
|
||||
{ "gl", Pair.New("OpenGL Version", Game.Renderer.GLVersion) },
|
||||
{ "windowsize", Pair.New("Window Size", "{0}x{1}".F(Game.Renderer.Resolution.Width, Game.Renderer.Resolution.Height)) },
|
||||
{ "windowscale", Pair.New("Window Scale", Game.Renderer.WindowScale.ToString("F2")) },
|
||||
{ "windowscale", Pair.New("Window Scale", Game.Renderer.WindowScale.ToString("F2", CultureInfo.InvariantCulture)) },
|
||||
{ "lang", Pair.New("System Language", lang) }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
if (item != null && item.Done && actor.HasTraitInfo<BuildingInfo>())
|
||||
{
|
||||
World.OrderGenerator = new PlaceBuildingOrderGenerator(CurrentQueue, icon.Name);
|
||||
World.OrderGenerator = new PlaceBuildingOrderGenerator(CurrentQueue, icon.Name, worldRenderer);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,6 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
public FrozenActor FrozenActorTooltip { get; private set; }
|
||||
public ResourceType ResourceTooltip { get; private set; }
|
||||
|
||||
public int EdgeScrollThreshold = 5;
|
||||
|
||||
int2? joystickScrollStart, joystickScrollEnd;
|
||||
int2? standardScrollStart;
|
||||
bool isStandardScrolling;
|
||||
@@ -308,7 +306,12 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
if (scrollType == MouseScrollType.Standard || scrollType == MouseScrollType.Inverted)
|
||||
{
|
||||
if (mi.Event == MouseInputEvent.Down && !isStandardScrolling)
|
||||
{
|
||||
if (!TakeMouseFocus(mi))
|
||||
return false;
|
||||
|
||||
standardScrollStart = mi.Location;
|
||||
}
|
||||
else if (mi.Event == MouseInputEvent.Move && (isStandardScrolling ||
|
||||
(standardScrollStart.HasValue && ((standardScrollStart.Value - mi.Location).Length > Game.Settings.Game.MouseScrollDeadzone))))
|
||||
{
|
||||
@@ -322,6 +325,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var wasStandardScrolling = isStandardScrolling;
|
||||
isStandardScrolling = false;
|
||||
standardScrollStart = null;
|
||||
YieldMouseFocus(mi);
|
||||
|
||||
if (wasStandardScrolling)
|
||||
return true;
|
||||
@@ -335,6 +339,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
if (!TakeMouseFocus(mi))
|
||||
return false;
|
||||
|
||||
joystickScrollStart = mi.Location;
|
||||
}
|
||||
|
||||
@@ -474,14 +479,15 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
ScrollDirection CheckForDirections()
|
||||
{
|
||||
var margin = Game.Settings.Game.ViewportEdgeScrollMargin;
|
||||
var directions = ScrollDirection.None;
|
||||
if (Viewport.LastMousePos.X < EdgeScrollThreshold)
|
||||
if (Viewport.LastMousePos.X < margin)
|
||||
directions |= ScrollDirection.Left;
|
||||
if (Viewport.LastMousePos.Y < EdgeScrollThreshold)
|
||||
if (Viewport.LastMousePos.Y < margin)
|
||||
directions |= ScrollDirection.Up;
|
||||
if (Viewport.LastMousePos.X >= Game.Renderer.Resolution.Width - EdgeScrollThreshold)
|
||||
if (Viewport.LastMousePos.X >= Game.Renderer.Resolution.Width - margin)
|
||||
directions |= ScrollDirection.Right;
|
||||
if (Viewport.LastMousePos.Y >= Game.Renderer.Resolution.Height - EdgeScrollThreshold)
|
||||
if (Viewport.LastMousePos.Y >= Game.Renderer.Resolution.Height - margin)
|
||||
directions |= ScrollDirection.Down;
|
||||
|
||||
return directions;
|
||||
|
||||
@@ -32,8 +32,11 @@ namespace OpenRA.Mods.Common
|
||||
// Then we iterate over this list, and find all actors for which their health radius is at least within lineWidth of the line.
|
||||
// For actors without a health radius, we simply check their center point.
|
||||
// The square in which we select all actors must be large enough to encompass the entire line's width.
|
||||
var xDir = Math.Sign(lineEnd.X - lineStart.X);
|
||||
var yDir = Math.Sign(lineEnd.Y - lineStart.Y);
|
||||
// xDir and yDir must never be 0, otherwise the overscan will be 0 in the respective direction.
|
||||
var xDiff = lineEnd.X - lineStart.X;
|
||||
var yDiff = lineEnd.Y - lineStart.Y;
|
||||
var xDir = xDiff < 0 ? -1 : 1;
|
||||
var yDir = yDiff < 0 ? -1 : 1;
|
||||
|
||||
var dir = new WVec(xDir, yDir, 0);
|
||||
var overselect = dir * (1024 + lineWidth.Length + targetExtraSearchRadius.Length);
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace OpenRA.Platforms.Default
|
||||
}
|
||||
|
||||
// A null indicates termination of that string, so add that to our list.
|
||||
devices.Add(Encoding.Default.GetString(buffer.ToArray()));
|
||||
devices.Add(Encoding.UTF8.GetString(buffer.ToArray()));
|
||||
buffer.Clear();
|
||||
|
||||
// Two successive nulls indicates the end of the list.
|
||||
@@ -266,7 +266,7 @@ namespace OpenRA.Platforms.Default
|
||||
slot.FrameStarted = currFrame;
|
||||
slot.IsRelative = relative;
|
||||
slot.SoundSource = null;
|
||||
slot.Sound = new OpenAlStreamingSound(source, loop, relative, pos, volume, channels, sampleBits, sampleRate, stream);
|
||||
slot.Sound = new OpenAlAsyncLoadSound(source, loop, relative, pos, volume, channels, sampleBits, sampleRate, stream);
|
||||
return slot.Sound;
|
||||
}
|
||||
|
||||
@@ -282,25 +282,33 @@ namespace OpenRA.Platforms.Default
|
||||
return;
|
||||
|
||||
var source = ((OpenAlSound)sound).Source;
|
||||
int state;
|
||||
AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE, out state);
|
||||
if (state == AL10.AL_PLAYING && paused)
|
||||
AL10.alSourcePause(source);
|
||||
else if (state == AL10.AL_PAUSED && !paused)
|
||||
AL10.alSourcePlay(source);
|
||||
PauseSound(source, paused);
|
||||
}
|
||||
|
||||
public void SetAllSoundsPaused(bool paused)
|
||||
{
|
||||
foreach (var source in sourcePool.Keys)
|
||||
PauseSound(source, paused);
|
||||
}
|
||||
|
||||
void PauseSound(uint source, bool paused)
|
||||
{
|
||||
int state;
|
||||
AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE, out state);
|
||||
if (paused)
|
||||
{
|
||||
int state;
|
||||
AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE, out state);
|
||||
if (state == AL10.AL_PLAYING && paused)
|
||||
if (state == AL10.AL_PLAYING)
|
||||
AL10.alSourcePause(source);
|
||||
else if (state == AL10.AL_PAUSED && !paused)
|
||||
else if (state == AL10.AL_INITIAL)
|
||||
{
|
||||
// If a sound hasn't started yet,
|
||||
// we indicate it should not play be transitioning it to the stopped state.
|
||||
AL10.alSourcePlay(source);
|
||||
AL10.alSourceStop(source);
|
||||
}
|
||||
}
|
||||
else if (!paused && state != AL10.AL_PLAYING)
|
||||
AL10.alSourcePlay(source);
|
||||
}
|
||||
|
||||
public void SetSoundVolume(float volume, ISound music, ISound video)
|
||||
@@ -483,149 +491,99 @@ namespace OpenRA.Platforms.Default
|
||||
}
|
||||
}
|
||||
|
||||
class OpenAlStreamingSound : OpenAlSound
|
||||
class OpenAlAsyncLoadSound : OpenAlSound
|
||||
{
|
||||
const int BufferCount = 3;
|
||||
const int BufferSizeInSecs = 1;
|
||||
readonly object bufferDequeueLock = new object();
|
||||
static readonly byte[] SilentData = new byte[2];
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
readonly Task streamTask;
|
||||
readonly Stack<uint> freeBuffers = new Stack<uint>(BufferCount);
|
||||
int totalSamplesPlayed;
|
||||
readonly Task playTask;
|
||||
|
||||
public OpenAlStreamingSound(uint source, bool looping, bool relative, WPos pos, float volume, int channels, int sampleBits, int sampleRate, Stream stream)
|
||||
public OpenAlAsyncLoadSound(uint source, bool looping, bool relative, WPos pos, float volume, int channels, int sampleBits, int sampleRate, Stream stream)
|
||||
: base(source, looping, relative, pos, volume, sampleRate)
|
||||
{
|
||||
streamTask = Task.Run(async () =>
|
||||
// Load a silent buffer into the source. Without this,
|
||||
// attempting to change the state (i.e. play/pause) the source fails on some systems.
|
||||
var silentSource = new OpenAlSoundSource(SilentData, channels, sampleBits, sampleRate);
|
||||
AL10.alSourcei(source, AL10.AL_BUFFER, (int)silentSource.Buffer);
|
||||
|
||||
playTask = Task.Run(async () =>
|
||||
{
|
||||
var format = OpenAlSoundEngine.MakeALFormat(channels, sampleBits);
|
||||
var bytesPerSample = sampleBits / 8;
|
||||
|
||||
var buffers = new uint[BufferCount];
|
||||
AL10.alGenBuffers(new IntPtr(buffers.Length), buffers);
|
||||
try
|
||||
MemoryStream memoryStream;
|
||||
using (stream)
|
||||
{
|
||||
foreach (var buffer in buffers)
|
||||
freeBuffers.Push(buffer);
|
||||
var data = new byte[sampleRate * bytesPerSample * BufferSizeInSecs];
|
||||
var streamEnd = false;
|
||||
|
||||
while (!streamEnd && !cts.IsCancellationRequested)
|
||||
memoryStream = new MemoryStream();
|
||||
try
|
||||
{
|
||||
// Fill the data array as fully as possible.
|
||||
var count = await ReadFillingBuffer(stream, data);
|
||||
streamEnd = count < data.Length;
|
||||
await stream.CopyToAsync(memoryStream, 81920, cts.Token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Sound was stopped early, cleanup the unused buffer and exit.
|
||||
AL10.alSourceStop(source);
|
||||
AL10.alSourcei(source, AL10.AL_BUFFER, 0);
|
||||
silentSource.Dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill a buffer and queue it for playback.
|
||||
var nextBuffer = freeBuffers.Pop();
|
||||
AL10.alBufferData(nextBuffer, format, data, new IntPtr(count), new IntPtr(sampleRate));
|
||||
AL10.alSourceQueueBuffers(source, new IntPtr(1), ref nextBuffer);
|
||||
var data = memoryStream.ToArray();
|
||||
var bytesPerSample = sampleBits / 8f;
|
||||
var lengthInSecs = data.Length / (channels * bytesPerSample * sampleRate);
|
||||
using (var soundSource = new OpenAlSoundSource(data, channels, sampleBits, sampleRate))
|
||||
{
|
||||
// Need to stop the source, before attaching the real input and deleting the silent one.
|
||||
AL10.alSourceStop(source);
|
||||
AL10.alSourcei(source, AL10.AL_BUFFER, (int)soundSource.Buffer);
|
||||
silentSource.Dispose();
|
||||
|
||||
lock (cts)
|
||||
lock (cts)
|
||||
{
|
||||
if (!cts.IsCancellationRequested)
|
||||
{
|
||||
if (!cts.IsCancellationRequested)
|
||||
// TODO: A race condition can happen between the state check and playing/rewinding if a
|
||||
// user pauses/resumes at the right moment. The window of opportunity is small and the
|
||||
// consequences are minor, so for now we'll ignore it.
|
||||
int state;
|
||||
AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out state);
|
||||
if (state != AL10.AL_STOPPED)
|
||||
AL10.alSourcePlay(source);
|
||||
else
|
||||
{
|
||||
// Once we have at least one buffer filled, we can actually start.
|
||||
// If streaming fell behind, the source will have stopped,
|
||||
// we also need to play it in this case to resume audio.
|
||||
int state;
|
||||
AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE, out state);
|
||||
if (state == AL10.AL_INITIAL || state == AL10.AL_STOPPED)
|
||||
{
|
||||
// If we resume playback from the stopped state, it resets to the beginning!
|
||||
// To avoid replaying the same audio, we need to dequeue the processed buffers first.
|
||||
if (state == AL10.AL_STOPPED)
|
||||
DequeueBuffers();
|
||||
|
||||
AL10.alSourcePlay(source);
|
||||
}
|
||||
// A stopped sound indicates it was paused before we finishing loaded.
|
||||
// We don't want to start playing it right away.
|
||||
// We rewind the source so when it is started, it plays from the beginning.
|
||||
AL10.alSourceRewind(source);
|
||||
}
|
||||
}
|
||||
|
||||
// Try and dequeue buffers as they become available to be reused.
|
||||
// When the stream ends, wait for all the buffers to be processed
|
||||
while (freeBuffers.Count < (streamEnd ? buffers.Length : 1))
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(BufferSizeInSecs), cts.Token).ConfigureAwait(false);
|
||||
DequeueBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Streaming has been cancelled, we'll need to perform some cleanup.
|
||||
}
|
||||
finally
|
||||
{
|
||||
// If we never actually started the source, we need to start it and then stop it.
|
||||
// Otherwise it is left in the initial state and never returned to the source pool.
|
||||
int state;
|
||||
AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out state);
|
||||
if (state == AL10.AL_INITIAL)
|
||||
AL10.alSourcePlay(Source);
|
||||
|
||||
// Ensure the source is stopped, which will mark all buffers as processed.
|
||||
// Dequeue these, so they can then be freed.
|
||||
AL10.alSourceStop(Source);
|
||||
lock (bufferDequeueLock)
|
||||
while (!cts.IsCancellationRequested)
|
||||
{
|
||||
int buffersProcessed;
|
||||
AL10.alGetSourcei(source, AL10.AL_BUFFERS_PROCESSED, out buffersProcessed);
|
||||
for (var i = 0; i < buffersProcessed; i++)
|
||||
// Need to check seek before state. Otherwise, the music can stop after our state check at
|
||||
// which point the seek will be zero, meaning we'll wait the full track length before seeing it
|
||||
// has stopped.
|
||||
var currentSeek = SeekPosition;
|
||||
|
||||
int state;
|
||||
AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out state);
|
||||
if (state == AL10.AL_STOPPED)
|
||||
break;
|
||||
|
||||
try
|
||||
{
|
||||
var dequeued = 0U;
|
||||
AL10.alSourceUnqueueBuffers(source, new IntPtr(1), ref dequeued);
|
||||
// Wait until the track is due to complete, and at most 60 times a second to prevent a
|
||||
// busy-wait.
|
||||
var delaySecs = Math.Max(lengthInSecs - currentSeek, 1 / 60f);
|
||||
await Task.Delay(TimeSpan.FromSeconds(delaySecs), cts.Token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Sound was stopped early, allow normal cleanup to occur.
|
||||
}
|
||||
}
|
||||
|
||||
AL10.alDeleteBuffers(new IntPtr(buffers.Length), buffers);
|
||||
stream.Dispose();
|
||||
AL10.alSourcei(Source, AL10.AL_BUFFER, 0);
|
||||
}
|
||||
}).ContinueWith(task =>
|
||||
{
|
||||
Game.RunAfterTick(() =>
|
||||
{
|
||||
throw new Exception("Failed to stream a sound.", task.Exception);
|
||||
});
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
|
||||
async Task<int> ReadFillingBuffer(Stream stream, byte[] buffer)
|
||||
{
|
||||
var offset = 0;
|
||||
int count;
|
||||
while (offset < buffer.Length &&
|
||||
(count = await stream.ReadAsync(buffer, offset, buffer.Length - offset, cts.Token).ConfigureAwait(false)) > 0)
|
||||
offset += count;
|
||||
return offset;
|
||||
}
|
||||
|
||||
void DequeueBuffers()
|
||||
{
|
||||
lock (bufferDequeueLock)
|
||||
{
|
||||
// Check for any processed buffers, and dequeue them for reuse.
|
||||
int buffersProcessed;
|
||||
AL10.alGetSourcei(Source, AL10.AL_BUFFERS_PROCESSED, out buffersProcessed);
|
||||
for (var i = 0; i < buffersProcessed; i++)
|
||||
{
|
||||
// Dequeue a processed buffer, so we can reuse it.
|
||||
var dequeued = 0U;
|
||||
AL10.alSourceUnqueueBuffers(Source, new IntPtr(1), ref dequeued);
|
||||
freeBuffers.Push(dequeued);
|
||||
|
||||
// When we remove a buffer, we need to account for this to calculate the overall seek position.
|
||||
// The final buffer in the track may be shorter then BufferSizeInSecs, so we'll need to check how
|
||||
// many bytes are actually in each buffer to avoid adding too much at the end.
|
||||
int byteSize;
|
||||
AL10.alGetBufferi(dequeued, AL10.AL_SIZE, out byteSize);
|
||||
|
||||
int bitRate;
|
||||
AL10.alGetBufferi(dequeued, AL10.AL_BITS, out bitRate);
|
||||
|
||||
totalSamplesPlayed += byteSize / (bitRate / 8);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
@@ -638,41 +596,16 @@ namespace OpenRA.Platforms.Default
|
||||
|
||||
try
|
||||
{
|
||||
streamTask.Wait();
|
||||
playTask.Wait();
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public override float SeekPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
// Stop buffers being dequeued whilst we calculate the seek position.
|
||||
lock (bufferDequeueLock)
|
||||
{
|
||||
int sampleOffset;
|
||||
AL10.alGetSourcei(Source, AL11.AL_SAMPLE_OFFSET, out sampleOffset);
|
||||
|
||||
int state;
|
||||
AL10.alGetSourcei(Source, AL10.AL_SOURCE_STATE, out state);
|
||||
|
||||
// If the source is not stopped, add the current offset to the total offset and return that.
|
||||
if (state != AL10.AL_STOPPED)
|
||||
return (sampleOffset + totalSamplesPlayed) / SampleRate;
|
||||
|
||||
// If the source stopped, the current offset will have been reset to 0.
|
||||
// We'll need to dequeue any buffers played first and then return the total.
|
||||
DequeueBuffers();
|
||||
return totalSamplesPlayed / SampleRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Complete
|
||||
{
|
||||
get { return streamTask.IsCompleted; }
|
||||
get { return playTask.IsCompleted; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
make.ps1
1
make.ps1
@@ -193,6 +193,7 @@ function Docs-Command
|
||||
{
|
||||
./make.ps1 version
|
||||
./OpenRA.Utility.exe all --docs | Out-File -Encoding "UTF8" DOCUMENTATION.md
|
||||
./OpenRA.Utility.exe all --weapon-docs | Out-File -Encoding "UTF8" WEAPONS.md
|
||||
./OpenRA.Utility.exe all --lua-docs | Out-File -Encoding "UTF8" Lua-API.md
|
||||
}
|
||||
else
|
||||
|
||||
Binary file not shown.
@@ -264,16 +264,18 @@ Container@PLAYER_WIDGETS:
|
||||
Width: 276
|
||||
Height: 36
|
||||
Children:
|
||||
LogicKeyListener@MODIFIER_OVERRIDES:
|
||||
Button@ATTACK_MOVE:
|
||||
X: 1
|
||||
Y: 1
|
||||
Width: 34
|
||||
Height: 34
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Attack Move
|
||||
TooltipDesc: Selected units will move to the desired location\nand attack any enemies they encounter en route.\n\nLeft-click icon then right-click on target location.
|
||||
TooltipDesc: Selected units will move to the desired location\nand attack any enemies they encounter en route.\n\nHold {(Ctrl)} while targeting to order an Assault Move\nthat attacks any units or structures encountered en route.\n\nLeft-click icon then right-click on target location.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
TooltipTemplate: BUTTON_WITH_DESC_HIGHLIGHT_TOOLTIP
|
||||
Children:
|
||||
Image@ICON:
|
||||
X: 5
|
||||
@@ -286,6 +288,7 @@ Container@PLAYER_WIDGETS:
|
||||
Width: 34
|
||||
Height: 34
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Force Move
|
||||
TooltipDesc: Selected units will move to the desired location\n - Default activity for the target is suppressed\n - Vehicles will attempt to crush enemies at the target location\n - Units entering transports will consider nearby alternatives\n\nLeft-click icon then right-click on target.\nHold {(Alt)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -302,6 +305,7 @@ Container@PLAYER_WIDGETS:
|
||||
Width: 34
|
||||
Height: 34
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Force Attack
|
||||
TooltipDesc: Selected units will attack the targeted unit or location\nignoring their default activity for the target.\n\nLeft-click icon then right-click on target.\nHold {(Ctrl)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -318,7 +322,7 @@ Container@PLAYER_WIDGETS:
|
||||
Width: 34
|
||||
Height: 34
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Guard
|
||||
TooltipDesc: Selected units will follow the targeted unit.\n\nLeft-click icon then right-click on target unit.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -335,6 +339,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 34
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Deploy
|
||||
TooltipDesc: Selected units will perform their default deploy activity\n - MCVs will unpack into a Construction Yard\n - Construction Yards will re-pack into a MCV\n - Transports will unload their passengers\n - Helicopters will return to base\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -351,6 +356,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 34
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Scatter
|
||||
TooltipDesc: Selected units will stop their current activity\nand move to a nearby location.\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -367,6 +373,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 34
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Stop
|
||||
TooltipDesc: Selected units will stop their current activity.\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -382,6 +389,7 @@ Container@PLAYER_WIDGETS:
|
||||
Width: 34
|
||||
Height: 34
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Waypoint Mode
|
||||
TooltipDesc: Use Waypoint Mode to give multiple linking commands\nto the selected units. Units will execute the commands\nimmediately upon receiving them.\n\nLeft-click icon then give commands in the game world.\nHold {(Shift)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -407,6 +415,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 26
|
||||
Background: stance-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Attack Anything Stance
|
||||
TooltipDesc: Set the selected units to Attack Anything stance:\n - Units will attack enemy units and structures on sight\n - Units will pursue attackers across the battlefield
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -423,6 +432,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 26
|
||||
Background: stance-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Defend Stance
|
||||
TooltipDesc: Set the selected units to Defend stance:\n - Units will attack enemy units on sight\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -439,6 +449,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 26
|
||||
Background: stance-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Return Fire Stance
|
||||
TooltipDesc: Set the selected units to Return Fire stance:\n - Units will retaliate against enemies that attack them\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -455,6 +466,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 26
|
||||
Background: stance-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Hold Fire Stance
|
||||
TooltipDesc: Set the selected units to Hold Fire stance:\n - Units will not fire upon enemies\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
|
||||
@@ -155,23 +155,41 @@ Cursors:
|
||||
move:
|
||||
Start: 0
|
||||
Length: 8
|
||||
move-minimap:
|
||||
Start: 8
|
||||
Length: 4
|
||||
move-rough:
|
||||
Start: 0
|
||||
Length: 8
|
||||
move-minimap:
|
||||
Start: 8
|
||||
Length: 4
|
||||
attackmove:
|
||||
Start: 12
|
||||
Length: 8
|
||||
attackmove-minimap:
|
||||
Start: 20
|
||||
Length: 4
|
||||
move-blocked:
|
||||
assaultmove:
|
||||
Start: 24
|
||||
Length: 8
|
||||
assaultmove-minimap:
|
||||
Start: 32
|
||||
Length: 4
|
||||
move-blocked:
|
||||
Start: 36
|
||||
Length: 1
|
||||
attackmove-blocked:
|
||||
Start: 37
|
||||
Length: 1
|
||||
assaultmove-blocked:
|
||||
Start: 38
|
||||
Length: 1
|
||||
move-blocked-minimap:
|
||||
Start: 25
|
||||
Start: 39
|
||||
Length: 1
|
||||
attackmove-blocked-minimap:
|
||||
Start: 39
|
||||
Length: 1
|
||||
assaultmove-blocked-minimap:
|
||||
Start: 40
|
||||
Length: 1
|
||||
mouse5.shp: cursor
|
||||
guard:
|
||||
|
||||
@@ -74,8 +74,8 @@ RMBO:
|
||||
MustBeDestroyed:
|
||||
RequiredForShortGame: true
|
||||
AutoTarget:
|
||||
TargetWhenIdle: false
|
||||
TargetWhenDamaged: true
|
||||
EnableStances: false
|
||||
InitialStance: ReturnFire
|
||||
Health:
|
||||
HP: 150
|
||||
|
||||
|
||||
@@ -155,3 +155,4 @@ ORCA.IN:
|
||||
-AutoTarget:
|
||||
-AutoTargetPriority@DEFAULT:
|
||||
-AutoTargetPriority@ATTACKANYTHING:
|
||||
-AttackMove:
|
||||
|
||||
@@ -37,6 +37,7 @@ UNITCRATE:
|
||||
Units: e3
|
||||
|
||||
APC:
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Health:
|
||||
HP: 1000
|
||||
MustBeDestroyed:
|
||||
|
||||
@@ -54,7 +54,7 @@ TRAN:
|
||||
HELI:
|
||||
Inherits: ^Helicopter
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove
|
||||
Valued:
|
||||
Cost: 1200
|
||||
Tooltip:
|
||||
@@ -113,7 +113,7 @@ HELI:
|
||||
ORCA:
|
||||
Inherits: ^Helicopter
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove
|
||||
Valued:
|
||||
Cost: 1200
|
||||
Tooltip:
|
||||
|
||||
@@ -50,6 +50,6 @@ airstrike.proxy:
|
||||
ClockSequence: clock
|
||||
CircleSequence: circles
|
||||
|
||||
TDTRUK:
|
||||
TRUCK:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
@@ -159,6 +159,15 @@
|
||||
ValidTargets: Infantry, Vehicle, Creep, Water, Structure, Defense
|
||||
InvalidTargets: NoAutoTarget
|
||||
|
||||
^AutoTargetGroundAssaultMove:
|
||||
Inherits: ^AutoTargetGround
|
||||
AutoTargetPriority@DEFAULT:
|
||||
RequiresCondition: !stance-attackanything && !assault-move
|
||||
AutoTargetPriority@ATTACKANYTHING:
|
||||
RequiresCondition: stance-attackanything || assault-move
|
||||
AttackMove:
|
||||
AssaultMoveScanCondition: assault-move
|
||||
|
||||
^AutoTargetAir:
|
||||
AutoTarget:
|
||||
AutoTargetPriority@DEFAULT:
|
||||
@@ -177,6 +186,15 @@
|
||||
ValidTargets: Infantry, Vehicle, Creep, Water, Air, Structure, Defense
|
||||
InvalidTargets: NoAutoTarget
|
||||
|
||||
^AutoTargetAllAssaultMove:
|
||||
Inherits: ^AutoTargetAll
|
||||
AutoTargetPriority@DEFAULT:
|
||||
RequiresCondition: !stance-attackanything && !assault-move
|
||||
AutoTargetPriority@ATTACKANYTHING:
|
||||
RequiresCondition: stance-attackanything || assault-move
|
||||
AttackMove:
|
||||
AssaultMoveScanCondition: assault-move
|
||||
|
||||
^AcceptsCloakCrate:
|
||||
Cloak:
|
||||
InitialDelay: 15
|
||||
@@ -455,7 +473,7 @@
|
||||
^DINO:
|
||||
Inherits@1: ^ExistsInWorld
|
||||
Inherits@2: ^SpriteActor
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Huntable:
|
||||
Health:
|
||||
HP: 1000
|
||||
@@ -516,7 +534,7 @@
|
||||
^Viceroid:
|
||||
Inherits@1: ^ExistsInWorld
|
||||
Inherits@2: ^SpriteActor
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Huntable:
|
||||
Health:
|
||||
HP: 300
|
||||
@@ -966,7 +984,9 @@
|
||||
RequiresForceFire: yes
|
||||
TargetTypes: Ground, Water
|
||||
Health:
|
||||
HP: 500
|
||||
HP: 600
|
||||
Armor:
|
||||
Type: Heavy
|
||||
SoundOnDamageTransition:
|
||||
DamagedSounds: xplos.aud
|
||||
DestroyedSounds: xplobig4.aud
|
||||
|
||||
@@ -133,3 +133,12 @@ STNK.Husk:
|
||||
IntoActor: stnk
|
||||
RenderSprites:
|
||||
Image: stnk.destroyed
|
||||
|
||||
TRUCK.Husk:
|
||||
Inherits: ^Husk
|
||||
Tooltip:
|
||||
Name: Supply Truck (Destroyed)
|
||||
TransformOnCapture:
|
||||
IntoActor: truck
|
||||
RenderSprites:
|
||||
Image: truck.destroyed
|
||||
@@ -1,13 +1,14 @@
|
||||
E1:
|
||||
Inherits: ^Soldier
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 100
|
||||
Tooltip:
|
||||
Name: Minigunner
|
||||
Buildable:
|
||||
BuildPaletteOrder: 10
|
||||
Prerequisites: barracks
|
||||
Queue: Infantry.GDI, Infantry.Nod
|
||||
Description: General-purpose infantry.\n Strong vs Infantry\n Weak vs Vehicles
|
||||
Mobile:
|
||||
@@ -26,7 +27,7 @@ E1:
|
||||
E2:
|
||||
Inherits: ^Soldier
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 160
|
||||
Tooltip:
|
||||
@@ -59,13 +60,14 @@ E2:
|
||||
E3:
|
||||
Inherits: ^Soldier
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove
|
||||
Valued:
|
||||
Cost: 300
|
||||
Tooltip:
|
||||
Name: Rocket Soldier
|
||||
Buildable:
|
||||
BuildPaletteOrder: 20
|
||||
Prerequisites: barracks
|
||||
Queue: Infantry.GDI, Infantry.Nod
|
||||
Description: Anti-tank/Anti-aircraft infantry. \n Strong vs Tanks, Aircraft\n Weak vs Infantry
|
||||
Mobile:
|
||||
@@ -87,7 +89,7 @@ E3:
|
||||
E4:
|
||||
Inherits: ^Soldier
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 200
|
||||
Tooltip:
|
||||
@@ -118,7 +120,7 @@ E4:
|
||||
E5:
|
||||
Inherits: ^Soldier
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 300
|
||||
Tooltip:
|
||||
@@ -160,10 +162,11 @@ E6:
|
||||
Name: Engineer
|
||||
Buildable:
|
||||
BuildPaletteOrder: 30
|
||||
Prerequisites: barracks
|
||||
Queue: Infantry.GDI, Infantry.Nod
|
||||
Description: Damages and captures enemy structures.\n Unarmed
|
||||
Mobile:
|
||||
Speed: 56
|
||||
Speed: 48
|
||||
Health:
|
||||
HP: 30
|
||||
Passenger:
|
||||
@@ -177,7 +180,7 @@ E6:
|
||||
RMBO:
|
||||
Inherits: ^Soldier
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 2000
|
||||
Tooltip:
|
||||
|
||||
@@ -776,6 +776,10 @@ SAM:
|
||||
Inherits@IDISABLE: ^DisabledOverlay
|
||||
Inherits@AUTOTARGET: ^AutoTargetAir
|
||||
Inherits@shape: ^2x1Shape
|
||||
HitShape:
|
||||
Type: Rectangle
|
||||
TopLeft: -768,-512
|
||||
BottomRight: 768,512
|
||||
Valued:
|
||||
Cost: 650
|
||||
Tooltip:
|
||||
@@ -928,7 +932,7 @@ ATWR:
|
||||
TurnSpeed: 255
|
||||
Offset: 128,128,384
|
||||
Armament@PRIMARY:
|
||||
Weapon: TowerMissle
|
||||
Weapon: TowerMissile
|
||||
LocalOffset: 256,128,0, 256,-128,0
|
||||
LocalYaw: -100,100
|
||||
Armament@SECONDARY:
|
||||
|
||||
@@ -82,7 +82,7 @@ APC:
|
||||
Inherits: ^Tank
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove
|
||||
Valued:
|
||||
Cost: 550
|
||||
Tooltip:
|
||||
@@ -132,7 +132,7 @@ ARTY:
|
||||
Inherits: ^Tank
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 600
|
||||
Tooltip:
|
||||
@@ -170,7 +170,7 @@ FTNK:
|
||||
Inherits: ^Tank
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 600
|
||||
Tooltip:
|
||||
@@ -205,7 +205,7 @@ BGGY:
|
||||
Inherits: ^Vehicle
|
||||
Inherits@@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 300
|
||||
Tooltip:
|
||||
@@ -241,7 +241,7 @@ BIKE:
|
||||
Inherits: ^Vehicle
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove
|
||||
Valued:
|
||||
Cost: 500
|
||||
Tooltip:
|
||||
@@ -279,7 +279,7 @@ JEEP:
|
||||
Inherits: ^Vehicle
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 400
|
||||
Tooltip:
|
||||
@@ -315,7 +315,7 @@ LTNK:
|
||||
Inherits: ^Tank
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 650
|
||||
Tooltip:
|
||||
@@ -354,7 +354,7 @@ MTNK:
|
||||
Inherits: ^Tank
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 800
|
||||
Tooltip:
|
||||
@@ -392,7 +392,7 @@ HTNK:
|
||||
Inherits: ^Tank
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove
|
||||
Valued:
|
||||
Cost: 1500
|
||||
Tooltip:
|
||||
@@ -443,7 +443,7 @@ MSAM:
|
||||
Inherits: ^Tank
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@CLOAK: ^AcceptsCloakCrate
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 1000
|
||||
Tooltip:
|
||||
@@ -525,7 +525,7 @@ MLRS:
|
||||
STNK:
|
||||
Inherits: ^Vehicle
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove
|
||||
Valued:
|
||||
Cost: 900
|
||||
Tooltip:
|
||||
@@ -586,12 +586,12 @@ MHQ:
|
||||
Buildable:
|
||||
Description: Mobile base of operations
|
||||
|
||||
TDTRUK:
|
||||
TRUCK:
|
||||
Inherits: ^Vehicle
|
||||
Buildable:
|
||||
Queue: Vehicle.GDI, Vehicle.Nod
|
||||
BuildPaletteOrder: 35
|
||||
Prerequisites: ~techlevel.low
|
||||
Prerequisites: vehicleproduction
|
||||
Description: Transports cash to other players.\n Unarmed
|
||||
Valued:
|
||||
Cost: 500
|
||||
@@ -610,3 +610,5 @@ TDTRUK:
|
||||
DeliversCash:
|
||||
Payload: 500
|
||||
PlayerExperience: 50
|
||||
SpawnActorOnDeath:
|
||||
Actor: TRUCK.Husk
|
||||
|
||||
@@ -337,8 +337,14 @@ apc.destroyed:
|
||||
Facings: 32
|
||||
ZOffset: -512
|
||||
|
||||
tdtruk:
|
||||
truck:
|
||||
idle:
|
||||
Facings: 32
|
||||
UseClassicFacingFudge: True
|
||||
icon: tdtrukicon
|
||||
icon: truckicon
|
||||
|
||||
truck.destroyed:
|
||||
idle: truck
|
||||
Facings: 32
|
||||
UseClassicFacingFudge: True
|
||||
ZOffset: -512
|
||||
|
||||
@@ -39,6 +39,8 @@ FlametankExplode:
|
||||
|
||||
HeliCrash:
|
||||
Inherits: ^DamagingExplosion
|
||||
Warhead@1Dam: SpreadDamage
|
||||
Damage: 100
|
||||
|
||||
HeliExplode:
|
||||
Warhead@1Dam: SpreadDamage
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
Damage: 35
|
||||
ValidTargets: Ground, Air
|
||||
Versus:
|
||||
None: 30
|
||||
None: 20
|
||||
Wood: 85
|
||||
Light: 100
|
||||
Heavy: 100
|
||||
@@ -89,7 +89,7 @@ OrcaAGMissiles:
|
||||
Damage: 28
|
||||
ValidTargets: Ground
|
||||
Versus:
|
||||
None: 50
|
||||
None: 30
|
||||
Wood: 100
|
||||
Light: 100
|
||||
Heavy: 75
|
||||
@@ -215,7 +215,7 @@ BoatMissile:
|
||||
VictimScanRadius: 0
|
||||
ValidTargets: Air
|
||||
|
||||
TowerMissle:
|
||||
TowerMissile:
|
||||
Inherits: ^MissileWeapon
|
||||
ReloadDelay: 15
|
||||
Range: 7c0
|
||||
|
||||
BIN
mods/d2k/bits/assaultmove.shp
Executable file
BIN
mods/d2k/bits/assaultmove.shp
Executable file
Binary file not shown.
BIN
mods/d2k/bits/attackmove.shp
Executable file
BIN
mods/d2k/bits/attackmove.shp
Executable file
Binary file not shown.
@@ -2,7 +2,6 @@ sidebar: chrome.png
|
||||
background-top: 0,0,226,295
|
||||
background-iconrow: 0,295,226,48
|
||||
background-bottom: 0,343,226,13
|
||||
background-supportoverlay: 236,212,60,48
|
||||
|
||||
sidebar-button: chrome.png
|
||||
background: 377,0,25,25
|
||||
|
||||
@@ -14,16 +14,6 @@ Container@PLAYER_WIDGETS:
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
ReadyText: READY
|
||||
HoldText: ON HOLD
|
||||
Container@PALETTE_FOREGROUND:
|
||||
Children:
|
||||
Image@ICON_TEMPLATE:
|
||||
X: 0 - 2
|
||||
Y: 0 - 2
|
||||
Width: 60
|
||||
Height: 48
|
||||
IgnoreMouseOver: true
|
||||
ImageCollection: sidebar
|
||||
ImageName: background-supportoverlay
|
||||
Image@COMMAND_BAR_BACKGROUND:
|
||||
X: 0
|
||||
Y: WINDOW_BOTTOM - HEIGHT
|
||||
@@ -38,15 +28,17 @@ Container@PLAYER_WIDGETS:
|
||||
Width: 275
|
||||
Height: 41
|
||||
Children:
|
||||
LogicKeyListener@MODIFIER_OVERRIDES:
|
||||
Button@ATTACK_MOVE:
|
||||
Width: 34
|
||||
Height: 41
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Attack Move
|
||||
TooltipDesc: Selected units will move to the desired location\nand attack any enemies they encounter en route.\n\nLeft-click icon then right-click on target location.
|
||||
TooltipDesc: Selected units will move to the desired location\nand attack any enemies they encounter en route.\n\nHold {(Ctrl)} while targeting to order an Assault Move\nthat attacks any units or structures encountered en route.\n\nLeft-click icon then right-click on target location.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
TooltipTemplate: BUTTON_WITH_DESC_HIGHLIGHT_TOOLTIP
|
||||
Children:
|
||||
Image@ICON:
|
||||
X: 4
|
||||
@@ -59,6 +51,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 41
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Force Move
|
||||
TooltipDesc: Selected units will move to the desired location\n - Default activity for the target is suppressed\n - Vehicles will attempt to crush enemies at the target location\n\nLeft-click icon then right-click on target.\nHold {(Alt)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -75,6 +68,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 41
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Force Attack
|
||||
TooltipDesc: Selected units will attack the targeted unit or location\nignoring their default activity for the target.\n\nLeft-click icon then right-click on target.\nHold {(Ctrl)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -91,7 +85,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 41
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Guard
|
||||
TooltipDesc: Selected units will follow the targeted unit.\n\nLeft-click icon then right-click on target unit.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -108,6 +102,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Deploy
|
||||
TooltipDesc: Selected units will perform their default deploy activity\n - MCVs will unpack into a Construction Yard\n - Thumpers will start or stop attracting worms\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -124,6 +119,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Scatter
|
||||
TooltipDesc: Selected units will stop their current activity\nand move to a nearby location.\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -140,6 +136,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Stop
|
||||
TooltipDesc: Selected units will stop their current activity.\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -155,6 +152,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 41
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Waypoint Mode
|
||||
TooltipDesc: Use Waypoint Mode to give multiple linking commands\nto the selected units. Units will execute the commands\nimmediately upon receiving them.\n\nLeft-click icon then give commands in the game world.\nHold {(Shift)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -178,6 +176,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background:
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Attack Anything Stance
|
||||
TooltipDesc: Set the selected units to Attack Anything stance:\n - Units will attack enemy units and structures on sight\n - Units will pursue attackers across the battlefield
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -194,6 +193,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background:
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Defend Stance
|
||||
TooltipDesc: Set the selected units to Defend stance:\n - Units will attack enemy units on sight\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -210,6 +210,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background:
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Return Fire Stance
|
||||
TooltipDesc: Set the selected units to Return Fire stance:\n - Units will retaliate against enemies that attack them\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -226,6 +227,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background:
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Hold Fire Stance
|
||||
TooltipDesc: Set the selected units to Hold Fire stance:\n - Units will not fire upon enemies\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
|
||||
@@ -128,16 +128,6 @@ Cursors:
|
||||
Length: 8
|
||||
X: 24
|
||||
Y: 24
|
||||
attackmove:
|
||||
Start: 16
|
||||
Length: 8
|
||||
X: 24
|
||||
Y: 24
|
||||
attackmove-minimap:
|
||||
Start: 16
|
||||
Length: 8
|
||||
X: 24
|
||||
Y: 24
|
||||
harvest:
|
||||
Start: 16
|
||||
Length: 8
|
||||
@@ -305,3 +295,41 @@ Cursors:
|
||||
Length: 3
|
||||
X: 12
|
||||
Y: 12
|
||||
attackmove.shp: mouse
|
||||
attackmove:
|
||||
Start: 0
|
||||
Length: 8
|
||||
X: -2
|
||||
Y: -2
|
||||
attackmove-minimap:
|
||||
Start: 0
|
||||
Length: 8
|
||||
X: -2
|
||||
Y: -2
|
||||
attackmove-blocked:
|
||||
Start: 8
|
||||
X: -2
|
||||
Y: -2
|
||||
attackmove-blocked-minimap:
|
||||
Start: 8
|
||||
X: -2
|
||||
Y: -2
|
||||
assaultmove.shp: mouse
|
||||
assaultmove:
|
||||
Start: 0
|
||||
Length: 8
|
||||
X: -2
|
||||
Y: -2
|
||||
assaultmove-minimap:
|
||||
Start: 0
|
||||
Length: 8
|
||||
X: -2
|
||||
Y: -2
|
||||
assaultmove-blocked:
|
||||
Start: 8
|
||||
X: -2
|
||||
Y: -2
|
||||
assaultmove-blocked-minimap:
|
||||
Start: 8
|
||||
X: -2
|
||||
Y: -2
|
||||
|
||||
@@ -132,6 +132,15 @@
|
||||
ValidTargets: Infantry, Vehicle, Creep, Water, Structure, Defense
|
||||
InvalidTargets: NoAutoTarget
|
||||
|
||||
^AutoTargetGroundAssaultMove:
|
||||
Inherits: ^AutoTargetGround
|
||||
AutoTargetPriority@DEFAULT:
|
||||
RequiresCondition: !stance-attackanything && !assault-move
|
||||
AutoTargetPriority@ATTACKANYTHING:
|
||||
RequiresCondition: stance-attackanything || assault-move
|
||||
AttackMove:
|
||||
AssaultMoveScanCondition: assault-move
|
||||
|
||||
^AutoTargetAll:
|
||||
AutoTarget:
|
||||
AttackAnythingCondition: stance-attackanything
|
||||
@@ -144,6 +153,15 @@
|
||||
ValidTargets: Infantry, Vehicle, Creep, Water, Air, Structure, Defense
|
||||
InvalidTargets: NoAutoTarget
|
||||
|
||||
^AutoTargetAllAssaultMove:
|
||||
Inherits: ^AutoTargetAll
|
||||
AutoTargetPriority@DEFAULT:
|
||||
RequiresCondition: !stance-attackanything && !assault-move
|
||||
AutoTargetPriority@ATTACKANYTHING:
|
||||
RequiresCondition: stance-attackanything || assault-move
|
||||
AttackMove:
|
||||
AssaultMoveScanCondition: assault-move
|
||||
|
||||
^Vehicle:
|
||||
Inherits@1: ^ExistsInWorld
|
||||
Inherits@2: ^GainsExperience
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
light_inf:
|
||||
Inherits: ^Infantry
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 10
|
||||
@@ -50,7 +50,7 @@ engineer:
|
||||
|
||||
trooper:
|
||||
Inherits: ^Infantry
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 20
|
||||
@@ -121,7 +121,7 @@ thumper:
|
||||
|
||||
fremen:
|
||||
Inherits: ^Infantry
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Tooltip:
|
||||
Name: Fremen
|
||||
Buildable:
|
||||
@@ -165,7 +165,7 @@ fremen:
|
||||
|
||||
grenadier:
|
||||
Inherits: ^Infantry
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 80
|
||||
@@ -196,7 +196,7 @@ grenadier:
|
||||
|
||||
sardaukar:
|
||||
Inherits: ^Infantry
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 80
|
||||
|
||||
@@ -100,7 +100,7 @@ harvester:
|
||||
|
||||
trike:
|
||||
Inherits: ^Vehicle
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Vehicle
|
||||
BuildPaletteOrder: 10
|
||||
@@ -140,7 +140,7 @@ trike:
|
||||
|
||||
quad:
|
||||
Inherits: ^Vehicle
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Vehicle
|
||||
Prerequisites: upgrade.light, ~techlevel.medium
|
||||
@@ -175,7 +175,7 @@ quad:
|
||||
|
||||
siege_tank:
|
||||
Inherits: ^Tank
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Armor
|
||||
Prerequisites: upgrade.heavy, ~techlevel.medium
|
||||
@@ -222,7 +222,7 @@ siege_tank:
|
||||
|
||||
missile_tank:
|
||||
Inherits: ^Tank
|
||||
Inherits@AUTOTARGET: ^AutoTargetAll
|
||||
Inherits@AUTOTARGET: ^AutoTargetAllAssaultMove
|
||||
Tooltip:
|
||||
Name: Missile Tank
|
||||
Buildable:
|
||||
@@ -261,7 +261,7 @@ missile_tank:
|
||||
|
||||
sonic_tank:
|
||||
Inherits: ^Vehicle
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Armor
|
||||
BuildPaletteOrder: 100
|
||||
@@ -296,7 +296,7 @@ sonic_tank:
|
||||
|
||||
devastator:
|
||||
Inherits: ^Tank
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Armor
|
||||
BuildPaletteOrder: 100
|
||||
@@ -341,7 +341,7 @@ devastator:
|
||||
|
||||
raider:
|
||||
Inherits: ^Vehicle
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Vehicle
|
||||
BuildPaletteOrder: 10
|
||||
@@ -407,7 +407,7 @@ stealth_raider:
|
||||
|
||||
deviator:
|
||||
Inherits: ^Tank
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Valued:
|
||||
Cost: 1000
|
||||
Tooltip:
|
||||
@@ -444,7 +444,7 @@ deviator:
|
||||
|
||||
^combat_tank:
|
||||
Inherits: ^Tank
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Armor
|
||||
BuildPaletteOrder: 40
|
||||
|
||||
@@ -36,7 +36,7 @@ harvester.husk:
|
||||
idle: DATA.R8
|
||||
Start: 1699
|
||||
Facings: -32
|
||||
ZOffset: -1023
|
||||
ZOffset: -512
|
||||
|
||||
trike:
|
||||
idle: DATA.R8
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 209 KiB |
@@ -15,10 +15,13 @@ Sound:
|
||||
Warhead@1Dam: SpreadDamage
|
||||
Range: 0, 32
|
||||
Falloff: 100, 100
|
||||
Damage: 150
|
||||
Damage: 86
|
||||
AffectsParent: false
|
||||
ValidStances: Neutral, Enemy
|
||||
Versus:
|
||||
none: 200
|
||||
light: 110
|
||||
wood: 110
|
||||
wall: 50
|
||||
building: 60
|
||||
heavy: 60
|
||||
@@ -28,11 +31,14 @@ Sound:
|
||||
DamageTypes: Prone50Percent, TriggerProne, SoundDeath
|
||||
Warhead@2Dam: SpreadDamage
|
||||
Range: 0, 32
|
||||
Falloff: 50, 50 # Only does half damage to friendly units
|
||||
Damage: 150
|
||||
Falloff: 100, 100
|
||||
Damage: 43 # Only does half damage to friendly units
|
||||
AffectsParent: false
|
||||
ValidStances: Ally
|
||||
Versus:
|
||||
none: 200
|
||||
light: 110
|
||||
wood: 110
|
||||
wall: 50
|
||||
building: 60
|
||||
heavy: 60
|
||||
|
||||
Binary file not shown.
@@ -43,16 +43,18 @@ Container@PLAYER_WIDGETS:
|
||||
Width: 275
|
||||
Height: 26
|
||||
Children:
|
||||
LogicKeyListener@MODIFIER_OVERRIDES:
|
||||
Button@ATTACK_MOVE:
|
||||
Logic: AddFactionSuffixLogic
|
||||
Width: 34
|
||||
Height: 26
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Attack Move
|
||||
TooltipDesc: Selected units will move to the desired location\nand attack any enemies they encounter en route.\n\nLeft-click icon then right-click on target location.
|
||||
TooltipDesc: Selected units will move to the desired location\nand attack any enemies they encounter en route.\n\nHold {(Ctrl)} while targeting to order an Assault Move\nthat attacks any units or structures encountered en route.\n\nLeft-click icon then right-click on target location.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
TooltipTemplate: BUTTON_WITH_DESC_HIGHLIGHT_TOOLTIP
|
||||
Children:
|
||||
Image@ICON:
|
||||
X: 5
|
||||
@@ -66,6 +68,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 26
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Force Move
|
||||
TooltipDesc: Selected units will move to the desired location\n - Default activity for the target is suppressed\n - Vehicles will attempt to crush enemies at the target location\n - Units entering transports will consider nearby alternatives\n - Chrono Tanks will teleport towards the target location\n\nLeft-click icon then right-click on target.\nHold {(Alt)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -83,6 +86,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 26
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Force Attack
|
||||
TooltipDesc: Selected units will attack the targeted unit or location\nignoring their default activity for the target.\n\nLeft-click icon then right-click on target.\nHold {(Ctrl)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -100,7 +104,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 26
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Guard
|
||||
TooltipDesc: Selected units will follow the targeted unit.\n\nLeft-click icon then right-click on target unit.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -118,8 +122,9 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Deploy
|
||||
TooltipDesc: Selected units will perform their default deploy activity\n - MCVs will unpack into a Construction Yard\n - Construction Yards will re-pack into a MCV\n - Transports will unload their passengers\n - Aircraft will return to base\n\nActs immediately on selected units.
|
||||
TooltipDesc: Selected units will perform their default deploy activity\n - MCVs will unpack into a Construction Yard\n - Construction Yards will re-pack into a MCV\n - Transports will unload their passengers\n - Demolition Trucks and MAD Tanks will self-destruct\n - Minelayers will deploy a mine\n - Aircraft will return to base\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
Children:
|
||||
Image@ICON:
|
||||
@@ -135,6 +140,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Scatter
|
||||
TooltipDesc: Selected units will stop their current activity\nand move to a nearby location.\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -152,6 +158,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Stop
|
||||
TooltipDesc: Selected units will stop their current activity.\n\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -168,6 +175,7 @@ Container@PLAYER_WIDGETS:
|
||||
Height: 26
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeySound: true
|
||||
TooltipText: Waypoint Mode
|
||||
TooltipDesc: Use Waypoint Mode to give multiple linking commands\nto the selected units. Units will execute the commands\nimmediately upon receiving them.\n\nLeft-click icon then give commands in the game world.\nHold {(Shift)} to activate temporarily while commanding units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -192,6 +200,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Attack Anything Stance
|
||||
TooltipDesc: Set the selected units to Attack Anything stance:\n - Units will attack enemy units and structures on sight\n - Units will pursue attackers across the battlefield
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -209,6 +218,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Defend Stance
|
||||
TooltipDesc: Set the selected units to Defend stance:\n - Units will attack enemy units on sight\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -226,6 +236,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Return Fire Stance
|
||||
TooltipDesc: Set the selected units to Return Fire stance:\n - Units will retaliate against enemies that attack them\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
@@ -243,6 +254,7 @@ Container@PLAYER_WIDGETS:
|
||||
VisualHeight: 0
|
||||
Background: command-button
|
||||
DisableKeyRepeat: true
|
||||
DisableKeySound: true
|
||||
TooltipText: Hold Fire Stance
|
||||
TooltipDesc: Set the selected units to Hold Fire stance:\n - Units will not fire upon enemies\n - Units will not move or pursue enemies
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
|
||||
@@ -217,3 +217,17 @@ Cursors:
|
||||
attackmove-minimap:
|
||||
Start: 4
|
||||
Length: 4
|
||||
attackmove-blocked:
|
||||
Start: 16
|
||||
attackmove-blocked-minimap:
|
||||
Start: 18
|
||||
assaultmove:
|
||||
Start: 8
|
||||
Length: 4
|
||||
assaultmove-minimap:
|
||||
Start: 12
|
||||
Length: 4
|
||||
assaultmove-blocked:
|
||||
Start: 17
|
||||
assaultmove-blocked-minimap:
|
||||
Start: 19
|
||||
|
||||
@@ -118,7 +118,7 @@ aftermath-linux: Aftermath Expansion Disc (English)
|
||||
readme.txt: 9902fb74c019df1b76ff5634e68f0371d790b5e0
|
||||
setup/install/patch.rtp: 5bce93f834f9322ddaa7233242e5b6c7fea0bf17
|
||||
Install:
|
||||
extract-raw: SETUP/INSTALL/PATCH.RTP
|
||||
extract-raw: setup/install/patch.rtp
|
||||
^Content/ra/v2/expand/expand2.mix:
|
||||
Offset: 4712984
|
||||
Length: 469922
|
||||
|
||||
BIN
mods/ra/maps/agenda.oramap
Normal file
BIN
mods/ra/maps/agenda.oramap
Normal file
Binary file not shown.
@@ -72,7 +72,6 @@ TRUK.mission:
|
||||
Prerequisites: ~disabled
|
||||
WithFacingSpriteBody:
|
||||
-SpawnActorOnDeath:
|
||||
-EjectOnDeath:
|
||||
RevealsShroud:
|
||||
Range: 4c0
|
||||
ValidStances: Ally, Enemy
|
||||
|
||||
@@ -41,6 +41,9 @@ HelicopterUnitTypes = { "e1", "e1", "e1", "e1", "e3", "e3" };
|
||||
|
||||
ParadropWaypoints = { Paradrop1, Paradrop2, Paradrop3, Paradrop4, Paradrop5, Paradrop6, Paradrop7, Paradrop8 }
|
||||
|
||||
Mig1Waypoints = { Mig11, Mig12, Mig13, Mig14 }
|
||||
Mig2Waypoints = { Mig21, Mig22, Mig23, Mig24 }
|
||||
|
||||
BindActorTriggers = function(a)
|
||||
if a.HasProperty("Hunt") then
|
||||
if a.Owner == allies then
|
||||
@@ -76,6 +79,18 @@ SendSovietUnits = function(entryCell, unitTypes, interval)
|
||||
Trigger.OnAllKilled(units, function() SendSovietUnits(entryCell, unitTypes, interval) end)
|
||||
end
|
||||
|
||||
SendMigs = function(waypoints)
|
||||
local migEntryPath = { waypoints[1].Location, waypoints[2].Location }
|
||||
local migs = Reinforcements.Reinforce(soviets, { "mig" }, migEntryPath, 4)
|
||||
Utils.Do(migs, function(mig)
|
||||
mig.Move(waypoints[3].Location)
|
||||
mig.Move(waypoints[4].Location)
|
||||
mig.Destroy()
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Seconds(40), function() SendMigs(waypoints) end)
|
||||
end
|
||||
|
||||
ShipAlliedUnits = function()
|
||||
local units = Reinforcements.ReinforceWithTransport(allies, "lst",
|
||||
ShipUnitTypes, { LstEntry.Location, LstUnload.Location }, { LstEntry.Location })[2]
|
||||
@@ -171,6 +186,9 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(5), ChronoshiftAlliedUnits)
|
||||
Utils.Do(ProducedUnitTypes, ProduceUnits)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), function() SendMigs(Mig1Waypoints) end)
|
||||
Trigger.AfterDelay(DateTime.Seconds(30), function() SendMigs(Mig2Waypoints) end)
|
||||
|
||||
SendSovietUnits(Entry1.Location, UnitTypes, 50)
|
||||
SendSovietUnits(Entry2.Location, UnitTypes, 50)
|
||||
SendSovietUnits(Entry3.Location, UnitTypes, 50)
|
||||
|
||||
@@ -1239,6 +1239,30 @@ Actors:
|
||||
ChronoshiftLocation: waypoint
|
||||
Location: 80,65
|
||||
Owner: Neutral
|
||||
Mig11: waypoint
|
||||
Location: 94,1
|
||||
Owner: Neutral
|
||||
Mig12: waypoint
|
||||
Location: 68,33
|
||||
Owner: Neutral
|
||||
Mig13: waypoint
|
||||
Location: 41,38
|
||||
Owner: Neutral
|
||||
Mig14: waypoint
|
||||
Location: 1,26
|
||||
Owner: Neutral
|
||||
Mig21: waypoint
|
||||
Location: 96,3
|
||||
Owner: Neutral
|
||||
Mig22: waypoint
|
||||
Location: 70,35
|
||||
Owner: Neutral
|
||||
Mig23: waypoint
|
||||
Location: 41,40
|
||||
Owner: Neutral
|
||||
Mig24: waypoint
|
||||
Location: 1,28
|
||||
Owner: Neutral
|
||||
|
||||
Rules: rules.yaml
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ UNITCRATE:
|
||||
Percentage: 0
|
||||
|
||||
APC:
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Health:
|
||||
HP: 1000
|
||||
MustBeDestroyed:
|
||||
|
||||
@@ -46,6 +46,7 @@ UNITCRATE:
|
||||
Percentage: 0
|
||||
|
||||
APC:
|
||||
Inherits@AUTOTARGET: ^AutoTargetGround
|
||||
Health:
|
||||
HP: 1000
|
||||
MustBeDestroyed:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -8,6 +8,8 @@ World:
|
||||
-StartGameNotification:
|
||||
MissionData:
|
||||
Briefing: Dr. Demitri, creator of a Soviet Super Tank, wants to defect.\n\nWe planned to extract him while the Soviets were testing their new weapon, but something has gone wrong.\n\nThe Super Tanks are out of control, and Demitri is missing -- likely hiding in the village to the far south.\n\nFind our outpost and start repairs on it, then find and evacuate Demitri.\n\nAs for the tanks, we can reprogram them. Send a spy into the Soviet radar dome in the NE, turning the tanks on their creators.\n
|
||||
WinVideo: sovbatl.vqa
|
||||
LossVideo: sovtstar.vqa
|
||||
|
||||
^Building:
|
||||
AnnounceOnSeen:
|
||||
@@ -161,7 +163,6 @@ PBOX:
|
||||
DamageCooldown: 150
|
||||
Selectable:
|
||||
Bounds: 44,38,0,-4
|
||||
-EjectOnDeath:
|
||||
RenderSprites:
|
||||
Image: 4TNK
|
||||
|
||||
@@ -184,7 +185,7 @@ DOME.NoInfiltrate:
|
||||
Image: DOME
|
||||
-InfiltrateForExploration:
|
||||
Targetable:
|
||||
TargetTypes: Ground, C4, DetonateAttack, MissionObjective
|
||||
TargetTypes: Ground, Structure, C4, DetonateAttack, MissionObjective
|
||||
|
||||
SPY:
|
||||
Infiltrates:
|
||||
@@ -194,7 +195,6 @@ BAD3TNK:
|
||||
Inherits: 3TNK
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
-EjectOnDeath:
|
||||
RenderSprites:
|
||||
Image: 3TNK
|
||||
|
||||
@@ -202,7 +202,6 @@ BADTRUK:
|
||||
Inherits: TRUK
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
-EjectOnDeath:
|
||||
RenderSprites:
|
||||
Image: TRUK
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
mods/ra/maps/poland-raid/map.bin
Normal file
BIN
mods/ra/maps/poland-raid/map.bin
Normal file
Binary file not shown.
BIN
mods/ra/maps/poland-raid/map.png
Normal file
BIN
mods/ra/maps/poland-raid/map.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
784
mods/ra/maps/poland-raid/map.yaml
Normal file
784
mods/ra/maps/poland-raid/map.yaml
Normal file
@@ -0,0 +1,784 @@
|
||||
MapFormat: 11
|
||||
|
||||
RequiresMod: ra
|
||||
|
||||
Title: Poland Raid
|
||||
|
||||
Author: s1w
|
||||
|
||||
Tileset: TEMPERAT
|
||||
|
||||
MapSize: 128,128
|
||||
|
||||
Bounds: 16,16,96,96
|
||||
|
||||
Visibility: Lobby
|
||||
|
||||
Categories: Conquest
|
||||
|
||||
Players:
|
||||
PlayerReference@Neutral:
|
||||
Name: Neutral
|
||||
OwnsWorld: True
|
||||
NonCombatant: True
|
||||
Faction: allies
|
||||
PlayerReference@Multi0:
|
||||
Name: Multi0
|
||||
Playable: True
|
||||
Faction: Random
|
||||
Enemies: Creeps
|
||||
AllowBots: false
|
||||
PlayerReference@Creeps:
|
||||
Name: Creeps
|
||||
NonCombatant: True
|
||||
Faction: allies
|
||||
Enemies: Multi0, Multi1, Multi2, Multi3, Multi4
|
||||
PlayerReference@Multi1:
|
||||
Name: Multi1
|
||||
Playable: True
|
||||
Faction: Random
|
||||
Enemies: Creeps
|
||||
AllowBots: false
|
||||
PlayerReference@Multi2:
|
||||
Name: Multi2
|
||||
Playable: True
|
||||
Faction: Random
|
||||
Enemies: Creeps
|
||||
AllowBots: false
|
||||
PlayerReference@Multi3:
|
||||
Name: Multi3
|
||||
Playable: True
|
||||
Faction: Random
|
||||
Enemies: Creeps
|
||||
AllowBots: false
|
||||
PlayerReference@Multi4:
|
||||
Name: Multi4
|
||||
Playable: True
|
||||
Faction: Random
|
||||
Enemies: Creeps
|
||||
AllowBots: false
|
||||
|
||||
Actors:
|
||||
Actor1: v16
|
||||
Location: 26,55
|
||||
Owner: Neutral
|
||||
Actor2: v18
|
||||
Location: 27,54
|
||||
Owner: Neutral
|
||||
Actor14: tc05
|
||||
Location: 94,32
|
||||
Owner: Neutral
|
||||
Actor15: tc05
|
||||
Location: 95,35
|
||||
Owner: Neutral
|
||||
Actor16: tc02
|
||||
Location: 33,20
|
||||
Owner: Neutral
|
||||
Actor17: tc04
|
||||
Location: 32,17
|
||||
Owner: Neutral
|
||||
Actor18: tc05
|
||||
Location: 34,18
|
||||
Owner: Neutral
|
||||
Actor19: tc05
|
||||
Location: 86,53
|
||||
Owner: Neutral
|
||||
Actor20: tc02
|
||||
Location: 86,34
|
||||
Owner: Neutral
|
||||
Actor21: tc02
|
||||
Location: 55,35
|
||||
Owner: Neutral
|
||||
Actor22: t17
|
||||
Location: 58,36
|
||||
Owner: Neutral
|
||||
Actor23: t07
|
||||
Location: 16,89
|
||||
Owner: Neutral
|
||||
Actor24: tc04
|
||||
Location: 19,90
|
||||
Owner: Neutral
|
||||
Actor25: tc04
|
||||
Location: 17,51
|
||||
Owner: Neutral
|
||||
Actor26: tc04
|
||||
Location: 22,52
|
||||
Owner: Neutral
|
||||
Actor27: tc04
|
||||
Location: 25,49
|
||||
Owner: Neutral
|
||||
Actor28: tc04
|
||||
Location: 18,56
|
||||
Owner: Neutral
|
||||
Actor29: tc05
|
||||
Location: 18,53
|
||||
Owner: Neutral
|
||||
Actor30: tc05
|
||||
Location: 23,47
|
||||
Owner: Neutral
|
||||
Actor31: tc03
|
||||
Location: 16,55
|
||||
Owner: Neutral
|
||||
Actor32: tc03
|
||||
Location: 21,55
|
||||
Owner: Neutral
|
||||
Actor34: tc01
|
||||
Location: 21,49
|
||||
Owner: Neutral
|
||||
Actor35: t17
|
||||
Location: 26,52
|
||||
Owner: Neutral
|
||||
Actor36: t17
|
||||
Location: 17,56
|
||||
Owner: Neutral
|
||||
Actor37: t14
|
||||
Location: 23,51
|
||||
Owner: Neutral
|
||||
Actor38: t14
|
||||
Location: 16,53
|
||||
Owner: Neutral
|
||||
Actor39: tc04
|
||||
Location: 29,109
|
||||
Owner: Neutral
|
||||
Actor41: tc01
|
||||
Location: 53,98
|
||||
Owner: Neutral
|
||||
Actor42: tc04
|
||||
Location: 37,86
|
||||
Owner: Neutral
|
||||
Actor43: tc02
|
||||
Location: 16,83
|
||||
Owner: Neutral
|
||||
Actor44: tc05
|
||||
Location: 40,109
|
||||
Owner: Neutral
|
||||
Actor45: tc04
|
||||
Location: 30,106
|
||||
Owner: Neutral
|
||||
Actor46: tc04
|
||||
Location: 27,107
|
||||
Owner: Neutral
|
||||
Actor47: tc02
|
||||
Location: 34,108
|
||||
Owner: Neutral
|
||||
Actor48: tc02
|
||||
Location: 32,108
|
||||
Owner: Neutral
|
||||
Actor49: tc02
|
||||
Location: 32,110
|
||||
Owner: Neutral
|
||||
Actor50: t03
|
||||
Location: 33,106
|
||||
Owner: Neutral
|
||||
Actor51: t03
|
||||
Location: 30,108
|
||||
Owner: Neutral
|
||||
Actor52: t16
|
||||
Location: 41,95
|
||||
Owner: Neutral
|
||||
Actor53: tc05
|
||||
Location: 109,109
|
||||
Owner: Neutral
|
||||
Actor54: tc05
|
||||
Location: 37,109
|
||||
Owner: Neutral
|
||||
Actor55: tc01
|
||||
Location: 35,109
|
||||
Owner: Neutral
|
||||
Actor62: tc01
|
||||
Location: 57,37
|
||||
Owner: Neutral
|
||||
Actor63: tc03
|
||||
Location: 59,37
|
||||
Owner: Neutral
|
||||
Actor64: tc03
|
||||
Location: 53,35
|
||||
Owner: Neutral
|
||||
Actor66: tc02
|
||||
Location: 41,51
|
||||
Owner: Neutral
|
||||
Actor67: tc01
|
||||
Location: 97,32
|
||||
Owner: Neutral
|
||||
Actor68: tc01
|
||||
Location: 97,33
|
||||
Owner: Neutral
|
||||
Actor69: tc03
|
||||
Location: 98,31
|
||||
Owner: Neutral
|
||||
Actor70: tc02
|
||||
Location: 77,88
|
||||
Owner: Neutral
|
||||
Actor71: tc04
|
||||
Location: 103,73
|
||||
Owner: Neutral
|
||||
Actor72: t12
|
||||
Location: 102,74
|
||||
Owner: Neutral
|
||||
Actor73: t03
|
||||
Location: 99,74
|
||||
Owner: Neutral
|
||||
Actor74: t08
|
||||
Location: 84,90
|
||||
Owner: Neutral
|
||||
Actor76: tc04
|
||||
Location: 94,75
|
||||
Owner: Neutral
|
||||
Actor77: tc05
|
||||
Location: 91,76
|
||||
Owner: Neutral
|
||||
Actor79: tc03
|
||||
Location: 85,76
|
||||
Owner: Neutral
|
||||
Actor80: tc04
|
||||
Location: 73,88
|
||||
Owner: Neutral
|
||||
Actor81: tc01
|
||||
Location: 71,88
|
||||
Owner: Neutral
|
||||
Actor82: tc01
|
||||
Location: 77,99
|
||||
Owner: Neutral
|
||||
Actor83: t07
|
||||
Location: 26,89
|
||||
Owner: Neutral
|
||||
Actor84: t08
|
||||
Location: 23,91
|
||||
Owner: Neutral
|
||||
Actor85: v12
|
||||
Location: 41,94
|
||||
Owner: Neutral
|
||||
Actor88: t11
|
||||
Location: 38,32
|
||||
Owner: Neutral
|
||||
Actor89: t08
|
||||
Location: 95,44
|
||||
Owner: Neutral
|
||||
Actor90: t12
|
||||
Location: 23,48
|
||||
Owner: Neutral
|
||||
Actor94: t16
|
||||
Location: 29,106
|
||||
Owner: Neutral
|
||||
Actor95: tc04
|
||||
Location: 54,74
|
||||
Owner: Neutral
|
||||
Actor96: tc05
|
||||
Location: 48,72
|
||||
Owner: Neutral
|
||||
Actor98: t12
|
||||
Location: 47,72
|
||||
Owner: Neutral
|
||||
Actor100: tc02
|
||||
Location: 39,78
|
||||
Owner: Neutral
|
||||
Actor101: tc02
|
||||
Location: 33,90
|
||||
Owner: Neutral
|
||||
Actor102: tc03
|
||||
Location: 41,76
|
||||
Owner: Neutral
|
||||
Actor103: t06
|
||||
Location: 47,73
|
||||
Owner: Neutral
|
||||
Actor104: t08
|
||||
Location: 33,78
|
||||
Owner: Neutral
|
||||
Actor105: t02
|
||||
Location: 32,89
|
||||
Owner: Neutral
|
||||
Actor106: tc01
|
||||
Location: 29,89
|
||||
Owner: Neutral
|
||||
Actor107: t07
|
||||
Location: 28,89
|
||||
Owner: Neutral
|
||||
Actor108: tc04
|
||||
Location: 34,75
|
||||
Owner: Neutral
|
||||
Actor109: t16
|
||||
Location: 35,74
|
||||
Owner: Neutral
|
||||
Actor110: tc02
|
||||
Location: 38,73
|
||||
Owner: Neutral
|
||||
Actor111: t11
|
||||
Location: 37,74
|
||||
Owner: Neutral
|
||||
Actor112: t11
|
||||
Location: 16,84
|
||||
Owner: Neutral
|
||||
Actor113: t05
|
||||
Location: 37,78
|
||||
Owner: Neutral
|
||||
Actor114: t17
|
||||
Location: 71,43
|
||||
Owner: Neutral
|
||||
Actor115: tc01
|
||||
Location: 76,32
|
||||
Owner: Neutral
|
||||
Actor116: t16
|
||||
Location: 75,31
|
||||
Owner: Neutral
|
||||
Actor117: t16
|
||||
Location: 87,48
|
||||
Owner: Neutral
|
||||
Actor118: t17
|
||||
Location: 85,44
|
||||
Owner: Neutral
|
||||
Actor119: t11
|
||||
Location: 79,46
|
||||
Owner: Neutral
|
||||
Actor120: t08
|
||||
Location: 72,40
|
||||
Owner: Neutral
|
||||
Actor121: t02
|
||||
Location: 69,21
|
||||
Owner: Neutral
|
||||
Actor122: t08
|
||||
Location: 70,22
|
||||
Owner: Neutral
|
||||
Actor123: tc01
|
||||
Location: 66,23
|
||||
Owner: Neutral
|
||||
Actor124: t16
|
||||
Location: 66,21
|
||||
Owner: Neutral
|
||||
Actor125: t05
|
||||
Location: 69,18
|
||||
Owner: Neutral
|
||||
Actor126: t13
|
||||
Location: 66,18
|
||||
Owner: Neutral
|
||||
Actor127: t01
|
||||
Location: 68,21
|
||||
Owner: Neutral
|
||||
Actor0: tc01
|
||||
Location: 94,24
|
||||
Owner: Neutral
|
||||
Actor132: tc04
|
||||
Location: 63,18
|
||||
Owner: Neutral
|
||||
Actor133: tc04
|
||||
Location: 40,49
|
||||
Owner: Neutral
|
||||
Actor138: tc01
|
||||
Location: 38,50
|
||||
Owner: Neutral
|
||||
Actor176: t16
|
||||
Location: 100,75
|
||||
Owner: Neutral
|
||||
Actor137: tc01
|
||||
Location: 42,96
|
||||
Owner: Neutral
|
||||
Actor190: t05
|
||||
Location: 28,50
|
||||
Owner: Neutral
|
||||
Actor139: tc01
|
||||
Location: 49,32
|
||||
Owner: Neutral
|
||||
Actor140: t05
|
||||
Location: 48,33
|
||||
Owner: Neutral
|
||||
Actor141: t01
|
||||
Location: 46,35
|
||||
Owner: Neutral
|
||||
Actor143: tc02
|
||||
Location: 65,34
|
||||
Owner: Neutral
|
||||
Actor144: tc01
|
||||
Location: 65,35
|
||||
Owner: Neutral
|
||||
Actor145: tc02
|
||||
Location: 65,37
|
||||
Owner: Neutral
|
||||
Actor146: t08
|
||||
Location: 56,37
|
||||
Owner: Neutral
|
||||
Actor147: tc05
|
||||
Location: 53,32
|
||||
Owner: Neutral
|
||||
Actor148: tc01
|
||||
Location: 56,33
|
||||
Owner: Neutral
|
||||
Actor149: t12
|
||||
Location: 57,34
|
||||
Owner: Neutral
|
||||
Actor150: tc04
|
||||
Location: 62,28
|
||||
Owner: Neutral
|
||||
Actor151: tc04
|
||||
Location: 59,34
|
||||
Owner: Neutral
|
||||
Actor152: t07
|
||||
Location: 61,28
|
||||
Owner: Neutral
|
||||
Actor153: t05
|
||||
Location: 60,27
|
||||
Owner: Neutral
|
||||
Actor154: tc01
|
||||
Location: 42,34
|
||||
Owner: Neutral
|
||||
Actor155: t07
|
||||
Location: 43,33
|
||||
Owner: Neutral
|
||||
Actor156: t08
|
||||
Location: 44,34
|
||||
Owner: Neutral
|
||||
Actor157: t16
|
||||
Location: 41,34
|
||||
Owner: Neutral
|
||||
Actor158: tc01
|
||||
Location: 80,30
|
||||
Owner: Neutral
|
||||
Actor159: t11
|
||||
Location: 79,29
|
||||
Owner: Neutral
|
||||
Actor8: t06
|
||||
Location: 89,30
|
||||
Owner: Neutral
|
||||
Actor128: t06
|
||||
Location: 95,25
|
||||
Owner: Neutral
|
||||
Actor163: t03
|
||||
Location: 71,33
|
||||
Owner: Neutral
|
||||
Actor164: t08
|
||||
Location: 57,53
|
||||
Owner: Neutral
|
||||
Actor165: t08
|
||||
Location: 30,89
|
||||
Owner: Neutral
|
||||
Actor166: tc01
|
||||
Location: 28,88
|
||||
Owner: Neutral
|
||||
Actor167: t11
|
||||
Location: 26,88
|
||||
Owner: Neutral
|
||||
Actor168: t07
|
||||
Location: 55,99
|
||||
Owner: Neutral
|
||||
Actor169: t13
|
||||
Location: 20,86
|
||||
Owner: Neutral
|
||||
Actor170: t11
|
||||
Location: 33,86
|
||||
Owner: Neutral
|
||||
Actor171: tc05
|
||||
Location: 16,90
|
||||
Owner: Neutral
|
||||
Actor172: tc02
|
||||
Location: 22,89
|
||||
Owner: Neutral
|
||||
Actor173: t02
|
||||
Location: 17,69
|
||||
Owner: Neutral
|
||||
Actor174: t11
|
||||
Location: 29,72
|
||||
Owner: Neutral
|
||||
Actor175: t11
|
||||
Location: 86,95
|
||||
Owner: Neutral
|
||||
Actor177: tc01
|
||||
Location: 36,16
|
||||
Owner: Neutral
|
||||
Actor178: tc02
|
||||
Location: 33,16
|
||||
Owner: Neutral
|
||||
Actor179: t15
|
||||
Location: 31,16
|
||||
Owner: Neutral
|
||||
Actor180: t11
|
||||
Location: 54,19
|
||||
Owner: Neutral
|
||||
Actor186: tc04
|
||||
Location: 109,77
|
||||
Owner: Neutral
|
||||
Actor187: tc01
|
||||
Location: 105,72
|
||||
Owner: Neutral
|
||||
Actor188: t10
|
||||
Location: 107,73
|
||||
Owner: Neutral
|
||||
Actor191: tc03
|
||||
Location: 27,110
|
||||
Owner: Neutral
|
||||
Actor192: t08
|
||||
Location: 24,51
|
||||
Owner: Neutral
|
||||
Actor193: t08
|
||||
Location: 21,51
|
||||
Owner: Neutral
|
||||
Actor194: t08
|
||||
Location: 22,49
|
||||
Owner: Neutral
|
||||
Actor134: tc04
|
||||
Location: 32,50
|
||||
Owner: Neutral
|
||||
Actor198: tc04
|
||||
Location: 18,71
|
||||
Owner: Neutral
|
||||
Actor199: t16
|
||||
Location: 16,70
|
||||
Owner: Neutral
|
||||
Actor200: tc02
|
||||
Location: 20,74
|
||||
Owner: Neutral
|
||||
Actor201: tc05
|
||||
Location: 17,77
|
||||
Owner: Neutral
|
||||
Actor202: tc03
|
||||
Location: 19,73
|
||||
Owner: Neutral
|
||||
Actor203: tc05
|
||||
Location: 16,67
|
||||
Owner: Neutral
|
||||
Actor204: t12
|
||||
Location: 19,66
|
||||
Owner: Neutral
|
||||
Actor205: t11
|
||||
Location: 107,83
|
||||
Owner: Neutral
|
||||
Actor206: t05
|
||||
Location: 108,110
|
||||
Owner: Neutral
|
||||
Actor207: t15
|
||||
Location: 65,59
|
||||
Owner: Neutral
|
||||
Actor208: tc03
|
||||
Location: 57,64
|
||||
Owner: Neutral
|
||||
Actor209: t17
|
||||
Location: 63,68
|
||||
Owner: Neutral
|
||||
Actor210: t16
|
||||
Location: 68,70
|
||||
Owner: Neutral
|
||||
Actor211: tc04
|
||||
Location: 62,66
|
||||
Owner: Neutral
|
||||
Actor212: t16
|
||||
Location: 16,50
|
||||
Owner: Neutral
|
||||
Actor213: t16
|
||||
Location: 21,46
|
||||
Owner: Neutral
|
||||
Actor214: t17
|
||||
Location: 20,48
|
||||
Owner: Neutral
|
||||
Actor215: t08
|
||||
Location: 25,38
|
||||
Owner: Neutral
|
||||
Actor216: t08
|
||||
Location: 21,58
|
||||
Owner: Neutral
|
||||
Actor197: tc02
|
||||
Location: 69,66
|
||||
Owner: Neutral
|
||||
Actor219: tc01
|
||||
Location: 72,67
|
||||
Owner: Neutral
|
||||
Actor224: tc01
|
||||
Location: 87,76
|
||||
Owner: Neutral
|
||||
Actor225: oilb
|
||||
Location: 68,68
|
||||
Owner: Neutral
|
||||
Actor99: brl3
|
||||
Location: 59,64
|
||||
Owner: Neutral
|
||||
Actor227: barl
|
||||
Location: 67,70
|
||||
Owner: Neutral
|
||||
Actor228: brl3
|
||||
Location: 66,68
|
||||
Owner: Neutral
|
||||
Actor226: oilb
|
||||
Location: 59,62
|
||||
Owner: Neutral
|
||||
Actor230: barl
|
||||
Location: 60,65
|
||||
Owner: Neutral
|
||||
Actor231: v15
|
||||
Location: 66,70
|
||||
Owner: Neutral
|
||||
Actor232: dog
|
||||
Location: 63,65
|
||||
Owner: Creeps
|
||||
Actor233: oilb
|
||||
Location: 23,34
|
||||
Owner: Neutral
|
||||
Actor229: barl
|
||||
Location: 61,65
|
||||
Owner: Neutral
|
||||
Actor235: brl3
|
||||
Location: 26,36
|
||||
Owner: Neutral
|
||||
Actor33: v07
|
||||
Location: 61,63
|
||||
Owner: Neutral
|
||||
Actor234: t05
|
||||
Location: 27,84
|
||||
Owner: Neutral
|
||||
Actor218: t05
|
||||
Location: 71,67
|
||||
Owner: Neutral
|
||||
Actor217: t16
|
||||
Location: 21,34
|
||||
Owner: Neutral
|
||||
Actor223: t13
|
||||
Location: 46,73
|
||||
Owner: Neutral
|
||||
Actor238: t08
|
||||
Location: 16,79
|
||||
Owner: Neutral
|
||||
Actor239: t02
|
||||
Location: 81,77
|
||||
Owner: Neutral
|
||||
Actor136: t16
|
||||
Location: 61,102
|
||||
Owner: Neutral
|
||||
Actor185: fenc
|
||||
Location: 49,84
|
||||
Owner: Neutral
|
||||
Actor3: t08
|
||||
Location: 53,75
|
||||
Owner: Neutral
|
||||
Actor78: t16
|
||||
Location: 111,42
|
||||
Owner: Neutral
|
||||
Actor61: tc01
|
||||
Location: 109,23
|
||||
Owner: Neutral
|
||||
Actor161: t08
|
||||
Location: 107,23
|
||||
Owner: Neutral
|
||||
Actor162: t07
|
||||
Location: 98,28
|
||||
Owner: Neutral
|
||||
Actor12: t07
|
||||
Location: 41,75
|
||||
Owner: Neutral
|
||||
Actor221: t08
|
||||
Location: 91,86
|
||||
Owner: Neutral
|
||||
Actor222: mine
|
||||
Owner: Neutral
|
||||
Location: 109,46
|
||||
Actor237: mine
|
||||
Owner: Neutral
|
||||
Location: 108,49
|
||||
Actor241: mine
|
||||
Owner: Neutral
|
||||
Location: 86,27
|
||||
Actor242: mine
|
||||
Owner: Neutral
|
||||
Location: 82,22
|
||||
Actor243: mine
|
||||
Owner: Neutral
|
||||
Location: 79,25
|
||||
Actor244: mine
|
||||
Owner: Neutral
|
||||
Location: 74,24
|
||||
Actor245: mine
|
||||
Owner: Neutral
|
||||
Location: 92,17
|
||||
Actor246: mine
|
||||
Owner: Neutral
|
||||
Location: 60,17
|
||||
Actor247: mine
|
||||
Owner: Neutral
|
||||
Location: 62,21
|
||||
Actor248: mine
|
||||
Owner: Neutral
|
||||
Location: 42,31
|
||||
Actor249: mine
|
||||
Owner: Neutral
|
||||
Location: 37,29
|
||||
Actor250: mine
|
||||
Owner: Neutral
|
||||
Location: 65,46
|
||||
Actor251: mine
|
||||
Owner: Neutral
|
||||
Location: 60,45
|
||||
Actor252: mine
|
||||
Owner: Neutral
|
||||
Location: 59,49
|
||||
Actor253: mine
|
||||
Owner: Neutral
|
||||
Location: 78,52
|
||||
Actor254: mine
|
||||
Owner: Neutral
|
||||
Location: 40,62
|
||||
Actor255: mine
|
||||
Owner: Neutral
|
||||
Location: 22,83
|
||||
Actor256: mine
|
||||
Owner: Neutral
|
||||
Location: 27,82
|
||||
Actor257: mine
|
||||
Owner: Neutral
|
||||
Location: 22,93
|
||||
Actor258: mine
|
||||
Owner: Neutral
|
||||
Location: 29,92
|
||||
Actor259: mine
|
||||
Owner: Neutral
|
||||
Location: 50,78
|
||||
Actor260: mine
|
||||
Owner: Neutral
|
||||
Location: 52,84
|
||||
Actor261: mine
|
||||
Owner: Neutral
|
||||
Location: 57,80
|
||||
Actor262: mine
|
||||
Owner: Neutral
|
||||
Location: 46,88
|
||||
Actor263: mine
|
||||
Owner: Neutral
|
||||
Location: 43,82
|
||||
Actor264: mine
|
||||
Owner: Neutral
|
||||
Location: 58,91
|
||||
Actor265: mine
|
||||
Owner: Neutral
|
||||
Location: 56,103
|
||||
Actor266: mine
|
||||
Owner: Neutral
|
||||
Location: 52,105
|
||||
Actor267: mine
|
||||
Owner: Neutral
|
||||
Location: 93,109
|
||||
Actor268: mine
|
||||
Owner: Neutral
|
||||
Location: 88,107
|
||||
Actor269: mine
|
||||
Owner: Neutral
|
||||
Location: 82,109
|
||||
Actor270: mine
|
||||
Owner: Neutral
|
||||
Location: 78,103
|
||||
Actor271: mine
|
||||
Owner: Neutral
|
||||
Location: 109,102
|
||||
Actor272: mine
|
||||
Owner: Neutral
|
||||
Location: 110,97
|
||||
Actor273: mine
|
||||
Owner: Neutral
|
||||
Location: 86,79
|
||||
Actor279: mpspawn
|
||||
Owner: Neutral
|
||||
Location: 46,24
|
||||
Actor280: mpspawn
|
||||
Owner: Neutral
|
||||
Location: 103,32
|
||||
Actor274: mpspawn
|
||||
Owner: Neutral
|
||||
Location: 26,66
|
||||
Actor275: mpspawn
|
||||
Owner: Neutral
|
||||
Location: 34,101
|
||||
Actor276: mpspawn
|
||||
Owner: Neutral
|
||||
Location: 99,85
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user