merged with paul's
This commit is contained in:
@@ -26,6 +26,7 @@ namespace OpenRa.Game
|
|||||||
|
|
||||||
readonly Animation repairButton;
|
readonly Animation repairButton;
|
||||||
readonly Animation sellButton;
|
readonly Animation sellButton;
|
||||||
|
readonly Animation pwrdownButton;
|
||||||
|
|
||||||
readonly SpriteRenderer buildPaletteRenderer;
|
readonly SpriteRenderer buildPaletteRenderer;
|
||||||
readonly Animation cantBuild;
|
readonly Animation cantBuild;
|
||||||
@@ -77,6 +78,9 @@ namespace OpenRa.Game
|
|||||||
|
|
||||||
sellButton = new Animation("sell");
|
sellButton = new Animation("sell");
|
||||||
sellButton.PlayRepeating("normal");
|
sellButton.PlayRepeating("normal");
|
||||||
|
|
||||||
|
pwrdownButton = new Animation("repair");
|
||||||
|
pwrdownButton.PlayRepeating("normal");
|
||||||
|
|
||||||
blank = SheetBuilder.Add(new Size(64, 48), 16);
|
blank = SheetBuilder.Add(new Size(64, 48), 16);
|
||||||
|
|
||||||
@@ -141,14 +145,21 @@ namespace OpenRa.Game
|
|||||||
DrawPower();
|
DrawPower();
|
||||||
chromeRenderer.Flush();
|
chromeRenderer.Flush();
|
||||||
DrawButtons();
|
DrawButtons();
|
||||||
|
DrawMinimap();
|
||||||
int paletteHeight = DrawBuildPalette(currentTab);
|
int paletteHeight = DrawBuildPalette(currentTab);
|
||||||
DrawBuildTabs(paletteHeight);
|
DrawBuildTabs(paletteHeight);
|
||||||
DrawChat();
|
DrawChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawMinimap()
|
||||||
|
{
|
||||||
|
var hasRadar = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains<ProvidesRadar>() && a.traits.Get<ProvidesRadar>().IsActive());
|
||||||
|
if (hasRadar)
|
||||||
|
Game.minimap.Draw(new float2(Game.viewport.Width - 128, 30));
|
||||||
|
}
|
||||||
|
|
||||||
void AddButton(Rectangle r, Action<bool> b) { buttons.Add(Pair.New(r, b)); }
|
void AddButton(Rectangle r, Action<bool> b) { buttons.Add(Pair.New(r, b)); }
|
||||||
|
|
||||||
void DrawBuildTabs(int paletteHeight)
|
void DrawBuildTabs(int paletteHeight)
|
||||||
{
|
{
|
||||||
const int tabWidth = 24;
|
const int tabWidth = 24;
|
||||||
@@ -285,7 +296,7 @@ namespace OpenRa.Game
|
|||||||
|
|
||||||
|
|
||||||
// Repair
|
// Repair
|
||||||
Rectangle repairRect = new Rectangle(Game.viewport.Width - 100, 5, repairButton.Image.bounds.Width, repairButton.Image.bounds.Height);
|
Rectangle repairRect = new Rectangle(Game.viewport.Width - 120, 5, repairButton.Image.bounds.Width, repairButton.Image.bounds.Height);
|
||||||
var repairDrawPos = Game.viewport.Location + new float2(repairRect.Location);
|
var repairDrawPos = Game.viewport.Location + new float2(repairRect.Location);
|
||||||
|
|
||||||
var hasFact = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains<ConstructionYard>());
|
var hasFact = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains<ConstructionYard>());
|
||||||
@@ -300,7 +311,7 @@ namespace OpenRa.Game
|
|||||||
buildPaletteRenderer.DrawSprite(repairButton.Image, repairDrawPos, PaletteType.Chrome);
|
buildPaletteRenderer.DrawSprite(repairButton.Image, repairDrawPos, PaletteType.Chrome);
|
||||||
|
|
||||||
// Sell
|
// Sell
|
||||||
Rectangle sellRect = new Rectangle(Game.viewport.Width - 60, 5,
|
Rectangle sellRect = new Rectangle(Game.viewport.Width - 80, 5,
|
||||||
sellButton.Image.bounds.Width, sellButton.Image.bounds.Height);
|
sellButton.Image.bounds.Width, sellButton.Image.bounds.Height);
|
||||||
|
|
||||||
var sellDrawPos = Game.viewport.Location + new float2(sellRect.Location);
|
var sellDrawPos = Game.viewport.Location + new float2(sellRect.Location);
|
||||||
@@ -310,6 +321,21 @@ namespace OpenRa.Game
|
|||||||
AddButton(sellRect, isLmb => Game.controller.ToggleInputMode<SellOrderGenerator>());
|
AddButton(sellRect, isLmb => Game.controller.ToggleInputMode<SellOrderGenerator>());
|
||||||
buildPaletteRenderer.DrawSprite(sellButton.Image, sellDrawPos, PaletteType.Chrome);
|
buildPaletteRenderer.DrawSprite(sellButton.Image, sellDrawPos, PaletteType.Chrome);
|
||||||
buildPaletteRenderer.Flush();
|
buildPaletteRenderer.Flush();
|
||||||
|
|
||||||
|
if (Game.Settings.PowerDownBuildings)
|
||||||
|
{
|
||||||
|
// Power Down
|
||||||
|
Rectangle pwrdownRect = new Rectangle(Game.viewport.Width - 40, 5,
|
||||||
|
pwrdownButton.Image.bounds.Width, pwrdownButton.Image.bounds.Height);
|
||||||
|
|
||||||
|
var pwrdownDrawPos = Game.viewport.Location + new float2(pwrdownRect.Location);
|
||||||
|
|
||||||
|
pwrdownButton.ReplaceAnim(Game.controller.orderGenerator is PowerDownOrderGenerator ? "pressed" : "normal");
|
||||||
|
|
||||||
|
AddButton(pwrdownRect, isLmb => Game.controller.ToggleInputMode<PowerDownOrderGenerator>());
|
||||||
|
buildPaletteRenderer.DrawSprite(pwrdownButton.Image, pwrdownDrawPos, PaletteType.Chrome);
|
||||||
|
}
|
||||||
|
buildPaletteRenderer.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleChronosphereButton()
|
void HandleChronosphereButton()
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace OpenRa.Game
|
|||||||
|
|
||||||
var maxSpread = GetMaximumSpread(weapon, warhead);
|
var maxSpread = GetMaximumSpread(weapon, warhead);
|
||||||
var hitActors = Game.FindUnitsInCircle(loc, maxSpread);
|
var hitActors = Game.FindUnitsInCircle(loc, maxSpread);
|
||||||
|
|
||||||
foreach (var victim in hitActors)
|
foreach (var victim in hitActors)
|
||||||
victim.InflictDamage(firedBy, (int)GetDamageToInflict(victim, loc, weapon, warhead), warhead);
|
victim.InflictDamage(firedBy, (int)GetDamageToInflict(victim, loc, weapon, warhead), warhead);
|
||||||
}
|
}
|
||||||
@@ -46,11 +46,10 @@ namespace OpenRa.Game
|
|||||||
{
|
{
|
||||||
if (!WeaponValidForTarget(weapon, target))
|
if (!WeaponValidForTarget(weapon, target))
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
var distance = (target.CenterLocation - loc).Length;
|
var distance = (target.CenterLocation - loc).Length*1/24f;
|
||||||
var rawDamage = weapon.Damage * (float)Math.Exp(-distance / warhead.Spread);
|
var rawDamage = weapon.Damage * (float)Math.Exp(-distance / warhead.Spread);
|
||||||
var multiplier = warhead.EffectivenessAgainst(target.Info.Armor);
|
var multiplier = warhead.EffectivenessAgainst(target.Info.Armor);
|
||||||
|
|
||||||
return rawDamage * multiplier;
|
return rawDamage * multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,5 +32,6 @@ namespace OpenRa.Game
|
|||||||
public static Cursor SellBlocked { get { return new Cursor("sell-blocked"); } }
|
public static Cursor SellBlocked { get { return new Cursor("sell-blocked"); } }
|
||||||
public static Cursor Repair { get { return new Cursor("repair"); } }
|
public static Cursor Repair { get { return new Cursor("repair"); } }
|
||||||
public static Cursor RepairBlocked { get { return new Cursor("repair-blocked"); } }
|
public static Cursor RepairBlocked { get { return new Cursor("repair-blocked"); } }
|
||||||
|
public static Cursor PowerDown { get { return new Cursor("powerdown"); } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace OpenRa.Game.GameRules
|
|||||||
|
|
||||||
// Gameplay options
|
// Gameplay options
|
||||||
public readonly bool RepairRequiresConyard = true;
|
public readonly bool RepairRequiresConyard = true;
|
||||||
|
public readonly bool PowerDownBuildings = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,16 @@ namespace OpenRa.Game.Graphics
|
|||||||
|
|
||||||
static Sprite[] LoadCursors(string filename)
|
static Sprite[] LoadCursors(string filename)
|
||||||
{
|
{
|
||||||
var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts));
|
try
|
||||||
return shp.Select(a => SheetBuilder.Add(a.Image, a.Size)).ToArray();
|
{
|
||||||
|
var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts));
|
||||||
|
return shp.Select(a => SheetBuilder.Add(a.Image, a.Size)).ToArray();
|
||||||
|
}
|
||||||
|
catch (System.IndexOutOfRangeException) // This will occur when loading a custom (RA-format) .shp
|
||||||
|
{
|
||||||
|
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
|
||||||
|
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Sprite[] LoadAllSprites(string filename) { return cursors[filename]; }
|
public static Sprite[] LoadAllSprites(string filename) { return cursors[filename]; }
|
||||||
|
|||||||
@@ -103,6 +103,7 @@
|
|||||||
<Compile Include="Orders\NetworkOrderSource.cs" />
|
<Compile Include="Orders\NetworkOrderSource.cs" />
|
||||||
<Compile Include="Orders\OrderIO.cs" />
|
<Compile Include="Orders\OrderIO.cs" />
|
||||||
<Compile Include="Orders\OrderManager.cs" />
|
<Compile Include="Orders\OrderManager.cs" />
|
||||||
|
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\RepairOrderGenerator.cs" />
|
<Compile Include="Orders\RepairOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\SellOrderGenerator.cs" />
|
<Compile Include="Orders\SellOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\ChronoshiftDestinationOrderGenerator.cs" />
|
<Compile Include="Orders\ChronoshiftDestinationOrderGenerator.cs" />
|
||||||
@@ -218,6 +219,7 @@
|
|||||||
<Compile Include="Traits\Minelayer.cs" />
|
<Compile Include="Traits\Minelayer.cs" />
|
||||||
<Compile Include="Traits\LimitedAmmo.cs" />
|
<Compile Include="Traits\LimitedAmmo.cs" />
|
||||||
<Compile Include="Traits\Passenger.cs" />
|
<Compile Include="Traits\Passenger.cs" />
|
||||||
|
<Compile Include="Traits\ProvidesRadar.cs" />
|
||||||
<Compile Include="Traits\Repairable.cs" />
|
<Compile Include="Traits\Repairable.cs" />
|
||||||
<Compile Include="Traits\Reservable.cs" />
|
<Compile Include="Traits\Reservable.cs" />
|
||||||
<Compile Include="Traits\SquishByTank.cs" />
|
<Compile Include="Traits\SquishByTank.cs" />
|
||||||
@@ -302,4 +304,4 @@
|
|||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</Target>
|
||||||
-->
|
-->
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
47
OpenRa.Game/Orders/PowerDownOrderGenerator.cs
Normal file
47
OpenRa.Game/Orders/PowerDownOrderGenerator.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using OpenRa.Game.GameRules;
|
||||||
|
using OpenRa.Game.Traits;
|
||||||
|
|
||||||
|
namespace OpenRa.Game.Orders
|
||||||
|
{
|
||||||
|
class PowerDownOrderGenerator : IOrderGenerator
|
||||||
|
{
|
||||||
|
public IEnumerable<Order> Order(int2 xy, MouseInput mi)
|
||||||
|
{
|
||||||
|
if (mi.Button == MouseButton.Right)
|
||||||
|
Game.controller.CancelInputMode();
|
||||||
|
|
||||||
|
return OrderInner(xy, mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<Order> OrderInner(int2 xy, MouseInput mi)
|
||||||
|
{
|
||||||
|
if (mi.Button == MouseButton.Left)
|
||||||
|
{
|
||||||
|
var loc = mi.Location + Game.viewport.Location;
|
||||||
|
var underCursor = Game.FindUnits(loc, loc)
|
||||||
|
.Where(a => a.Owner == Game.LocalPlayer
|
||||||
|
&& a.traits.Contains<Building>()
|
||||||
|
&& a.Info.Selectable).FirstOrDefault();
|
||||||
|
|
||||||
|
var building = underCursor != null ? underCursor.Info as BuildingInfo : null;
|
||||||
|
|
||||||
|
if (building != null)
|
||||||
|
yield return new Order("PowerDown", underCursor, null, int2.Zero, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Tick() { }
|
||||||
|
public void Render() { }
|
||||||
|
|
||||||
|
public Cursor GetCursor(int2 xy, MouseInput mi)
|
||||||
|
{
|
||||||
|
mi.Button = MouseButton.Left;
|
||||||
|
return OrderInner(xy, mi).Any()
|
||||||
|
? Cursor.PowerDown : Cursor.PowerDown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
using OpenRa.Game.GameRules;
|
using OpenRa.Game.GameRules;
|
||||||
using OpenRa.Game.Graphics;
|
using OpenRa.Game.Graphics;
|
||||||
using OpenRa.Game.Traits;
|
using OpenRa.Game.Traits;
|
||||||
@@ -50,11 +51,11 @@ namespace OpenRa.Game
|
|||||||
|
|
||||||
foreach (var a in myBuildings)
|
foreach (var a in myBuildings)
|
||||||
{
|
{
|
||||||
var bi = a.Info as BuildingInfo;
|
var p = a.traits.Get<Building>().GetPowerUsage();
|
||||||
if (bi.Power > 0) /* todo: is this how real-ra scales it? */
|
if (p > 0)
|
||||||
PowerProvided += (a.Health * bi.Power) / bi.Strength;
|
PowerProvided += p;
|
||||||
else
|
else
|
||||||
PowerDrained -= bi.Power;
|
PowerDrained -= p;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PowerProvided - PowerDrained < 0)
|
if (PowerProvided - PowerDrained < 0)
|
||||||
|
|||||||
@@ -26,12 +26,9 @@ namespace OpenRa.Game.Traits
|
|||||||
|
|
||||||
protected override void QueueAttack( Actor self, Order order )
|
protected override void QueueAttack( Actor self, Order order )
|
||||||
{
|
{
|
||||||
var bi = self.Info as BuildingInfo;
|
var b = self.traits.Get<Building>();
|
||||||
if (bi != null && bi.Powered && self.Owner.GetPowerState() != PowerState.Normal)
|
if (b != null && b.InsuffientPower())
|
||||||
{
|
|
||||||
if (self.Owner == Game.LocalPlayer) Sound.Play("nopowr1.aud");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */
|
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */
|
||||||
/* todo: choose the appropriate weapon, when only one works against this target */
|
/* todo: choose the appropriate weapon, when only one works against this target */
|
||||||
|
|||||||
@@ -5,20 +5,66 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using OpenRa.Game.Effects;
|
using OpenRa.Game.Effects;
|
||||||
|
using OpenRa.Game.Graphics;
|
||||||
|
|
||||||
namespace OpenRa.Game.Traits
|
namespace OpenRa.Game.Traits
|
||||||
{
|
{
|
||||||
class Building : INotifyDamage, IOrder, ITick
|
class Building : INotifyDamage, IOrder, ITick, IRenderModifier
|
||||||
{
|
{
|
||||||
|
readonly Actor self;
|
||||||
public readonly BuildingInfo unitInfo;
|
public readonly BuildingInfo unitInfo;
|
||||||
bool isRepairing = false;
|
bool isRepairing = false;
|
||||||
|
bool isPoweredDown = false;
|
||||||
|
|
||||||
public Building(Actor self)
|
public Building(Actor self)
|
||||||
{
|
{
|
||||||
|
this.self = self;
|
||||||
unitInfo = (BuildingInfo)self.Info;
|
unitInfo = (BuildingInfo)self.Info;
|
||||||
self.CenterLocation = Game.CellSize
|
self.CenterLocation = Game.CellSize
|
||||||
* ((float2)self.Location + .5f * (float2)unitInfo.Dimensions);
|
* ((float2)self.Location + .5f * (float2)unitInfo.Dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool InsuffientPower()
|
||||||
|
{
|
||||||
|
return (isPoweredDown || (unitInfo.Powered && self.Owner.GetPowerState() != PowerState.Normal));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetPowerUsage()
|
||||||
|
{
|
||||||
|
if (isPoweredDown)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (unitInfo.Power > 0) /* todo: is this how real-ra scales it? */
|
||||||
|
return (self.Health * unitInfo.Power) / unitInfo.Strength;
|
||||||
|
else
|
||||||
|
return unitInfo.Power;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Animation iconAnim;
|
||||||
|
public IEnumerable<Renderable>
|
||||||
|
ModifyRender(Actor self, IEnumerable<Renderable> rs)
|
||||||
|
{
|
||||||
|
if (!InsuffientPower())
|
||||||
|
return rs;
|
||||||
|
|
||||||
|
List<Renderable> nrs = new List<Renderable>(rs);
|
||||||
|
foreach(var r in rs)
|
||||||
|
{
|
||||||
|
// Need 2 shadows to make it dark enough
|
||||||
|
nrs.Add(r.WithPalette(PaletteType.Shadow));
|
||||||
|
nrs.Add(r.WithPalette(PaletteType.Shadow));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPoweredDown)
|
||||||
|
{
|
||||||
|
iconAnim = new Animation("powerdown");
|
||||||
|
iconAnim.PlayRepeating("disabled");
|
||||||
|
nrs.Add(new Renderable(iconAnim.Image, self.CenterLocation - 0.5f*iconAnim.Image.size, PaletteType.Chrome));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return nrs;
|
||||||
|
}
|
||||||
|
|
||||||
public void Damaged(Actor self, AttackInfo e)
|
public void Damaged(Actor self, AttackInfo e)
|
||||||
{
|
{
|
||||||
@@ -43,6 +89,12 @@ namespace OpenRa.Game.Traits
|
|||||||
{
|
{
|
||||||
isRepairing = !isRepairing;
|
isRepairing = !isRepairing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (order.OrderString == "PowerDown")
|
||||||
|
{
|
||||||
|
isPoweredDown = !isPoweredDown;
|
||||||
|
Sound.Play((isPoweredDown) ? "bleep12.aud" : "bleep11.aud");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int remainingTicks;
|
int remainingTicks;
|
||||||
|
|||||||
28
OpenRa.Game/Traits/ProvidesRadar.cs
Normal file
28
OpenRa.Game/Traits/ProvidesRadar.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenRa.Game.Traits
|
||||||
|
{
|
||||||
|
class ProvidesRadar
|
||||||
|
{
|
||||||
|
Actor self;
|
||||||
|
public ProvidesRadar(Actor self)
|
||||||
|
{
|
||||||
|
this.self = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsActive()
|
||||||
|
{
|
||||||
|
// TODO: Check for nearby MRJ
|
||||||
|
|
||||||
|
// Check if powered
|
||||||
|
var b = self.traits.Get<Building>();
|
||||||
|
if (b != null && b.InsuffientPower())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -403,6 +403,12 @@
|
|||||||
<sequence name="repair2-blocked" start="213" length="1" />
|
<sequence name="repair2-blocked" start="213" length="1" />
|
||||||
<sequence name="ability-minimap" start="214" length="8" />
|
<sequence name="ability-minimap" start="214" length="8" />
|
||||||
</cursor>
|
</cursor>
|
||||||
|
<cursor src="speed">
|
||||||
|
<sequence name="powerdown" start="3" length="12" />
|
||||||
|
</cursor>
|
||||||
|
<unit name="powerdown">
|
||||||
|
<sequence name="disabled" start="3" length="1" src="speed" />
|
||||||
|
</unit>
|
||||||
<unit name="120mm">
|
<unit name="120mm">
|
||||||
<sequence name="idle" start="0" length="1" />
|
<sequence name="idle" start="0" length="1" />
|
||||||
</unit>
|
</unit>
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ SpawnOffset=0,-4
|
|||||||
LongDesc=Produces and reloads helicopters
|
LongDesc=Produces and reloads helicopters
|
||||||
[DOME]
|
[DOME]
|
||||||
Description=Radar Dome
|
Description=Radar Dome
|
||||||
Traits=Building, RenderBuilding
|
Traits=Building, RenderBuilding, ProvidesRadar
|
||||||
Dimensions=2,2
|
Dimensions=2,2
|
||||||
Footprint=xx xx
|
Footprint=xx xx
|
||||||
SelectionPriority=3
|
SelectionPriority=3
|
||||||
|
|||||||
Reference in New Issue
Block a user