@@ -619,6 +619,8 @@
|
|||||||
<Compile Include="UtilityCommands\CheckSequenceSprites.cs" />
|
<Compile Include="UtilityCommands\CheckSequenceSprites.cs" />
|
||||||
<Compile Include="UtilityCommands\FixClassicTilesets.cs" />
|
<Compile Include="UtilityCommands\FixClassicTilesets.cs" />
|
||||||
<Compile Include="Graphics\TilesetSpecificSpriteSequence.cs" />
|
<Compile Include="Graphics\TilesetSpecificSpriteSequence.cs" />
|
||||||
|
<Compile Include="Traits\Pluggable.cs" />
|
||||||
|
<Compile Include="Traits\Plug.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace OpenRA.Mods.Common.Orders
|
|||||||
readonly string building;
|
readonly string building;
|
||||||
readonly BuildingInfo buildingInfo;
|
readonly BuildingInfo buildingInfo;
|
||||||
readonly PlaceBuildingInfo placeBuildingInfo;
|
readonly PlaceBuildingInfo placeBuildingInfo;
|
||||||
|
readonly BuildingInfluence buildingInfluence;
|
||||||
readonly string race;
|
readonly string race;
|
||||||
readonly Sprite buildOk;
|
readonly Sprite buildOk;
|
||||||
readonly Sprite buildBlocked;
|
readonly Sprite buildBlocked;
|
||||||
@@ -52,6 +53,8 @@ namespace OpenRA.Mods.Common.Orders
|
|||||||
|
|
||||||
buildOk = map.SequenceProvider.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0);
|
buildOk = map.SequenceProvider.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0);
|
||||||
buildBlocked = map.SequenceProvider.GetSequence("overlay", "build-invalid").GetSprite(0);
|
buildBlocked = map.SequenceProvider.GetSequence("overlay", "build-invalid").GetSprite(0);
|
||||||
|
|
||||||
|
buildingInfluence = producer.World.WorldActor.Trait<BuildingInfluence>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
public IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||||
@@ -73,16 +76,33 @@ namespace OpenRA.Mods.Common.Orders
|
|||||||
|
|
||||||
if (mi.Button == MouseButton.Left)
|
if (mi.Button == MouseButton.Left)
|
||||||
{
|
{
|
||||||
|
var orderType = "PlaceBuilding";
|
||||||
var topLeft = xy - FootprintUtils.AdjustForBuildingSize(buildingInfo);
|
var topLeft = xy - FootprintUtils.AdjustForBuildingSize(buildingInfo);
|
||||||
if (!world.CanPlaceBuilding(building, buildingInfo, topLeft, null)
|
|
||||||
|| !buildingInfo.IsCloseEnoughToBase(world, producer.Owner, building, topLeft))
|
var plugInfo = world.Map.Rules.Actors[building].Traits.GetOrDefault<PlugInfo>();
|
||||||
|
if (plugInfo != null)
|
||||||
{
|
{
|
||||||
Sound.PlayNotification(world.Map.Rules, producer.Owner, "Speech", "BuildingCannotPlaceAudio", producer.Owner.Country.Race);
|
orderType = "PlacePlug";
|
||||||
yield break;
|
if (!AcceptsPlug(topLeft, plugInfo))
|
||||||
|
{
|
||||||
|
Sound.PlayNotification(world.Map.Rules, producer.Owner, "Speech", "BuildingCannotPlaceAudio", producer.Owner.Country.Race);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!world.CanPlaceBuilding(building, buildingInfo, topLeft, null)
|
||||||
|
|| !buildingInfo.IsCloseEnoughToBase(world, producer.Owner, building, topLeft))
|
||||||
|
{
|
||||||
|
Sound.PlayNotification(world.Map.Rules, producer.Owner, "Speech", "BuildingCannotPlaceAudio", producer.Owner.Country.Race);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (world.Map.Rules.Actors[building].Traits.Contains<LineBuildInfo>())
|
||||||
|
orderType = "LineBuild";
|
||||||
}
|
}
|
||||||
|
|
||||||
var isLineBuild = world.Map.Rules.Actors[building].Traits.Contains<LineBuildInfo>();
|
yield return new Order(orderType, producer.Owner.PlayerActor, false)
|
||||||
yield return new Order(isLineBuild ? "LineBuild" : "PlaceBuilding", producer.Owner.PlayerActor, false)
|
|
||||||
{
|
{
|
||||||
TargetLocation = topLeft,
|
TargetLocation = topLeft,
|
||||||
TargetActor = producer,
|
TargetActor = producer,
|
||||||
@@ -101,6 +121,16 @@ namespace OpenRA.Mods.Common.Orders
|
|||||||
p.Tick();
|
p.Tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AcceptsPlug(CPos cell, PlugInfo plug)
|
||||||
|
{
|
||||||
|
var host = buildingInfluence.GetBuildingAt(cell);
|
||||||
|
if (host == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var location = host.Location;
|
||||||
|
return host.TraitsImplementing<Pluggable>().Any(p => location + p.Info.Offset == cell && p.AcceptsPlug(host, plug.Type));
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||||
public IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world)
|
public IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world)
|
||||||
{
|
{
|
||||||
@@ -116,10 +146,17 @@ namespace OpenRA.Mods.Common.Orders
|
|||||||
|
|
||||||
var cells = new Dictionary<CPos, bool>();
|
var cells = new Dictionary<CPos, bool>();
|
||||||
|
|
||||||
// Linebuild for walls.
|
var plugInfo = rules.Actors[building].Traits.GetOrDefault<PlugInfo>();
|
||||||
// Requires a 1x1 footprint
|
if (plugInfo != null)
|
||||||
if (rules.Actors[building].Traits.Contains<LineBuildInfo>())
|
|
||||||
{
|
{
|
||||||
|
if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1)
|
||||||
|
throw new InvalidOperationException("Plug requires a 1x1 sized Building");
|
||||||
|
|
||||||
|
cells.Add(topLeft, AcceptsPlug(topLeft, plugInfo));
|
||||||
|
}
|
||||||
|
else if (rules.Actors[building].Traits.Contains<LineBuildInfo>())
|
||||||
|
{
|
||||||
|
// Linebuild for walls.
|
||||||
if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1)
|
if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1)
|
||||||
throw new InvalidOperationException("LineBuild requires a 1x1 sized Building");
|
throw new InvalidOperationException("LineBuild requires a 1x1 sized Building");
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
public abstract class AttackBaseInfo : ITraitInfo
|
public abstract class AttackBaseInfo : UpgradableTraitInfo, ITraitInfo
|
||||||
{
|
{
|
||||||
[Desc("Armament names")]
|
[Desc("Armament names")]
|
||||||
public readonly string[] Armaments = { "primary", "secondary" };
|
public readonly string[] Armaments = { "primary", "secondary" };
|
||||||
@@ -35,11 +35,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public abstract object Create(ActorInitializer init);
|
public abstract object Create(ActorInitializer init);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class AttackBase : IIssueOrder, IResolveOrder, IOrderVoice, ISync
|
public abstract class AttackBase : UpgradableTrait<AttackBaseInfo>, IIssueOrder, IResolveOrder, IOrderVoice, ISync
|
||||||
{
|
{
|
||||||
[Sync] public bool IsAttacking { get; internal set; }
|
[Sync] public bool IsAttacking { get; internal set; }
|
||||||
public IEnumerable<Armament> Armaments { get { return getArmaments(); } }
|
public IEnumerable<Armament> Armaments { get { return getArmaments(); } }
|
||||||
public readonly AttackBaseInfo Info;
|
|
||||||
|
|
||||||
protected Lazy<IFacing> facing;
|
protected Lazy<IFacing> facing;
|
||||||
protected Lazy<Building> building;
|
protected Lazy<Building> building;
|
||||||
@@ -49,9 +48,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
|
|
||||||
public AttackBase(Actor self, AttackBaseInfo info)
|
public AttackBase(Actor self, AttackBaseInfo info)
|
||||||
|
: base(info)
|
||||||
{
|
{
|
||||||
this.self = self;
|
this.self = self;
|
||||||
Info = info;
|
|
||||||
|
|
||||||
var armaments = Exts.Lazy(() => self.TraitsImplementing<Armament>()
|
var armaments = Exts.Lazy(() => self.TraitsImplementing<Armament>()
|
||||||
.Where(a => info.Armaments.Contains(a.Info.Name)));
|
.Where(a => info.Armaments.Contains(a.Info.Name)));
|
||||||
@@ -65,7 +64,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
protected virtual bool CanAttack(Actor self, Target target)
|
protected virtual bool CanAttack(Actor self, Target target)
|
||||||
{
|
{
|
||||||
if (!self.IsInWorld)
|
if (!self.IsInWorld || IsTraitDisabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!HasAnyValidWeapons(target))
|
if (!HasAnyValidWeapons(target))
|
||||||
@@ -101,7 +100,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var armament = Armaments.FirstOrDefault(a => a.Weapon.Warheads.Any(w => (w is DamageWarhead)));
|
var armament = Armaments.FirstOrDefault(a => a.Weapon.Warheads.Any(w => (w is DamageWarhead)));
|
||||||
if (armament == null)
|
if (armament == null || IsTraitDisabled)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
var negativeDamage = (armament.Weapon.Warheads.FirstOrDefault(w => (w is DamageWarhead)) as DamageWarhead).Damage < 0;
|
var negativeDamage = (armament.Weapon.Warheads.FirstOrDefault(w => (w is DamageWarhead)) as DamageWarhead).Damage < 0;
|
||||||
@@ -149,6 +148,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public bool HasAnyValidWeapons(Target t)
|
public bool HasAnyValidWeapons(Target t)
|
||||||
{
|
{
|
||||||
|
if (IsTraitDisabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (Info.AttackRequiresEnteringCell && !positionable.Value.CanEnterCell(t.Actor.Location, null, false))
|
if (Info.AttackRequiresEnteringCell && !positionable.Value.CanEnterCell(t.Actor.Location, null, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -157,14 +159,19 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public WRange GetMaximumRange()
|
public WRange GetMaximumRange()
|
||||||
{
|
{
|
||||||
return Armaments.Select(a => a.Weapon.Range).Append(WRange.Zero).Max();
|
if (IsTraitDisabled)
|
||||||
|
return WRange.Zero;
|
||||||
|
|
||||||
|
return Armaments.Where(a => !a.IsTraitDisabled)
|
||||||
|
.Select(a => a.Weapon.Range)
|
||||||
|
.Append(WRange.Zero).Max();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Armament ChooseArmamentForTarget(Target t) { return Armaments.FirstOrDefault(a => a.Weapon.IsValidAgainst(t, self.World, self)); }
|
public Armament ChooseArmamentForTarget(Target t) { return Armaments.FirstOrDefault(a => a.Weapon.IsValidAgainst(t, self.World, self)); }
|
||||||
|
|
||||||
public void AttackTarget(Target target, bool queued, bool allowMove)
|
public void AttackTarget(Target target, bool queued, bool allowMove)
|
||||||
{
|
{
|
||||||
if (self.IsDisabled())
|
if (self.IsDisabled() || IsTraitDisabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!target.IsValidFor(self))
|
if (!target.IsValidFor(self))
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (!Cloaked || self.Owner.IsAlliedWith(viewer))
|
if (!Cloaked || self.Owner.IsAlliedWith(viewer))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return self.World.ActorsWithTrait<DetectCloaked>().Any(a => a.Actor.Owner.IsAlliedWith(viewer)
|
return self.World.ActorsWithTrait<DetectCloaked>().Any(a => !a.Trait.IsTraitDisabled && a.Actor.Owner.IsAlliedWith(viewer)
|
||||||
&& Info.CloakTypes.Intersect(a.Trait.Info.CloakTypes).Any()
|
&& Info.CloakTypes.Intersect(a.Trait.Info.CloakTypes).Any()
|
||||||
&& (self.CenterPosition - a.Actor.CenterPosition).Length <= WRange.FromCells(a.Trait.Info.Range).Range);
|
&& (self.CenterPosition - a.Actor.CenterPosition).Length <= WRange.FromCells(a.Trait.Info.Range).Range);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using OpenRA.Traits;
|
|||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
[Desc("Actor can reveal Cloak actors in a specified range.")]
|
[Desc("Actor can reveal Cloak actors in a specified range.")]
|
||||||
public class DetectCloakedInfo : ITraitInfo
|
public class DetectCloakedInfo : UpgradableTraitInfo, ITraitInfo
|
||||||
{
|
{
|
||||||
[Desc("Specific cloak classifications I can reveal.")]
|
[Desc("Specific cloak classifications I can reveal.")]
|
||||||
public readonly string[] CloakTypes = { "Cloak" };
|
public readonly string[] CloakTypes = { "Cloak" };
|
||||||
@@ -24,13 +24,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public object Create(ActorInitializer init) { return new DetectCloaked(this); }
|
public object Create(ActorInitializer init) { return new DetectCloaked(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DetectCloaked
|
public class DetectCloaked : UpgradableTrait<DetectCloakedInfo>
|
||||||
{
|
{
|
||||||
public readonly DetectCloakedInfo Info;
|
public DetectCloaked(DetectCloakedInfo info) : base(info) { }
|
||||||
|
|
||||||
public DetectCloaked(DetectCloakedInfo info)
|
|
||||||
{
|
|
||||||
Info = info;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "PlaceBuilding" || order.OrderString == "LineBuild")
|
if (order.OrderString == "PlaceBuilding" || order.OrderString == "LineBuild" || order.OrderString == "PlacePlug")
|
||||||
{
|
{
|
||||||
self.World.AddFrameEndTask(w =>
|
self.World.AddFrameEndTask(w =>
|
||||||
{
|
{
|
||||||
@@ -69,6 +69,27 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
playSounds = false;
|
playSounds = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (order.OrderString == "PlacePlug")
|
||||||
|
{
|
||||||
|
var host = self.World.WorldActor.Trait<BuildingInfluence>().GetBuildingAt(order.TargetLocation);
|
||||||
|
if (host == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var plugInfo = unit.Traits.GetOrDefault<PlugInfo>();
|
||||||
|
if (plugInfo == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var location = host.Location;
|
||||||
|
var pluggable = host.TraitsImplementing<Pluggable>()
|
||||||
|
.FirstOrDefault(p => location + p.Info.Offset == order.TargetLocation && p.AcceptsPlug(host, plugInfo.Type));
|
||||||
|
|
||||||
|
if (pluggable == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pluggable.EnablePlug(host, plugInfo.Type);
|
||||||
|
foreach (var s in buildingInfo.BuildSounds)
|
||||||
|
Sound.PlayToPlayer(order.Player, s, host.CenterPosition);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!self.World.CanPlaceBuilding(order.TargetString, buildingInfo, order.TargetLocation, null)
|
if (!self.World.CanPlaceBuilding(order.TargetString, buildingInfo, order.TargetLocation, null)
|
||||||
|
|||||||
24
OpenRA.Mods.Common/Traits/Plug.cs
Normal file
24
OpenRA.Mods.Common/Traits/Plug.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
|
||||||
|
* This file is part of OpenRA, which is free software. It is made
|
||||||
|
* available to you under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.Traits
|
||||||
|
{
|
||||||
|
public class PlugInfo : TraitInfo<Plug>
|
||||||
|
{
|
||||||
|
[Desc("Plug type (matched against Upgrades in Pluggable)")]
|
||||||
|
public readonly string Type = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Plug { }
|
||||||
|
}
|
||||||
79
OpenRA.Mods.Common/Traits/Pluggable.cs
Normal file
79
OpenRA.Mods.Common/Traits/Pluggable.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
|
||||||
|
* This file is part of OpenRA, which is free software. It is made
|
||||||
|
* available to you under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.Traits
|
||||||
|
{
|
||||||
|
public class PluggableInfo : ITraitInfo, Requires<UpgradeManagerInfo>
|
||||||
|
{
|
||||||
|
[Desc("Footprint cell offset where a plug can be placed.")]
|
||||||
|
public readonly CVec Offset = CVec.Zero;
|
||||||
|
|
||||||
|
[FieldLoader.LoadUsing("LoadUpgrades")]
|
||||||
|
[Desc("Upgrades to grant for each accepted plug type.")]
|
||||||
|
public readonly Dictionary<string, string[]> Upgrades = null;
|
||||||
|
|
||||||
|
static object LoadUpgrades(MiniYaml y)
|
||||||
|
{
|
||||||
|
MiniYaml upgrades;
|
||||||
|
|
||||||
|
if (!y.ToDictionary().TryGetValue("Upgrades", out upgrades))
|
||||||
|
return new Dictionary<string, string[]>();
|
||||||
|
|
||||||
|
return upgrades.Nodes.ToDictionary(
|
||||||
|
kv => kv.Key,
|
||||||
|
kv => FieldLoader.GetValue<string[]>("(value)", kv.Value.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Create(ActorInitializer init) { return new Pluggable(init.Self, this); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Pluggable
|
||||||
|
{
|
||||||
|
public readonly PluggableInfo Info;
|
||||||
|
readonly UpgradeManager upgradeManager;
|
||||||
|
string active;
|
||||||
|
|
||||||
|
public Pluggable(Actor self, PluggableInfo info)
|
||||||
|
{
|
||||||
|
Info = info;
|
||||||
|
upgradeManager = self.Trait<UpgradeManager>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AcceptsPlug(Actor self, string type)
|
||||||
|
{
|
||||||
|
return active == null && Info.Upgrades.ContainsKey(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnablePlug(Actor self, string type)
|
||||||
|
{
|
||||||
|
string[] upgrades;
|
||||||
|
if (!Info.Upgrades.TryGetValue(type, out upgrades))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var u in upgrades)
|
||||||
|
upgradeManager.GrantUpgrade(self, u, this);
|
||||||
|
|
||||||
|
active = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisablePlug(Actor self, string type)
|
||||||
|
{
|
||||||
|
if (type != active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var u in Info.Upgrades[type])
|
||||||
|
upgradeManager.RevokeUpgrade(self, u, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Mods.Common.Graphics;
|
using OpenRA.Mods.Common.Graphics;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
@@ -32,9 +33,17 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (self.Owner != self.World.LocalPlayer)
|
if (self.Owner != self.World.LocalPlayer)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
|
var range = self.TraitsImplementing<DetectCloaked>()
|
||||||
|
.Where(a => !a.IsTraitDisabled)
|
||||||
|
.Select(a => WRange.FromCells(a.Info.Range))
|
||||||
|
.Append(WRange.Zero).Max();
|
||||||
|
|
||||||
|
if (range == WRange.Zero)
|
||||||
|
yield break;
|
||||||
|
|
||||||
yield return new RangeCircleRenderable(
|
yield return new RangeCircleRenderable(
|
||||||
self.CenterPosition,
|
self.CenterPosition,
|
||||||
WRange.FromCells(self.Info.Traits.Get<DetectCloakedInfo>().Range),
|
range,
|
||||||
0,
|
0,
|
||||||
Color.FromArgb(128, Color.LimeGreen),
|
Color.FromArgb(128, Color.LimeGreen),
|
||||||
Color.FromArgb(96, Color.Black));
|
Color.FromArgb(96, Color.Black));
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public IEnumerable<IRenderable> Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition)
|
public IEnumerable<IRenderable> Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition)
|
||||||
{
|
{
|
||||||
var armaments = ai.Traits.WithInterface<ArmamentInfo>();
|
var armaments = ai.Traits.WithInterface<ArmamentInfo>()
|
||||||
|
.Where(a => a.UpgradeMinEnabledLevel == 0);
|
||||||
var range = FallbackRange;
|
var range = FallbackRange;
|
||||||
|
|
||||||
if (armaments.Any())
|
if (armaments.Any())
|
||||||
@@ -69,9 +70,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (self.Owner != self.World.LocalPlayer)
|
if (self.Owner != self.World.LocalPlayer)
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
|
var range = attack.GetMaximumRange();
|
||||||
|
if (range == WRange.Zero)
|
||||||
|
yield break;
|
||||||
|
|
||||||
yield return new RangeCircleRenderable(
|
yield return new RangeCircleRenderable(
|
||||||
self.CenterPosition,
|
self.CenterPosition,
|
||||||
attack.GetMaximumRange(),
|
range,
|
||||||
0,
|
0,
|
||||||
Color.FromArgb(128, Color.Yellow),
|
Color.FromArgb(128, Color.Yellow),
|
||||||
Color.FromArgb(96, Color.Black));
|
Color.FromArgb(96, Color.Black));
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ using OpenRA.Traits;
|
|||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
[Desc("Renders a decorative animation on units and buildings.")]
|
[Desc("Renders a decorative animation on units and buildings.")]
|
||||||
public class WithIdleOverlayInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<IBodyOrientationInfo>
|
public class WithIdleOverlayInfo : UpgradableTraitInfo, ITraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<IBodyOrientationInfo>
|
||||||
{
|
{
|
||||||
[Desc("Sequence name to use")]
|
[Desc("Sequence name to use")]
|
||||||
public readonly string Sequence = "idle-overlay";
|
public readonly string Sequence = "idle-overlay";
|
||||||
@@ -37,6 +37,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
|
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
|
||||||
{
|
{
|
||||||
|
if (UpgradeMinEnabledLevel > 0)
|
||||||
|
yield break;
|
||||||
|
|
||||||
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
|
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
|
||||||
var facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
|
var facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
|
||||||
var anim = new Animation(init.World, image, () => facing);
|
var anim = new Animation(init.World, image, () => facing);
|
||||||
@@ -48,12 +51,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WithIdleOverlay : INotifyDamageStateChanged, INotifyBuildComplete, INotifySold, INotifyTransform
|
public class WithIdleOverlay : UpgradableTrait<WithIdleOverlayInfo>, INotifyDamageStateChanged, INotifyBuildComplete, INotifySold, INotifyTransform
|
||||||
{
|
{
|
||||||
Animation overlay;
|
Animation overlay;
|
||||||
bool buildComplete;
|
bool buildComplete;
|
||||||
|
|
||||||
public WithIdleOverlay(Actor self, WithIdleOverlayInfo info)
|
public WithIdleOverlay(Actor self, WithIdleOverlayInfo info)
|
||||||
|
: base(info)
|
||||||
{
|
{
|
||||||
var rs = self.Trait<RenderSprites>();
|
var rs = self.Trait<RenderSprites>();
|
||||||
var body = self.Trait<IBodyOrientation>();
|
var body = self.Trait<IBodyOrientation>();
|
||||||
@@ -65,7 +69,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
rs.Add("idle_overlay_{0}".F(info.Sequence),
|
rs.Add("idle_overlay_{0}".F(info.Sequence),
|
||||||
new AnimationWithOffset(overlay,
|
new AnimationWithOffset(overlay,
|
||||||
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
|
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
|
||||||
() => !buildComplete,
|
() => IsTraitDisabled || !buildComplete,
|
||||||
() => info.PauseOnLowPower && disabled.Any(d => d.Disabled),
|
() => info.PauseOnLowPower && disabled.Any(d => d.Disabled),
|
||||||
p => WithTurret.ZOffsetFromCenter(self, p, 1)),
|
p => WithTurret.ZOffsetFromCenter(self, p, 1)),
|
||||||
info.Palette, info.IsPlayerPalette);
|
info.Palette, info.IsPlayerPalette);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ using OpenRA.Traits;
|
|||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
[Desc("Renders the MuzzleSequence from the Armament trait.")]
|
[Desc("Renders the MuzzleSequence from the Armament trait.")]
|
||||||
class WithMuzzleFlashInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<AttackBaseInfo>, Requires<ArmamentInfo>
|
class WithMuzzleFlashInfo : UpgradableTraitInfo, ITraitInfo, Requires<RenderSpritesInfo>, Requires<AttackBaseInfo>, Requires<ArmamentInfo>
|
||||||
{
|
{
|
||||||
[Desc("Ignore the weapon position, and always draw relative to the center of the actor")]
|
[Desc("Ignore the weapon position, and always draw relative to the center of the actor")]
|
||||||
public readonly bool IgnoreOffset = false;
|
public readonly bool IgnoreOffset = false;
|
||||||
@@ -25,13 +25,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public object Create(ActorInitializer init) { return new WithMuzzleFlash(init.Self, this); }
|
public object Create(ActorInitializer init) { return new WithMuzzleFlash(init.Self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class WithMuzzleFlash : INotifyAttack, IRender, ITick
|
class WithMuzzleFlash : UpgradableTrait<WithMuzzleFlashInfo>, INotifyAttack, IRender, ITick
|
||||||
{
|
{
|
||||||
Dictionary<Barrel, bool> visible = new Dictionary<Barrel, bool>();
|
Dictionary<Barrel, bool> visible = new Dictionary<Barrel, bool>();
|
||||||
Dictionary<Barrel, AnimationWithOffset> anims = new Dictionary<Barrel, AnimationWithOffset>();
|
Dictionary<Barrel, AnimationWithOffset> anims = new Dictionary<Barrel, AnimationWithOffset>();
|
||||||
Func<int> getFacing;
|
Func<int> getFacing;
|
||||||
|
|
||||||
public WithMuzzleFlash(Actor self, WithMuzzleFlashInfo info)
|
public WithMuzzleFlash(Actor self, WithMuzzleFlashInfo info)
|
||||||
|
: base(info)
|
||||||
{
|
{
|
||||||
var render = self.Trait<RenderSprites>();
|
var render = self.Trait<RenderSprites>();
|
||||||
var facing = self.TraitOrDefault<IFacing>();
|
var facing = self.TraitOrDefault<IFacing>();
|
||||||
@@ -64,7 +65,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
anims.Add(barrel,
|
anims.Add(barrel,
|
||||||
new AnimationWithOffset(muzzleFlash,
|
new AnimationWithOffset(muzzleFlash,
|
||||||
() => info.IgnoreOffset ? WVec.Zero : armClosure.MuzzleOffset(self, barrel),
|
() => info.IgnoreOffset ? WVec.Zero : armClosure.MuzzleOffset(self, barrel),
|
||||||
() => !visible[barrel],
|
() => IsTraitDisabled || !visible[barrel],
|
||||||
() => false,
|
() => false,
|
||||||
p => WithTurret.ZOffsetFromCenter(self, p, 2)));
|
p => WithTurret.ZOffsetFromCenter(self, p, 2)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ using OpenRA.Traits;
|
|||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
[Desc("Renders turrets for units with the Turreted trait.")]
|
[Desc("Renders turrets for units with the Turreted trait.")]
|
||||||
public class WithTurretInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<TurretedInfo>, Requires<IBodyOrientationInfo>
|
public class WithTurretInfo : UpgradableTraitInfo, ITraitInfo, IRenderActorPreviewSpritesInfo,
|
||||||
|
Requires<RenderSpritesInfo>, Requires<TurretedInfo>, Requires<IBodyOrientationInfo>
|
||||||
{
|
{
|
||||||
[Desc("Sequence name to use")]
|
[Desc("Sequence name to use")]
|
||||||
public readonly string Sequence = "turret";
|
public readonly string Sequence = "turret";
|
||||||
@@ -35,6 +36,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
|
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
|
||||||
{
|
{
|
||||||
|
if (UpgradeMinEnabledLevel > 0)
|
||||||
|
yield break;
|
||||||
|
|
||||||
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
|
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
|
||||||
var t = init.Actor.Traits.WithInterface<TurretedInfo>()
|
var t = init.Actor.Traits.WithInterface<TurretedInfo>()
|
||||||
.First(tt => tt.Turret == Turret);
|
.First(tt => tt.Turret == Turret);
|
||||||
@@ -52,9 +56,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WithTurret : ITick
|
public class WithTurret : UpgradableTrait<WithTurretInfo>, ITick
|
||||||
{
|
{
|
||||||
WithTurretInfo info;
|
|
||||||
RenderSprites rs;
|
RenderSprites rs;
|
||||||
IBodyOrientation body;
|
IBodyOrientation body;
|
||||||
AttackBase ab;
|
AttackBase ab;
|
||||||
@@ -63,8 +66,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
Animation anim;
|
Animation anim;
|
||||||
|
|
||||||
public WithTurret(Actor self, WithTurretInfo info)
|
public WithTurret(Actor self, WithTurretInfo info)
|
||||||
|
: base(info)
|
||||||
{
|
{
|
||||||
this.info = info;
|
|
||||||
rs = self.Trait<RenderSprites>();
|
rs = self.Trait<RenderSprites>();
|
||||||
body = self.Trait<IBodyOrientation>();
|
body = self.Trait<IBodyOrientation>();
|
||||||
|
|
||||||
@@ -76,8 +79,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
anim = new Animation(self.World, rs.GetImage(self), () => t.TurretFacing);
|
anim = new Animation(self.World, rs.GetImage(self), () => t.TurretFacing);
|
||||||
anim.Play(info.Sequence);
|
anim.Play(info.Sequence);
|
||||||
rs.Add("turret_{0}".F(info.Turret), new AnimationWithOffset(
|
rs.Add("turret_{0}_{1}".F(info.Turret, info.Sequence), new AnimationWithOffset(
|
||||||
anim, () => TurretOffset(self), null, () => false, p => ZOffsetFromCenter(self, p, 1)));
|
anim, () => TurretOffset(self), () => IsTraitDisabled, () => false, p => ZOffsetFromCenter(self, p, 1)));
|
||||||
|
|
||||||
// Restrict turret facings to match the sprite
|
// Restrict turret facings to match the sprite
|
||||||
t.QuantizedFacings = anim.CurrentSequence.Facings;
|
t.QuantizedFacings = anim.CurrentSequence.Facings;
|
||||||
@@ -85,7 +88,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
WVec TurretOffset(Actor self)
|
WVec TurretOffset(Actor self)
|
||||||
{
|
{
|
||||||
if (!info.Recoils)
|
if (!Info.Recoils)
|
||||||
return t.Position(self);
|
return t.Position(self);
|
||||||
|
|
||||||
var recoil = arms.Aggregate(WRange.Zero, (a, b) => a + b.Recoil);
|
var recoil = arms.Aggregate(WRange.Zero, (a, b) => a + b.Recoil);
|
||||||
@@ -97,10 +100,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public void Tick(Actor self)
|
public void Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (info.AimSequence == null)
|
if (Info.AimSequence == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var sequence = ab.IsAttacking ? info.AimSequence : info.Sequence;
|
var sequence = ab.IsAttacking ? Info.AimSequence : Info.Sequence;
|
||||||
anim.ReplaceAnim(sequence);
|
anim.ReplaceAnim(sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
public abstract class SupportPowerInfo : ITraitInfo
|
public abstract class SupportPowerInfo : UpgradableTraitInfo, ITraitInfo
|
||||||
{
|
{
|
||||||
[Desc("Measured in seconds.")]
|
[Desc("Measured in seconds.")]
|
||||||
public readonly int ChargeTime = 0;
|
public readonly int ChargeTime = 0;
|
||||||
@@ -53,15 +53,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public SupportPowerInfo() { OrderName = GetType().Name + "Order"; }
|
public SupportPowerInfo() { OrderName = GetType().Name + "Order"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SupportPower
|
public class SupportPower : UpgradableTrait<SupportPowerInfo>
|
||||||
{
|
{
|
||||||
public readonly Actor Self;
|
public readonly Actor Self;
|
||||||
public readonly SupportPowerInfo Info;
|
|
||||||
protected RadarPing ping;
|
protected RadarPing ping;
|
||||||
|
|
||||||
public SupportPower(Actor self, SupportPowerInfo info)
|
public SupportPower(Actor self, SupportPowerInfo info)
|
||||||
|
: base(info)
|
||||||
{
|
{
|
||||||
Info = info;
|
|
||||||
Self = self;
|
Self = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (!Powers.TryGetValue(key, out sp))
|
if (!Powers.TryGetValue(key, out sp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sp.Disabled = false;
|
sp.PrerequisitesAvailable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PrerequisitesUnavailable(string key)
|
public void PrerequisitesUnavailable(string key)
|
||||||
@@ -141,7 +141,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (!Powers.TryGetValue(key, out sp))
|
if (!Powers.TryGetValue(key, out sp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sp.Disabled = true;
|
sp.PrerequisitesAvailable(false);
|
||||||
sp.RemainingTime = sp.TotalTime;
|
sp.RemainingTime = sp.TotalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,17 +158,25 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public int RemainingTime;
|
public int RemainingTime;
|
||||||
public int TotalTime;
|
public int TotalTime;
|
||||||
public bool Active { get; private set; }
|
public bool Active { get; private set; }
|
||||||
public bool Disabled { get; set; }
|
public bool Disabled { get { return !prereqsAvailable || !upgradeAvailable; } }
|
||||||
|
|
||||||
public SupportPowerInfo Info { get { return Instances.Select(i => i.Info).FirstOrDefault(); } }
|
public SupportPowerInfo Info { get { return Instances.Select(i => i.Info).FirstOrDefault(); } }
|
||||||
public bool Ready { get { return Active && RemainingTime == 0; } }
|
public bool Ready { get { return Active && RemainingTime == 0; } }
|
||||||
|
|
||||||
|
bool upgradeAvailable;
|
||||||
|
bool prereqsAvailable = true;
|
||||||
|
|
||||||
public SupportPowerInstance(string key, SupportPowerManager manager)
|
public SupportPowerInstance(string key, SupportPowerManager manager)
|
||||||
{
|
{
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PrerequisitesAvailable(bool available)
|
||||||
|
{
|
||||||
|
prereqsAvailable = available;
|
||||||
|
}
|
||||||
|
|
||||||
static bool InstanceDisabled(SupportPower sp)
|
static bool InstanceDisabled(SupportPower sp)
|
||||||
{
|
{
|
||||||
return sp.Self.TraitsImplementing<IDisable>().Any(d => d.Disabled);
|
return sp.Self.TraitsImplementing<IDisable>().Any(d => d.Disabled);
|
||||||
@@ -178,6 +186,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
bool notifiedReady;
|
bool notifiedReady;
|
||||||
public void Tick()
|
public void Tick()
|
||||||
{
|
{
|
||||||
|
upgradeAvailable = Instances.Any(i => !i.IsTraitDisabled);
|
||||||
|
if (!upgradeAvailable)
|
||||||
|
RemainingTime = TotalTime;
|
||||||
|
|
||||||
Active = !Disabled && Instances.Any(i => !i.Self.IsDisabled());
|
Active = !Disabled && Instances.Any(i => !i.Self.IsDisabled());
|
||||||
if (!Active)
|
if (!Active)
|
||||||
return;
|
return;
|
||||||
@@ -226,7 +238,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
notifiedCharging = notifiedReady = false;
|
notifiedCharging = notifiedReady = false;
|
||||||
|
|
||||||
if (Info.OneShot)
|
if (Info.OneShot)
|
||||||
Disabled = true;
|
PrerequisitesAvailable(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,13 @@
|
|||||||
CloakDelay: 90
|
CloakDelay: 90
|
||||||
MustBeDestroyed:
|
MustBeDestroyed:
|
||||||
|
|
||||||
|
^BuildingPlug:
|
||||||
|
Building:
|
||||||
|
BuildSounds: place2.aud
|
||||||
|
KillsSelf:
|
||||||
|
RemoveInstead: true
|
||||||
|
RenderSprites:
|
||||||
|
|
||||||
^Infantry:
|
^Infantry:
|
||||||
AppearsOnRadar:
|
AppearsOnRadar:
|
||||||
Health:
|
Health:
|
||||||
|
|||||||
@@ -86,6 +86,46 @@ GAPOWR:
|
|||||||
TargetTypes: Ground, C4, DetonateAttack, SpyInfiltrate
|
TargetTypes: Ground, C4, DetonateAttack, SpyInfiltrate
|
||||||
ScalePowerWithHealth:
|
ScalePowerWithHealth:
|
||||||
DisabledOverlay:
|
DisabledOverlay:
|
||||||
|
Pluggable@pluga:
|
||||||
|
Offset: 0,1
|
||||||
|
Upgrades:
|
||||||
|
powrup: powrup.a
|
||||||
|
Power@pluga:
|
||||||
|
UpgradeTypes: powrup.a
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Amount: 50
|
||||||
|
WithIdleOverlay@pluga:
|
||||||
|
UpgradeTypes: powrup.a
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Sequence: idle-powrupa
|
||||||
|
Pluggable@plugb:
|
||||||
|
Offset: 1,1
|
||||||
|
Upgrades:
|
||||||
|
powrup: powrup.b
|
||||||
|
WithIdleOverlay@plugb:
|
||||||
|
UpgradeTypes: powrup.b
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Sequence: idle-powrupb
|
||||||
|
Power@plugb:
|
||||||
|
UpgradeTypes: powrup.b
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Amount: 50
|
||||||
|
|
||||||
|
GAPOWRUP:
|
||||||
|
Inherits: ^BuildingPlug
|
||||||
|
Valued:
|
||||||
|
Cost: 150
|
||||||
|
Tooltip:
|
||||||
|
Name: Power Turbine
|
||||||
|
Description: Provides extra power generation
|
||||||
|
Buildable:
|
||||||
|
Queue: Defense
|
||||||
|
BuildPaletteOrder: 10
|
||||||
|
Prerequisites: gapowr, ~structures.gdi
|
||||||
|
Plug:
|
||||||
|
Type: powrup
|
||||||
|
Power:
|
||||||
|
Amount: 50
|
||||||
|
|
||||||
GAPILE:
|
GAPILE:
|
||||||
Inherits: ^Building
|
Inherits: ^Building
|
||||||
@@ -430,7 +470,7 @@ GAWALL:
|
|||||||
Inherits: ^Wall
|
Inherits: ^Wall
|
||||||
Buildable:
|
Buildable:
|
||||||
Queue: Defense
|
Queue: Defense
|
||||||
BuildPaletteOrder: 1001
|
BuildPaletteOrder: 20
|
||||||
Prerequisites: ~structures.gdi
|
Prerequisites: ~structures.gdi
|
||||||
SoundOnDamageTransition:
|
SoundOnDamageTransition:
|
||||||
DamagedSounds:
|
DamagedSounds:
|
||||||
@@ -910,14 +950,13 @@ NASTLH:
|
|||||||
Selectable:
|
Selectable:
|
||||||
Bounds: 124, 64, 15, 13
|
Bounds: 124, 64, 15, 13
|
||||||
|
|
||||||
#TODO: Placeholder, replace with Component Tower + Vulcan Upgrade
|
GACTWR:
|
||||||
GAVULC:
|
|
||||||
Inherits: ^Building
|
Inherits: ^Building
|
||||||
Valued:
|
Valued:
|
||||||
Cost: 600
|
Cost: 600
|
||||||
Tooltip:
|
Tooltip:
|
||||||
Name: Vulcan Tower
|
Name: Component Tower
|
||||||
Description: Basic base defense. \nRequires no power to operate.\n Strong vs infantry and light armor\n Cannot target Aircraft
|
Description: Modular tower for base defenses.
|
||||||
Buildable:
|
Buildable:
|
||||||
Queue: Defense
|
Queue: Defense
|
||||||
BuildPaletteOrder: 30
|
BuildPaletteOrder: 30
|
||||||
@@ -938,26 +977,60 @@ GAVULC:
|
|||||||
RenderRangeCircle:
|
RenderRangeCircle:
|
||||||
RenderDetectionCircle:
|
RenderDetectionCircle:
|
||||||
DetectCloaked:
|
DetectCloaked:
|
||||||
|
UpgradeTypes: tower
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
Range: 5
|
Range: 5
|
||||||
AutoTarget:
|
AutoTarget:
|
||||||
Turreted:
|
Turreted:
|
||||||
ROT: 10
|
ROT: 10
|
||||||
InitialFacing: 50
|
InitialFacing: 50
|
||||||
AttackTurreted:
|
AttackTurreted:
|
||||||
WithTurret:
|
UpgradeTypes: tower
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
CanPowerDown:
|
||||||
|
WithTurret@VULC:
|
||||||
|
UpgradeTypes: tower.vulcan
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
Recoils: no
|
Recoils: no
|
||||||
Armament@PRIMARY:
|
Sequence: turret-vulcan
|
||||||
|
WithTurret@ROCKET:
|
||||||
|
UpgradeTypes: tower.rocket
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Recoils: no
|
||||||
|
Sequence: turret-rocket
|
||||||
|
WithTurret@SAM:
|
||||||
|
UpgradeTypes: tower.sam
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Recoils: no
|
||||||
|
Sequence: turret-sam
|
||||||
|
Armament@VULCPRIMARY:
|
||||||
|
UpgradeTypes: tower.vulcan
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
Weapon: VulcanTower
|
Weapon: VulcanTower
|
||||||
LocalOffset: 768,85,512
|
LocalOffset: 768,85,512
|
||||||
MuzzleSequence: muzzle
|
MuzzleSequence: muzzle
|
||||||
MuzzleSplitFacings: 8
|
MuzzleSplitFacings: 8
|
||||||
Armament@SECONDARY:
|
Armament@VULCSECONDARY:
|
||||||
|
UpgradeTypes: tower.vulcan
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
Name: secondary
|
Name: secondary
|
||||||
Weapon: VulcanTower
|
Weapon: VulcanTower
|
||||||
LocalOffset: 768,-85,512
|
LocalOffset: 768,-85,512
|
||||||
MuzzleSequence: muzzle
|
MuzzleSequence: muzzle
|
||||||
MuzzleSplitFacings: 8
|
MuzzleSplitFacings: 8
|
||||||
|
Armament@ROCKET:
|
||||||
|
UpgradeTypes: tower.rocket
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Weapon: RPGTower
|
||||||
|
LocalOffset: 512,-128,512
|
||||||
|
Armament@SAM:
|
||||||
|
UpgradeTypes: tower.sam
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Weapon: SAMTower
|
||||||
|
LocalOffset: 512,0,512
|
||||||
WithMuzzleFlash:
|
WithMuzzleFlash:
|
||||||
|
UpgradeTypes: tower.vulcan
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
WithIdleOverlay@LIGHTS:
|
WithIdleOverlay@LIGHTS:
|
||||||
Sequence: idle-lights
|
Sequence: idle-lights
|
||||||
LineBuildNode:
|
LineBuildNode:
|
||||||
@@ -965,106 +1038,67 @@ GAVULC:
|
|||||||
-RenderBuilding:
|
-RenderBuilding:
|
||||||
RenderBuildingWall:
|
RenderBuildingWall:
|
||||||
Type: wall
|
Type: wall
|
||||||
|
Power@base:
|
||||||
|
Amount: -10
|
||||||
|
Power@turrets:
|
||||||
|
UpgradeTypes: tower
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Amount: -20
|
||||||
|
Power@samextra:
|
||||||
|
UpgradeTypes: tower.sam
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Amount: -10
|
||||||
|
Pluggable:
|
||||||
|
Upgrades:
|
||||||
|
tower.vulcan: tower, tower.vulcan
|
||||||
|
tower.rocket: tower, tower.rocket
|
||||||
|
tower.sam: tower, tower.sam
|
||||||
|
|
||||||
|
GAVULC:
|
||||||
|
Inherits: ^BuildingPlug
|
||||||
|
Valued:
|
||||||
|
Cost: 150
|
||||||
|
Tooltip:
|
||||||
|
Name: Vulcan Tower
|
||||||
|
Description: Basic base defense. \nRequires no power to operate.\n Strong vs infantry and light armor\n Cannot target Aircraft
|
||||||
|
Buildable:
|
||||||
|
Queue: Defense
|
||||||
|
BuildPaletteOrder: 40
|
||||||
|
Prerequisites: gactwr, gapile, ~structures.gdi
|
||||||
|
Plug:
|
||||||
|
Type: tower.vulcan
|
||||||
Power:
|
Power:
|
||||||
Amount: -20
|
Amount: -20
|
||||||
|
|
||||||
#TODO: Placeholder, replace with Component Tower + RPG Upgrade
|
|
||||||
GAROCK:
|
GAROCK:
|
||||||
Inherits: ^Building
|
Inherits: ^BuildingPlug
|
||||||
Valued:
|
Valued:
|
||||||
Cost: 1000
|
Cost: 600
|
||||||
Tooltip:
|
Tooltip:
|
||||||
Name: RPG Tower
|
Name: RPG Upgrade
|
||||||
Description: GDI Advanced base defense.\nRequires power to operate.\n Strong vs armored ground units\n Cannot target Aircraft
|
Description: GDI Advanced base defense.\nRequires power to operate.\n Strong vs armored ground units\n Cannot target Aircraft
|
||||||
Buildable:
|
Buildable:
|
||||||
Queue: Defense
|
Queue: Defense
|
||||||
BuildPaletteOrder: 40
|
BuildPaletteOrder: 40
|
||||||
Prerequisites: gapile, ~structures.gdi
|
Prerequisites: gactwr, gapile, ~structures.gdi
|
||||||
Building:
|
Plug:
|
||||||
Selectable:
|
Type: tower.rocket
|
||||||
Bounds: 48, 48, 0, -12
|
|
||||||
RequiresPower:
|
|
||||||
DisabledOverlay:
|
|
||||||
-GivesBuildableArea:
|
|
||||||
Health:
|
|
||||||
HP: 500
|
|
||||||
Armor:
|
|
||||||
Type: Light
|
|
||||||
RevealsShroud:
|
|
||||||
Range: 6c0
|
|
||||||
BodyOrientation:
|
|
||||||
QuantizedFacings: 32
|
|
||||||
RenderRangeCircle:
|
|
||||||
RenderDetectionCircle:
|
|
||||||
DetectCloaked:
|
|
||||||
Range: 5
|
|
||||||
AutoTarget:
|
|
||||||
Turreted:
|
|
||||||
ROT: 10
|
|
||||||
InitialFacing: 50
|
|
||||||
AttackTurreted:
|
|
||||||
WithTurret:
|
|
||||||
Recoils: no
|
|
||||||
Armament:
|
|
||||||
Weapon: RPGTower
|
|
||||||
LocalOffset: 512,-128,512
|
|
||||||
WithIdleOverlay@LIGHTS:
|
|
||||||
Sequence: idle-lights
|
|
||||||
LineBuildNode:
|
|
||||||
Types: turret
|
|
||||||
-RenderBuilding:
|
|
||||||
RenderBuildingWall:
|
|
||||||
Type: wall
|
|
||||||
Power:
|
Power:
|
||||||
Amount: -50
|
Amount: -20
|
||||||
|
|
||||||
#TODO: Placeholder, replace with Component Tower + SAM Upgrade
|
|
||||||
GACSAM:
|
GACSAM:
|
||||||
Inherits: ^Building
|
Inherits: ^BuildingPlug
|
||||||
Valued:
|
Valued:
|
||||||
Cost: 600
|
Cost: 300
|
||||||
Tooltip:
|
Tooltip:
|
||||||
Name: S.A.M. Tower
|
Name: SAM. Upgrade
|
||||||
Description: GDI Anti-Air base defense. \nRequires power to operate.\n Strong vs all Aircraft\n Cannot target ground units
|
Description: GDI Anti-Air base defense. \nRequires power to operate.\n Strong vs all Aircraft\n Cannot target ground units
|
||||||
Buildable:
|
Buildable:
|
||||||
Queue: Defense
|
Queue: Defense
|
||||||
BuildPaletteOrder: 60
|
BuildPaletteOrder: 40
|
||||||
Prerequisites: garadr, ~structures.gdi
|
Prerequisites: gactwr, garadr, ~structures.gdi
|
||||||
Building:
|
Plug:
|
||||||
Selectable:
|
Type: tower.sam
|
||||||
Bounds: 48, 48, 0, -12
|
|
||||||
RequiresPower:
|
|
||||||
DisabledOverlay:
|
|
||||||
-GivesBuildableArea:
|
|
||||||
Health:
|
|
||||||
HP: 500
|
|
||||||
Armor:
|
|
||||||
Type: Light
|
|
||||||
RevealsShroud:
|
|
||||||
Range: 6c0
|
|
||||||
BodyOrientation:
|
|
||||||
QuantizedFacings: 32
|
|
||||||
RenderRangeCircle:
|
|
||||||
RenderDetectionCircle:
|
|
||||||
DetectCloaked:
|
|
||||||
Range: 5
|
|
||||||
AutoTarget:
|
|
||||||
Turreted:
|
|
||||||
ROT: 10
|
|
||||||
InitialFacing: 50
|
|
||||||
AttackTurreted:
|
|
||||||
WithTurret:
|
|
||||||
Recoils: no
|
|
||||||
Armament:
|
|
||||||
Weapon: SAMTower
|
|
||||||
LocalOffset: 512,0,512
|
|
||||||
WithIdleOverlay@LIGHTS:
|
|
||||||
Sequence: idle-lights
|
|
||||||
LineBuildNode:
|
|
||||||
Types: turret
|
|
||||||
-RenderBuilding:
|
|
||||||
RenderBuildingWall:
|
|
||||||
Type: wall
|
|
||||||
Power:
|
Power:
|
||||||
Amount: -30
|
Amount: -30
|
||||||
|
|
||||||
@@ -1291,16 +1325,16 @@ NAMISL:
|
|||||||
GAPLUG:
|
GAPLUG:
|
||||||
Inherits: ^Building
|
Inherits: ^Building
|
||||||
Valued:
|
Valued:
|
||||||
Cost: 1800
|
Cost: 1000
|
||||||
Tooltip:
|
Tooltip:
|
||||||
Name: GDI Upgrade Center
|
Name: GDI Upgrade Center
|
||||||
Description: Provides the Orbital Ion Cannon support power.\nRequires power to operate.
|
Description: Can be upgraded for additional technology
|
||||||
Selectable:
|
Selectable:
|
||||||
Bounds: 115,120,0,-20
|
Bounds: 115,120,0,-20
|
||||||
Buildable:
|
Buildable:
|
||||||
BuildPaletteOrder: 100
|
BuildPaletteOrder: 100
|
||||||
Prerequisites: proc, gatech
|
Prerequisites: proc, gatech
|
||||||
Queue: Defense
|
Queue: Building
|
||||||
Building:
|
Building:
|
||||||
Footprint: xxx xxx
|
Footprint: xxx xxx
|
||||||
Dimensions: 2,3
|
Dimensions: 2,3
|
||||||
@@ -1321,6 +1355,8 @@ GAPLUG:
|
|||||||
RevealsShroud:
|
RevealsShroud:
|
||||||
Range: 6c0
|
Range: 6c0
|
||||||
IonCannonPower:
|
IonCannonPower:
|
||||||
|
UpgradeTypes: plug.ioncannon
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
Icon: ioncannon
|
Icon: ioncannon
|
||||||
Effect: ionbeam
|
Effect: ionbeam
|
||||||
ChargeTime: 180
|
ChargeTime: 180
|
||||||
@@ -1336,6 +1372,42 @@ GAPLUG:
|
|||||||
SupportPowerChargeBar:
|
SupportPowerChargeBar:
|
||||||
Power:
|
Power:
|
||||||
Amount: -150
|
Amount: -150
|
||||||
|
Power@ioncannon:
|
||||||
|
UpgradeTypes: plug.ioncannon
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Amount: -100
|
||||||
|
Pluggable@pluga:
|
||||||
|
Offset: 0,2
|
||||||
|
Upgrades:
|
||||||
|
plug.ioncannon: plug.ioncannon, plug.ioncannona
|
||||||
|
WithIdleOverlay@ioncannona:
|
||||||
|
UpgradeTypes: plug.ioncannona
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Sequence: idle-ioncannona
|
||||||
|
Pluggable@plugb:
|
||||||
|
Offset: 1,2
|
||||||
|
Upgrades:
|
||||||
|
plug.ioncannon: plug.ioncannon, plug.ioncannonb
|
||||||
|
WithIdleOverlay@ioncannonb:
|
||||||
|
UpgradeTypes: plug.ioncannonb
|
||||||
|
UpgradeMinEnabledLevel: 1
|
||||||
|
Sequence: idle-ioncannonb
|
||||||
|
|
||||||
|
GAPLUG3:
|
||||||
|
Inherits: ^BuildingPlug
|
||||||
|
Valued:
|
||||||
|
Cost: 1500
|
||||||
|
Tooltip:
|
||||||
|
Name: Ion Cannon Uplink
|
||||||
|
Description: Enables use of the Ion Cannon
|
||||||
|
Buildable:
|
||||||
|
Queue: Defense
|
||||||
|
BuildPaletteOrder: 1000
|
||||||
|
Prerequisites: gaplug, gatech, ~structures.gdi
|
||||||
|
Plug:
|
||||||
|
Type: plug.ioncannon
|
||||||
|
Power:
|
||||||
|
Amount: -100
|
||||||
|
|
||||||
ANYPOWER:
|
ANYPOWER:
|
||||||
Tooltip:
|
Tooltip:
|
||||||
|
|||||||
@@ -67,6 +67,22 @@ gapowr:
|
|||||||
damaged-idle-plug: gtpowr_b
|
damaged-idle-plug: gtpowr_b
|
||||||
Length: 12
|
Length: 12
|
||||||
Tick: 200
|
Tick: 200
|
||||||
|
idle-powrupa: gtpowr_b
|
||||||
|
Length: 12
|
||||||
|
Tick: 200
|
||||||
|
Offset: -48, -24
|
||||||
|
damaged-idle-powrupa: gtpowr_b
|
||||||
|
Length: 12
|
||||||
|
Tick: 200
|
||||||
|
Offset: -48, -24
|
||||||
|
idle-powrupb: gtpowr_b
|
||||||
|
Length: 12
|
||||||
|
Tick: 200
|
||||||
|
Offset: -24, -12
|
||||||
|
damaged-idle-powrupb: gtpowr_b
|
||||||
|
Length: 12
|
||||||
|
Tick: 200
|
||||||
|
Offset: -24, -12
|
||||||
make: gtpowrmk
|
make: gtpowrmk
|
||||||
Length: 20
|
Length: 20
|
||||||
ShadowStart: 20
|
ShadowStart: 20
|
||||||
@@ -74,6 +90,9 @@ gapowr:
|
|||||||
Offset: 0, 0
|
Offset: 0, 0
|
||||||
UseTilesetCode: false
|
UseTilesetCode: false
|
||||||
|
|
||||||
|
gapowrup:
|
||||||
|
icon: turbicon
|
||||||
|
|
||||||
gapile:
|
gapile:
|
||||||
Defaults:
|
Defaults:
|
||||||
Offset: 0, -24
|
Offset: 0, -24
|
||||||
@@ -654,7 +673,7 @@ nastlh:
|
|||||||
Offset: 0, 0
|
Offset: 0, 0
|
||||||
UseTilesetCode: false
|
UseTilesetCode: false
|
||||||
|
|
||||||
gavulc:
|
gactwr:
|
||||||
Defaults:
|
Defaults:
|
||||||
Offset: 0, -12
|
Offset: 0, -12
|
||||||
UseTilesetCode: true
|
UseTilesetCode: true
|
||||||
@@ -667,7 +686,21 @@ gavulc:
|
|||||||
Start: 2
|
Start: 2
|
||||||
ShadowStart: 5
|
ShadowStart: 5
|
||||||
Tick: 400
|
Tick: 400
|
||||||
turret: gtctwr_b
|
idle-lights: gtctwr_a
|
||||||
|
Length: 6
|
||||||
|
Tick: 200
|
||||||
|
damaged-idle-lights: gtctwr_a
|
||||||
|
Length: 6
|
||||||
|
Tick: 200
|
||||||
|
make: gtctwrmk
|
||||||
|
Length: 11
|
||||||
|
ShadowStart: 11
|
||||||
|
turret-vulcan: gtctwr_b
|
||||||
|
Facings: 32
|
||||||
|
turret-rocket: gtctwr_c
|
||||||
|
Facings: 32
|
||||||
|
UseTilesetCode: false
|
||||||
|
turret-sam: gtctwr_d
|
||||||
Facings: 32
|
Facings: 32
|
||||||
muzzle0: mgun-n
|
muzzle0: mgun-n
|
||||||
Length: *
|
Length: *
|
||||||
@@ -693,74 +726,18 @@ gavulc:
|
|||||||
muzzle7: mgun-ne
|
muzzle7: mgun-ne
|
||||||
Length: *
|
Length: *
|
||||||
UseTilesetCode: false
|
UseTilesetCode: false
|
||||||
idle-lights: gtctwr_a
|
icon: towricon
|
||||||
Length: 6
|
|
||||||
Tick: 200
|
|
||||||
damaged-idle-lights: gtctwr_a
|
|
||||||
Length: 6
|
|
||||||
Tick: 200
|
|
||||||
make: gtctwrmk
|
|
||||||
Length: 11
|
|
||||||
ShadowStart: 11
|
|
||||||
icon: twr1icon
|
|
||||||
Offset: 0, 0
|
Offset: 0, 0
|
||||||
UseTilesetCode: false
|
UseTilesetCode: false
|
||||||
|
|
||||||
|
gavulc:
|
||||||
|
icon: twr1icon
|
||||||
|
|
||||||
garock:
|
garock:
|
||||||
Defaults:
|
|
||||||
Offset: 0, -12
|
|
||||||
UseTilesetCode: true
|
|
||||||
idle: gtctwr
|
|
||||||
ShadowStart: 3
|
|
||||||
damaged-idle: gtctwr
|
|
||||||
Start: 1
|
|
||||||
ShadowStart: 4
|
|
||||||
dead: gtctwr
|
|
||||||
Start: 2
|
|
||||||
ShadowStart: 5
|
|
||||||
Tick: 400
|
|
||||||
turret: gtctwr_c
|
|
||||||
Facings: 32
|
|
||||||
idle-lights: gtctwr_a
|
|
||||||
Length: 6
|
|
||||||
Tick: 200
|
|
||||||
damaged-idle-lights: gtctwr_a
|
|
||||||
Length: 6
|
|
||||||
Tick: 200
|
|
||||||
make: gtctwrmk
|
|
||||||
Length: 11
|
|
||||||
ShadowStart: 11
|
|
||||||
icon: twr2icon
|
icon: twr2icon
|
||||||
Offset: 0, 0
|
|
||||||
UseTilesetCode: false
|
|
||||||
|
|
||||||
gacsam:
|
gacsam:
|
||||||
Defaults:
|
|
||||||
Offset: 0, -12
|
|
||||||
UseTilesetCode: true
|
|
||||||
idle: gtctwr
|
|
||||||
ShadowStart: 3
|
|
||||||
damaged-idle: gtctwr
|
|
||||||
Start: 1
|
|
||||||
ShadowStart: 4
|
|
||||||
dead: gtctwr
|
|
||||||
Start: 2
|
|
||||||
ShadowStart: 5
|
|
||||||
Tick: 400
|
|
||||||
turret: gtctwr_d
|
|
||||||
Facings: 32
|
|
||||||
idle-lights: gtctwr_a
|
|
||||||
Length: 6
|
|
||||||
Tick: 200
|
|
||||||
damaged-idle-lights: gtctwr_a
|
|
||||||
Length: 6
|
|
||||||
Tick: 200
|
|
||||||
make: gtctwrmk
|
|
||||||
Length: 11
|
|
||||||
ShadowStart: 11
|
|
||||||
icon: twr3icon
|
icon: twr3icon
|
||||||
Offset: 0, 0
|
|
||||||
UseTilesetCode: false
|
|
||||||
|
|
||||||
gahpad:
|
gahpad:
|
||||||
Defaults:
|
Defaults:
|
||||||
@@ -1038,9 +1015,21 @@ gaplug:
|
|||||||
Start: 8
|
Start: 8
|
||||||
Length: 8
|
Length: 8
|
||||||
Tick: 120
|
Tick: 120
|
||||||
|
idle-ioncannona: gaplug_f
|
||||||
|
Length: 15
|
||||||
|
Tick: 120
|
||||||
|
Reverses: true
|
||||||
|
Offset: -12, -42
|
||||||
|
idle-ioncannonb: gaplug_f
|
||||||
|
Length: 15
|
||||||
|
Reverses: true
|
||||||
|
Tick: 120
|
||||||
make: gtplugmk
|
make: gtplugmk
|
||||||
Length: 17
|
Length: 17
|
||||||
ShadowStart: 17
|
ShadowStart: 17
|
||||||
icon: plugicon
|
icon: plugicon
|
||||||
Offset: 0, 0
|
Offset: 0, 0
|
||||||
UseTilesetCode: false
|
UseTilesetCode: false
|
||||||
|
|
||||||
|
gaplug3:
|
||||||
|
icon: rad3icon
|
||||||
Reference in New Issue
Block a user