Last active
August 29, 2015 14:04
-
-
Save phrohdoh/6ac0738589f510cdc2ab to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using OpenRA.Primitives; | |
using OpenRA.Traits; | |
using OpenRA.Mods.RA.Buildings; | |
using OpenRA.Mods.RA.Render; | |
using OpenRA.Graphics; | |
namespace OpenRA.Mods.RA | |
{ | |
[Desc("Actor allows/restricts pathing under certain conditions.")] | |
public class GateInfo : ITraitInfo, Requires<BuildingInfo>, Requires<RenderBuildingInfo> | |
{ | |
[Desc("Actor should wait N ticks before attempting to close again.")] | |
public readonly int TryCloseTicks = 50; | |
[Desc("Animation to play when closing. This will be played in reverse when opening.")] | |
public readonly string CloseAnimation = "closing"; | |
public object Create(ActorInitializer init) { return new Gate(init.self, this); } | |
} | |
public interface IConditionalPathBlocking { bool ShouldBlockActor(Actor self, Actor other); } | |
public class Gate : ITick, INotifyBlockingMove, IConditionalPathBlocking | |
{ | |
public bool IsOpen { get; private set; } | |
GateInfo info; | |
Animation animation; | |
RenderBuilding render; | |
int ticks; | |
public Gate(Actor self, GateInfo info) | |
{ | |
this.info = info; | |
ticks = info.TryCloseTicks; | |
render = self.Trait<RenderBuilding>(); | |
animation = new Animation(self.World, render.GetImage(self)); | |
} | |
public bool ShouldBlockActor(Actor self, Actor other) | |
{ | |
var hostile = other.AppearsFriendlyTo(self); | |
if (hostile && !IsOpen) | |
{ | |
Game.Debug("Hostile {0}, Open {1}".F(hostile, IsOpen)); | |
return true; | |
} | |
Game.Debug("Not blocking!"); | |
return false; | |
} | |
public void OnNotifyBlockingMove(Actor self, Actor blocking) | |
{ | |
if (ShouldBlockActor(self, blocking)) | |
{ | |
Game.Debug("{0} is blocking {1}. Abort Open().".F(self.Info.Name, blocking.Info.Name)); | |
return; | |
} | |
Open(self); | |
} | |
public void Tick(Actor self) | |
{ | |
if (--ticks <= 0) | |
return; | |
ticks = info.TryCloseTicks; | |
var occupied = self.OccupiesSpace.OccupiedCells(); | |
var cells = occupied.Select(c => c.First); | |
var blockers = cells.SelectMany(c => self.World.ActorMap.GetUnitsAt(c)); | |
if (blockers.Any()) | |
{ | |
Game.Debug("Gate{0} wants to close, but has {1} blockers!".F(self.ActorID, blockers.Count())); | |
return; | |
} | |
Close(self); | |
} | |
void Open(Actor self) | |
{ | |
if (IsOpen) | |
{ | |
ticks = info.TryCloseTicks; | |
return; | |
} | |
Game.Debug("Gate{0} opening!".F(self.ActorID)); | |
animation.PlayBackwardsThen(info.CloseAnimation, () => IsOpen = true); | |
} | |
void Close(Actor self) | |
{ | |
if (!IsOpen) | |
return; | |
Game.Debug("Gate{0} closing!".F(self.ActorID)); | |
IsOpen = false; | |
animation.Play(info.CloseAnimation); | |
} | |
} | |
} | |
// In MobileInfo | |
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor, bool checkTransientActors, bool blockedByMovers) | |
{ | |
if (MovementCostForCell(world, cell) == int.MaxValue) | |
return false; | |
if (SharesCell && world.ActorMap.HasFreeSubCell(cell)) | |
return true; | |
if (checkTransientActors) | |
{ | |
var canIgnoreMovingAllies = self != null && !blockedByMovers; | |
var needsCellExclusively = self == null || Crushes == null; | |
foreach(var a in world.ActorMap.GetUnitsAt(cell)) | |
{ | |
if (a == ignoreActor) continue; | |
// Neutral/enemy units are blockers. Allied units that are moving are not blockers. | |
if (canIgnoreMovingAllies && self.Owner.Stances[a.Owner] == Stance.Ally && IsMovingInMyDirection(self, a)) continue; | |
// Non-sharable unit can enter a cell with shareable units only if it can crush all of them. | |
if (needsCellExclusively) return false; | |
foreach (var pathing in a.TraitsImplementing<IConditionalPathBlocking>()) | |
{ | |
Game.Debug("Trying TI ICPB"); | |
if (pathing.ShouldBlockActor(a, self)) | |
{ | |
Game.Debug("a is blocking self"); | |
return false; | |
} | |
} | |
if (!a.HasTrait<ICrushable>()) | |
{ | |
Game.Debug("{0} does not have any ICrushable traits!".F(a.Info.Name)); | |
return false; | |
} | |
foreach (var crushable in a.TraitsImplementing<ICrushable>()) | |
if (!crushable.CrushableBy(Crushes, self.Owner)) | |
return false; | |
} | |
} | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment