Move ValidRelations from Capturable to Captures
To better match weapon definitions
This commit is contained in:
committed by
Matthias Mailänder
parent
161f4cbdff
commit
5cc59ae3ac
@@ -37,7 +37,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
}
|
||||
|
||||
if (!targetIsDeadOrHiddenActor && target.Type != TargetType.FrozenActor &&
|
||||
(enterCaptureManager == null || !enterCaptureManager.CanBeTargetedBy(enterActor, self, manager)))
|
||||
(enterCaptureManager == null || !manager.CanTarget(enterCaptureManager)))
|
||||
Cancel(self, true);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
// Make sure we can still capture the target before entering
|
||||
// (but not before, because this may stop the actor in the middle of nowhere)
|
||||
if (enterCaptureManager == null || !enterCaptureManager.CanBeTargetedBy(enterActor, self, manager))
|
||||
if (enterCaptureManager == null || !manager.CanTarget(enterCaptureManager))
|
||||
{
|
||||
Cancel(self, true);
|
||||
return false;
|
||||
@@ -59,7 +59,7 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
// StartCapture returns false when a capture delay is enabled
|
||||
// We wait until it returns true before allowing entering the target
|
||||
if (!manager.StartCapture(self, enterActor, enterCaptureManager, out var captures))
|
||||
if (!manager.StartCapture(enterCaptureManager, out var captures))
|
||||
return false;
|
||||
|
||||
if (!captures.Info.ConsumedByCapture)
|
||||
@@ -80,11 +80,11 @@ namespace OpenRA.Mods.Common.Activities
|
||||
if (enterActor != targetActor)
|
||||
return;
|
||||
|
||||
if (enterCaptureManager.BeingCaptured || !enterCaptureManager.CanBeTargetedBy(enterActor, self, manager))
|
||||
if (enterCaptureManager.BeingCaptured || !manager.CanTarget(enterCaptureManager))
|
||||
return;
|
||||
|
||||
// Prioritize capturing over sabotaging
|
||||
var captures = manager.ValidCapturesWithLowestSabotageThreshold(self, enterActor, enterCaptureManager);
|
||||
var captures = manager.ValidCapturesWithLowestSabotageThreshold(enterCaptureManager);
|
||||
if (captures == null)
|
||||
return;
|
||||
|
||||
@@ -134,25 +134,25 @@ namespace OpenRA.Mods.Common.Activities
|
||||
|
||||
protected override void OnLastRun(Actor self)
|
||||
{
|
||||
CancelCapture(self);
|
||||
CancelCapture();
|
||||
base.OnLastRun(self);
|
||||
}
|
||||
|
||||
protected override void OnActorDispose(Actor self)
|
||||
{
|
||||
CancelCapture(self);
|
||||
CancelCapture();
|
||||
base.OnActorDispose(self);
|
||||
}
|
||||
|
||||
public override void Cancel(Actor self, bool keepQueue = false)
|
||||
{
|
||||
CancelCapture(self);
|
||||
CancelCapture();
|
||||
base.Cancel(self, keepQueue);
|
||||
}
|
||||
|
||||
void CancelCapture(Actor self)
|
||||
void CancelCapture()
|
||||
{
|
||||
manager.CancelCapture(self, enterActor, enterCaptureManager);
|
||||
manager.CancelCapture(enterCaptureManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA.Mods.Common.Scripting
|
||||
public bool CanCapture(Actor target)
|
||||
{
|
||||
var targetManager = target.TraitOrDefault<CaptureManager>();
|
||||
return targetManager != null && targetManager.CanBeTargetedBy(target, Self, captureManager);
|
||||
return targetManager != null && captureManager.CanTarget(targetManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (captureManager == null)
|
||||
return false;
|
||||
|
||||
return capturers.Any(tp => captureManager.CanBeTargetedBy(target, tp.Actor, tp.Trait));
|
||||
return capturers.Any(tp => tp.Trait.CanTarget(captureManager));
|
||||
})
|
||||
.OrderByDescending(target => target.GetSellValue())
|
||||
.Take(maximumCaptureTargetOptions);
|
||||
|
||||
@@ -22,9 +22,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("CaptureTypes (from the Captures trait) that are able to capture this.")]
|
||||
public readonly BitSet<CaptureType> Types = default;
|
||||
|
||||
[Desc("What player relationships the target's owner needs to be captured by this actor.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Cancel the actor's current activity when getting captured.")]
|
||||
public readonly bool CancelActivity = false;
|
||||
|
||||
|
||||
@@ -38,32 +38,21 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Should units friendly to the capturing actor auto-target this actor while it is being captured?")]
|
||||
public readonly bool PreventsAutoTarget = true;
|
||||
|
||||
public override object Create(ActorInitializer init) { return new CaptureManager(this); }
|
||||
|
||||
public bool CanBeTargetedBy(FrozenActor frozenActor, Actor captor, Captures captures)
|
||||
{
|
||||
if (captures.IsTraitDisabled)
|
||||
return false;
|
||||
|
||||
// TODO: FrozenActors don't yet have a way of caching conditions, so we can't filter disabled traits
|
||||
// This therefore assumes that all Capturable traits are enabled, which is probably wrong.
|
||||
// Actors with FrozenUnderFog should therefore not disable the Capturable trait.
|
||||
var stance = captor.Owner.RelationshipWith(frozenActor.Owner);
|
||||
return frozenActor.Info.TraitInfos<CapturableInfo>()
|
||||
.Any(c => c.ValidRelationships.HasRelationship(stance) && captures.Info.CaptureTypes.Overlaps(c.Types));
|
||||
}
|
||||
public override object Create(ActorInitializer init) { return new CaptureManager(init.Self, this); }
|
||||
}
|
||||
|
||||
public class CaptureManager : INotifyCreated, INotifyCapture, ITick, IDisableEnemyAutoTarget
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly CaptureManagerInfo info;
|
||||
|
||||
IMove move;
|
||||
ICaptureProgressWatcher[] progressWatchers;
|
||||
|
||||
BitSet<CaptureType> allyCapturableTypes;
|
||||
BitSet<CaptureType> neutralCapturableTypes;
|
||||
BitSet<CaptureType> enemyCapturableTypes;
|
||||
BitSet<CaptureType> capturesTypes;
|
||||
BitSet<CaptureType> allyCapturesTypes;
|
||||
BitSet<CaptureType> neutralCapturesTypes;
|
||||
BitSet<CaptureType> enemyCapturesTypes;
|
||||
BitSet<CaptureType> capturableTypes;
|
||||
|
||||
IEnumerable<Capturable> enabledCapturable;
|
||||
IEnumerable<Captures> enabledCaptures;
|
||||
@@ -81,8 +70,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public bool BeingCaptured { get; private set; }
|
||||
|
||||
public CaptureManager(CaptureManagerInfo info)
|
||||
public CaptureManager(Actor self, CaptureManagerInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
@@ -103,69 +93,74 @@ namespace OpenRA.Mods.Common.Traits
|
||||
RefreshCapturable();
|
||||
}
|
||||
|
||||
public void RefreshCapturable()
|
||||
public void RefreshCaptures()
|
||||
{
|
||||
allyCapturableTypes = neutralCapturableTypes = enemyCapturableTypes = default;
|
||||
foreach (var c in enabledCapturable)
|
||||
allyCapturesTypes = neutralCapturesTypes = enemyCapturesTypes = default;
|
||||
foreach (var c in enabledCaptures)
|
||||
{
|
||||
if (c.Info.ValidRelationships.HasRelationship(PlayerRelationship.Ally))
|
||||
allyCapturableTypes = allyCapturableTypes.Union(c.Info.Types);
|
||||
allyCapturesTypes = allyCapturesTypes.Union(c.Info.CaptureTypes);
|
||||
|
||||
if (c.Info.ValidRelationships.HasRelationship(PlayerRelationship.Neutral))
|
||||
neutralCapturableTypes = neutralCapturableTypes.Union(c.Info.Types);
|
||||
neutralCapturesTypes = neutralCapturesTypes.Union(c.Info.CaptureTypes);
|
||||
|
||||
if (c.Info.ValidRelationships.HasRelationship(PlayerRelationship.Enemy))
|
||||
enemyCapturableTypes = enemyCapturableTypes.Union(c.Info.Types);
|
||||
enemyCapturesTypes = enemyCapturesTypes.Union(c.Info.CaptureTypes);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshCaptures()
|
||||
public void RefreshCapturable()
|
||||
{
|
||||
capturesTypes = enabledCaptures.Aggregate(
|
||||
capturableTypes = enabledCapturable.Aggregate(
|
||||
default(BitSet<CaptureType>),
|
||||
(a, b) => a.Union(b.Info.CaptureTypes));
|
||||
(a, b) => a.Union(b.Info.Types));
|
||||
}
|
||||
|
||||
public bool CanBeTargetedBy(Actor self, Actor captor, CaptureManager captorManager)
|
||||
/// <summary>Should only be called from the captor's CaptureManager.</summary>
|
||||
public bool CanTarget(CaptureManager target)
|
||||
{
|
||||
var relationship = captor.Owner.RelationshipWith(self.Owner);
|
||||
if (relationship.HasRelationship(PlayerRelationship.Enemy))
|
||||
return captorManager.capturesTypes.Overlaps(enemyCapturableTypes);
|
||||
|
||||
if (relationship.HasRelationship(PlayerRelationship.Neutral))
|
||||
return captorManager.capturesTypes.Overlaps(neutralCapturableTypes);
|
||||
|
||||
if (relationship.HasRelationship(PlayerRelationship.Ally))
|
||||
return captorManager.capturesTypes.Overlaps(allyCapturableTypes);
|
||||
|
||||
return false;
|
||||
return CanTarget(target.self.Owner, target.capturableTypes);
|
||||
}
|
||||
|
||||
public bool CanBeTargetedBy(Actor self, Actor captor, Captures captures)
|
||||
/// <summary>Should only be called from the captor CaptureManager.</summary>
|
||||
public bool CanTarget(FrozenActor target)
|
||||
{
|
||||
if (captures.IsTraitDisabled)
|
||||
if (!target.Info.HasTraitInfo<CaptureManagerInfo>())
|
||||
return false;
|
||||
|
||||
var relationship = captor.Owner.RelationshipWith(self.Owner);
|
||||
// TODO: FrozenActors don't yet have a way of caching conditions, so we can't filter disabled traits
|
||||
// This therefore assumes that all Capturable traits are enabled, which is probably wrong.
|
||||
// Actors with FrozenUnderFog should therefore not disable the Capturable trait.
|
||||
var targetTypes = target.Info.TraitInfos<CapturableInfo>().Aggregate(
|
||||
default(BitSet<CaptureType>),
|
||||
(a, b) => a.Union(b.Types));
|
||||
|
||||
return CanTarget(target.Owner, targetTypes);
|
||||
}
|
||||
|
||||
bool CanTarget(Player target, BitSet<CaptureType> captureTypes)
|
||||
{
|
||||
var relationship = self.Owner.RelationshipWith(target);
|
||||
if (relationship.HasRelationship(PlayerRelationship.Enemy))
|
||||
return captures.Info.CaptureTypes.Overlaps(enemyCapturableTypes);
|
||||
return captureTypes.Overlaps(enemyCapturesTypes);
|
||||
|
||||
if (relationship.HasRelationship(PlayerRelationship.Neutral))
|
||||
return captures.Info.CaptureTypes.Overlaps(neutralCapturableTypes);
|
||||
return captureTypes.Overlaps(neutralCapturesTypes);
|
||||
|
||||
if (relationship.HasRelationship(PlayerRelationship.Ally))
|
||||
return captures.Info.CaptureTypes.Overlaps(allyCapturableTypes);
|
||||
return captureTypes.Overlaps(allyCapturesTypes);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Captures ValidCapturesWithLowestSabotageThreshold(Actor self, Actor captee, CaptureManager capteeManager)
|
||||
public Captures ValidCapturesWithLowestSabotageThreshold(CaptureManager target)
|
||||
{
|
||||
if (captee.IsDead)
|
||||
if (target.self.IsDead)
|
||||
return null;
|
||||
|
||||
var relationship = self.Owner.RelationshipWith(target.self.Owner);
|
||||
foreach (var c in enabledCaptures.OrderBy(c => c.Info.SabotageThreshold).ThenBy(c => c.Info.CaptureDelay))
|
||||
if (capteeManager.CanBeTargetedBy(captee, self, c))
|
||||
if (c.Info.ValidRelationships.HasRelationship(relationship) && target.capturableTypes.Overlaps(c.Info.CaptureTypes))
|
||||
return c;
|
||||
|
||||
return null;
|
||||
@@ -182,7 +177,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
/// This method grants the capturing conditions on the captor and target and returns
|
||||
/// true if the captor is able to start entering or false if it needs to wait.
|
||||
/// </summary>
|
||||
public bool StartCapture(Actor self, Actor target, CaptureManager targetManager, out Captures captures)
|
||||
public bool StartCapture(CaptureManager targetManager, out Captures captures)
|
||||
{
|
||||
captures = null;
|
||||
|
||||
@@ -190,10 +185,11 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (self.WillDispose)
|
||||
return false;
|
||||
|
||||
var target = targetManager.self;
|
||||
if (target != currentTarget)
|
||||
{
|
||||
if (currentTarget != null)
|
||||
CancelCapture(self, currentTarget, currentTargetManager);
|
||||
if (currentTargetManager != null)
|
||||
CancelCapture(currentTargetManager);
|
||||
|
||||
targetManager.currentCaptors.Add(self);
|
||||
currentTarget = target;
|
||||
@@ -209,7 +205,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (targetManager.beingCapturedToken == Actor.InvalidConditionToken)
|
||||
targetManager.beingCapturedToken = target.GrantCondition(targetManager.info.BeingCapturedCondition);
|
||||
|
||||
captures = ValidCapturesWithLowestSabotageThreshold(self, target, targetManager);
|
||||
captures = ValidCapturesWithLowestSabotageThreshold(targetManager);
|
||||
if (captures == null)
|
||||
return false;
|
||||
|
||||
@@ -243,11 +239,12 @@ namespace OpenRA.Mods.Common.Traits
|
||||
/// This method revokes the capturing conditions on the captor and target
|
||||
/// and resets any capturing progress.
|
||||
/// </summary>
|
||||
public void CancelCapture(Actor self, Actor target, CaptureManager targetManager)
|
||||
public void CancelCapture(CaptureManager targetManager)
|
||||
{
|
||||
if (currentTarget == null)
|
||||
return;
|
||||
|
||||
var target = targetManager.self;
|
||||
foreach (var w in progressWatchers)
|
||||
w.Update(self, self, target, 0, 0);
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[Desc("Experience granted to the capturing player.")]
|
||||
public readonly int PlayerExperience = 0;
|
||||
|
||||
[Desc("What player relationships the target's owner needs to be captured by this actor.")]
|
||||
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Neutral | PlayerRelationship.Enemy;
|
||||
|
||||
[Desc("Relationships that the structure's previous owner needs to have for the capturing player to receive Experience.")]
|
||||
public readonly PlayerRelationship PlayerExperienceRelationships = PlayerRelationship.Enemy;
|
||||
|
||||
@@ -69,12 +72,12 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public class Captures : ConditionalTrait<CapturesInfo>, IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
readonly CaptureManager captureManager;
|
||||
public readonly CaptureManager CaptureManager;
|
||||
|
||||
public Captures(Actor self, CapturesInfo info)
|
||||
: base(info)
|
||||
{
|
||||
captureManager = self.Trait<CaptureManager>();
|
||||
CaptureManager = self.Trait<CaptureManager>();
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
@@ -110,8 +113,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
self.ShowTargetLines();
|
||||
}
|
||||
|
||||
protected override void TraitEnabled(Actor self) { captureManager.RefreshCaptures(); }
|
||||
protected override void TraitDisabled(Actor self) { captureManager.RefreshCaptures(); }
|
||||
protected override void TraitEnabled(Actor self) { CaptureManager.RefreshCaptures(); }
|
||||
protected override void TraitDisabled(Actor self) { CaptureManager.RefreshCaptures(); }
|
||||
|
||||
sealed class CaptureOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
@@ -125,8 +128,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var captureManager = target.TraitOrDefault<CaptureManager>();
|
||||
if (captureManager == null || !captureManager.CanBeTargetedBy(target, self, captures))
|
||||
var targetManager = target.TraitOrDefault<CaptureManager>();
|
||||
if (targetManager == null || !captures.CaptureManager.CanTarget(targetManager))
|
||||
{
|
||||
cursor = captures.Info.EnterBlockedCursor;
|
||||
return false;
|
||||
@@ -147,8 +150,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public override bool CanTargetFrozenActor(Actor self, FrozenActor target, TargetModifiers modifiers, ref string cursor)
|
||||
{
|
||||
var captureManagerInfo = target.Info.TraitInfoOrDefault<CaptureManagerInfo>();
|
||||
if (captureManagerInfo == null || !captureManagerInfo.CanBeTargetedBy(target, self, captures))
|
||||
if (!captures.CaptureManager.CanTarget(target))
|
||||
{
|
||||
cursor = captures.Info.EnterBlockedCursor;
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#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;
|
||||
|
||||
namespace OpenRA.Mods.Common.UpdateRules.Rules
|
||||
{
|
||||
public class RemoveValidRelationsFromCapturable : UpdateRule
|
||||
{
|
||||
public override string Name => "Remove ValidRelations property from Capturable.";
|
||||
|
||||
public override string Description => "ValidRelations has been moved from Capturable to Captures to match weapon definitions.";
|
||||
|
||||
readonly List<string> locations = new();
|
||||
|
||||
public override IEnumerable<string> AfterUpdate(ModData modData)
|
||||
{
|
||||
if (locations.Any())
|
||||
yield return Description + "\n" +
|
||||
"ValidRelations have been removed from:\n" +
|
||||
UpdateUtils.FormatMessageList(locations);
|
||||
|
||||
locations.Clear();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNodeBuilder actorNode)
|
||||
{
|
||||
foreach (var capturable in actorNode.ChildrenMatching("Capturable"))
|
||||
{
|
||||
if (capturable.RemoveNodes("ValidRelations") > 0)
|
||||
locations.Add($"{actorNode.Key}: {capturable.Key} ({actorNode.Location.Filename})");
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,7 @@ namespace OpenRA.Mods.Common.UpdateRules
|
||||
new UpdatePath("playtest-20230801", new UpdateRule[]
|
||||
{
|
||||
// bleed only changes here.
|
||||
new RemoveValidRelationsFromCapturable(),
|
||||
|
||||
// Execute these rules last to avoid premature yaml merge crashes.
|
||||
new AbstractDocking(),
|
||||
|
||||
@@ -1076,7 +1076,6 @@
|
||||
CaptureManager:
|
||||
Capturable:
|
||||
Types: husk
|
||||
ValidRelationships: Enemy, Neutral, Ally
|
||||
TransformOnCapture:
|
||||
ForceHealthPercentage: 25
|
||||
Tooltip:
|
||||
|
||||
@@ -213,8 +213,12 @@ E6:
|
||||
SabotageThreshold: 55
|
||||
PlayerExperience: 10
|
||||
Captures@CAPTURES:
|
||||
CaptureTypes: building, husk
|
||||
CaptureTypes: building
|
||||
PlayerExperience: 10
|
||||
Captures@CATURESHUSK:
|
||||
CaptureTypes: husk
|
||||
PlayerExperience: 10
|
||||
ValidRelationships: Enemy, Neutral, Ally
|
||||
-AttackFrontal:
|
||||
|
||||
RMBO:
|
||||
|
||||
@@ -25,7 +25,6 @@ MISS:
|
||||
Name: Soviet Air Force HQ
|
||||
Capturable:
|
||||
Types: building
|
||||
ValidRelationships: Enemy
|
||||
CaptureManager:
|
||||
|
||||
TENT:
|
||||
|
||||
@@ -1062,7 +1062,6 @@
|
||||
CaptureManager:
|
||||
Capturable:
|
||||
Types: husk
|
||||
ValidRelationships: Enemy, Neutral
|
||||
TransformOnCapture:
|
||||
ForceHealthPercentage: 15
|
||||
InfiltrateForTransform:
|
||||
|
||||
Reference in New Issue
Block a user