Add drop pod reinforcements.
This commit is contained in:
78
OpenRA.Mods.Cnc/Projectiles/DropPodImpact.cs
Normal file
78
OpenRA.Mods.Cnc/Projectiles/DropPodImpact.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2020 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.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Cnc.Effects
|
||||
{
|
||||
public class DropPodImpact : IProjectile
|
||||
{
|
||||
readonly Target target;
|
||||
readonly Animation entryAnimation;
|
||||
readonly Player firedBy;
|
||||
readonly string entryPalette;
|
||||
readonly WeaponInfo weapon;
|
||||
readonly WPos launchPos;
|
||||
|
||||
int weaponDelay;
|
||||
bool impacted = false;
|
||||
|
||||
public DropPodImpact(Player firedBy, WeaponInfo weapon, World world, WPos launchPos, Target target,
|
||||
int delay, string entryEffect, string entrySequence, string entryPalette)
|
||||
{
|
||||
this.target = target;
|
||||
this.firedBy = firedBy;
|
||||
this.weapon = weapon;
|
||||
this.entryPalette = entryPalette;
|
||||
weaponDelay = delay;
|
||||
this.launchPos = launchPos;
|
||||
|
||||
entryAnimation = new Animation(world, entryEffect);
|
||||
entryAnimation.PlayThen(entrySequence, () => Finish(world));
|
||||
|
||||
if (weapon.Report != null && weapon.Report.Any())
|
||||
Game.Sound.Play(SoundType.World, weapon.Report, world, launchPos);
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
entryAnimation.Tick();
|
||||
|
||||
if (!impacted && weaponDelay-- <= 0)
|
||||
{
|
||||
var warheadArgs = new WarheadArgs
|
||||
{
|
||||
Weapon = weapon,
|
||||
Source = target.CenterPosition,
|
||||
SourceActor = firedBy.PlayerActor,
|
||||
WeaponTarget = target
|
||||
};
|
||||
|
||||
weapon.Impact(target, warheadArgs);
|
||||
impacted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
return entryAnimation.Render(launchPos, wr.Palette(entryPalette));
|
||||
}
|
||||
|
||||
void Finish(World world)
|
||||
{
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
159
OpenRA.Mods.Cnc/Traits/SupportPowers/DropPodsPower.cs
Normal file
159
OpenRA.Mods.Cnc/Traits/SupportPowers/DropPodsPower.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2020 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.Linq;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Mods.Cnc.Effects;
|
||||
using OpenRA.Mods.Common;
|
||||
using OpenRA.Mods.Common.Activities;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Cnc.Traits
|
||||
{
|
||||
public class DropPodsPowerInfo : SupportPowerInfo, IRulesetLoaded
|
||||
{
|
||||
[FieldLoader.Require]
|
||||
[Desc("Drop pod unit")]
|
||||
[ActorReference(typeof(AircraftInfo), typeof(FallsToEarthInfo))]
|
||||
public readonly string[] UnitTypes = null;
|
||||
|
||||
[Desc("Number of drop pods spawned.")]
|
||||
public readonly int2 Drops = new int2(5, 8);
|
||||
|
||||
[Desc("Sets the approach direction.")]
|
||||
public readonly int PodFacing = 32;
|
||||
|
||||
[Desc("Maximum offset from targetLocation")]
|
||||
public readonly int PodScatter = 3;
|
||||
|
||||
[Desc("Effect sequence sprite image")]
|
||||
public readonly string EntryEffect = "podring";
|
||||
|
||||
[Desc("Effect sequence to display in the air.")]
|
||||
[SequenceReference("Effect")]
|
||||
public readonly string EntryEffectSequence = "idle";
|
||||
|
||||
[PaletteReference]
|
||||
public readonly string EntryEffectPalette = "effect";
|
||||
|
||||
[ActorReference]
|
||||
[Desc("Actor to spawn when the attack starts")]
|
||||
public readonly string CameraActor = null;
|
||||
|
||||
[Desc("Number of ticks to keep the camera alive")]
|
||||
public readonly int CameraRemoveDelay = 25;
|
||||
|
||||
[Desc("Which weapon to fire")]
|
||||
[WeaponReference]
|
||||
public readonly string Weapon = "Vulcan2";
|
||||
|
||||
public WeaponInfo WeaponInfo { get; private set; }
|
||||
|
||||
[Desc("Apply the weapon impact this many ticks into the effect")]
|
||||
public readonly int WeaponDelay = 0;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new DropPodsPower(init.Self, this); }
|
||||
|
||||
public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
|
||||
{
|
||||
WeaponInfo weapon;
|
||||
var weaponToLower = (Weapon ?? string.Empty).ToLowerInvariant();
|
||||
if (!rules.Weapons.TryGetValue(weaponToLower, out weapon))
|
||||
throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower));
|
||||
|
||||
WeaponInfo = weapon;
|
||||
|
||||
base.RulesetLoaded(rules, ai);
|
||||
}
|
||||
}
|
||||
|
||||
public class DropPodsPower : SupportPower
|
||||
{
|
||||
readonly DropPodsPowerInfo info;
|
||||
|
||||
public DropPodsPower(Actor self, DropPodsPowerInfo info)
|
||||
: base(self, info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public override void Activate(Actor self, Order order, SupportPowerManager manager)
|
||||
{
|
||||
base.Activate(self, order, manager);
|
||||
|
||||
SendDropPods(self, order, info.PodFacing);
|
||||
}
|
||||
|
||||
public void SendDropPods(Actor self, Order order, int podFacing)
|
||||
{
|
||||
var actorInfo = self.World.Map.Rules.Actors[info.UnitTypes.First().ToLowerInvariant()];
|
||||
var aircraftInfo = actorInfo.TraitInfo<AircraftInfo>();
|
||||
var altitude = aircraftInfo.CruiseAltitude.Length;
|
||||
var approachRotation = WRot.FromFacing(podFacing);
|
||||
var fallsToEarthInfo = actorInfo.TraitInfo<FallsToEarthInfo>();
|
||||
var delta = new WVec(0, -altitude * aircraftInfo.Speed / fallsToEarthInfo.Velocity.Length, 0).Rotate(approachRotation);
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
var target = order.Target.CenterPosition;
|
||||
var targetCell = self.World.Map.CellContaining(target);
|
||||
var podLocations = self.World.Map.FindTilesInCircle(targetCell, info.PodScatter)
|
||||
.Where(c => aircraftInfo.LandableTerrainTypes.Contains(w.Map.GetTerrainInfo(c).Type)
|
||||
&& !self.World.ActorMap.GetActorsAt(c).Any());
|
||||
|
||||
if (!podLocations.Any())
|
||||
return;
|
||||
|
||||
if (info.CameraActor != null)
|
||||
{
|
||||
var camera = w.CreateActor(info.CameraActor, new TypeDictionary
|
||||
{
|
||||
new LocationInit(targetCell),
|
||||
new OwnerInit(self.Owner),
|
||||
});
|
||||
|
||||
camera.QueueActivity(new Wait(info.CameraRemoveDelay));
|
||||
camera.QueueActivity(new RemoveSelf());
|
||||
}
|
||||
|
||||
PlayLaunchSounds();
|
||||
|
||||
var drops = self.World.SharedRandom.Next(info.Drops.X, info.Drops.Y);
|
||||
for (var i = 0; i < drops; i++)
|
||||
{
|
||||
var unitType = info.UnitTypes.Random(self.World.SharedRandom);
|
||||
var podLocation = podLocations.Random(self.World.SharedRandom);
|
||||
var podTarget = Target.FromCell(w, podLocation);
|
||||
var location = self.World.Map.CenterOfCell(podLocation) - delta + new WVec(0, 0, altitude);
|
||||
|
||||
var pod = w.CreateActor(false, unitType, new TypeDictionary
|
||||
{
|
||||
new CenterPositionInit(location),
|
||||
new OwnerInit(self.Owner),
|
||||
new FacingInit(podFacing)
|
||||
});
|
||||
|
||||
var aircraft = pod.Trait<Aircraft>();
|
||||
if (!aircraft.CanLand(podLocation))
|
||||
pod.Dispose();
|
||||
else
|
||||
{
|
||||
w.Add(new DropPodImpact(self.Owner, info.WeaponInfo, w, location, podTarget, info.WeaponDelay,
|
||||
info.EntryEffect, info.EntryEffectSequence, info.EntryEffectPalette));
|
||||
w.Add(pod);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,52 @@ DPOD:
|
||||
EmptySequence: pip-ammoempty
|
||||
Palette: pips
|
||||
|
||||
DPOD2:
|
||||
Inherits@2: ^ExistsInWorld
|
||||
Valued:
|
||||
Cost: 10
|
||||
Tooltip:
|
||||
Name: Drop Pod
|
||||
Health:
|
||||
HP: 6000
|
||||
Armor:
|
||||
Type: Light
|
||||
Aircraft:
|
||||
TurnSpeed: 5
|
||||
Speed: 300
|
||||
CruiseAltitude: 16c0
|
||||
MaximumPitch: 110
|
||||
LandableTerrainTypes: Clear, Road, Rail, DirtRoad, Rough
|
||||
HiddenUnderFog:
|
||||
Type: CenterPosition
|
||||
BodyOrientation:
|
||||
UseClassicPerspectiveFudge: False
|
||||
RenderSprites:
|
||||
Image: pod
|
||||
WithFacingSpriteBody:
|
||||
QuantizeFacingsFromSequence:
|
||||
HitShape:
|
||||
Interactable:
|
||||
WithShadow:
|
||||
SmokeTrailWhenDamaged:
|
||||
Sprite: largesmoke
|
||||
MinDamage: Undamaged
|
||||
FallsToEarth:
|
||||
Explosion: DropPodExplode
|
||||
Moves: true
|
||||
Velocity: 768
|
||||
MaximumSpinSpeed: 0
|
||||
|
||||
DPOD2E1:
|
||||
Inherits: DPOD2
|
||||
SpawnActorOnDeath:
|
||||
Actor: E1R3
|
||||
|
||||
DPOD2E2:
|
||||
Inherits: DPOD2
|
||||
SpawnActorOnDeath:
|
||||
Actor: E2R3
|
||||
|
||||
DSHP:
|
||||
Inherits: ^Aircraft
|
||||
Inherits@CARGOPIPS: ^CargoPips
|
||||
|
||||
@@ -33,6 +33,15 @@ E2:
|
||||
ProducibleWithLevel:
|
||||
Prerequisites: barracks.upgraded
|
||||
|
||||
E2R3:
|
||||
Inherits: E2
|
||||
RenderSprites:
|
||||
Image: E2
|
||||
ProducibleWithLevel:
|
||||
Prerequisites: techlevel.low
|
||||
InitialLevels: 3
|
||||
-Buildable:
|
||||
|
||||
MEDIC:
|
||||
Inherits: ^Soldier
|
||||
Inherits@EXPERIENCE: ^GainsExperience
|
||||
|
||||
@@ -481,6 +481,18 @@ GAPLUG:
|
||||
SelectTargetSpeechNotification: SelectTarget
|
||||
DisplayRadarPing: True
|
||||
CameraActor: camera
|
||||
DropPodsPower:
|
||||
Cursor: ioncannon
|
||||
PauseOnCondition: disabled || empdisable
|
||||
RequiresCondition: plug.droppoda || plug.droppodb
|
||||
Icon: droppods
|
||||
Description: Drop Pods
|
||||
LongDesc: Drop Pod reinforcements.\nSmall team of elite soldiers orbital drops\nto target location.
|
||||
SelectTargetSpeechNotification: SelectTarget
|
||||
DisplayRadarPing: true
|
||||
ChargeInterval: 10000
|
||||
UnitTypes: DPOD2E1, DPOD2E2
|
||||
CameraActor: camera
|
||||
ProduceActorPower:
|
||||
PauseOnCondition: disabled || empdisable
|
||||
RequiresCondition: plug.hunterseekera || plug.hunterseekerb
|
||||
@@ -504,17 +516,23 @@ GAPLUG:
|
||||
Power@hunterseeker:
|
||||
RequiresCondition: plug.hunterseekera || plug.hunterseekerb
|
||||
Amount: -50
|
||||
Power@droppod:
|
||||
RequiresCondition: plug.droppoda || plug.droppodb
|
||||
Amount: -20
|
||||
Pluggable@pluga:
|
||||
Offset: 0,2
|
||||
Conditions:
|
||||
plug.ioncannon: plug.ioncannona
|
||||
plug.hunterseeker: plug.hunterseekera
|
||||
plug.droppod: plug.droppoda
|
||||
Requirements:
|
||||
plug.ioncannon: !build-incomplete && !plug.ioncannonb && !plug.ioncannona && !plug.hunterseekera
|
||||
plug.hunterseeker: !build-incomplete && !plug.hunterseekerb && !plug.ioncannona && !plug.hunterseekera
|
||||
plug.ioncannon: !build-incomplete && !plug.ioncannonb && !plug.ioncannona && !plug.hunterseekera && !plug.droppoda
|
||||
plug.hunterseeker: !build-incomplete && !plug.hunterseekerb && !plug.ioncannona && !plug.hunterseekera && !plug.droppoda
|
||||
plug.droppod: !build-incomplete && !plug.droppodb && !plug.ioncannona && !plug.hunterseekera && !plug.droppoda
|
||||
EditorOptions:
|
||||
plug.ioncannon: Ion Cannon
|
||||
plug.hunterseeker: Hunter Seeker
|
||||
plug.droppod: Drop Pod Reinforcements
|
||||
WithIdleOverlay@ioncannona:
|
||||
RequiresCondition: !build-incomplete && plug.ioncannona
|
||||
PauseOnCondition: disabled
|
||||
@@ -523,17 +541,24 @@ GAPLUG:
|
||||
RequiresCondition: !build-incomplete && plug.hunterseekera
|
||||
PauseOnCondition: disabled
|
||||
Sequence: idle-hunterseekera
|
||||
WithIdleOverlay@droppoda:
|
||||
RequiresCondition: !build-incomplete && plug.droppoda
|
||||
PauseOnCondition: disabled
|
||||
Sequence: idle-droppoda
|
||||
Pluggable@plugb:
|
||||
Offset: 1,2
|
||||
Conditions:
|
||||
plug.ioncannon: plug.ioncannonb
|
||||
plug.hunterseeker: plug.hunterseekerb
|
||||
plug.droppod: plug.droppodb
|
||||
Requirements:
|
||||
plug.ioncannon: !build-incomplete && !plug.ioncannona && !plug.ioncannonb && !plug.hunterseekerb
|
||||
plug.hunterseeker: !build-incomplete && !plug.hunterseekera && !plug.ioncannonb && !plug.hunterseekerb
|
||||
plug.ioncannon: !build-incomplete && !plug.ioncannona && !plug.ioncannonb && !plug.hunterseekerb && !plug.droppodb
|
||||
plug.hunterseeker: !build-incomplete && !plug.hunterseekera && !plug.ioncannonb && !plug.hunterseekerb && !plug.droppodb
|
||||
plug.droppod: !build-incomplete && !plug.droppoda && !plug.ioncannonb && !plug.hunterseekerb && !plug.droppodb
|
||||
EditorOptions:
|
||||
plug.ioncannon: Ion Cannon
|
||||
plug.hunterseeker: Hunter Seeker
|
||||
plug.droppod: Drop Pod Reinforcements
|
||||
WithIdleOverlay@ioncannonb:
|
||||
RequiresCondition: !build-incomplete && plug.ioncannonb
|
||||
PauseOnCondition: disabled
|
||||
@@ -542,6 +567,10 @@ GAPLUG:
|
||||
RequiresCondition: !build-incomplete && plug.hunterseekerb
|
||||
PauseOnCondition: disabled
|
||||
Sequence: idle-hunterseekerb
|
||||
WithIdleOverlay@droppodb:
|
||||
RequiresCondition: plug.droppodb
|
||||
PauseOnCondition: disabled
|
||||
Sequence: idle-droppodb
|
||||
ProvidesPrerequisite@buildingname:
|
||||
ProvidesPrerequisite@pluggableion:
|
||||
RequiresCondition: !plug.ioncannona && !plug.ioncannonb
|
||||
@@ -595,3 +624,19 @@ GAPLUG3:
|
||||
Type: plug.ioncannon
|
||||
Power:
|
||||
Amount: -100
|
||||
|
||||
GAPLUG4:
|
||||
Inherits: ^BuildingPlug
|
||||
Valued:
|
||||
Cost: 1000
|
||||
Tooltip:
|
||||
Name: Drop Pod Node
|
||||
Buildable:
|
||||
Queue: Building
|
||||
BuildPaletteOrder: 180
|
||||
Prerequisites: gaplug, gatech, ~structures.gdi, ~techlevel.superweapons
|
||||
Description: Enables use of the Drop Pod Reinforcements.
|
||||
Plug:
|
||||
Type: plug.droppod
|
||||
Power:
|
||||
Amount: -20
|
||||
|
||||
@@ -38,6 +38,15 @@ E1:
|
||||
RevealsShroud:
|
||||
Range: 5c0
|
||||
|
||||
E1R3:
|
||||
Inherits: E1
|
||||
RenderSprites:
|
||||
Image: e1.gdi
|
||||
ProducibleWithLevel:
|
||||
Prerequisites: techlevel.low
|
||||
InitialLevels: 3
|
||||
-Buildable:
|
||||
|
||||
ENGINEER:
|
||||
Inherits: ^Soldier
|
||||
Inherits@selection: ^SelectableSupportUnit
|
||||
|
||||
@@ -30,3 +30,9 @@ apache:
|
||||
orcatran:
|
||||
Inherits: ^VehicleOverlays
|
||||
icon: crryicon
|
||||
|
||||
pod:
|
||||
Inherits: ^VehicleOverlays
|
||||
idle:
|
||||
Facings: 1
|
||||
Length: 1
|
||||
|
||||
@@ -211,6 +211,18 @@ explosion:
|
||||
small_grey_explosion: xgrysml2
|
||||
medium_grey_explosion: xgrymed1
|
||||
large_grey_explosion: xgrymed2
|
||||
droppod_explosion: droppod
|
||||
Length: 8
|
||||
Tick: 360
|
||||
droppod2_explosion: droppod2
|
||||
Length: 8
|
||||
Tick: 360
|
||||
droppody_explosion: droppody
|
||||
Length: 8
|
||||
Tick: 360
|
||||
droppody2_explosion: droppody2
|
||||
Length: 8
|
||||
Tick: 360
|
||||
|
||||
discus:
|
||||
idle:
|
||||
@@ -440,6 +452,7 @@ icon:
|
||||
ioncannon: ioncicon
|
||||
hunterseeker: detnicon
|
||||
emp: pulsicon
|
||||
droppods: podsicon
|
||||
|
||||
clustermissile:
|
||||
up: mltimisl-placeholder # TODO: use voxel
|
||||
@@ -655,3 +668,8 @@ typeglyphs:
|
||||
Start: 3
|
||||
structure:
|
||||
Start: 4
|
||||
|
||||
podring:
|
||||
idle:
|
||||
Frames: 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
|
||||
Length: *
|
||||
|
||||
@@ -1977,6 +1977,13 @@ gaplug:
|
||||
Length: 15
|
||||
Reverses: true
|
||||
Tick: 120
|
||||
idle-droppoda: gaplug_d
|
||||
Length: 15
|
||||
Tick: 120
|
||||
Offset: -12, -42, 30
|
||||
idle-droppodb: gaplug_d
|
||||
Length: 15
|
||||
Tick: 120
|
||||
make: gtplugmk
|
||||
Length: 17
|
||||
ShadowStart: 17
|
||||
@@ -2009,3 +2016,12 @@ gaplug3:
|
||||
Length: 14
|
||||
Tick: 120
|
||||
icon: rad3icon
|
||||
|
||||
gaplug4:
|
||||
place: gtplug_d
|
||||
Offset: 24,-48, 48
|
||||
UseTilesetCode: true
|
||||
Reverses: true
|
||||
Length: 14
|
||||
Tick: 120
|
||||
icon: rad1icon
|
||||
|
||||
@@ -66,3 +66,8 @@ Demolish:
|
||||
Explosions: large_twlt
|
||||
ExplosionPalette: effect-ignore-lighting-alpha75
|
||||
ImpactSounds: expnew09.aud
|
||||
|
||||
DropPodExplode:
|
||||
Warhead@1Eff: CreateEffect
|
||||
Explosions: droppod_explosion, droppod2_explosion, droppody_explosion, droppody2_explosion
|
||||
ExplosionPalette: effect-ignore-lighting-alpha75
|
||||
|
||||
Reference in New Issue
Block a user