Compare commits
60 Commits
devtest-20
...
release-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
299b757045 | ||
|
|
389e105e1c | ||
|
|
81ace98362 | ||
|
|
4c347199f5 | ||
|
|
bf0a300682 | ||
|
|
d7310be875 | ||
|
|
a150800a1e | ||
|
|
904b71b890 | ||
|
|
bdaff27656 | ||
|
|
5b0875f66f | ||
|
|
d110b9c648 | ||
|
|
94028c8246 | ||
|
|
766c091c1c | ||
|
|
645b181af7 | ||
|
|
6864b2462f | ||
|
|
16e63a9487 | ||
|
|
3c87adbad5 | ||
|
|
cff7c01de0 | ||
|
|
eba1f86572 | ||
|
|
4113ac0771 | ||
|
|
3c445ef029 | ||
|
|
a88687257e | ||
|
|
60749b250f | ||
|
|
5f60fba445 | ||
|
|
ae03c66059 | ||
|
|
53950fa7f4 | ||
|
|
efb51c19bd | ||
|
|
88526d661d | ||
|
|
d7b117ca92 | ||
|
|
52d93d4654 | ||
|
|
afa6e5ee10 | ||
|
|
f4dba7f9c7 | ||
|
|
2b18c57b41 | ||
|
|
adacbb1b9d | ||
|
|
e4ae5a64b3 | ||
|
|
8f29983bd5 | ||
|
|
49fd2ed6da | ||
|
|
c9f9a8923a | ||
|
|
bab8d70cd0 | ||
|
|
ce5911f47a | ||
|
|
ee0f7bc98a | ||
|
|
77ddb2386a | ||
|
|
73413a4e20 | ||
|
|
dad11df42b | ||
|
|
2bf1640e2b | ||
|
|
405d59a8ea | ||
|
|
eadf381843 | ||
|
|
7e8b0fd288 | ||
|
|
dfd37ea7b6 | ||
|
|
c19c922931 | ||
|
|
0d2f8013a6 | ||
|
|
5a6afcb01e | ||
|
|
327f417024 | ||
|
|
4207717749 | ||
|
|
6922f7653e | ||
|
|
ec54eca7f4 | ||
|
|
9d8fea871c | ||
|
|
aa50ce266e | ||
|
|
716dd78058 | ||
|
|
6a1972f8bb |
1
AUTHORS
1
AUTHORS
@@ -101,6 +101,7 @@ Also thanks to:
|
||||
* Michael Rätzel
|
||||
* Michael Silber (frühstück)
|
||||
* Michael Sztolcman (s1w_)
|
||||
* Muh
|
||||
* Mustafa Alperen Seki (MustaphaTR)
|
||||
* Neil Shivkar (havok13888)
|
||||
* Nooze
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace OpenRA
|
||||
TargetString = 0x04,
|
||||
Queued = 0x08,
|
||||
ExtraLocation = 0x10,
|
||||
ExtraData = 0x20
|
||||
ExtraData = 0x20,
|
||||
TargetIsCell = 0x40
|
||||
}
|
||||
|
||||
static class OrderFieldsExts
|
||||
@@ -45,6 +46,7 @@ namespace OpenRA
|
||||
public CPos ExtraLocation;
|
||||
public uint ExtraData;
|
||||
public bool IsImmediate;
|
||||
|
||||
public bool SuppressVisualFeedback;
|
||||
public Actor VisualFeedbackTarget;
|
||||
|
||||
@@ -60,7 +62,7 @@ namespace OpenRA
|
||||
{
|
||||
get
|
||||
{
|
||||
return Target.SerializableCell.HasValue ? Target.SerializableCell.Value : CPos.Zero;
|
||||
return Target.SerializableCell ?? CPos.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +70,7 @@ namespace OpenRA
|
||||
|
||||
Order(string orderString, Actor subject, Target target, string targetString, bool queued, CPos extraLocation, uint extraData)
|
||||
{
|
||||
OrderString = orderString;
|
||||
OrderString = orderString ?? "";
|
||||
Subject = subject;
|
||||
Target = target;
|
||||
TargetString = targetString;
|
||||
@@ -127,8 +129,18 @@ namespace OpenRA
|
||||
|
||||
case TargetType.Terrain:
|
||||
{
|
||||
if (world != null)
|
||||
target = Target.FromCell(world, (CPos)r.ReadInt2());
|
||||
if (flags.HasField(OrderFields.TargetIsCell))
|
||||
{
|
||||
var cell = new CPos(r.ReadInt32(), r.ReadInt32(), r.ReadByte());
|
||||
var subCell = (SubCell)r.ReadInt32();
|
||||
if (world != null)
|
||||
target = Target.FromCell(world, cell, subCell);
|
||||
}
|
||||
else
|
||||
{
|
||||
var pos = new WPos(r.ReadInt32(), r.ReadInt32(), r.ReadInt32());
|
||||
target = Target.FromPos(pos);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -137,7 +149,7 @@ namespace OpenRA
|
||||
|
||||
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
|
||||
var queued = flags.HasField(OrderFields.Queued);
|
||||
var extraLocation = (CPos)(flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero);
|
||||
var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? new CPos(r.ReadInt32(), r.ReadInt32(), r.ReadByte()) : CPos.Zero;
|
||||
var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0;
|
||||
|
||||
if (world == null)
|
||||
@@ -235,10 +247,6 @@ namespace OpenRA
|
||||
public Order(string orderString, Actor subject, Target target, bool queued)
|
||||
: this(orderString, subject, target, null, queued, CPos.Zero, 0) { }
|
||||
|
||||
public Order(string orderstring, Order order)
|
||||
: this(orderstring, order.Subject, order.Target,
|
||||
order.TargetString, order.Queued, order.ExtraLocation, order.ExtraData) { }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
var minLength = OrderString.Length + 1 + (IsImmediate ? 1 + TargetString.Length + 1 : 6);
|
||||
@@ -273,6 +281,9 @@ namespace OpenRA
|
||||
if (ExtraData != 0)
|
||||
fields |= OrderFields.ExtraData;
|
||||
|
||||
if (Target.SerializableCell != null)
|
||||
fields |= OrderFields.TargetIsCell;
|
||||
|
||||
w.Write((byte)fields);
|
||||
|
||||
if (fields.HasField(OrderFields.Target))
|
||||
@@ -288,8 +299,13 @@ namespace OpenRA
|
||||
w.Write(Target.FrozenActor.ID);
|
||||
break;
|
||||
case TargetType.Terrain:
|
||||
// SerializableCell is guaranteed to be non-null if Type == TargetType.Terrain
|
||||
w.Write(Target.SerializableCell.Value);
|
||||
if (fields.HasField(OrderFields.TargetIsCell))
|
||||
{
|
||||
w.Write(Target.SerializableCell.Value);
|
||||
w.Write((int)Target.SerializableSubCell);
|
||||
}
|
||||
else
|
||||
w.Write(Target.SerializablePos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -310,7 +326,8 @@ namespace OpenRA
|
||||
{
|
||||
return ("OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." +
|
||||
"\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n").F(
|
||||
OrderString, Subject, TargetActor != null ? TargetActor.Info.Name : null, TargetLocation, TargetString, IsImmediate, Player != null ? Player.PlayerName : null);
|
||||
OrderString, Subject, TargetActor != null ? TargetActor.Info.Name : null, TargetLocation,
|
||||
TargetString, IsImmediate, Player != null ? Player.PlayerName : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,14 @@ namespace OpenRA.Network
|
||||
{
|
||||
w.Write(cell.X);
|
||||
w.Write(cell.Y);
|
||||
w.Write(cell.Layer);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter w, WPos pos)
|
||||
{
|
||||
w.Write(pos.X);
|
||||
w.Write(pos.Y);
|
||||
w.Write(pos.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,11 @@ namespace OpenRA.Network
|
||||
if (client != null)
|
||||
{
|
||||
var pause = order.TargetString == "Pause";
|
||||
|
||||
// Prevent injected unpause orders from restarting a finished game
|
||||
if (orderManager.World.PauseStateLocked && !pause)
|
||||
break;
|
||||
|
||||
if (orderManager.World.Paused != pause && world != null && world.LobbyInfo.NonBotClients.Count() > 1)
|
||||
{
|
||||
var pausetext = "The game is {0} by {1}".F(pause ? "paused" : "un-paused", client.Name);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace OpenRA.Orders
|
||||
static Target TargetForInput(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
var actor = world.ScreenMap.ActorsAtMouse(mi)
|
||||
.Where(a => a.Actor.Info.HasTraitInfo<ITargetableInfo>() && !world.FogObscures(a.Actor))
|
||||
.Where(a => !a.Actor.IsDead && a.Actor.Info.HasTraitInfo<ITargetableInfo>() && !world.FogObscures(a.Actor))
|
||||
.WithHighestSelectionPriority(worldPixel);
|
||||
|
||||
if (actor != null)
|
||||
@@ -51,6 +51,13 @@ namespace OpenRA.Orders
|
||||
if (!actorsInvolved.Any())
|
||||
yield break;
|
||||
|
||||
// HACK: This is required by the hacky player actions-per-minute calculation
|
||||
// TODO: Reimplement APM properly and then remove this
|
||||
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor, false)
|
||||
{
|
||||
TargetString = actorsInvolved.Select(a => a.ActorID).JoinWith(",")
|
||||
};
|
||||
|
||||
foreach (var o in orders)
|
||||
yield return CheckSameOrder(o.Order, o.Trait.IssueOrder(o.Actor, o.Order, o.Target, mi.Modifiers.HasModifier(Modifiers.Shift)));
|
||||
}
|
||||
@@ -81,7 +88,10 @@ namespace OpenRA.Orders
|
||||
// Used for classic mouse orders, determines whether or not action at xy is move or select
|
||||
public virtual bool InputOverridesSelection(WorldRenderer wr, World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
var actor = world.ScreenMap.ActorsAtMouse(xy).WithHighestSelectionPriority(xy);
|
||||
var actor = world.ScreenMap.ActorsAtMouse(xy)
|
||||
.Where(a => !a.Actor.IsDead)
|
||||
.WithHighestSelectionPriority(xy);
|
||||
|
||||
if (actor == null)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -254,38 +254,33 @@ namespace OpenRA.Traits
|
||||
|
||||
void ITick.Tick(Actor self)
|
||||
{
|
||||
// Update visibility at the end of the tick to make sure that
|
||||
// the fog/shroud state has been updated for the tick
|
||||
self.World.AddFrameEndTask(w =>
|
||||
UpdateDirtyFrozenActorsFromDirtyBins();
|
||||
|
||||
var frozenActorsToRemove = new List<FrozenActor>();
|
||||
VisibilityHash = 0;
|
||||
FrozenHash = 0;
|
||||
|
||||
foreach (var kvp in frozenActorsById)
|
||||
{
|
||||
UpdateDirtyFrozenActorsFromDirtyBins();
|
||||
var id = kvp.Key;
|
||||
var hash = (int)id;
|
||||
FrozenHash += hash;
|
||||
|
||||
var frozenActorsToRemove = new List<FrozenActor>();
|
||||
VisibilityHash = 0;
|
||||
FrozenHash = 0;
|
||||
var frozenActor = kvp.Value;
|
||||
frozenActor.Tick();
|
||||
if (dirtyFrozenActorIds.Contains(id))
|
||||
frozenActor.UpdateVisibility();
|
||||
|
||||
foreach (var kvp in frozenActorsById)
|
||||
{
|
||||
var id = kvp.Key;
|
||||
var hash = (int)id;
|
||||
FrozenHash += hash;
|
||||
if (frozenActor.Visible)
|
||||
VisibilityHash += hash;
|
||||
else if (frozenActor.Actor == null)
|
||||
frozenActorsToRemove.Add(frozenActor);
|
||||
}
|
||||
|
||||
var frozenActor = kvp.Value;
|
||||
frozenActor.Tick();
|
||||
if (dirtyFrozenActorIds.Contains(id))
|
||||
frozenActor.UpdateVisibility();
|
||||
dirtyFrozenActorIds.Clear();
|
||||
|
||||
if (frozenActor.Visible)
|
||||
VisibilityHash += hash;
|
||||
else if (frozenActor.Actor == null)
|
||||
frozenActorsToRemove.Add(frozenActor);
|
||||
}
|
||||
|
||||
dirtyFrozenActorIds.Clear();
|
||||
|
||||
foreach (var fa in frozenActorsToRemove)
|
||||
Remove(fa);
|
||||
});
|
||||
foreach (var fa in frozenActorsToRemove)
|
||||
Remove(fa);
|
||||
}
|
||||
|
||||
void UpdateDirtyFrozenActorsFromDirtyBins()
|
||||
|
||||
@@ -26,12 +26,19 @@ namespace OpenRA.Traits
|
||||
FrozenActor frozen;
|
||||
WPos pos;
|
||||
CPos? cell;
|
||||
SubCell? subCell;
|
||||
int generation;
|
||||
|
||||
public static Target FromPos(WPos p) { return new Target { pos = p, type = TargetType.Terrain }; }
|
||||
public static Target FromCell(World w, CPos c, SubCell subCell = SubCell.FullCell)
|
||||
{
|
||||
return new Target { pos = w.Map.CenterOfSubCell(c, subCell), cell = c, type = TargetType.Terrain };
|
||||
return new Target
|
||||
{
|
||||
pos = w.Map.CenterOfSubCell(c, subCell),
|
||||
cell = c,
|
||||
subCell = subCell,
|
||||
type = TargetType.Terrain
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -201,5 +208,7 @@ namespace OpenRA.Traits
|
||||
internal TargetType SerializableType { get { return type; } }
|
||||
internal Actor SerializableActor { get { return actor; } }
|
||||
internal CPos? SerializableCell { get { return cell; } }
|
||||
internal SubCell? SerializableSubCell { get { return subCell; } }
|
||||
internal WPos SerializablePos { get { return pos; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ namespace OpenRA.Traits
|
||||
return rect;
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
public void TickRender()
|
||||
{
|
||||
foreach (var a in addOrUpdateActors)
|
||||
{
|
||||
|
||||
@@ -353,7 +353,6 @@ namespace OpenRA
|
||||
ActorsWithTrait<ITick>().DoTimed(x => x.Trait.Tick(x.Actor), "Trait");
|
||||
|
||||
effects.DoTimed(e => e.Tick(this), "Effect");
|
||||
ScreenMap.Tick();
|
||||
}
|
||||
|
||||
while (frameEndActions.Count != 0)
|
||||
@@ -364,6 +363,7 @@ namespace OpenRA
|
||||
public void TickRender(WorldRenderer wr)
|
||||
{
|
||||
ActorsWithTrait<ITickRender>().DoTimed(x => x.Trait.TickRender(wr, x.Actor), "Render");
|
||||
ScreenMap.TickRender();
|
||||
}
|
||||
|
||||
public IEnumerable<Actor> Actors { get { return actors.Values; } }
|
||||
|
||||
@@ -129,6 +129,8 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
return new Order("Detonate", self, false);
|
||||
}
|
||||
|
||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return true; }
|
||||
|
||||
string IOrderVoice.VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return info.Voice;
|
||||
|
||||
@@ -86,6 +86,8 @@ namespace OpenRA.Mods.Cnc.Traits
|
||||
return new Order("PlaceMine", self, Target.FromCell(self.World, self.Location), false);
|
||||
}
|
||||
|
||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return true; }
|
||||
|
||||
void IResolveOrder.ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "BeginMinefield")
|
||||
|
||||
@@ -198,7 +198,8 @@ namespace OpenRA.Mods.Common.AI
|
||||
if (sumOfMaxHp == 0)
|
||||
return 0.0f;
|
||||
|
||||
return (sumOfHp * normalizeByValue) / sumOfMaxHp;
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
return (int)((long)sumOfHp * normalizeByValue / sumOfMaxHp);
|
||||
}
|
||||
|
||||
static float RelativePower(IEnumerable<Actor> own, IEnumerable<Actor> enemy)
|
||||
|
||||
@@ -1257,8 +1257,8 @@ namespace OpenRA.Mods.Common.AI
|
||||
if (!e.Attacker.Info.HasTraitInfo<ITargetableInfo>())
|
||||
return;
|
||||
|
||||
// Protected harvesters or building
|
||||
if ((self.Info.HasTraitInfo<HarvesterInfo>() || self.Info.HasTraitInfo<BuildingInfo>()) &&
|
||||
// Protected priority assets, MCVs, harvesters and buildings
|
||||
if ((self.Info.HasTraitInfo<HarvesterInfo>() || self.Info.HasTraitInfo<BuildingInfo>() || self.Info.HasTraitInfo<BaseBuildingInfo>()) &&
|
||||
Player.Stances[e.Attacker.Owner] == Stance.Enemy)
|
||||
{
|
||||
defenseCenter = e.Attacker.Location;
|
||||
|
||||
@@ -160,7 +160,12 @@ namespace OpenRA.Mods.Common.AI
|
||||
|
||||
case DecisionMetric.Health:
|
||||
var health = a.TraitOrDefault<Health>();
|
||||
return (health != null) ? (health.HP / health.MaxHP) * Attractiveness : 0;
|
||||
|
||||
if (health == null)
|
||||
return 0;
|
||||
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
return (int)((long)health.HP * Attractiveness / health.MaxHP);
|
||||
|
||||
default:
|
||||
return Attractiveness;
|
||||
|
||||
@@ -58,7 +58,9 @@ namespace OpenRA.Mods.Common.Activities
|
||||
return;
|
||||
|
||||
var capturesInfo = activeCaptures.Info;
|
||||
var lowEnoughHealth = health.HP <= capturable.Info.CaptureThreshold * health.MaxHP / 100;
|
||||
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var lowEnoughHealth = health.HP <= (int)(capturable.Info.CaptureThreshold * (long)health.MaxHP / 100);
|
||||
if (!capturesInfo.Sabotage || lowEnoughHealth || actor.Owner.NonCombatant)
|
||||
{
|
||||
var oldOwner = actor.Owner;
|
||||
@@ -80,7 +82,8 @@ namespace OpenRA.Mods.Common.Activities
|
||||
}
|
||||
else
|
||||
{
|
||||
var damage = health.MaxHP * capturesInfo.SabotageHPRemoval / 100;
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var damage = (int)((long)health.MaxHP * capturesInfo.SabotageHPRemoval / 100);
|
||||
actor.InflictDamage(self, new Damage(damage));
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,9 @@ namespace OpenRA.Mods.Common.Activities
|
||||
{
|
||||
var unitCost = self.Info.TraitInfo<ValuedInfo>().Cost;
|
||||
var hpToRepair = repairsUnits.Info.HpPerStep;
|
||||
var cost = Math.Max(1, (hpToRepair * unitCost * repairsUnits.Info.ValuePercentage) / (health.MaxHP * 100));
|
||||
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var cost = Math.Max(1, (int)(((long)hpToRepair * unitCost * repairsUnits.Info.ValuePercentage) / (health.MaxHP * 100L)));
|
||||
|
||||
if (!played)
|
||||
{
|
||||
|
||||
@@ -34,9 +34,12 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
var cost = self.GetSellValue();
|
||||
var sellValue = self.GetSellValue();
|
||||
|
||||
var refund = (cost * sellableInfo.RefundPercent * (health == null ? 1 : health.HP)) / (100 * (health == null ? 1 : health.MaxHP));
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var hp = health != null ? (long)health.HP : 1L;
|
||||
var maxHP = health != null ? (long)health.MaxHP : 1L;
|
||||
var refund = (int)((sellValue * sellableInfo.RefundPercent * hp) / (100 * maxHP));
|
||||
playerResources.GiveCash(refund);
|
||||
|
||||
foreach (var ns in self.TraitsImplementing<INotifySold>())
|
||||
|
||||
@@ -122,7 +122,8 @@ namespace OpenRA.Mods.Common.Activities
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if (health != null)
|
||||
{
|
||||
var newHP = ForceHealthPercentage > 0 ? ForceHealthPercentage : (health.HP * 100) / health.MaxHP;
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var newHP = ForceHealthPercentage > 0 ? ForceHealthPercentage : (int)(health.HP * 100L / health.MaxHP);
|
||||
init.Add(new HealthInit(newHP));
|
||||
}
|
||||
|
||||
|
||||
@@ -134,20 +134,12 @@ namespace OpenRA.Mods.Common.Commands
|
||||
break;
|
||||
|
||||
case "kill":
|
||||
var args = arg.Split(' ');
|
||||
var damageTypes = new HashSet<string>();
|
||||
|
||||
foreach (var damageType in args)
|
||||
damageTypes.Add(damageType);
|
||||
|
||||
foreach (var actor in world.Selection.Actors)
|
||||
{
|
||||
if (actor.IsDead)
|
||||
continue;
|
||||
|
||||
var health = actor.TraitOrDefault<Health>();
|
||||
if (health != null)
|
||||
health.InflictDamage(actor, actor, new Damage(health.HP, damageTypes), true);
|
||||
world.IssueOrder(new Order("DevKill", world.LocalPlayer.PlayerActor, Target.FromActor(actor), false) { TargetString = arg });
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -158,7 +150,7 @@ namespace OpenRA.Mods.Common.Commands
|
||||
if (actor.Disposed)
|
||||
continue;
|
||||
|
||||
actor.Dispose();
|
||||
world.IssueOrder(new Order("DevDispose", world.LocalPlayer.PlayerActor, Target.FromActor(actor), false));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -39,10 +39,7 @@ namespace OpenRA.Mods.Common.Commands
|
||||
{
|
||||
case "pause":
|
||||
if (Game.IsHost || (world.LocalPlayer != null && world.LocalPlayer.WinState != WinState.Lost))
|
||||
world.IssueOrder(new Order("PauseGame", null, false)
|
||||
{
|
||||
TargetString = world.Paused ? "UnPause" : "Pause"
|
||||
});
|
||||
world.SetPauseState(!world.Paused);
|
||||
|
||||
break;
|
||||
case "surrender":
|
||||
|
||||
@@ -511,6 +511,7 @@
|
||||
<Compile Include="Traits\Conditions\ProximityExternalCondition.cs" />
|
||||
<Compile Include="Traits\Conditions\GrantConditionOnAttack.cs" />
|
||||
<Compile Include="Traits\Conditions\GrantConditionOnDamageState.cs" />
|
||||
<Compile Include="Traits\Conditions\GrantConditionOnFaction.cs" />
|
||||
<Compile Include="Traits\Conditions\GrantConditionOnTerrain.cs" />
|
||||
<Compile Include="Traits\Conditions\GrantConditionOnMovement.cs" />
|
||||
<Compile Include="Traits\Conditions\GrantConditionOnPrerequisite.cs" />
|
||||
|
||||
@@ -663,9 +663,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
Order IIssueDeployOrder.IssueDeployOrder(Actor self)
|
||||
{
|
||||
if (!Info.RearmBuildings.Any())
|
||||
return null;
|
||||
|
||||
return new Order("ReturnToBase", self, false);
|
||||
}
|
||||
|
||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return Info.RearmBuildings.Any(); }
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (!Info.MoveIntoShroud && !self.Owner.Shroud.IsExplored(order.TargetLocation))
|
||||
@@ -675,9 +680,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
case "Move":
|
||||
case "Enter":
|
||||
case "ReturnToBase":
|
||||
case "Stop":
|
||||
return Info.Voice;
|
||||
case "ReturnToBase":
|
||||
return Info.RearmBuildings.Any() ? Info.Voice : null;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
@@ -764,7 +770,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
self.QueueActivity(new HeliLand(self, true));
|
||||
}
|
||||
}
|
||||
else if (order.OrderString == "ReturnToBase")
|
||||
else if (order.OrderString == "ReturnToBase" && Info.RearmBuildings.Any())
|
||||
{
|
||||
UnReserve();
|
||||
self.CancelActivity();
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public WeaponInfo ExplosionWeapon { get; private set; }
|
||||
|
||||
public object Create(ActorInitializer init) { return new FallsToEarth(init.Self, this); }
|
||||
public object Create(ActorInitializer init) { return new FallsToEarth(init, this); }
|
||||
public void RulesetLoaded(Ruleset rules, ActorInfo ai)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Explosion))
|
||||
@@ -42,11 +42,18 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public class FallsToEarth
|
||||
public class FallsToEarth : IEffectiveOwner
|
||||
{
|
||||
public FallsToEarth(Actor self, FallsToEarthInfo info)
|
||||
readonly Player effectiveOwner;
|
||||
|
||||
public FallsToEarth(ActorInitializer init, FallsToEarthInfo info)
|
||||
{
|
||||
self.QueueActivity(false, new FallToEarth(self, info));
|
||||
init.Self.QueueActivity(false, new FallToEarth(init.Self, info));
|
||||
effectiveOwner = init.Contains<EffectiveOwnerInit>() ? init.Get<EffectiveOwnerInit, Player>() : init.Self.Owner;
|
||||
}
|
||||
|
||||
// We return init.Self.Owner if there's no effective owner
|
||||
bool IEffectiveOwner.Disguised { get { return true; } }
|
||||
Player IEffectiveOwner.Owner { get { return effectiveOwner; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return new Order("Detonate", self, false);
|
||||
}
|
||||
|
||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return true; }
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return info.Voice;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
[Desc("Used together with ClassicProductionQueue.")]
|
||||
public class PrimaryBuildingInfo : ITraitInfo
|
||||
public class PrimaryBuildingInfo : ConditionalTraitInfo
|
||||
{
|
||||
[GrantedConditionReference]
|
||||
[Desc("The condition to grant to self while this is the primary building.")]
|
||||
@@ -35,23 +35,24 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("The speech notification to play when selecting a primary building.")]
|
||||
public readonly string SelectionNotification = "PrimaryBuildingSelected";
|
||||
|
||||
public object Create(ActorInitializer init) { return new PrimaryBuilding(init.Self, this); }
|
||||
[Desc("List of production queues for which the primary flag should be set.",
|
||||
"If empty, the list given in the `Produces` property of the `Production` trait will be used.")]
|
||||
public readonly string[] ProductionQueues = { };
|
||||
|
||||
public override object Create(ActorInitializer init) { return new PrimaryBuilding(init.Self, this); }
|
||||
}
|
||||
|
||||
public class PrimaryBuilding : INotifyCreated, IIssueOrder, IResolveOrder
|
||||
public class PrimaryBuilding : ConditionalTrait<PrimaryBuildingInfo>, INotifyCreated, IIssueOrder, IResolveOrder
|
||||
{
|
||||
const string OrderID = "PrimaryProducer";
|
||||
|
||||
readonly PrimaryBuildingInfo info;
|
||||
ConditionManager conditionManager;
|
||||
int primaryToken = ConditionManager.InvalidConditionToken;
|
||||
|
||||
public bool IsPrimary { get; private set; }
|
||||
|
||||
public PrimaryBuilding(Actor self, PrimaryBuildingInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
: base(info) { }
|
||||
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
@@ -60,7 +61,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
IEnumerable<IOrderTargeter> IIssueOrder.Orders
|
||||
{
|
||||
get { yield return new DeployOrderTargeter(OrderID, 1); }
|
||||
get
|
||||
{
|
||||
if (IsTraitDisabled)
|
||||
yield break;
|
||||
|
||||
yield return new DeployOrderTargeter(OrderID, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Order IIssueOrder.IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
@@ -86,7 +93,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
// Cancel existing primaries
|
||||
// TODO: THIS IS SHIT
|
||||
foreach (var p in self.Info.TraitInfo<ProductionInfo>().Produces)
|
||||
var queues = Info.ProductionQueues.Length == 0 ? self.Info.TraitInfos<ProductionInfo>().SelectMany(pi => pi.Produces) : Info.ProductionQueues;
|
||||
foreach (var q in queues)
|
||||
{
|
||||
foreach (var b in self.World
|
||||
.ActorsWithTrait<PrimaryBuilding>()
|
||||
@@ -94,17 +102,25 @@ namespace OpenRA.Mods.Common.Traits
|
||||
a.Actor != self &&
|
||||
a.Actor.Owner == self.Owner &&
|
||||
a.Trait.IsPrimary &&
|
||||
a.Actor.Info.TraitInfo<ProductionInfo>().Produces.Contains(p)))
|
||||
a.Actor.Info.TraitInfos<ProductionInfo>().Any(pi => pi.Produces.Contains(q))))
|
||||
b.Trait.SetPrimaryProducer(b.Actor, false);
|
||||
}
|
||||
|
||||
if (conditionManager != null && primaryToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(info.PrimaryCondition))
|
||||
primaryToken = conditionManager.GrantCondition(self, info.PrimaryCondition);
|
||||
if (conditionManager != null && primaryToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.PrimaryCondition))
|
||||
primaryToken = conditionManager.GrantCondition(self, Info.PrimaryCondition);
|
||||
|
||||
Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SelectionNotification, self.Owner.Faction.InternalName);
|
||||
Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", Info.SelectionNotification, self.Owner.Faction.InternalName);
|
||||
}
|
||||
else if (primaryToken != ConditionManager.InvalidConditionToken)
|
||||
primaryToken = conditionManager.RevokeCondition(self, primaryToken);
|
||||
}
|
||||
|
||||
protected override void TraitEnabled(Actor self) { }
|
||||
|
||||
protected override void TraitDisabled(Actor self)
|
||||
{
|
||||
if (IsPrimary)
|
||||
SetPrimaryProducer(self, !IsPrimary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
// The cost is the same regardless of the amount of people repairing
|
||||
var hpToRepair = Math.Min(Info.RepairStep, health.MaxHP - health.HP);
|
||||
var cost = Math.Max(1, (hpToRepair * Info.RepairPercent * buildingValue) / (health.MaxHP * 100));
|
||||
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var cost = Math.Max(1, (int)(((long)hpToRepair * Info.RepairPercent * buildingValue) / (health.MaxHP * 100L)));
|
||||
|
||||
// TakeCash will return false if the player can't pay, and will stop him from contributing this Tick
|
||||
var activePlayers = Repairers.Count(player => player.PlayerActor.Trait<PlayerResources>().TakeCash(cost, true));
|
||||
|
||||
@@ -109,7 +109,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
var health = target.Trait<Health>();
|
||||
var lowEnoughHealth = health.HP <= c.Info.CaptureThreshold * health.MaxHP / 100;
|
||||
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var lowEnoughHealth = health.HP <= (int)(c.Info.CaptureThreshold * (long)health.MaxHP / 100);
|
||||
|
||||
cursor = !capturesInfo.Sabotage || lowEnoughHealth || target.Owner.NonCombatant
|
||||
? capturesInfo.EnterCursor : capturesInfo.SabotageCursor;
|
||||
@@ -129,7 +131,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
var health = target.Info.TraitInfoOrDefault<HealthInfo>();
|
||||
var lowEnoughHealth = target.HP <= c.CaptureThreshold * health.HP / 100;
|
||||
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var lowEnoughHealth = target.HP <= (int)(c.CaptureThreshold * (long)health.HP / 100);
|
||||
|
||||
cursor = !capturesInfo.Sabotage || lowEnoughHealth || target.Owner.NonCombatant
|
||||
? capturesInfo.EnterCursor : capturesInfo.SabotageCursor;
|
||||
|
||||
@@ -178,6 +178,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return new Order("Unload", self, false);
|
||||
}
|
||||
|
||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return true; }
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Unload")
|
||||
|
||||
@@ -138,6 +138,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return new Order("GrantConditionOnDeploy", self, false);
|
||||
}
|
||||
|
||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return true; }
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "GrantConditionOnDeploy" || deployState == DeployState.Deploying || deployState == DeployState.Undeploying)
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2018 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Grants a condition while the trait is active.")]
|
||||
class GrantConditionOnFactionInfo : ConditionalTraitInfo
|
||||
{
|
||||
[FieldLoader.Require]
|
||||
[GrantedConditionReference]
|
||||
[Desc("Condition to grant.")]
|
||||
public readonly string Condition = null;
|
||||
|
||||
[Desc("Only grant this condition for certain factions.")]
|
||||
public readonly HashSet<string> Factions = new HashSet<string>();
|
||||
|
||||
[Desc("Should it recheck everything when it is captured?")]
|
||||
public readonly bool ResetOnOwnerChange = false;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new GrantConditionOnFaction(init, this); }
|
||||
}
|
||||
|
||||
class GrantConditionOnFaction : ConditionalTrait<GrantConditionOnFactionInfo>, INotifyOwnerChanged
|
||||
{
|
||||
ConditionManager conditionManager;
|
||||
int conditionToken = ConditionManager.InvalidConditionToken;
|
||||
string faction;
|
||||
|
||||
public GrantConditionOnFaction(ActorInitializer init, GrantConditionOnFactionInfo info)
|
||||
: base(info)
|
||||
{
|
||||
faction = init.Contains<FactionInit>() ? init.Get<FactionInit, string>() : init.Self.Owner.Faction.InternalName;
|
||||
}
|
||||
|
||||
protected override void Created(Actor self)
|
||||
{
|
||||
conditionManager = self.Trait<ConditionManager>();
|
||||
|
||||
base.Created(self);
|
||||
}
|
||||
|
||||
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
|
||||
{
|
||||
if (Info.ResetOnOwnerChange && faction != newOwner.Faction.InternalName)
|
||||
{
|
||||
faction = newOwner.Faction.InternalName;
|
||||
|
||||
TraitDisabled(self);
|
||||
TraitEnabled(self);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void TraitEnabled(Actor self)
|
||||
{
|
||||
if (conditionToken == ConditionManager.InvalidConditionToken && Info.Factions.Contains(faction))
|
||||
conditionToken = conditionManager.GrantCondition(self, Info.Condition);
|
||||
}
|
||||
|
||||
protected override void TraitDisabled(Actor self)
|
||||
{
|
||||
if (conditionToken == ConditionManager.InvalidConditionToken)
|
||||
return;
|
||||
|
||||
conditionToken = conditionManager.RevokeCondition(self, conditionToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (totalTiles == 0)
|
||||
return;
|
||||
|
||||
damageThreshold = (Info.DamageThreshold * health.MaxHP + (100 - Info.DamageThreshold) * safeTiles * health.MaxHP / totalTiles) / 100;
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
damageThreshold = (int)((Info.DamageThreshold * (long)health.MaxHP + (100 - Info.DamageThreshold) * safeTiles * (long)health.MaxHP / totalTiles) / 100);
|
||||
|
||||
// Actors start with maximum damage applied
|
||||
var delta = health.HP - damageThreshold;
|
||||
|
||||
@@ -60,8 +60,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
var dudesValue = info.ValuePercent * cost / 100;
|
||||
if (health != null)
|
||||
{
|
||||
if (100 * health.HP >= info.MinHpPercent * health.MaxHP)
|
||||
dudesValue = health.HP * dudesValue / health.MaxHP;
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
if (100L * health.HP >= info.MinHpPercent * (long)health.MaxHP)
|
||||
dudesValue = (int)((long)health.HP * dudesValue / health.MaxHP);
|
||||
else
|
||||
dudesValue = 0;
|
||||
}
|
||||
|
||||
@@ -134,7 +134,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (Info.DamageThreshold == 0)
|
||||
return;
|
||||
|
||||
if (health.HP * 100 < Info.DamageThreshold * health.MaxHP)
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
if (health.HP * 100L < Info.DamageThreshold * (long)health.MaxHP)
|
||||
self.World.AddFrameEndTask(w => self.Kill(e.Attacker));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
Info = info;
|
||||
MaxHP = info.HP > 0 ? info.HP : 1;
|
||||
|
||||
hp = init.Contains<HealthInit>() ? init.Get<HealthInit, int>() * MaxHP / 100 : MaxHP;
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
hp = init.Contains<HealthInit>() ? (int)(init.Get<HealthInit, int>() * (long)MaxHP / 100) : MaxHP;
|
||||
|
||||
DisplayHP = hp;
|
||||
}
|
||||
|
||||
@@ -213,6 +213,34 @@ namespace OpenRA.Mods.Common.Traits
|
||||
break;
|
||||
}
|
||||
|
||||
case "DevKill":
|
||||
{
|
||||
if (order.Target.Type != TargetType.Actor)
|
||||
break;
|
||||
|
||||
var actor = order.Target.Actor;
|
||||
var health = actor.TraitOrDefault<Health>();
|
||||
var args = order.TargetString.Split(' ');
|
||||
var damageTypes = new HashSet<string>();
|
||||
|
||||
foreach (var damageType in args)
|
||||
damageTypes.Add(damageType);
|
||||
|
||||
if (health != null)
|
||||
health.InflictDamage(actor, actor, new Damage(health.HP, damageTypes), true);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "DevDispose":
|
||||
{
|
||||
if (order.Target.Type != TargetType.Actor)
|
||||
break;
|
||||
|
||||
order.Target.Actor.Dispose();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public readonly string CancelledAudio = "Cancelled";
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new ProductionQueue(init, init.Self.Owner.PlayerActor, this); }
|
||||
|
||||
public void RulesetLoaded(Ruleset rules, ActorInfo ai) {
|
||||
if (LowPowerSlowdown <= 0)
|
||||
throw new YamlException("Production queue must have LowPowerSlowdown of at least 1.");
|
||||
}
|
||||
}
|
||||
|
||||
public class ProductionQueue : IResolveOrder, ITick, ITechTreeElement, INotifyOwnerChanged, INotifyKilled, INotifySold, ISync, INotifyTransform, INotifyCreated
|
||||
|
||||
@@ -32,7 +32,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
int IPowerModifier.GetPowerModifier()
|
||||
{
|
||||
return 100 * health.HP / health.MaxHP;
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
return (int)(100L * health.HP / health.MaxHP);
|
||||
}
|
||||
|
||||
void INotifyDamage.Damaged(Actor self, AttackInfo e) { power.UpdateActor(self); }
|
||||
|
||||
@@ -16,43 +16,45 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.Common.Traits.Render
|
||||
{
|
||||
[Desc("Display the time remaining until the super weapon attached to the actor is ready.")]
|
||||
class SupportPowerChargeBarInfo : ITraitInfo
|
||||
class SupportPowerChargeBarInfo : ConditionalTraitInfo
|
||||
{
|
||||
[Desc("Defines to which players the bar is to be shown.")]
|
||||
public readonly Stance DisplayStances = Stance.Ally;
|
||||
|
||||
public readonly Color Color = Color.Magenta;
|
||||
|
||||
public object Create(ActorInitializer init) { return new SupportPowerChargeBar(init.Self, this); }
|
||||
public override object Create(ActorInitializer init) { return new SupportPowerChargeBar(init.Self, this); }
|
||||
}
|
||||
|
||||
class SupportPowerChargeBar : ISelectionBar, INotifyOwnerChanged
|
||||
class SupportPowerChargeBar : ConditionalTrait<SupportPowerChargeBarInfo>, ISelectionBar, INotifyOwnerChanged
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly SupportPowerChargeBarInfo info;
|
||||
SupportPowerManager spm;
|
||||
|
||||
public SupportPowerChargeBar(Actor self, SupportPowerChargeBarInfo info)
|
||||
: base(info)
|
||||
{
|
||||
this.self = self;
|
||||
this.info = info;
|
||||
spm = self.Owner.PlayerActor.Trait<SupportPowerManager>();
|
||||
}
|
||||
|
||||
float ISelectionBar.GetValue()
|
||||
{
|
||||
if (IsTraitDisabled)
|
||||
return 0;
|
||||
|
||||
var power = spm.GetPowersForActor(self).FirstOrDefault(sp => !sp.Disabled);
|
||||
if (power == null)
|
||||
return 0;
|
||||
|
||||
var viewer = self.World.RenderPlayer ?? self.World.LocalPlayer;
|
||||
if (viewer != null && !info.DisplayStances.HasStance(self.Owner.Stances[viewer]))
|
||||
if (viewer != null && !Info.DisplayStances.HasStance(self.Owner.Stances[viewer]))
|
||||
return 0;
|
||||
|
||||
return 1 - (float)power.RemainingTime / power.TotalTime;
|
||||
}
|
||||
|
||||
Color ISelectionBar.GetColor() { return info.Color; }
|
||||
Color ISelectionBar.GetColor() { return Info.Color; }
|
||||
bool ISelectionBar.DisplayWhenEmpty { get { return false; } }
|
||||
|
||||
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
|
||||
|
||||
@@ -55,7 +55,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (self.IsDead || IsTraitDisabled)
|
||||
return;
|
||||
|
||||
if (health.HP >= Info.HealIfBelow * health.MaxHP / 100)
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
if (health.HP >= Info.HealIfBelow * (long)health.MaxHP / 100)
|
||||
return;
|
||||
|
||||
if (damageTicks > 0)
|
||||
@@ -67,7 +68,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (--ticks <= 0)
|
||||
{
|
||||
ticks = Info.Delay;
|
||||
self.InflictDamage(self, new Damage(-(Info.Step + Info.PercentageStep * health.MaxHP / 100), Info.DamageTypes));
|
||||
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
self.InflictDamage(self, new Damage((int)(-(Info.Step + Info.PercentageStep * (long)health.MaxHP / 100)), Info.DamageTypes));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,14 +94,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
get
|
||||
{
|
||||
var sellValue = self.GetSellValue() * info.RefundPercent / 100;
|
||||
if (health.Value != null)
|
||||
{
|
||||
sellValue *= health.Value.HP;
|
||||
sellValue /= health.Value.MaxHP;
|
||||
}
|
||||
var sellValue = self.GetSellValue();
|
||||
|
||||
return "Refund: $" + sellValue;
|
||||
// Cast to long to avoid overflow when multiplying by the health
|
||||
var hp = health != null ? (long)health.Value.HP : 1L;
|
||||
var maxHP = health != null ? (long)health.Value.MaxHP : 1L;
|
||||
var refund = (int)((sellValue * info.RefundPercent * hp) / (100 * maxHP));
|
||||
|
||||
return "Refund: $" + refund;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,14 +57,18 @@ namespace OpenRA.Mods.Common.Traits
|
||||
base.Activate(self, order, manager);
|
||||
|
||||
var info = Info as ProduceActorPowerInfo;
|
||||
var sp = self.TraitsImplementing<Production>()
|
||||
.FirstOrDefault(p => p.Info.Produces.Contains(info.Type));
|
||||
var producers = self.World.ActorsWithTrait<Production>()
|
||||
.Where(x => x.Actor.Owner == self.Owner
|
||||
&& !x.Trait.IsTraitDisabled
|
||||
&& x.Trait.Info.Produces.Contains(info.Type))
|
||||
.OrderByDescending(x => x.Actor.IsPrimaryBuilding())
|
||||
.ThenByDescending(x => x.Actor.ActorID);
|
||||
|
||||
// TODO: The power should not reset if the production fails.
|
||||
// Fixing this will require a larger rework of the support power code
|
||||
var activated = false;
|
||||
|
||||
if (sp != null)
|
||||
foreach (var p in producers)
|
||||
{
|
||||
foreach (var name in info.Actors)
|
||||
{
|
||||
@@ -75,8 +79,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
new FactionInit(BuildableInfo.GetInitialFaction(ai, faction))
|
||||
};
|
||||
|
||||
activated |= sp.Produce(self, ai, info.Type, inits);
|
||||
activated |= p.Trait.Produce(p.Actor, ai, info.Type, inits);
|
||||
}
|
||||
|
||||
if (activated)
|
||||
break;
|
||||
}
|
||||
|
||||
if (activated)
|
||||
|
||||
@@ -124,7 +124,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return NoInstances;
|
||||
|
||||
return a.TraitsImplementing<SupportPower>()
|
||||
.Select(t => Powers[MakeKey(t)]);
|
||||
.Select(t => Powers[MakeKey(t)])
|
||||
.Where(p => p.Instances.Any(i => !i.IsTraitDisabled && i.Self == a));
|
||||
}
|
||||
|
||||
public void PrerequisitesAvailable(string key)
|
||||
@@ -232,7 +233,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!Ready)
|
||||
return;
|
||||
|
||||
var power = Instances.Where(i => !i.IsTraitPaused)
|
||||
var power = Instances.Where(i => !i.IsTraitPaused && !i.IsTraitDisabled)
|
||||
.MinByOrDefault(a =>
|
||||
{
|
||||
if (a.Self.OccupiesSpace == null)
|
||||
|
||||
@@ -77,7 +77,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
readonly TooltipInfo info;
|
||||
|
||||
public ITooltipInfo TooltipInfo { get { return info; } }
|
||||
public Player Owner { get { return self.Owner; } }
|
||||
|
||||
public Player Owner
|
||||
{
|
||||
get
|
||||
{
|
||||
return self.EffectiveOwner != null ? self.EffectiveOwner.Owner : self.Owner;
|
||||
}
|
||||
}
|
||||
|
||||
public Tooltip(Actor self, TooltipInfo info)
|
||||
: base(info)
|
||||
|
||||
@@ -105,6 +105,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return new Order("DeployTransform", self, false);
|
||||
}
|
||||
|
||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return !IsTraitPaused && !IsTraitDisabled; }
|
||||
|
||||
public void DeployTransform(bool queued)
|
||||
{
|
||||
if (!queued && !CanDeploy())
|
||||
|
||||
@@ -323,6 +323,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public interface IIssueDeployOrder
|
||||
{
|
||||
Order IssueDeployOrder(Actor self);
|
||||
bool CanIssueDeployOrder(Actor self);
|
||||
}
|
||||
|
||||
public enum ActorPreviewType { PlaceBuilding, ColorPicker, MapEditorSidebar }
|
||||
|
||||
@@ -19,11 +19,11 @@ namespace OpenRA.Mods.Common
|
||||
|
||||
public class WebServices : IGlobalModData
|
||||
{
|
||||
public readonly string ServerList = "http://master.openra.net/games";
|
||||
public readonly string ServerAdvertise = "http://master.openra.net/ping";
|
||||
public readonly string MapRepository = "http://resource.openra.net/map/";
|
||||
public readonly string GameNews = "http://master.openra.net/gamenews";
|
||||
public readonly string VersionCheck = "http://master.openra.net/versioncheck";
|
||||
public readonly string ServerList = "https://master.openra.net/games";
|
||||
public readonly string ServerAdvertise = "https://master.openra.net/ping";
|
||||
public readonly string MapRepository = "https://resource.openra.net/map/";
|
||||
public readonly string GameNews = "https://master.openra.net/gamenews";
|
||||
public readonly string VersionCheck = "https://master.openra.net/versioncheck";
|
||||
|
||||
public ModVersionStatus ModVersionStatus { get; private set; }
|
||||
const int VersionCheckProtocol = 1;
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
BindButtonIcon(deployButton);
|
||||
|
||||
deployButton.IsDisabled = () => { UpdateStateIfNecessary(); return !selectedDeploys.Any(pair => pair.Trait.IsTraitEnabled()); };
|
||||
deployButton.IsDisabled = () => { UpdateStateIfNecessary(); return !selectedDeploys.Any(pair => pair.Trait.CanIssueDeployOrder(pair.Actor)); };
|
||||
deployButton.IsHighlighted = () => deployHighlighted > 0;
|
||||
deployButton.OnClick = () =>
|
||||
{
|
||||
@@ -307,8 +307,9 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
UpdateStateIfNecessary();
|
||||
|
||||
var orders = selectedDeploys
|
||||
.Where(pair => pair.Trait.IsTraitEnabled())
|
||||
.Where(pair => pair.Trait.CanIssueDeployOrder(pair.Actor))
|
||||
.Select(d => d.Trait.IssueDeployOrder(d.Actor))
|
||||
.Where(d => d != null)
|
||||
.ToArray();
|
||||
|
||||
foreach (var o in orders)
|
||||
|
||||
@@ -145,7 +145,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
AddChatLine(chatLine.Color, chatLine.Name, chatLine.Text, true);
|
||||
|
||||
orderManager.AddChatLine += AddChatLineWrapper;
|
||||
Game.BeforeGameStart += UnregisterEvents;
|
||||
|
||||
chatText.IsDisabled = () => world.IsReplay && !Game.Settings.Debug.EnableDebugCommandsInReplays;
|
||||
|
||||
@@ -177,12 +176,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnregisterEvents()
|
||||
{
|
||||
orderManager.AddChatLine -= AddChatLineWrapper;
|
||||
Game.BeforeGameStart -= UnregisterEvents;
|
||||
}
|
||||
|
||||
public void OpenChat()
|
||||
{
|
||||
chatText.Text = "";
|
||||
@@ -203,14 +196,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
|
||||
public void AddChatLineWrapper(Color c, string from, string text)
|
||||
{
|
||||
AddChatLine(c, from, text, false);
|
||||
}
|
||||
|
||||
void AddChatLine(Color c, string from, string text, bool replayCache)
|
||||
{
|
||||
if (!replayCache && chatOverlayDisplay != null)
|
||||
if (chatOverlayDisplay != null)
|
||||
chatOverlayDisplay.AddLine(c, from, text);
|
||||
|
||||
// HACK: Force disable the chat notification sound for the in-menu chat dialog
|
||||
// This works around our inability to disable the sounds for the in-game dialog when it is hidden
|
||||
AddChatLine(c, from, text, chatOverlay == null);
|
||||
}
|
||||
|
||||
void AddChatLine(Color c, string from, string text, bool suppressSound)
|
||||
{
|
||||
var template = chatTemplate.Clone();
|
||||
var nameLabel = template.Get<LabelWidget>("NAME");
|
||||
var textLabel = template.Get<LabelWidget>("TEXT");
|
||||
@@ -243,8 +238,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
if (scrolledToBottom)
|
||||
chatScrollPanel.ScrollToBottom(smooth: true);
|
||||
|
||||
if (!replayCache)
|
||||
if (!suppressSound)
|
||||
Game.Sound.PlayNotification(modRules, null, "Sounds", "ChatLine", null);
|
||||
}
|
||||
|
||||
bool disposed = false;
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
orderManager.AddChatLine -= AddChatLineWrapper;
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
if (statsHotkeys[i].IsActivatedBy(e))
|
||||
{
|
||||
Game.Sound.PlayNotification(modData.DefaultRules, null, "Sounds", "ClickSound", null);
|
||||
OpenMenuPanel(stats, new WidgetArgs() { { "activePanel", i } });
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -128,6 +128,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
if (statsHotkeys[i].IsActivatedBy(e))
|
||||
{
|
||||
Game.Sound.PlayNotification(modData.DefaultRules, null, "Sounds", "ClickSound", null);
|
||||
statsDropDownOptions[i].OnClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
var timeMultiplier = pm.PowerState != PowerState.Normal ? tooltipIcon.ProductionQueue.Info.LowPowerSlowdown : 1;
|
||||
|
||||
timeLabel.Text = formatBuildTime.Update(buildTime * timeMultiplier);
|
||||
timeLabel.TextColor = pm.PowerState != PowerState.Normal ? Color.Red : Color.White;
|
||||
timeLabel.TextColor = (pm.PowerState != PowerState.Normal && tooltipIcon.ProductionQueue.Info.LowPowerSlowdown > 1) ? Color.Red : Color.White;
|
||||
var timeSize = font.Measure(timeLabel.Text);
|
||||
|
||||
costLabel.Text = cost.ToString();
|
||||
@@ -143,4 +143,4 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
tooltipContainer.BeforeRender = () =>
|
||||
{
|
||||
var icon = palette.TooltipIcon;
|
||||
if (icon == null)
|
||||
if (icon == null || icon.Power == null || icon.Power.Instances.Count == 0)
|
||||
return;
|
||||
|
||||
var sp = icon.Power;
|
||||
|
||||
@@ -298,6 +298,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
});
|
||||
musicBin.IsVisible = () => panel == PanelType.Music;
|
||||
|
||||
ServerListLogic serverListLogic = null;
|
||||
if (!skirmishMode)
|
||||
{
|
||||
Action<GameServer> doNothingWithServer = _ => { };
|
||||
@@ -307,6 +308,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{ "onJoin", doNothingWithServer },
|
||||
});
|
||||
|
||||
serverListLogic = serversBin.LogicObjects.Select(l => l as ServerListLogic).FirstOrDefault(l => l != null);
|
||||
serversBin.IsVisible = () => panel == PanelType.Servers;
|
||||
}
|
||||
|
||||
@@ -334,7 +336,14 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
serversTab.IsHighlighted = () => panel == PanelType.Servers;
|
||||
serversTab.IsDisabled = () => panel == PanelType.Kick || panel == PanelType.ForceStart;
|
||||
serversTab.OnClick = () => panel = PanelType.Servers;
|
||||
serversTab.OnClick = () =>
|
||||
{
|
||||
// Refresh the list when switching to the servers tab
|
||||
if (serverListLogic != null && panel != PanelType.Servers)
|
||||
serverListLogic.RefreshServerList();
|
||||
|
||||
panel = PanelType.Servers;
|
||||
};
|
||||
}
|
||||
|
||||
// Force start panel
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
game.Spectators > 0 ? ", {0} Spectator{1}".F(game.Spectators, game.Spectators != 1 ? "s" : "") : "");
|
||||
}
|
||||
|
||||
void RefreshServerList()
|
||||
public void RefreshServerList()
|
||||
{
|
||||
// Query in progress
|
||||
if (currentQuery != null)
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace OpenRA.Mods.D2k.UtilityCommands
|
||||
{ 360, Pair.New("light_inf", "Harkonnen") },
|
||||
{ 361, Pair.New("trooper", "Harkonnen") },
|
||||
{ 362, Pair.New("fremen", "Harkonnen") },
|
||||
{ 363, Pair.New("sardaukar", "Harkonnen") },
|
||||
{ 363, Pair.New("mpsardaukar", "Harkonnen") },
|
||||
{ 364, Pair.New("engineer", "Harkonnen") },
|
||||
{ 365, Pair.New("harvester", "Harkonnen") },
|
||||
{ 366, Pair.New("mcv", "Harkonnen") },
|
||||
|
||||
@@ -18,51 +18,57 @@ namespace OpenRA.Test
|
||||
[TestFixture]
|
||||
public class OrderTest
|
||||
{
|
||||
Order order;
|
||||
Order targetInvalid;
|
||||
Order immediateOrder;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
byte[] RoundTripOrder(byte[] bytes)
|
||||
{
|
||||
order = new Order("TestOrder", null, false)
|
||||
{
|
||||
TargetString = "TestTarget",
|
||||
ExtraData = 1234,
|
||||
ExtraLocation = new CPos(555, 555)
|
||||
};
|
||||
return Order.Deserialize(null, new BinaryReader(new MemoryStream(bytes))).Serialize();
|
||||
}
|
||||
|
||||
targetInvalid = new Order("TestOrder", null, Target.Invalid, false);
|
||||
[TestCase(TestName = "Order data persists over serialization (empty)")]
|
||||
public void SerializeEmpty()
|
||||
{
|
||||
var o = new Order().Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
immediateOrder = new Order("TestOrderImmediate", null, false)
|
||||
[TestCase(TestName = "Order data persists over serialization (unqueued)")]
|
||||
public void SerializeUnqueued()
|
||||
{
|
||||
var o = new Order("Test", null, false).Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (queued)")]
|
||||
public void SerializeQueued()
|
||||
{
|
||||
var o = new Order("Test", null, true).Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (pos target)")]
|
||||
public void SerializePos()
|
||||
{
|
||||
var o = new Order("Test", null, Target.FromPos(new WPos(int.MinValue, 0, int.MaxValue)), false).Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (invalid target)")]
|
||||
public void SerializeInvalid()
|
||||
{
|
||||
var o = new Order("Test", null, Target.Invalid, false).Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Order data persists over serialization (extra fields)")]
|
||||
public void SerializeExtra()
|
||||
{
|
||||
var o = new Order("Test", null, Target.Invalid, true)
|
||||
{
|
||||
TargetString = "TargetString",
|
||||
ExtraLocation = new CPos(int.MinValue, int.MaxValue, 128),
|
||||
ExtraData = uint.MaxValue,
|
||||
IsImmediate = true,
|
||||
TargetString = "TestTarget"
|
||||
};
|
||||
}
|
||||
|
||||
Order RoundTripOrder(Order o)
|
||||
{
|
||||
var serializedData = new MemoryStream(o.Serialize());
|
||||
return Order.Deserialize(null, new BinaryReader(serializedData));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Data persists over serialization")]
|
||||
public void SerializeA()
|
||||
{
|
||||
Assert.That(RoundTripOrder(order).ToString(), Is.EqualTo(order.ToString()));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Data persists over serialization (Immediate order)")]
|
||||
public void SerializeB()
|
||||
{
|
||||
Assert.That(RoundTripOrder(immediateOrder).ToString(), Is.EqualTo(immediateOrder.ToString()));
|
||||
}
|
||||
|
||||
[TestCase(TestName = "Data persists over serialization (Invalid target)")]
|
||||
public void SerializeC()
|
||||
{
|
||||
Assert.That(RoundTripOrder(targetInvalid).ToString(), Is.EqualTo(targetInvalid.ToString()));
|
||||
}.Serialize();
|
||||
Assert.That(RoundTripOrder(o), Is.EqualTo(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ Container@PLAYER_WIDGETS:
|
||||
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.
|
||||
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\nActs immediately on selected units.
|
||||
TooltipContainer: TOOLTIP_CONTAINER
|
||||
Children:
|
||||
Image@ICON:
|
||||
|
||||
@@ -317,6 +317,10 @@
|
||||
HitShape:
|
||||
EditorTilesetFilter:
|
||||
Categories: Aircraft
|
||||
SpawnActorOnDeath:
|
||||
RequiresCondition: airborne
|
||||
OwnerType: InternalName
|
||||
EffectiveOwnerFromOwner: true
|
||||
|
||||
^Infantry:
|
||||
Inherits@1: ^ExistsInWorld
|
||||
@@ -441,7 +445,7 @@
|
||||
^CivInfantry:
|
||||
Inherits: ^Infantry
|
||||
Valued:
|
||||
Cost: 70
|
||||
Cost: 10
|
||||
Tooltip:
|
||||
Name: Civilian
|
||||
GenericVisibility: None
|
||||
|
||||
@@ -840,7 +840,7 @@ OBLI:
|
||||
DecorationBounds: 22,44,0,-10
|
||||
SelectionDecorations:
|
||||
Health:
|
||||
HP: 60000
|
||||
HP: 75000
|
||||
Armor:
|
||||
Type: Heavy
|
||||
RevealsShroud:
|
||||
|
||||
@@ -95,6 +95,8 @@ APC:
|
||||
BuildPaletteOrder: 30
|
||||
Prerequisites: pyle
|
||||
Queue: Vehicle.GDI
|
||||
BuildDuration: 900
|
||||
BuildDurationModifier: 40
|
||||
Description: Armed infantry transport.\nCan attack Aircraft.\n Strong vs Vehicles\n Weak vs Infantry
|
||||
Mobile:
|
||||
TurnSpeed: 8
|
||||
|
||||
@@ -138,10 +138,10 @@ APCGun:
|
||||
Spread: 128
|
||||
Damage: 2000
|
||||
Versus:
|
||||
None: 35
|
||||
Wood: 35
|
||||
None: 30
|
||||
Wood: 25
|
||||
Light: 75
|
||||
Heavy: 35
|
||||
Heavy: 25
|
||||
DamageTypes: Prone50Percent, TriggerProne, DefaultDeath
|
||||
Warhead@2Eff: CreateEffect
|
||||
Explosions: small_poof
|
||||
|
||||
@@ -28,7 +28,7 @@ Speech:
|
||||
Guarding: GUARD
|
||||
HarvesterAttack: HATTK
|
||||
InsufficientFunds: MONEY
|
||||
Leave: ABORT
|
||||
Leave:
|
||||
Lose: MFAIL
|
||||
LowPower: POWER
|
||||
MissileLaunchDetected: LAUNC
|
||||
|
||||
@@ -19,9 +19,21 @@ World:
|
||||
hard: Hard
|
||||
Default: easy
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -19,9 +19,21 @@ World:
|
||||
hard: Hard
|
||||
Default: easy
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -23,9 +23,21 @@ carryall.reinforce:
|
||||
Cargo:
|
||||
MaxWeight: 10
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -23,9 +23,21 @@ carryall.reinforce:
|
||||
Cargo:
|
||||
MaxWeight: 10
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -57,7 +57,7 @@ grenadier:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
sardaukar:
|
||||
mpsardaukar:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
|
||||
@@ -19,9 +19,21 @@ World:
|
||||
hard: Hard
|
||||
Default: easy
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -19,9 +19,21 @@ World:
|
||||
hard: Hard
|
||||
Default: easy
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -23,9 +23,21 @@ carryall.reinforce:
|
||||
Cargo:
|
||||
MaxWeight: 10
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -23,9 +23,21 @@ carryall.reinforce:
|
||||
Cargo:
|
||||
MaxWeight: 10
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -280,6 +280,6 @@ WorldLoaded = function()
|
||||
SendHarkonnenReinforcements(DateTime.Seconds(35), 2)
|
||||
|
||||
local ordosCondition = function() return player.IsObjectiveCompleted(KillOrdos) end
|
||||
TriggerCarryallReinforcements(player, ordos_main, BaseAreaTriggers[1], OrdosHunters[1], OrdosHunterPaths[3], ordosCondition)
|
||||
TriggerCarryallReinforcements(player, ordos_main, BaseAreaTriggers[2], OrdosHunters[2], OrdosHunterPaths[2], ordosCondition)
|
||||
TriggerCarryallReinforcements(player, ordos_main, BaseAreaTriggers[1], OrdosHunters[1], OrdosHunterPaths[2], ordosCondition)
|
||||
TriggerCarryallReinforcements(player, ordos_main, BaseAreaTriggers[2], OrdosHunters[2], OrdosHunterPaths[1], ordosCondition)
|
||||
end
|
||||
|
||||
@@ -54,7 +54,7 @@ siege_tank:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
sardaukar:
|
||||
mpsardaukar:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ missile_tank:
|
||||
Buildable:
|
||||
Prerequisites: ~heavy.missile_tank, upgrade.heavy, research_centre
|
||||
|
||||
sardaukar:
|
||||
mpsardaukar:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ missile_tank:
|
||||
Buildable:
|
||||
Prerequisites: ~heavy.missile_tank, upgrade.heavy, research_centre
|
||||
|
||||
sardaukar:
|
||||
mpsardaukar:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@ sardaukar:
|
||||
Buildable:
|
||||
Prerequisites: ~barracks, ~player.corrino
|
||||
|
||||
mpsardaukar:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
grenadier:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
@@ -36,7 +36,7 @@ frigate:
|
||||
LandableTerrainTypes: Sand, Rock, Transition, Spice, SpiceSand, Dune, Concrete
|
||||
VTOL: true # The frigate would teleport to land otherwise
|
||||
|
||||
sardaukar:
|
||||
mpsardaukar:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
|
||||
@@ -37,14 +37,9 @@ frigate:
|
||||
LandableTerrainTypes: Sand, Rock, Transition, Spice, SpiceSand, Dune, Concrete
|
||||
VTOL: true # The frigate would teleport to land otherwise
|
||||
|
||||
palace:
|
||||
ProvidesPrerequisite@sardaukar:
|
||||
Prerequisite: palace.sardaukar
|
||||
Factions: corrino
|
||||
|
||||
sardaukar:
|
||||
mpsardaukar:
|
||||
Buildable:
|
||||
Prerequisites: barracks, ~palace.sardaukar
|
||||
Prerequisites: ~disabled
|
||||
|
||||
grenadier:
|
||||
Buildable:
|
||||
|
||||
@@ -40,14 +40,9 @@ frigate:
|
||||
LandableTerrainTypes: Sand, Rock, Transition, Spice, SpiceSand, Dune, Concrete
|
||||
VTOL: true # The frigate would teleport to land otherwise
|
||||
|
||||
palace:
|
||||
ProvidesPrerequisite@sardaukar:
|
||||
Prerequisite: palace.sardaukar
|
||||
Factions: corrino
|
||||
|
||||
sardaukar:
|
||||
mpsardaukar:
|
||||
Buildable:
|
||||
Prerequisites: barracks, ~palace.sardaukar
|
||||
Prerequisites: ~disabled
|
||||
|
||||
grenadier:
|
||||
Buildable:
|
||||
|
||||
@@ -19,9 +19,21 @@ World:
|
||||
hard: Hard
|
||||
Default: easy
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -19,9 +19,21 @@ World:
|
||||
hard: Hard
|
||||
Default: easy
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -23,9 +23,21 @@ carryall.reinforce:
|
||||
Cargo:
|
||||
MaxWeight: 10
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -23,9 +23,21 @@ carryall.reinforce:
|
||||
Cargo:
|
||||
MaxWeight: 10
|
||||
|
||||
construction_yard:
|
||||
Production:
|
||||
Produces: Building
|
||||
upgrade.conyard:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.barracks:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.light:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
upgrade.heavy:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
|
||||
concreteb:
|
||||
Buildable:
|
||||
|
||||
@@ -38,7 +38,7 @@ AtreidesVehicleTypes = { "trike", "trike", "quad" }
|
||||
AtreidesTankTypes = { "combat_tank_a", "combat_tank_a", "combat_tank_a", "siege_tank" }
|
||||
AtreidesStarportTypes = { "trike.starport", "quad.starport", "siege_tank.starport", "missile_tank.starport", "combat_tank_a.starport" }
|
||||
|
||||
HarkonnenInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper", "sardaukar" }
|
||||
HarkonnenInfantryTypes = { "light_inf", "light_inf", "light_inf", "trooper", "trooper", "mpsardaukar" }
|
||||
HarkonnenVehicleTypes = { "trike", "quad", "quad" }
|
||||
HarkonnenTankTypes = { "combat_tank_h", "combat_tank_h", "combat_tank_h", "siege_tank" }
|
||||
HarkonnenStarportTypes = { "trike.starport", "quad.starport", "siege_tank.starport", "missile_tank.starport", "combat_tank_h.starport" }
|
||||
|
||||
@@ -656,7 +656,7 @@ Actors:
|
||||
SubCell: 3
|
||||
Facing: 0
|
||||
TurretFacing: 0
|
||||
har_sardaukar: sardaukar
|
||||
har_sardaukar: mpsardaukar
|
||||
Owner: Harkonnen
|
||||
Location: 82,28
|
||||
SubCell: 3
|
||||
|
||||
@@ -61,6 +61,12 @@ grenadier:
|
||||
Cost: 0
|
||||
|
||||
sardaukar:
|
||||
Buildable:
|
||||
Prerequisites: ~player.corrino
|
||||
Valued:
|
||||
Cost: 0
|
||||
|
||||
mpsardaukar:
|
||||
Valued:
|
||||
Cost: 0
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ Player:
|
||||
carryall: 1%
|
||||
light_inf: 65%
|
||||
trooper: 40%
|
||||
sardaukar: 20%
|
||||
harvester: 1%
|
||||
mpsardaukar: 20%
|
||||
grenadier: 20%
|
||||
harvester: 1%
|
||||
trike.starport: 5%
|
||||
quad.starport: 7.5%
|
||||
siege_tank.starport: 5%
|
||||
@@ -172,7 +172,7 @@ Player:
|
||||
carryall: 1%
|
||||
light_inf: 65%
|
||||
trooper: 40%
|
||||
sardaukar: 20%
|
||||
mpsardaukar: 20%
|
||||
grenadier: 20%
|
||||
harvester: 1%
|
||||
trike.starport: 7.5%
|
||||
@@ -292,7 +292,7 @@ Player:
|
||||
carryall: 1%
|
||||
light_inf: 65%
|
||||
trooper: 40%
|
||||
sardaukar: 20%
|
||||
mpsardaukar: 20%
|
||||
grenadier: 20%
|
||||
harvester: 1%
|
||||
trike.starport: 5%
|
||||
|
||||
@@ -27,6 +27,9 @@ carryall.reinforce:
|
||||
RequiresCondition: airborne
|
||||
SpawnActorOnDeath:
|
||||
Actor: carryall.husk
|
||||
RequiresCondition: airborne
|
||||
OwnerType: InternalName
|
||||
EffectiveOwnerFromOwner: true
|
||||
Carryall:
|
||||
LoadingDelay: 10
|
||||
UnloadingDelay: 15
|
||||
@@ -95,6 +98,8 @@ ornithopter:
|
||||
Name: Ornithopter
|
||||
SpawnActorOnDeath:
|
||||
Actor: ornithopter.husk
|
||||
OwnerType: InternalName
|
||||
EffectiveOwnerFromOwner: true
|
||||
RejectsOrders:
|
||||
RevealOnFire:
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ engineer:
|
||||
Inherits: ^Infantry
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 50
|
||||
BuildPaletteOrder: 30
|
||||
Prerequisites: upgrade.barracks, ~techlevel.medium
|
||||
BuildDuration: 108
|
||||
BuildDurationModifier: 40
|
||||
@@ -82,7 +82,7 @@ thumper:
|
||||
-RevealOnFire:
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 60
|
||||
BuildPaletteOrder: 40
|
||||
Prerequisites: upgrade.barracks, ~techlevel.high
|
||||
BuildDuration: 108
|
||||
BuildDurationModifier: 40
|
||||
@@ -129,7 +129,7 @@ fremen:
|
||||
Name: Fremen
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 100
|
||||
BuildPaletteOrder: 80
|
||||
Prerequisites: ~disabled
|
||||
Description: Elite infantry unit armed with assault rifles and rockets\n Strong vs Infantry, Vehicles\n Weak vs Artillery\n Special Ability: Invisibility
|
||||
Mobile:
|
||||
@@ -169,7 +169,7 @@ grenadier:
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 80
|
||||
BuildPaletteOrder: 60
|
||||
Prerequisites: ~barracks.atreides, upgrade.barracks, high_tech_factory, ~techlevel.medium
|
||||
BuildDuration: 81 ## Wasn't converted, copied from Sardauker who has same value in TibEd.
|
||||
BuildDurationModifier: 40
|
||||
@@ -200,13 +200,13 @@ sardaukar:
|
||||
Inherits@AUTOTARGET: ^AutoTargetGroundAssaultMove
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 80
|
||||
Prerequisites: ~barracks.harkonnen, upgrade.barracks, high_tech_factory, ~techlevel.medium
|
||||
BuildPaletteOrder: 50
|
||||
Prerequisites: ~palace.sardaukar, ~techlevel.high
|
||||
BuildDuration: 81
|
||||
BuildDurationModifier: 40
|
||||
Description: Elite assault infantry\n Strong vs Infantry, Vehicles\n Weak vs Artillery
|
||||
Description: Elite assault infantry of Corrino\n Strong vs Infantry, Vehicles\n Weak vs Artillery
|
||||
Valued:
|
||||
Cost: 200
|
||||
Cost: 120
|
||||
Tooltip:
|
||||
Name: Sardaukar
|
||||
Health:
|
||||
@@ -229,6 +229,23 @@ sardaukar:
|
||||
EmptyWeapon: SardDeath
|
||||
Chance: 100
|
||||
|
||||
mpsardaukar:
|
||||
Inherits: sardaukar
|
||||
Buildable:
|
||||
Queue: Infantry
|
||||
BuildPaletteOrder: 70
|
||||
Prerequisites: ~barracks.harkonnen, upgrade.barracks, high_tech_factory, ~techlevel.medium
|
||||
BuildDuration: 133
|
||||
Description: Elite assault infantry of Harkonnen\n Strong vs Infantry, Vehicles\n Weak vs Artillery
|
||||
Valued:
|
||||
Cost: 200
|
||||
Armament@PRIMARY:
|
||||
Weapon: M_LMG_H
|
||||
Armament@SECONDARY:
|
||||
Weapon: M_HMG_H
|
||||
RenderSprites:
|
||||
Image: sardaukar
|
||||
|
||||
saboteur:
|
||||
Inherits: ^Infantry
|
||||
Buildable:
|
||||
@@ -266,7 +283,7 @@ nsfremen:
|
||||
Inherits: fremen
|
||||
Tooltip:
|
||||
Buildable:
|
||||
BuildPaletteOrder: 105
|
||||
BuildPaletteOrder: 90
|
||||
Prerequisites: ~disabled
|
||||
Description: Elite infantry unit armed with assault rifles and rockets\n Strong vs Infantry, Vehicles\n Weak vs Artillery
|
||||
RenderSprites:
|
||||
|
||||
@@ -32,7 +32,7 @@ Player:
|
||||
ClassicProductionQueue@Starport:
|
||||
Type: Starport
|
||||
BuildDurationModifier: 212
|
||||
LowPowerSlowdown: 0
|
||||
LowPowerSlowdown: 1
|
||||
BlockedAudio: NoRoom
|
||||
QueuedAudio: OrderPlaced
|
||||
ReadyAudio:
|
||||
@@ -46,11 +46,10 @@ Player:
|
||||
ClassicProductionQueue@Upgrade: # Upgrade is defined after others so it won't be automatically selected by ProductionQueueFromSelection.
|
||||
Type: Upgrade
|
||||
BuildDurationModifier: 250
|
||||
LowPowerSlowdown: 0
|
||||
LowPowerSlowdown: 1
|
||||
QueuedAudio: Upgrading
|
||||
ReadyAudio: NewOptions
|
||||
BlockedAudio: NoRoom
|
||||
SpeedUp: true
|
||||
PlaceBuilding:
|
||||
SupportPowerManager:
|
||||
ScriptTriggers:
|
||||
|
||||
@@ -102,6 +102,7 @@ construction_yard:
|
||||
Palette: d2k
|
||||
PrimaryBuilding:
|
||||
PrimaryCondition: primary
|
||||
ProductionQueues: Building
|
||||
ProvidesPrerequisite@buildingname:
|
||||
GrantConditionOnPrerequisite:
|
||||
Prerequisites: upgrade.conyard
|
||||
@@ -194,7 +195,7 @@ barracks:
|
||||
TopLeft: -1024, -1024
|
||||
BottomRight: 1024, 1024
|
||||
Armor:
|
||||
Type: wood
|
||||
Type: building
|
||||
RevealsShroud:
|
||||
Range: 3c768
|
||||
RallyPoint:
|
||||
@@ -209,6 +210,7 @@ barracks:
|
||||
Produces: Infantry, Upgrade
|
||||
PrimaryBuilding:
|
||||
PrimaryCondition: primary
|
||||
ProductionQueues: Infantry
|
||||
ProductionBar:
|
||||
ProvidesPrerequisite@atreides:
|
||||
Prerequisite: barracks.atreides
|
||||
@@ -279,7 +281,7 @@ refinery:
|
||||
TopLeft: -1536, 0
|
||||
BottomRight: 512, 1024
|
||||
Armor:
|
||||
Type: building
|
||||
Type: heavy
|
||||
RevealsShroud:
|
||||
Range: 4c768
|
||||
Refinery:
|
||||
@@ -333,7 +335,7 @@ silo:
|
||||
Health:
|
||||
HP: 15000
|
||||
Armor:
|
||||
Type: wall
|
||||
Type: building
|
||||
RevealsShroud:
|
||||
Range: 2c768
|
||||
RenderSprites:
|
||||
@@ -389,7 +391,7 @@ light_factory:
|
||||
TopLeft: -1536, -1024
|
||||
BottomRight: 1536, 1024
|
||||
Armor:
|
||||
Type: light
|
||||
Type: building
|
||||
RevealsShroud:
|
||||
Range: 4c768
|
||||
RenderSprites:
|
||||
@@ -408,6 +410,7 @@ light_factory:
|
||||
Produces: Vehicle, Upgrade
|
||||
PrimaryBuilding:
|
||||
PrimaryCondition: primary
|
||||
ProductionQueues: Vehicle
|
||||
ProductionBar:
|
||||
ProvidesPrerequisite@atreides:
|
||||
Prerequisite: light.atreides
|
||||
@@ -480,7 +483,7 @@ heavy_factory:
|
||||
TopLeft: -512, -1536
|
||||
BottomRight: 512, -512
|
||||
Armor:
|
||||
Type: wood
|
||||
Type: building
|
||||
RevealsShroud:
|
||||
Range: 4c768
|
||||
RallyPoint:
|
||||
@@ -492,6 +495,7 @@ heavy_factory:
|
||||
Produces: Armor, Upgrade
|
||||
PrimaryBuilding:
|
||||
PrimaryCondition: primary
|
||||
ProductionQueues: Armor
|
||||
ProductionBar:
|
||||
ProvidesPrerequisite@atreides:
|
||||
Prerequisite: heavy.atreides
|
||||
@@ -574,7 +578,7 @@ outpost:
|
||||
TopLeft: -1536, -1024
|
||||
BottomRight: 1536, 1024
|
||||
Armor:
|
||||
Type: light
|
||||
Type: building
|
||||
RevealsShroud:
|
||||
Range: 4c768
|
||||
ProvidesRadar:
|
||||
@@ -626,7 +630,7 @@ starport:
|
||||
TopLeft: -512, 512
|
||||
BottomRight: 512, 1536
|
||||
Armor:
|
||||
Type: building
|
||||
Type: heavy
|
||||
RevealsShroud:
|
||||
Range: 4c768
|
||||
RallyPoint:
|
||||
@@ -653,6 +657,7 @@ starport:
|
||||
ProductionBar:
|
||||
PrimaryBuilding:
|
||||
PrimaryCondition: primary
|
||||
ProductionQueues: Starport
|
||||
ProvidesPrerequisite@atreides:
|
||||
Prerequisite: starport.atreides
|
||||
Factions: atreides
|
||||
@@ -685,7 +690,7 @@ wall:
|
||||
Inherits@1: ^SpriteActor
|
||||
Interactable:
|
||||
CombatDebugOverlay:
|
||||
HiddenUnderShroud:
|
||||
FrozenUnderFog:
|
||||
ScriptTriggers:
|
||||
Buildable:
|
||||
Queue: Building
|
||||
@@ -816,7 +821,7 @@ large_gun_turret:
|
||||
Health:
|
||||
HP: 30000
|
||||
Armor:
|
||||
Type: concrete
|
||||
Type: heavy
|
||||
RevealsShroud:
|
||||
Range: 5c768
|
||||
BodyOrientation:
|
||||
@@ -902,6 +907,10 @@ high_tech_factory:
|
||||
Name: High Tech Factory
|
||||
ProductionFromMapEdge:
|
||||
Produces: Aircraft, Upgrade
|
||||
ProductionBar:
|
||||
PrimaryBuilding:
|
||||
PrimaryCondition: primary
|
||||
ProductionQueues: Aircraft
|
||||
Exit:
|
||||
SpawnOffset: 0,0,728
|
||||
ExitCell: 0,0
|
||||
@@ -923,7 +932,7 @@ high_tech_factory:
|
||||
TopLeft: -512, -1536
|
||||
BottomRight: 512, -512
|
||||
Armor:
|
||||
Type: wood
|
||||
Type: building
|
||||
RevealsShroud:
|
||||
Range: 4c768
|
||||
RenderSprites:
|
||||
@@ -964,6 +973,12 @@ high_tech_factory:
|
||||
ReferencePoint: Top, Right
|
||||
ZOffset: 256
|
||||
RequiresCondition: stardecoration
|
||||
WithTextDecoration@primary:
|
||||
RequiresSelection: true
|
||||
Text: PRIMARY
|
||||
ReferencePoint: Top
|
||||
ZOffset: 256
|
||||
RequiresCondition: primary
|
||||
|
||||
research_centre:
|
||||
Inherits: ^Building
|
||||
@@ -998,7 +1013,7 @@ research_centre:
|
||||
TopLeft: -512, -1536
|
||||
BottomRight: 512, -512
|
||||
Armor:
|
||||
Type: wood
|
||||
Type: building
|
||||
RevealsShroud:
|
||||
Range: 4c768
|
||||
RenderSprites:
|
||||
@@ -1050,7 +1065,7 @@ palace:
|
||||
TopLeft: -512, 512
|
||||
BottomRight: 1536, 1536
|
||||
Armor:
|
||||
Type: wood
|
||||
Type: heavy
|
||||
RevealsShroud:
|
||||
Range: 4c768
|
||||
RenderSprites:
|
||||
@@ -1071,10 +1086,23 @@ palace:
|
||||
ProvidesPrerequisite@saboteur:
|
||||
Prerequisite: palace.saboteur
|
||||
Factions: ordos
|
||||
ProvidesPrerequisite@sardaukar:
|
||||
Prerequisite: palace.sardaukar
|
||||
Factions: corrino
|
||||
PrimaryBuilding:
|
||||
PrimaryCondition: primary
|
||||
RequiresCondition: atreides || ordos
|
||||
WithTextDecoration@primary:
|
||||
RequiresSelection: true
|
||||
Text: PRIMARY
|
||||
ReferencePoint: Top
|
||||
ZOffset: 256
|
||||
RequiresCondition: primary && (atreides || ordos)
|
||||
NukePower:
|
||||
Cursor: nuke
|
||||
Icon: deathhand
|
||||
PauseOnCondition: disabled
|
||||
RequiresCondition: harkonnen
|
||||
Prerequisites: ~techlevel.superweapons, ~palace.nuke
|
||||
ChargeInterval: 7500
|
||||
Description: Death Hand
|
||||
@@ -1091,7 +1119,7 @@ palace:
|
||||
ArrowSequence: arrow
|
||||
CircleSequence: circles
|
||||
WithNukeLaunchOverlay:
|
||||
RequiresCondition: !launchpad-damaged
|
||||
RequiresCondition: !launchpad-damaged && harkonnen
|
||||
GrantConditionOnDamageState@LAUNCHPADDAMAGED:
|
||||
Condition: launchpad-damaged
|
||||
ValidDamageState: Medium, Heavy, Critical
|
||||
@@ -1100,6 +1128,7 @@ palace:
|
||||
LongDesc: Elite infantry unit armed with assault rifles and rockets\n Strong vs Infantry, Vehicles\n Weak vs Artillery\n Special Ability: Invisibility
|
||||
Icon: fremen
|
||||
PauseOnCondition: disabled
|
||||
RequiresCondition: atreides
|
||||
Prerequisites: ~techlevel.superweapons, ~palace.fremen
|
||||
Actors: fremen, fremen
|
||||
Type: Palace
|
||||
@@ -1112,6 +1141,7 @@ palace:
|
||||
LongDesc: Sneaky infantry, armed with explosives\n Strong vs Buildings\n Weak vs Everything\n Special Ability: destroy buildings
|
||||
Icon: saboteur
|
||||
PauseOnCondition: disabled
|
||||
RequiresCondition: ordos
|
||||
Prerequisites: ~techlevel.superweapons, ~palace.saboteur
|
||||
Actors: saboteur
|
||||
Type: Palace
|
||||
@@ -1130,7 +1160,18 @@ palace:
|
||||
ExitCell: 0,3
|
||||
Production:
|
||||
Produces: Palace
|
||||
RequiresCondition: atreides || ordos
|
||||
GrantConditionOnFaction@Atreides:
|
||||
Condition: atreides
|
||||
Factions: atreides, fremen
|
||||
GrantConditionOnFaction@Harkonnen:
|
||||
Condition: harkonnen
|
||||
Factions: harkonnen
|
||||
GrantConditionOnFaction@Ordos:
|
||||
Condition: ordos
|
||||
Factions: ordos, mercenary, smuggler
|
||||
SupportPowerChargeBar:
|
||||
RequiresCondition: atreides || harkonnen || ordos
|
||||
ProvidesPrerequisite@buildingname:
|
||||
|
||||
conyard.atreides:
|
||||
|
||||
@@ -169,6 +169,7 @@ World:
|
||||
DebugPauseState:
|
||||
RadarPings:
|
||||
ObjectivesPanel:
|
||||
ExitDelay: 0
|
||||
PanelName: SKIRMISH_STATS
|
||||
LoadWidgetAtGameStart:
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ M_LMG:
|
||||
Inherits: ^MG
|
||||
ReloadDelay: 40
|
||||
|
||||
M_LMG_H:
|
||||
Inherits: M_LMG
|
||||
ReloadDelay: 50
|
||||
|
||||
M_HMG:
|
||||
Inherits: ^MG
|
||||
ReloadDelay: 40
|
||||
@@ -54,6 +58,10 @@ M_HMG:
|
||||
cy: 20
|
||||
harvester: 50
|
||||
|
||||
M_HMG_H:
|
||||
Inherits: M_HMG
|
||||
ReloadDelay: 50
|
||||
|
||||
Fremen_L:
|
||||
Inherits: M_HMG
|
||||
Report: BAZOOK2.WAV
|
||||
|
||||
BIN
mods/ra/maps/a-nuclear-winter/map.bin
Normal file
BIN
mods/ra/maps/a-nuclear-winter/map.bin
Normal file
Binary file not shown.
BIN
mods/ra/maps/a-nuclear-winter/map.png
Normal file
BIN
mods/ra/maps/a-nuclear-winter/map.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
2391
mods/ra/maps/a-nuclear-winter/map.yaml
Normal file
2391
mods/ra/maps/a-nuclear-winter/map.yaml
Normal file
File diff suppressed because it is too large
Load Diff
20
mods/ra/maps/a-nuclear-winter/rules.yaml
Normal file
20
mods/ra/maps/a-nuclear-winter/rules.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
World:
|
||||
WeatherOverlay:
|
||||
ChangingWindLevel: true
|
||||
WindLevels: -5, -3, -2, 0, 2, 3, 5, 6
|
||||
WindTick: 150, 550
|
||||
InstantWindChanges: false
|
||||
UseSquares: true
|
||||
ParticleSize: 2, 3
|
||||
ScatterDirection: -1, 1
|
||||
Gravity: 1.00, 2.00
|
||||
SwingOffset: 1.0, 1.5
|
||||
SwingSpeed: 0.001, 0.025
|
||||
SwingAmplitude: 1.0, 1.5
|
||||
ParticleColors: ECECEC, E4E4E4, D0D0D0, BCBCBC
|
||||
LineTailAlphaValue: 0
|
||||
GlobalLightingPaletteEffect:
|
||||
Red: 0.88
|
||||
Green: 0.93
|
||||
Blue: 1.06
|
||||
Ambient: 1.09
|
||||
Binary file not shown.
@@ -240,6 +240,10 @@ InitTriggers = function()
|
||||
end)
|
||||
|
||||
Trigger.OnInfiltrated(Prison, function()
|
||||
if not greece.IsObjectiveCompleted(infWarfactory) then
|
||||
Media.DisplayMessage("Good work! But next time skip the heroics!", "Battlefield Control")
|
||||
greece.MarkCompletedObjective(infWarfactory)
|
||||
end
|
||||
Trigger.ClearAll(Spy)
|
||||
Trigger.AfterDelay(DateTime.Seconds(2), MissInfiltrated)
|
||||
end)
|
||||
|
||||
@@ -1399,7 +1399,7 @@ Actors:
|
||||
Prison: miss
|
||||
Location: 25,106
|
||||
Owner: USSR
|
||||
Warfactory: weap
|
||||
Warfactory: weap.infiltratable
|
||||
Location: 43,50
|
||||
Owner: USSR
|
||||
Warfactory2: weap
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user