Implemented Harvester territory marking with a simple resource claim system in ResourceClaimLayer trait added to World. Added customCost for PathSearch to support new Harvester search preferences. Explicit delivery order forces harvester to always deliver to that refinery. Explicit harvest order frees harvester from forced delivery refinery and allows for auto-balancing. Harvesters auto-balance refinery choice such that no more than 3 harvesters are linked to any one refinery at a time. Harvesters try very hard to not block the refinery dock location. Harvesters try to avoid enemy territory when searching for resources. Group-select harvest order intelligently disperses harvesters around the order location. Fixed PathFinder caching to not be a sliding window. This is a correctness issue. Sliding window causes no-route paths to be cached permanently in tight move loops and doesn't allow eventual progress to be made. This may have negative performance implications.
143 lines
4.1 KiB
C#
143 lines
4.1 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright 2007-2011 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.Collections.Generic;
|
|
using System.Linq;
|
|
using OpenRA.Mods.RA.Activities;
|
|
using OpenRA.Mods.RA.Effects;
|
|
using OpenRA.Mods.RA.Render;
|
|
using OpenRA.Traits;
|
|
|
|
namespace OpenRA.Mods.RA
|
|
{
|
|
public class OreRefineryInfo : ITraitInfo
|
|
{
|
|
public readonly int2 DockOffset = new int2(1, 2);
|
|
|
|
public readonly bool ShowTicks = true;
|
|
public readonly int TickLifetime = 30;
|
|
public readonly int TickVelocity = 2;
|
|
public readonly int TickRate = 10;
|
|
|
|
public virtual object Create(ActorInitializer init) { return new OreRefinery(init.self, this); }
|
|
}
|
|
|
|
public class OreRefinery : ITick, IAcceptOre, INotifyKilled, INotifySold, INotifyCapture, IExplodeModifier, ISync
|
|
{
|
|
readonly Actor self;
|
|
readonly OreRefineryInfo Info;
|
|
PlayerResources PlayerResources;
|
|
|
|
int currentDisplayTick = 0;
|
|
int currentDisplayValue = 0;
|
|
|
|
[Sync] public int Ore = 0;
|
|
[Sync] Actor dockedHarv = null;
|
|
[Sync] bool preventDock = false;
|
|
|
|
public bool AllowDocking { get { return !preventDock; } }
|
|
public CVec DeliverOffset { get { return (CVec)Info.DockOffset; } }
|
|
|
|
public virtual Activity DockSequence(Actor harv, Actor self) { return new RAHarvesterDockSequence(harv, self); }
|
|
|
|
public OreRefinery(Actor self, OreRefineryInfo info)
|
|
{
|
|
this.self = self;
|
|
Info = info;
|
|
PlayerResources = self.Owner.PlayerActor.Trait<PlayerResources>();
|
|
currentDisplayTick = Info.TickRate;
|
|
}
|
|
|
|
public IEnumerable<TraitPair<Harvester>> GetLinkedHarvesters()
|
|
{
|
|
return self.World.ActorsWithTrait<Harvester>()
|
|
.Where(a => a.Trait.LinkedProc == self);
|
|
}
|
|
|
|
public bool CanGiveOre(int amount) { return PlayerResources.CanGiveOre(amount); }
|
|
|
|
public void GiveOre(int amount)
|
|
{
|
|
PlayerResources.GiveOre(amount);
|
|
if (Info.ShowTicks)
|
|
currentDisplayValue += amount;
|
|
}
|
|
|
|
void CancelDock(Actor self)
|
|
{
|
|
preventDock = true;
|
|
|
|
// Cancel the dock sequence
|
|
if (dockedHarv != null && !dockedHarv.IsDead())
|
|
dockedHarv.CancelActivity();
|
|
}
|
|
|
|
public void Tick(Actor self)
|
|
{
|
|
// Harvester was killed while unloading
|
|
if (dockedHarv != null && dockedHarv.IsDead())
|
|
{
|
|
self.Trait<RenderBuilding>().CancelCustomAnim(self);
|
|
dockedHarv = null;
|
|
}
|
|
|
|
if (Info.ShowTicks && currentDisplayValue > 0 && --currentDisplayTick <= 0)
|
|
{
|
|
var temp = currentDisplayValue;
|
|
if (self.World.LocalPlayer != null && self.Owner.Stances[self.World.LocalPlayer] == Stance.Ally)
|
|
self.World.AddFrameEndTask(w => w.Add(new CashTick(temp, Info.TickLifetime, Info.TickVelocity, self.CenterLocation, self.Owner.ColorRamp.GetColor(0))));
|
|
currentDisplayTick = Info.TickRate;
|
|
currentDisplayValue = 0;
|
|
}
|
|
}
|
|
|
|
public void Killed(Actor self, AttackInfo e)
|
|
{
|
|
CancelDock(self);
|
|
foreach (var harv in GetLinkedHarvesters())
|
|
harv.Trait.UnlinkProc(harv.Actor, self);
|
|
}
|
|
|
|
public void OnDock(Actor harv, DeliverResources dockOrder)
|
|
{
|
|
if (!preventDock)
|
|
{
|
|
harv.QueueActivity( new CallFunc( () => dockedHarv = harv, false ) );
|
|
harv.QueueActivity( DockSequence(harv, self) );
|
|
harv.QueueActivity( new CallFunc( () => dockedHarv = null, false ) );
|
|
}
|
|
harv.QueueActivity( new CallFunc( () => harv.Trait<Harvester>().ContinueHarvesting(harv) ) );
|
|
}
|
|
|
|
public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner)
|
|
{
|
|
// Steal any docked harv too
|
|
if (dockedHarv != null)
|
|
dockedHarv.ChangeOwner(newOwner);
|
|
|
|
// Unlink any non-docked harvs
|
|
foreach (var harv in GetLinkedHarvesters())
|
|
if (harv.Actor.Owner == oldOwner)
|
|
harv.Trait.UnlinkProc(harv.Actor, self);
|
|
|
|
PlayerResources = newOwner.PlayerActor.Trait<PlayerResources>();
|
|
}
|
|
|
|
public void Selling(Actor self) { CancelDock(self); }
|
|
public void Sold(Actor self)
|
|
{
|
|
foreach (var harv in GetLinkedHarvesters())
|
|
harv.Trait.UnlinkProc(harv.Actor, self);
|
|
}
|
|
|
|
public bool ShouldExplode(Actor self) { return Ore > 0; }
|
|
}
|
|
}
|