- EditorActorLayer now tracks previews on map with a SpatiallyPartitioned instead of a Dictionary. This allows the copy-paste logic to call an efficient PreviewsInCellRegion method, instead of asking for previews cell-by-cell. - EditorActorPreview subscribes to the CellEntryChanged methods on the map. Previously the preview was refreshed regardless of which cell changed. Now the preview only regenerates if the preview's footprint has been affected.
118 lines
3.7 KiB
C#
118 lines
3.7 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright (c) The OpenRA Developers and Contributors
|
|
* 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, either version 3 of
|
|
* the License, or (at your option) any later version. For more
|
|
* information, see COPYING.
|
|
*/
|
|
#endregion
|
|
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using OpenRA.Mods.Common.Traits;
|
|
using OpenRA.Traits;
|
|
|
|
namespace OpenRA.Mods.Cnc.Traits
|
|
{
|
|
[TraitLocation(SystemActors.EditorWorld)]
|
|
sealed class TSEditorResourceLayerInfo : EditorResourceLayerInfo, Requires<EditorActorLayerInfo>
|
|
{
|
|
public readonly string VeinType = "Veins";
|
|
|
|
[ActorReference]
|
|
[Desc("Actor types that should be treated as veins for adjacency.")]
|
|
public readonly HashSet<string> VeinholeActors = new();
|
|
|
|
public override object Create(ActorInitializer init) { return new TSEditorResourceLayer(init.Self, this); }
|
|
}
|
|
|
|
sealed class TSEditorResourceLayer : EditorResourceLayer
|
|
{
|
|
readonly TSEditorResourceLayerInfo info;
|
|
readonly EditorActorLayer actorLayer;
|
|
|
|
public TSEditorResourceLayer(Actor self, TSEditorResourceLayerInfo info)
|
|
: base(self, info)
|
|
{
|
|
this.info = info;
|
|
actorLayer = self.Trait<EditorActorLayer>();
|
|
}
|
|
|
|
bool IsValidVeinNeighbour(CPos cell, CPos neighbour)
|
|
{
|
|
if (!Map.Contains(neighbour))
|
|
return false;
|
|
|
|
// Cell is automatically valid if it contains a veinhole actor
|
|
if (actorLayer.PreviewsAtCell(neighbour).Any(a => info.VeinholeActors.Contains(a.Info.Name)))
|
|
return true;
|
|
|
|
// Neighbour must be flat or a cardinal slope, unless the resource cell itself is a slope
|
|
if (Map.Ramp[cell] == 0 && Map.Ramp[neighbour] > 4)
|
|
return false;
|
|
|
|
var terrainInfo = Map.Rules.TerrainInfo;
|
|
var terrainType = terrainInfo.TerrainTypes[terrainInfo.GetTerrainInfo(Map.Tiles[neighbour]).TerrainType].Type;
|
|
return info.ResourceTypes[info.VeinType].AllowedTerrainTypes.Contains(terrainType);
|
|
}
|
|
|
|
protected override bool AllowResourceAt(string resourceType, CPos cell)
|
|
{
|
|
var mapResources = Map.Resources;
|
|
if (!mapResources.Contains(cell))
|
|
return false;
|
|
|
|
// Resources are allowed on flat terrain and cardinal slopes
|
|
if (Map.Ramp[cell] > 4)
|
|
return false;
|
|
|
|
if (!info.ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
|
|
return false;
|
|
|
|
// Ignore custom terrain types when spawning resources in the editor
|
|
var terrainInfo = Map.Rules.TerrainInfo;
|
|
var terrainType = terrainInfo.TerrainTypes[terrainInfo.GetTerrainInfo(Map.Tiles[cell]).TerrainType].Type;
|
|
if (!resourceInfo.AllowedTerrainTypes.Contains(terrainType))
|
|
return false;
|
|
|
|
// Veins must be placed next to a compatible border cell
|
|
if (resourceType == info.VeinType)
|
|
{
|
|
var neighboursValid = Common.Util.ExpandFootprint(cell, false)
|
|
.All(c => IsValidVeinNeighbour(cell, c));
|
|
|
|
if (!neighboursValid)
|
|
return false;
|
|
}
|
|
|
|
// TODO: Check against actors in the EditorActorLayer
|
|
return true;
|
|
}
|
|
|
|
protected override int AddResource(string resourceType, CPos cell, int amount = 1)
|
|
{
|
|
var added = base.AddResource(resourceType, cell, amount);
|
|
|
|
// Update neighbouring cells if needed to provide space for vein borders
|
|
var resourceIsVeins = resourceType == info.VeinType;
|
|
foreach (var c in Common.Util.ExpandFootprint(cell, false))
|
|
{
|
|
if (!Map.Resources.Contains(c))
|
|
continue;
|
|
|
|
var resourceIndex = Map.Resources[c].Type;
|
|
if (resourceIndex == 0 || !ResourceTypesByIndex.TryGetValue(resourceIndex, out var neighourResourceType))
|
|
neighourResourceType = null;
|
|
|
|
var neighbourIsVeins = neighourResourceType == info.VeinType;
|
|
if (resourceIsVeins ^ neighbourIsVeins)
|
|
ClearResources(c);
|
|
}
|
|
|
|
return added;
|
|
}
|
|
}
|
|
}
|