177 lines
4.1 KiB
C#
177 lines
4.1 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.Collections.Generic;
|
|
using System.Linq;
|
|
using OpenRA.Graphics;
|
|
using OpenRA.Mods.Common.Activities;
|
|
using OpenRA.Mods.Common.Traits;
|
|
using OpenRA.Mods.D2k.Activities;
|
|
using OpenRA.Mods.RA;
|
|
using OpenRA.Mods.RA.Traits;
|
|
using OpenRA.Traits;
|
|
|
|
namespace OpenRA.Mods.D2k.Traits
|
|
{
|
|
[Desc("Automatically transports harvesters with the Carryable trait between resource fields and refineries")]
|
|
public class AutoCarryallInfo : ITraitInfo, Requires<IBodyOrientationInfo>
|
|
{
|
|
public object Create(ActorInitializer init) { return new AutoCarryall(init.self, this); }
|
|
}
|
|
|
|
public class AutoCarryall : INotifyBecomingIdle, INotifyKilled, ISync, IRender
|
|
{
|
|
readonly Actor self;
|
|
readonly WRange carryHeight;
|
|
|
|
// The actor we are currently carrying.
|
|
[Sync] Actor carrying;
|
|
|
|
// TODO: Use ActorPreviews so that this can support actors with multiple sprites
|
|
Animation anim;
|
|
|
|
public bool Busy { get; internal set; }
|
|
|
|
public AutoCarryall(Actor self, AutoCarryallInfo info)
|
|
{
|
|
this.self = self;
|
|
carryHeight = self.Trait<Helicopter>().Info.LandAltitude;
|
|
}
|
|
|
|
public void OnBecomingIdle(Actor self)
|
|
{
|
|
FindCarryableForTransport();
|
|
|
|
if (!Busy)
|
|
self.QueueActivity(new HeliFlyCircle(self));
|
|
}
|
|
|
|
// A carryable notifying us that he'd like to be carried
|
|
public bool RequestTransportNotify(Actor carryable)
|
|
{
|
|
if (Busy)
|
|
return false;
|
|
|
|
if (ReserveCarryable(carryable))
|
|
{
|
|
self.QueueActivity(false, new CarryUnit(self, carryable));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FindCarryableForTransport()
|
|
{
|
|
// get all carryables who want transport
|
|
var carryables = self.World.ActorsWithTrait<Carryable>()
|
|
.Where(p =>
|
|
{
|
|
var actor = p.Actor;
|
|
if (actor == null)
|
|
return false;
|
|
|
|
if (actor.Owner != self.Owner)
|
|
return false;
|
|
|
|
if (actor.IsDead)
|
|
return false;
|
|
|
|
var trait = p.Trait;
|
|
if (trait.Reserved)
|
|
return false;
|
|
|
|
if (!trait.WantsTransport)
|
|
return false;
|
|
|
|
return true;
|
|
})
|
|
.OrderBy(p => (self.Location - p.Actor.Location).LengthSquared);
|
|
|
|
foreach (var p in carryables)
|
|
{
|
|
// Check if its actually me who's the best candidate
|
|
if (p.Trait.GetClosestIdleCarrier() == self && ReserveCarryable(p.Actor))
|
|
{
|
|
self.QueueActivity(false, new CarryUnit(self, p.Actor));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reserve the carryable so its ours exclusively
|
|
public bool ReserveCarryable(Actor carryable)
|
|
{
|
|
if (carryable.Trait<Carryable>().Reserve(self))
|
|
{
|
|
carrying = carryable;
|
|
Busy = true;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Unreserve the carryable
|
|
public void UnreserveCarryable()
|
|
{
|
|
if (carrying != null)
|
|
{
|
|
if (carrying.IsInWorld && !carrying.IsDead)
|
|
carrying.Trait<Carryable>().UnReserve(self);
|
|
|
|
carrying = null;
|
|
}
|
|
|
|
Busy = false;
|
|
}
|
|
|
|
// INotifyKilled
|
|
public void Killed(Actor self, AttackInfo e)
|
|
{
|
|
if (carrying != null)
|
|
{
|
|
carrying.Kill(e.Attacker);
|
|
carrying = null;
|
|
}
|
|
|
|
UnreserveCarryable();
|
|
}
|
|
|
|
// Called when carryable is inside.
|
|
public void AttachCarryable(Actor carryable)
|
|
{
|
|
// Create a new animation for our carryable unit
|
|
anim = new Animation(self.World, RenderSprites.GetImage(carryable.Info), RenderSprites.MakeFacingFunc(self));
|
|
anim.PlayRepeating("idle");
|
|
anim.IsDecoration = true;
|
|
}
|
|
|
|
// Called when released
|
|
public void CarryableReleased()
|
|
{
|
|
anim = null;
|
|
}
|
|
|
|
public IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
|
|
{
|
|
// Render the carryable below us TODO: Implement RenderSprites trait
|
|
if (anim != null && !self.World.FogObscures(self))
|
|
{
|
|
anim.Tick();
|
|
var renderables = anim.Render(self.CenterPosition + new WVec(0, 0, -carryHeight.Range), wr.Palette("player" + carrying.Owner.InternalName));
|
|
|
|
foreach (var rr in renderables)
|
|
yield return rr;
|
|
}
|
|
}
|
|
}
|
|
}
|