Track visibility modifiers on FrozenActors.

This commit is contained in:
Paul Chote
2018-12-10 20:44:03 +00:00
committed by Oliver Brakmann
parent 5f79c31a57
commit 224377f078
5 changed files with 42 additions and 21 deletions

View File

@@ -46,7 +46,17 @@ namespace OpenRA.Traits
public DamageState DamageState { get; private set; } public DamageState DamageState { get; private set; }
readonly IHealth health; readonly IHealth health;
// The Visible flag is tied directly to the actor visibility under the fog.
// If Visible is true, the actor is made invisible (via FrozenUnderFog/IDefaultVisibility)
// and this FrozenActor is rendered instead.
// The Hidden flag covers the edge case that occurs when the backing actor was last "seen"
// to be cloaked or otherwise not CanBeViewedByPlayer()ed. Setting Visible to true when
// the actor is hidden under the fog would leak the actors position via the tooltips and
// AutoTargetability, and keeping Visible as false would cause the actor to be rendered
// under the fog.
public bool Visible = true; public bool Visible = true;
public bool Hidden = false;
public bool Shrouded { get; private set; } public bool Shrouded { get; private set; }
public bool NeedRenderables { get; set; } public bool NeedRenderables { get; set; }
public IRenderable[] Renderables = NoRenderables; public IRenderable[] Renderables = NoRenderables;
@@ -101,6 +111,7 @@ namespace OpenRA.Traits
{ {
Owner = actor.Owner; Owner = actor.Owner;
TargetTypes = actor.GetEnabledTargetTypes(); TargetTypes = actor.GetEnabledTargetTypes();
Hidden = !actor.CanBeViewedByPlayer(viewer);
if (health != null) if (health != null)
{ {
@@ -145,6 +156,11 @@ namespace OpenRA.Traits
NeedRenderables |= Visible && !wasVisible; NeedRenderables |= Visible && !wasVisible;
} }
public void Invalidate()
{
Owner = null;
}
public void Flash() public void Flash()
{ {
flashTicks = 5; flashTicks = 5;

View File

@@ -80,13 +80,21 @@ namespace OpenRA.Traits
public bool IsValidFor(Actor targeter) public bool IsValidFor(Actor targeter)
{ {
if (targeter == null || Type == TargetType.Invalid) if (targeter == null)
return false; return false;
if (actor != null && !actor.IsTargetableBy(targeter)) switch (Type)
return false; {
case TargetType.Actor:
return true; return actor.IsTargetableBy(targeter);
case TargetType.FrozenActor:
return frozen.IsValid && frozen.Visible && !frozen.Hidden;
case TargetType.Invalid:
return false;
default:
case TargetType.Terrain:
return true;
}
} }
// Currently all or nothing. // Currently all or nothing.

View File

@@ -39,6 +39,7 @@ namespace OpenRA.Mods.Cnc.Traits
static readonly FrozenActorAction Remove = (fufubg, fal, gps, fa) => static readonly FrozenActorAction Remove = (fufubg, fal, gps, fa) =>
{ {
// Removes the frozen actor. Once done, we no longer need to track GPS updates. // Removes the frozen actor. Once done, we no longer need to track GPS updates.
fa.Invalidate();
fal.Remove(fa); fal.Remove(fa);
gps.UnregisterForOnGpsRefreshed(fufubg.self, fufubg); gps.UnregisterForOnGpsRefreshed(fufubg.self, fufubg);
}; };

View File

@@ -68,11 +68,13 @@ namespace OpenRA.Mods.Common.Traits
frozenStates = new PlayerDictionary<FrozenState>(self.World, (player, playerIndex) => frozenStates = new PlayerDictionary<FrozenState>(self.World, (player, playerIndex) =>
{ {
var frozenActor = new FrozenActor(self, footprint, player, startsRevealed); var frozenActor = new FrozenActor(self, footprint, player, startsRevealed);
if (startsRevealed)
UpdateFrozenActor(self, frozenActor, playerIndex);
player.PlayerActor.Trait<FrozenActorLayer>().Add(frozenActor); player.PlayerActor.Trait<FrozenActorLayer>().Add(frozenActor);
return new FrozenState(frozenActor) { IsVisible = startsRevealed }; return new FrozenState(frozenActor) { IsVisible = startsRevealed };
}); });
if (startsRevealed)
for (var playerIndex = 0; playerIndex < frozenStates.Count; playerIndex++)
UpdateFrozenActor(self, frozenStates[playerIndex].FrozenActor, playerIndex);
} }
void UpdateFrozenActor(Actor self, FrozenActor frozenActor, int playerIndex) void UpdateFrozenActor(Actor self, FrozenActor frozenActor, int playerIndex)

View File

@@ -246,26 +246,20 @@ namespace OpenRA.Mods.Common.Widgets
} }
var frozen = world.ScreenMap.FrozenActorsAtMouse(world.RenderPlayer, worldPixel) var frozen = world.ScreenMap.FrozenActorsAtMouse(world.RenderPlayer, worldPixel)
.Where(a => a.TooltipInfo != null && a.IsValid) .Where(a => a.TooltipInfo != null && a.IsValid && a.Visible && !a.Hidden)
.WithHighestSelectionPriority(worldPixel); .WithHighestSelectionPriority(worldPixel);
if (frozen != null) if (frozen != null)
{ {
var actor = frozen.Actor; FrozenActorTooltip = frozen;
// HACK: This leaks the cloak state through the fog (cloaked buildings will not show tooltips) // HACK: This leaks the tooltip state through the fog
if (actor == null || actor.TraitsImplementing<IVisibilityModifier>().All(t => t.IsVisible(actor, world.RenderPlayer))) // This will cause issues for any downstream mods that use IProvideTooltipInfo on enemy actors
{ if (frozen.Actor != null)
FrozenActorTooltip = frozen; ActorTooltipExtra = frozen.Actor.TraitsImplementing<IProvideTooltipInfo>().ToArray();
// HACK: This leaks the tooltip state through the fog TooltipType = WorldTooltipType.FrozenActor;
// This will cause issues for any downstream mods that use IProvideTooltipInfo on enemy actors return;
if (frozen.Actor != null)
ActorTooltipExtra = frozen.Actor.TraitsImplementing<IProvideTooltipInfo>().ToArray();
TooltipType = WorldTooltipType.FrozenActor;
return;
}
} }
if (resourceLayer != null) if (resourceLayer != null)