Rebased. (+1 squashed commits)

Squashed commits:

[43010a0] Fixes. (+1 squashed commits)

Squashed commits:

[94ee90e] Fixes. (+1 squashed commits)

Squashed commits:

[ef827c7] Style cop updates. Updates to LevelUp, Cloak, and UnitUpgrade to allow multiple units within range, plus maximum extra unit limit. (+1 squashed commits)

Squashed commits:

[2103b01] Dupe crate action updates and fixes. (+2 squashed commit)

Squashed commit:

[0f4df4a] Added DuplicateUnitCrateAction.

[2787fa1] Clarity update. (+1 squashed commits)

Squashed commits:

[93ddc3b] Crate updates.
+Multiple units per crate allowed.
+Allow time delay on crate actions.
This commit is contained in:
UberWaffe
2014-07-10 20:55:02 +02:00
parent 582c1016e9
commit 94b1f53ebf
16 changed files with 374 additions and 63 deletions

View File

@@ -17,15 +17,22 @@ namespace OpenRA.Mods.RA
public class CrateActionInfo : ITraitInfo
{
[Desc("Chance of getting this crate, assuming the collector is compatible.")]
public int SelectionShares = 10;
public readonly int SelectionShares = 10;
[Desc("An animation defined in sequence yaml(s) to draw.")]
public string Effect = null;
public readonly string Effect = null;
[Desc("Palette to draw the animation in.")]
public string Palette = "effect";
public readonly string Palette = "effect";
[Desc("Audio clip to play when the crate is collected.")]
public string Notification = null;
[ActorReference]
public string[] ExcludedActorTypes = { };
public readonly string Notification = null;
[Desc("The earliest time (in ticks) that this crate action can occur on.")]
public readonly int TimeDelay = 0;
[Desc("Actor types that this crate action will not occur for.")]
[ActorReference] public string[] ExcludedActorTypes = { };
public virtual object Create(ActorInitializer init) { return new CrateAction(init.self, this); }
}
@@ -43,6 +50,9 @@ namespace OpenRA.Mods.RA
public int GetSelectionSharesOuter(Actor collector)
{
if (self.World.WorldTick < info.TimeDelay)
return 0;
if (info.ExcludedActorTypes.Contains(collector.Info.Name))
return 0;

View File

@@ -8,17 +8,31 @@
*/
#endregion
using System.Linq;
namespace OpenRA.Mods.RA.Crates
{
[Desc("Grants the collector the ability to cloak.")]
public class CloakCrateActionInfo : CrateActionInfo
{
[Desc("The range to search for extra collectors in.", "Extra collectors will also be granted the crate action.")]
public readonly WRange Range = new WRange(3);
[Desc("The maximum number of extra collectors to grant the crate action to.")]
public readonly int MaxExtraCollectors = 4;
public override object Create(ActorInitializer init) { return new CloakCrateAction(init.self, this); }
}
public class CloakCrateAction : CrateAction
{
CloakCrateActionInfo Info;
public CloakCrateAction(Actor self, CloakCrateActionInfo info)
: base(self, info) { }
: base(self, info)
{
Info = info;
}
public override int GetSelectionShares(Actor collector)
{
@@ -32,6 +46,25 @@ namespace OpenRA.Mods.RA.Crates
public override void Activate(Actor collector)
{
collector.Trait<Cloak>().ReceivedCloakCrate(collector);
var inRange = self.World.FindActorsInCircle(self.CenterPosition, Info.Range);
inRange = inRange.Where(a =>
(a.Owner == collector.Owner) &&
(a != collector) &&
(a.TraitOrDefault<Cloak>() != null) &&
(a.TraitOrDefault<Cloak>().AcceptsCloakCrate));
if (inRange.Any())
{
if (Info.MaxExtraCollectors > -1)
inRange = inRange.Take(Info.MaxExtraCollectors);
if (inRange.Any())
foreach (Actor actor in inRange)
{
actor.Trait<Cloak>().ReceivedCloakCrate(actor);
}
}
base.Activate(collector);
}
}

View File

@@ -0,0 +1,121 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.RA.Move;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Crates
{
[Desc("Creates duplicates of the actor that collects the crate.")]
class DuplicateUnitCrateActionInfo : CrateActionInfo
{
[Desc("The maximum number of duplicates to make.")]
public readonly int MaxAmount = 2;
[Desc("The minimum number of duplicates to make.","Overrules MaxDuplicatesWorth.")]
public readonly int MinAmount = 1;
[Desc("The maximum total cost allowed for the duplicates.","Duplication stops if the total worth will exceed this number.","-1 = no limit")]
public readonly int MaxDuplicatesWorth = -1;
[Desc("The list of unit types we are allowed to duplicate.")]
public readonly string[] ValidDuplicateTypes = { "Ground", "Water" };
[Desc("Which races this crate action can occur for.")]
public readonly string[] ValidRaces = { };
[Desc("Is the new duplicates given to a specific owner, regardless of whom collected it?")]
public readonly string Owner = null;
public override object Create(ActorInitializer init) { return new DuplicateUnitCrateAction(init.self, this); }
}
class DuplicateUnitCrateAction : CrateAction
{
public readonly DuplicateUnitCrateActionInfo Info;
readonly List<CPos> usedCells = new List<CPos>();
public DuplicateUnitCrateAction(Actor self, DuplicateUnitCrateActionInfo info)
: base(self, info) { Info = info; }
public bool CanGiveTo(Actor collector)
{
if (Info.ValidRaces.Any() && !Info.ValidRaces.Contains(collector.Owner.Country.Race))
return false;
var targetable = collector.Info.Traits.GetOrDefault<ITargetableInfo>();
if (targetable == null ||
!Info.ValidDuplicateTypes.Intersect(targetable.GetTargetTypes()).Any())
return false;
if (!GetSuitableCells(collector.Location, collector.Info.Name).Any()) return false;
return true;
}
public override int GetSelectionShares(Actor collector)
{
if (!CanGiveTo(collector)) return 0;
return base.GetSelectionShares(collector);
}
public override void Activate(Actor collector)
{
int AllowedWorthLeft = Info.MaxDuplicatesWorth;
int DupesMade = 0;
while ((DupesMade < Info.MaxAmount) && (AllowedWorthLeft > 0) || (DupesMade < Info.MinAmount))
{
//If the collector has a cost, and we have a max duplicate worth, then update how much dupe worth is left
var unitCost = collector.Info.Traits.Get<ValuedInfo>().Cost;
AllowedWorthLeft -= (Info.MaxDuplicatesWorth > 0) ? unitCost : 0;
if ((AllowedWorthLeft < 0) && (DupesMade >= Info.MinAmount))
break;
DupesMade++;
var location = ChooseEmptyCellNear(collector, collector.Info.Name);
if (location != null)
{
usedCells.Add(location.Value);
collector.World.AddFrameEndTask(
w => w.CreateActor(collector.Info.Name, new TypeDictionary
{
new LocationInit(location.Value),
new OwnerInit(Info.Owner ?? collector.Owner.InternalName)
}));
}
}
base.Activate(collector);
}
IEnumerable<CPos> GetSuitableCells(CPos near, string unitName)
{
var mi = self.World.Map.Rules.Actors[unitName].Traits.Get<MobileInfo>();
for (var i = -3; i < 4; i++)
for (var j = -3; j < 4; j++)
if (mi.CanEnterCell(self.World, self, near + new CVec(i, j), null, true, true))
yield return near + new CVec(i, j);
}
CPos? ChooseEmptyCellNear(Actor a, string unit)
{
var possibleCells = GetSuitableCells(a.Location, unit).Where(c => !usedCells.Contains(c)).ToArray();
if (possibleCells.Length == 0)
return null;
return possibleCells.Random(self.World.SharedRandom);
}
}
}

View File

@@ -12,10 +12,11 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
[Desc("Fires a weapon at the location when collected.")]
class ExplodeCrateActionInfo : CrateActionInfo
{
[WeaponReference]
public string Weapon = null;
[Desc("The weapon to fire upon collection.")]
[WeaponReference] public string Weapon = null;
public override object Create(ActorInitializer init) { return new ExplodeCrateAction(init.self, this); }
}

View File

@@ -13,9 +13,13 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
[Desc("Gives cash to the collector.")]
class GiveCashCrateActionInfo : CrateActionInfo
{
[Desc("Amount of cash to give.")]
public int Amount = 2000;
[Desc("Should the collected amount be displayed as a cash tick?")]
public bool UseCashTick = false;
public override object Create(ActorInitializer init) { return new GiveCashCrateAction(init.self, this); }

View File

@@ -12,9 +12,12 @@ using System.Linq;
namespace OpenRA.Mods.RA.Crates
{
[Desc("Spawns units when collected.","Adjust selection shares when player has no base.")]
class GiveMcvCrateActionInfo : GiveUnitCrateActionInfo
{
[Desc("The selection shares to use if the collector has no base.")]
public int NoBaseSelectionShares = 1000;
public override object Create(ActorInitializer init) { return new GiveMcvCrateAction(init.self, this); }
}

View File

@@ -16,36 +16,40 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Crates
{
[Desc("Spawns units when collected.")]
class GiveUnitCrateActionInfo : CrateActionInfo
{
[Desc("The list of units to spawn.")]
[ActorReference]
[Desc("Unit to give")]
public readonly string Unit = null;
[Desc("Override the owner of the newly spawned unit: e.g Creeps or Neutral")]
public readonly string Owner = null;
public readonly string[] Units = { };
[Desc("Races that are allowed to trigger this action")]
public readonly string[] Race = null;
public readonly string[] Race = { };
[Desc("Override the owner of the newly spawned unit: e.g. Creeps or Neutral")]
public readonly string Owner = null;
public override object Create(ActorInitializer init) { return new GiveUnitCrateAction(init.self, this); }
}
class GiveUnitCrateAction : CrateAction
{
GiveUnitCrateActionInfo Info;
public readonly GiveUnitCrateActionInfo Info;
readonly List<CPos> usedCells = new List<CPos>();
public GiveUnitCrateAction(Actor self, GiveUnitCrateActionInfo info)
: base(self, info) { Info = info; }
public bool CanGiveTo(Actor collector)
{
if (Info.Race != null && !Info.Race.Contains(collector.Owner.Country.Race))
if (Info.Race.Any() && !Info.Race.Contains(collector.Owner.Country.Race))
return false;
// avoid dumping tanks in the sea, and ships on dry land.
if (!GetSuitableCells(collector.Location).Any())
return false;
foreach (string unit in Info.Units)
{
// avoid dumping tanks in the sea, and ships on dry land.
if (!GetSuitableCells(collector.Location, unit).Any()) return false;
}
return true;
}
@@ -58,21 +62,28 @@ namespace OpenRA.Mods.RA.Crates
public override void Activate(Actor collector)
{
var location = ChooseEmptyCellNear(collector);
if (location != null)
collector.World.AddFrameEndTask(
w => w.CreateActor(Info.Unit, new TypeDictionary
foreach (var u in Info.Units)
{
var unit = u; // avoiding access to modified closure
var location = ChooseEmptyCellNear(collector, unit);
if (location != null)
{
usedCells.Add(location.Value);
collector.World.AddFrameEndTask(
w => w.CreateActor(unit, new TypeDictionary
{
new LocationInit(location.Value ),
new LocationInit(location.Value),
new OwnerInit(Info.Owner ?? collector.Owner.InternalName)
}));
}
}
base.Activate(collector);
}
IEnumerable<CPos> GetSuitableCells(CPos near)
IEnumerable<CPos> GetSuitableCells(CPos near, string unitName)
{
var mi = self.World.Map.Rules.Actors[Info.Unit].Traits.Get<MobileInfo>();
var mi = self.World.Map.Rules.Actors[unitName].Traits.Get<MobileInfo>();
for (var i = -1; i < 2; i++)
for (var j = -1; j < 2; j++)
@@ -80,9 +91,9 @@ namespace OpenRA.Mods.RA.Crates
yield return near + new CVec(i, j);
}
CPos? ChooseEmptyCellNear(Actor a)
CPos? ChooseEmptyCellNear(Actor a, string unit)
{
var possibleCells = GetSuitableCells(a.Location).ToArray();
var possibleCells = GetSuitableCells(a.Location, unit).Where(c => !usedCells.Contains(c)).ToArray();
if (possibleCells.Length == 0)
return null;

View File

@@ -13,6 +13,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Crates
{
[Desc("Heals all actors that belong to the owner of the collector.")]
class HealUnitsCrateActionInfo : CrateActionInfo
{
public override object Create(ActorInitializer init) { return new HealUnitsCrateAction(init.self, this); }

View File

@@ -10,6 +10,7 @@
namespace OpenRA.Mods.RA
{
[Desc("Hides the entire map in shroud.")]
class HideMapCrateActionInfo : CrateActionInfo
{
public override object Create(ActorInitializer init) { return new HideMapCrateAction(init.self, this); }

View File

@@ -8,19 +8,34 @@
*/
#endregion
using System.Linq;
namespace OpenRA.Mods.RA
{
[Desc("Gives experience levels to the collector.")]
class LevelUpCrateActionInfo : CrateActionInfo
{
[Desc("Number of experience levels to give.")]
public readonly int Levels = 1;
[Desc("The range to search for extra collectors in.", "Extra collectors will also be granted the crate action.")]
public readonly WRange Range = new WRange(3);
[Desc("The maximum number of extra collectors to grant the crate action to.")]
public readonly int MaxExtraCollectors = 4;
public override object Create(ActorInitializer init) { return new LevelUpCrateAction(init.self, this); }
}
class LevelUpCrateAction : CrateAction
{
LevelUpCrateActionInfo Info;
public LevelUpCrateAction(Actor self, LevelUpCrateActionInfo info)
: base(self,info) {}
: base(self, info)
{
Info = info;
}
public override int GetSelectionShares(Actor collector)
{
@@ -37,6 +52,29 @@ namespace OpenRA.Mods.RA
gainsExperience.GiveLevels(((LevelUpCrateActionInfo)info).Levels);
});
var inRange = self.World.FindActorsInCircle(self.CenterPosition, Info.Range);
inRange = inRange.Where(a =>
(a.Owner == collector.Owner) &&
(a != collector) &&
(a.TraitOrDefault<GainsExperience>() != null) &&
(a.TraitOrDefault<GainsExperience>().CanGainLevel));
if (inRange.Any())
{
if (Info.MaxExtraCollectors > -1)
inRange = inRange.Take(Info.MaxExtraCollectors);
if (inRange.Any())
foreach (Actor actor in inRange)
{
actor.World.AddFrameEndTask(w =>
{
var gainsExperience = actor.TraitOrDefault<GainsExperience>();
if (gainsExperience != null)
gainsExperience.GiveLevels(((LevelUpCrateActionInfo)info).Levels);
});
}
}
base.Activate(collector);
}
}

View File

@@ -12,9 +12,12 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
[Desc("Reveals the entire map.")]
class RevealMapCrateActionInfo : CrateActionInfo
{
[Desc("Should the map also be revealed for the allies of the collector's owner.")]
public readonly bool IncludeAllies = false;
public override object Create(ActorInitializer init) { return new RevealMapCrateAction(init.self, this); }
}

View File

@@ -13,10 +13,12 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Crates
{
[Desc("Gives a supportpower to the collector.")]
class SupportPowerCrateActionInfo : CrateActionInfo
{
[ActorReference]
public readonly string Proxy = null;
[Desc("Which proxy actor, which grants the support power, to spawn.")]
[ActorReference] public readonly string Proxy = null;
public override object Create(ActorInitializer init) { return new SupportPowerCrateAction(init.self, this); }
}

View File

@@ -8,30 +8,42 @@
*/
#endregion
using System.Linq;
namespace OpenRA.Mods.RA.Crates
{
[Desc("Grants an upgrade to the collector.")]
public class UnitUpgradeCrateActionInfo : CrateActionInfo
{
[Desc("The upgrade to grant.")]
public readonly UnitUpgrade? Upgrade = null;
[Desc("The number of levels of the upgrade to grant.")]
public readonly int Levels = 1;
[Desc("The range to search for extra collectors in.","Extra collectors will also be granted the crate action.")]
public readonly WRange Range = new WRange(3);
[Desc("The maximum number of extra collectors to grant the crate action to.","-1 = no limit")]
public readonly int MaxExtraCollectors = 4;
public override object Create(ActorInitializer init) { return new UnitUpgradeCrateAction(init.self, this); }
}
public class UnitUpgradeCrateAction : CrateAction
{
UnitUpgradeCrateActionInfo crateInfo;
UnitUpgradeCrateActionInfo Info;
public UnitUpgradeCrateAction(Actor self, UnitUpgradeCrateActionInfo info)
: base(self, info)
{
crateInfo = info;
Info = info;
}
public override int GetSelectionShares(Actor collector)
{
var up = collector.TraitOrDefault<GainsUnitUpgrades>();
return up != null && up.CanGainUnitUpgrade(crateInfo.Upgrade) ? info.SelectionShares : 0;
return up != null && up.CanGainUnitUpgrade(Info.Upgrade) ? info.SelectionShares : 0;
}
public override void Activate(Actor collector)
@@ -40,9 +52,32 @@ namespace OpenRA.Mods.RA.Crates
{
var gainsStatBonuses = collector.TraitOrDefault<GainsUnitUpgrades>();
if (gainsStatBonuses != null)
gainsStatBonuses.GiveUnitUpgrade(crateInfo.Upgrade, crateInfo.Levels);
gainsStatBonuses.GiveUnitUpgrade(Info.Upgrade, Info.Levels);
});
var inRange = self.World.FindActorsInCircle(self.CenterPosition, Info.Range);
inRange = inRange.Where(a =>
(a.Owner == collector.Owner) &&
(a != collector) &&
(a.TraitOrDefault<GainsUnitUpgrades>() != null) &&
(a.TraitOrDefault<GainsUnitUpgrades>().CanGainUnitUpgrade(Info.Upgrade)));
if (inRange.Any())
{
if (Info.MaxExtraCollectors > -1)
inRange = inRange.Take(Info.MaxExtraCollectors);
if (inRange.Any())
foreach (Actor actor in inRange)
{
actor.World.AddFrameEndTask(w =>
{
var gainsStatBonuses = actor.TraitOrDefault<GainsUnitUpgrades>();
if (gainsStatBonuses != null)
gainsStatBonuses.GiveUnitUpgrade(Info.Upgrade, Info.Levels);
});
}
}
base.Activate(collector);
}
}

View File

@@ -117,6 +117,7 @@
<Compile Include="Air\Aircraft.cs" />
<Compile Include="Air\AttackHeli.cs" />
<Compile Include="Air\AttackPlane.cs" />
<Compile Include="Crates\DuplicateUnitCrateAction.cs" />
<Compile Include="Effects\Beacon.cs" />
<Compile Include="Player\PlaceBeacon.cs" />
<Compile Include="MenuPaletteEffect.cs" />

View File

@@ -20,61 +20,75 @@ CRATE:
SelectionShares: 40
GiveUnitCrateAction@Trike:
SelectionShares: 20
Unit: trike
Units: trike
GiveUnitCrateAction@Raider:
SelectionShares: 15
Unit: raider
Units: raider
ValidRaces: ordos
GiveUnitCrateAction@Quad:
SelectionShares: 40
Unit: quad
Units: quad
GiveUnitCrateAction@CombatA:
SelectionShares: 10
Unit: combata
Units: combata
ValidRaces: atreides
GiveUnitCrateAction@CombatH:
SelectionShares: 10
Unit: combath
Units: combath
ValidRaces: harkonnen
GiveUnitCrateAction@CombatO:
SelectionShares: 10
Unit: combato
Units: combato
ValidRaces: ordos
GiveUnitCrateAction@SiegeTank:
SelectionShares: 10
Unit: siegetank
Units: siegetank
GiveUnitCrateAction@MissileTank:
SelectionShares: 10
Unit: missiletank
Units: missiletank
GiveUnitCrateAction@StealthRaider:
SelectionShares: 7
Unit: stealthraider
Units: stealthraider
ValidRaces: ordos
GiveUnitCrateAction@Fremen:
SelectionShares: 5
Unit: fremen
Units: fremen,fremen
ValidRaces: atreides
GiveUnitCrateAction@Sardaukar:
SelectionShares: 8
Unit: sardaukar
Units: sardaukar,sardaukar
ValidRaces: harkonnen
GiveUnitCrateAction@Saboteur:
SelectionShares: 3
Unit: saboteur
Units: saboteur,saboteur
ValidRaces: ordos
GiveUnitCrateAction@SonicTank:
SelectionShares: 5
Unit: sonictank
Units: sonictank
ValidRaces: atreides
GiveUnitCrateAction@Devast:
SelectionShares: 2
Unit: devast
Units: devast
ValidRaces: harkonnen
GiveUnitCrateAction@DeviatorTank:
SelectionShares: 5
Unit: deviatortank
Units: deviatortank
ValidRaces: ordos
GiveMcvCrateAction@Atreides:
SelectionShares: 0
NoBaseSelectionShares: 9001
Unit: mcva
Units: mcva
ValidRaces: atreides
GiveMcvCrateAction@Harkonnen:
SelectionShares: 0
NoBaseSelectionShares: 9001
Unit: mcvh
Units: mcvh
ValidRaces: harkonnen
GiveMcvCrateAction@Ordos:
SelectionShares: 0
NoBaseSelectionShares: 9001
Unit: mcvo
Units: mcvo
ValidRaces: ordos
RenderSprites:
Palette: effect
WithCrateBody:

View File

@@ -89,31 +89,64 @@ CRATE:
SelectionShares: 5
Proxy: powerproxy.parabombs
Effect: parabombs
DuplicateUnitCrateAction:
SelectionShares: 10
MaxAmount: 5
MinAmount: 1
MaxDuplicatesWorth: 1500
GiveMcvCrateAction:
SelectionShares: 2
NoBaseSelectionShares: 100
Unit: mcv
Units: mcv
GiveUnitCrateAction@jeep:
SelectionShares: 7
Unit: jeep
Units: jeep
ValidRaces: allies
TimeDelay: 3000
GiveUnitCrateAction@arty:
SelectionShares: 6
Unit: arty
Units: arty
ValidRaces: allies
TimeDelay: 4500
GiveUnitCrateAction@v2rl:
SelectionShares: 6
Unit: v2rl
Units: v2rl
ValidRaces: soviet
TimeDelay: 4500
GiveUnitCrateAction@1tnk:
SelectionShares: 5
Unit: 1tnk
Units: 1tnk
ValidRaces: allies
TimeDelay: 3000
GiveUnitCrateAction@2tnk:
SelectionShares: 4
Unit: 2tnk
Units: 2tnk
ValidRaces: allies
TimeDelay: 4500
GiveUnitCrateAction@3tnk:
SelectionShares: 4
Unit: 3tnk
Units: 3tnk
ValidRaces: soviet
TimeDelay: 4500
GiveUnitCrateAction@4tnk:
SelectionShares: 3
Unit: 4tnk
Units: 4tnk
ValidRaces: soviet
TimeDelay: 9000
GiveUnitCrateAction@squadlight:
SelectionShares: 7
Units: e1,e1,e1,e3,e3
ValidRaces: allies, soviet
GiveUnitCrateAction@squadheavyallies:
SelectionShares: 7
Units: e1,e1,e1,e1,e3,e3,e3,e6,medi
ValidRaces: allies
TimeDelay: 4500
GiveUnitCrateAction@squadheavysoviet:
SelectionShares: 7
Units: e1,e1,e4,e4,e3,e3,e3
ValidRaces: soviet
TimeDelay: 4500
RenderSprites:
Palette: effect
WithCrateBody: