refactoring the Harvesters' pathfinding. Now they in first place assess which is the closest resource inside their search area and then a path is calculated Changed the way harvesters find resources by always trying to find the closest resource to their refinery. Changed the strategy of finding to find resources in Annulus.
170 lines
5.0 KiB
C#
170 lines
5.0 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright 2007-2015 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.Drawing;
|
|
using System.Linq;
|
|
using OpenRA.Activities;
|
|
using OpenRA.Mods.Common.Pathfinder;
|
|
using OpenRA.Mods.Common.Traits;
|
|
using OpenRA.Traits;
|
|
|
|
namespace OpenRA.Mods.Common.Activities
|
|
{
|
|
public class FindResources : Activity
|
|
{
|
|
readonly Harvester harv;
|
|
readonly HarvesterInfo harvInfo;
|
|
readonly Mobile mobile;
|
|
readonly MobileInfo mobileInfo;
|
|
readonly ResourceLayer resLayer;
|
|
readonly ResourceClaimLayer territory;
|
|
readonly IPathFinder pathFinder;
|
|
|
|
CPos? avoidCell;
|
|
|
|
public FindResources(Actor self)
|
|
{
|
|
harv = self.Trait<Harvester>();
|
|
harvInfo = self.Info.Traits.Get<HarvesterInfo>();
|
|
mobile = self.Trait<Mobile>();
|
|
mobileInfo = self.Info.Traits.Get<MobileInfo>();
|
|
resLayer = self.World.WorldActor.Trait<ResourceLayer>();
|
|
territory = self.World.WorldActor.TraitOrDefault<ResourceClaimLayer>();
|
|
pathFinder = self.World.WorldActor.Trait<IPathFinder>();
|
|
}
|
|
|
|
public FindResources(Actor self, CPos avoidCell)
|
|
: this(self)
|
|
{
|
|
this.avoidCell = avoidCell;
|
|
}
|
|
|
|
public override Activity Tick(Actor self)
|
|
{
|
|
if (IsCanceled || NextActivity != null)
|
|
return NextActivity;
|
|
|
|
var deliver = new DeliverResources(self);
|
|
|
|
if (harv.IsFull)
|
|
return Util.SequenceActivities(deliver, NextActivity);
|
|
|
|
var closestHarvestablePosition = ClosestHarvestablePos(self);
|
|
|
|
// If no harvestable position could be found, either deliver the remaining resources
|
|
// or get out of the way and do not disturb.
|
|
if (!closestHarvestablePosition.HasValue)
|
|
{
|
|
if (!harv.IsEmpty)
|
|
return deliver;
|
|
|
|
var cachedPosition = self.Location;
|
|
harv.UnblockRefinery(self);
|
|
|
|
// Only do this if UnblockRefinery did nothing.
|
|
if (self.Location == cachedPosition)
|
|
{
|
|
var unblockCell = harv.LastHarvestedCell ?? (self.Location + new CVec(0, 4));
|
|
var moveTo = mobile.NearestMoveableCell(unblockCell, 2, 5);
|
|
self.QueueActivity(mobile.MoveTo(moveTo, 1));
|
|
self.SetTargetLine(Target.FromCell(self.World, moveTo), Color.Gray, false);
|
|
}
|
|
|
|
var randFrames = self.World.SharedRandom.Next(100, 175);
|
|
return Util.SequenceActivities(NextActivity, new Wait(randFrames), this);
|
|
}
|
|
else
|
|
{
|
|
var next = this;
|
|
|
|
// Attempt to claim a resource as ours
|
|
if (territory != null)
|
|
{
|
|
if (!territory.ClaimResource(self, closestHarvestablePosition.Value))
|
|
return Util.SequenceActivities(new Wait(25), next);
|
|
}
|
|
|
|
// If not given a direct order, assume ordered to the first resource location we find:
|
|
if (!harv.LastOrderLocation.HasValue)
|
|
harv.LastOrderLocation = closestHarvestablePosition;
|
|
|
|
self.SetTargetLine(Target.FromCell(self.World, closestHarvestablePosition.Value), Color.Red, false);
|
|
|
|
var notify = self.TraitsImplementing<INotifyHarvesterAction>();
|
|
|
|
foreach (var n in notify)
|
|
n.MovingToResources(self, closestHarvestablePosition.Value, next);
|
|
|
|
return Util.SequenceActivities(mobile.MoveTo(closestHarvestablePosition.Value, 1), new HarvestResource(self), next);
|
|
}
|
|
}
|
|
|
|
bool IsHarvestable(Actor self, CPos pos)
|
|
{
|
|
var resType = resLayer.GetResource(pos);
|
|
if (resType == null)
|
|
return false;
|
|
|
|
// Can the harvester collect this kind of resource?
|
|
if (!harvInfo.Resources.Contains(resType.Info.Name))
|
|
return false;
|
|
|
|
if (territory != null)
|
|
{
|
|
// Another harvester has claimed this resource:
|
|
ResourceClaim claim;
|
|
if (territory.IsClaimedByAnyoneElse(self as Actor, pos, out claim))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the closest harvestable pos between the current position of the harvester
|
|
/// and the last order location
|
|
/// </summary>
|
|
CPos? ClosestHarvestablePos(Actor self)
|
|
{
|
|
// Determine where to search from and how far to search:
|
|
var searchFromLoc = harv.LastOrderLocation ?? (harv.LastLinkedProc ?? harv.LinkedProc ?? self).Location;
|
|
var searchRadius = harv.LastOrderLocation.HasValue ? harvInfo.SearchFromOrderRadius : harvInfo.SearchFromProcRadius;
|
|
var searchRadiusSquared = searchRadius * searchRadius;
|
|
|
|
var search = PathSearch.Search(self.World, mobileInfo, self, true,
|
|
loc => IsHarvestable(self, loc))
|
|
.WithCustomCost(loc =>
|
|
{
|
|
if ((avoidCell.HasValue && loc == avoidCell.Value) ||
|
|
(loc - self.Location).LengthSquared > searchRadiusSquared)
|
|
return int.MaxValue;
|
|
|
|
return 0;
|
|
})
|
|
.FromPoint(self.Location)
|
|
.FromPoint(searchFromLoc);
|
|
|
|
// Find any harvestable resources:
|
|
var path = pathFinder.FindPath(search);
|
|
|
|
if (path.Count > 0)
|
|
return path[0];
|
|
|
|
return null;
|
|
}
|
|
|
|
public override IEnumerable<Target> GetTargets(Actor self)
|
|
{
|
|
yield return Target.FromCell(self.World, self.Location);
|
|
}
|
|
}
|
|
}
|