Files
OpenRA/OpenRA.Mods.D2k/Traits/Carryable.cs
2015-01-01 22:51:12 +01:00

168 lines
4.2 KiB
C#

#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;
using System.Linq;
using OpenRA.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.D2k.Activities;
using OpenRA.Traits;
namespace OpenRA.Mods.D2k.Traits
{
[Desc("Can be carried by units with the trait `AutoCarryall`.")]
public class CarryableInfo : ITraitInfo
{
[Desc("Required distance away from destination before requesting a pickup.")]
public int MinDistance = 6;
public object Create(ActorInitializer init) { return new Carryable(init.self, this); }
}
public class Carryable : IDisableMove, INotifyHarvesterAction
{
readonly CarryableInfo info;
readonly Actor self;
public bool Reserved { get; private set; }
// If we're locked there isnt much we can do. We'll have to wait for the carrier to finish with us. We should not move or get new orders!
bool locked;
public bool WantsTransport { get; private set; }
public CPos Destination;
Activity afterLandActivity;
public Carryable(Actor self, CarryableInfo info)
{
this.info = info;
this.self = self;
locked = false;
Reserved = false;
WantsTransport = false;
}
public void MovingToResources(Actor self, CPos targetCell, Activity next) { RequestTransport(targetCell, next); }
public void MovingToRefinery(Actor self, CPos targetCell, Activity next) { RequestTransport(targetCell, next); }
void RequestTransport(CPos destination, Activity afterLandActivity)
{
if (locked || Reserved)
return;
if (destination == CPos.Zero)
return;
if ((self.Location - destination).Length < info.MinDistance)
return;
Destination = destination;
this.afterLandActivity = afterLandActivity;
WantsTransport = true;
// Inform all idle carriers
var carriers = self.World.ActorsWithTrait<AutoCarryall>()
.Where(c => !c.Trait.Busy && !c.Actor.IsDead && c.Actor.Owner == self.Owner)
.OrderBy(p => (self.Location - p.Actor.Location).LengthSquared);
foreach (var carrier in carriers)
{
// Notify the carrier and see if he's willing to transport us..
if (carrier.Trait.RequestTransportNotify(self))
break; // If true then we're done
}
}
// No longer want to be carried
public void MovementCancelled(Actor self)
{
if (locked)
return;
WantsTransport = false;
Reserved = false;
// TODO: We could implement something like a carrier.Trait<AutoCarryAll>().CancelTransportNotify(self) and call it here
}
// We do not handle Harvested notification
public void Harvested(Actor self, ResourceType resource) { }
public Actor GetClosestIdleCarrier()
{
// Find carriers
var carriers = self.World.ActorsWithTrait<AutoCarryall>()
.Where(p => p.Actor.Owner == self.Owner && !p.Trait.Busy)
.Select(h => h.Actor);
return WorldUtils.ClosestTo(carriers, self);
}
// This gets called by carrier after we touched down
public void Dropped()
{
WantsTransport = false;
locked = false;
if (afterLandActivity != null)
self.QueueActivity(false, afterLandActivity);
}
public bool Reserve(Actor carrier)
{
if ((self.Location - Destination).Length < info.MinDistance)
{
MovementCancelled(self);
return false;
}
Reserved = true;
return true;
}
public void UnReserve(Actor carrier)
{
Reserved = false;
locked = false;
}
// Prepare for transport pickup
public bool StandbyForPickup(Actor carrier)
{
if (Destination == CPos.Zero)
return false;
if (locked || !WantsTransport)
return false;
// Last change to change our mind...
if ((self.Location - Destination).Length < info.MinDistance)
{
MovementCancelled(self);
return false;
}
// Cancel our activities
self.CancelActivity();
locked = true;
return true;
}
// IMoveDisabled
public bool MoveDisabled(Actor self)
{
// We do not want to move while being locked. The carrier will try to pick us up.
return locked;
}
}
}