Merge Mods.RA into Mods.Cnc

This commit is contained in:
reaperrr
2017-02-12 01:08:31 +01:00
parent cdfa3fddf8
commit 0c3a786d10
47 changed files with 98 additions and 245 deletions

View File

@@ -0,0 +1,60 @@
#region Copyright & License Information
/*
* Copyright 2007-2017 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 OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Activities
{
class Infiltrate : Enter
{
readonly Actor target;
readonly Stance validStances;
readonly Cloak cloak;
readonly string notification;
readonly int experience;
public Infiltrate(Actor self, Actor target, EnterBehaviour enterBehaviour, Stance validStances, string notification, int experience)
: base(self, target, enterBehaviour)
{
this.target = target;
this.validStances = validStances;
this.notification = notification;
this.experience = experience;
cloak = self.TraitOrDefault<Cloak>();
}
protected override void OnInside(Actor self)
{
if (target.IsDead)
return;
var stance = self.Owner.Stances[target.Owner];
if (!validStances.HasStance(stance))
return;
if (cloak != null && cloak.Info.UncloakOn.HasFlag(UncloakType.Infiltrate))
cloak.Uncloak();
foreach (var t in target.TraitsImplementing<INotifyInfiltrated>())
t.Infiltrated(target, self);
var exp = self.Owner.PlayerActor.TraitOrDefault<PlayerExperience>();
if (exp != null)
exp.GiveExperience(experience);
if (!string.IsNullOrEmpty(notification))
Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech",
notification, self.Owner.Faction.InternalName);
}
}
}

View File

@@ -0,0 +1,109 @@
#region Copyright & License Information
/*
* Copyright 2007-2017 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.Activities;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Activities
{
// Assumes you have Minelayer on that unit
public class LayMines : Activity
{
readonly Minelayer minelayer;
readonly MinelayerInfo info;
readonly AmmoPool[] ammoPools;
readonly IMove movement;
readonly HashSet<string> rearmBuildings;
public LayMines(Actor self)
{
minelayer = self.TraitOrDefault<Minelayer>();
info = self.Info.TraitInfo<MinelayerInfo>();
ammoPools = self.TraitsImplementing<AmmoPool>().ToArray();
movement = self.Trait<IMove>();
rearmBuildings = info.RearmBuildings;
}
public override Activity Tick(Actor self)
{
if (IsCanceled)
return NextActivity;
if (ammoPools != null && ammoPools.Any(p => p.Info.Name == info.AmmoPoolName && !p.HasAmmo()))
{
// Rearm (and possibly repair) at rearm building, then back out here to refill the minefield some more
var rearmTarget = self.World.Actors.Where(a => self.Owner.Stances[a.Owner] == Stance.Ally
&& rearmBuildings.Contains(a.Info.Name))
.ClosestTo(self);
if (rearmTarget == null)
return new Wait(20);
return ActivityUtils.SequenceActivities(
new MoveAdjacentTo(self, Target.FromActor(rearmTarget)),
movement.MoveTo(self.World.Map.CellContaining(rearmTarget.CenterPosition), rearmTarget),
new Rearm(self),
new Repair(self, rearmTarget),
this);
}
if (minelayer.Minefield.Contains(self.Location) && ShouldLayMine(self, self.Location))
{
LayMine(self);
return ActivityUtils.SequenceActivities(new Wait(20), this); // A little wait after placing each mine, for show
}
if (minelayer.Minefield.Length > 0)
{
// Don't get stuck forever here
for (var n = 0; n < 20; n++)
{
var p = minelayer.Minefield.Random(self.World.SharedRandom);
if (ShouldLayMine(self, p))
return ActivityUtils.SequenceActivities(movement.MoveTo(p, 0), this);
}
}
// TODO: Return somewhere likely to be safe (near rearm building) so we're not sitting out in the minefield.
return new Wait(20); // nothing to do here
}
static bool ShouldLayMine(Actor self, CPos p)
{
// If there is no unit (other than me) here, we want to place a mine here
return self.World.ActorMap.GetActorsAt(p).All(a => a == self);
}
void LayMine(Actor self)
{
if (ammoPools != null)
{
var pool = ammoPools.FirstOrDefault(x => x.Info.Name == info.AmmoPoolName);
if (pool == null)
return;
pool.TakeAmmo();
}
self.World.AddFrameEndTask(
w => w.CreateActor(info.Mine, new TypeDictionary
{
new LocationInit(self.Location),
new OwnerInit(self.Owner),
}));
}
}
}

View File

@@ -0,0 +1,78 @@
#region Copyright & License Information
/*
* Copyright 2007-2017 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;
using System.Linq;
using OpenRA.Activities;
using OpenRA.GameRules;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Activities
{
class Leap : Activity
{
readonly Mobile mobile;
readonly WeaponInfo weapon;
readonly int length;
WPos from;
WPos to;
int ticks;
WAngle angle;
public Leap(Actor self, Actor target, Armament a, WDist speed, WAngle angle)
{
var targetMobile = target.TraitOrDefault<Mobile>();
if (targetMobile == null)
throw new InvalidOperationException("Leap requires a target actor with the Mobile trait");
this.weapon = a.Weapon;
this.angle = angle;
mobile = self.Trait<Mobile>();
mobile.SetLocation(mobile.FromCell, mobile.FromSubCell, targetMobile.FromCell, targetMobile.FromSubCell);
mobile.IsMoving = true;
from = self.CenterPosition;
to = self.World.Map.CenterOfSubCell(targetMobile.FromCell, targetMobile.FromSubCell);
length = Math.Max((to - from).Length / speed.Length, 1);
// HACK: why isn't this using the interface?
self.Trait<WithInfantryBody>().Attacking(self, Target.FromActor(target), a);
if (weapon.Report != null && weapon.Report.Any())
Game.Sound.Play(SoundType.World, weapon.Report.Random(self.World.SharedRandom), self.CenterPosition);
}
public override Activity Tick(Actor self)
{
if (ticks == 0 && IsCanceled)
return NextActivity;
mobile.SetVisualPosition(self, WPos.LerpQuadratic(from, to, angle, ++ticks, length));
if (ticks >= length)
{
mobile.SetLocation(mobile.ToCell, mobile.ToSubCell, mobile.ToCell, mobile.ToSubCell);
mobile.FinishedMoving(self);
mobile.IsMoving = false;
self.World.ActorMap.GetActorsAt(mobile.ToCell, mobile.ToSubCell)
.Except(new[] { self }).Where(t => weapon.IsValidAgainst(t, self))
.Do(t => t.Kill(self));
return NextActivity;
}
return this;
}
}
}

View File

@@ -0,0 +1,130 @@
#region Copyright & License Information
/*
* Copyright 2007-2017 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;
using System.Linq;
using OpenRA.Activities;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Activities
{
public interface IPreventsTeleport { bool PreventsTeleport(Actor self); }
public class Teleport : Activity
{
readonly Actor teleporter;
readonly int? maximumDistance;
CPos destination;
bool killCargo;
bool screenFlash;
string sound;
public Teleport(Actor teleporter, CPos destination, int? maximumDistance, bool killCargo, bool screenFlash, string sound)
{
var max = teleporter.World.Map.Grid.MaximumTileSearchRange;
if (maximumDistance > max)
throw new InvalidOperationException("Teleport distance cannot exceed the value of MaximumTileSearchRange ({0}).".F(max));
this.teleporter = teleporter;
this.destination = destination;
this.maximumDistance = maximumDistance;
this.killCargo = killCargo;
this.screenFlash = screenFlash;
this.sound = sound;
}
public override Activity Tick(Actor self)
{
var pc = self.TraitOrDefault<PortableChrono>();
if (teleporter == self && pc != null && !pc.CanTeleport)
return NextActivity;
foreach (var condition in self.TraitsImplementing<IPreventsTeleport>())
if (condition.PreventsTeleport(self))
return NextActivity;
var bestCell = ChooseBestDestinationCell(self, destination);
if (bestCell == null)
return NextActivity;
destination = bestCell.Value;
Game.Sound.Play(SoundType.World, sound, self.CenterPosition);
Game.Sound.Play(SoundType.World, sound, self.World.Map.CenterOfCell(destination));
self.Trait<IPositionable>().SetPosition(self, destination);
self.Generation++;
if (killCargo)
{
var cargo = self.TraitOrDefault<Cargo>();
if (cargo != null && teleporter != null)
{
while (!cargo.IsEmpty(self))
{
var a = cargo.Unload(self);
// Kill all the units that are unloaded into the void
// Kill() handles kill and death statistics
a.Kill(teleporter);
}
}
}
// Consume teleport charges if this wasn't triggered via chronosphere
if (teleporter == self && pc != null)
pc.ResetChargeTime();
// Trigger screen desaturate effect
if (screenFlash)
foreach (var a in self.World.ActorsWithTrait<ChronoshiftPaletteEffect>())
a.Trait.Enable();
if (teleporter != null && self != teleporter && !teleporter.Disposed)
{
var building = teleporter.TraitOrDefault<WithSpriteBody>();
if (building != null && building.DefaultAnimation.HasSequence("active"))
building.PlayCustomAnimation(teleporter, "active");
}
return NextActivity;
}
CPos? ChooseBestDestinationCell(Actor self, CPos destination)
{
if (teleporter == null)
return null;
var restrictTo = maximumDistance == null ? null : self.World.Map.FindTilesInCircle(self.Location, maximumDistance.Value);
if (maximumDistance != null)
destination = restrictTo.MinBy(x => (x - destination).LengthSquared);
var pos = self.Trait<IPositionable>();
if (pos.CanEnterCell(destination) && teleporter.Owner.Shroud.IsExplored(destination))
return destination;
var max = maximumDistance != null ? maximumDistance.Value : teleporter.World.Map.Grid.MaximumTileSearchRange;
foreach (var tile in self.World.Map.FindTilesInCircle(destination, max))
{
if (teleporter.Owner.Shroud.IsExplored(tile)
&& (restrictTo == null || (restrictTo != null && restrictTo.Contains(tile)))
&& pos.CanEnterCell(tile))
return tile;
}
return null;
}
}
}