0ad/binaries/data/mods/public/simulation/components/Fogging.js
wraitii 7bf933d5f6 Fix VisualActor tech changes for mirages
Correctly recompute the actor when something changes that could modify
it (ownership change, ...).
Make sure mirages are updated when they reappear after being hidden.
Make sure foundations have proper identity classes.
Make sure mirages don't respond to value modifications in the visual
component.
Clarify a few comments.

Earlier work by: Sandarac
Fixes #2907

Differential Revision: https://code.wildfiregames.com/D576
This was SVN commit r24279.
2020-11-28 08:57:15 +00:00

231 lines
6.7 KiB
JavaScript

const VIS_HIDDEN = 0;
const VIS_FOGGED = 1;
const VIS_VISIBLE = 2;
function Fogging() {}
Fogging.prototype.Schema =
"<a:help>Allows this entity to be replaced by mirage entities in the fog-of-war.</a:help>" +
"<empty/>";
Fogging.prototype.Init = function()
{
this.activated = false;
this.mirages = [];
this.miraged = [];
this.seen = [];
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
for (let player = 0; player < numPlayers; ++player)
{
this.mirages.push(INVALID_ENTITY);
this.miraged.push(false);
this.seen.push(false);
}
};
Fogging.prototype.Activate = function()
{
let mustUpdate = !this.activated;
this.activated = true;
if (mustUpdate)
{
// Load a mirage for each player who has already seen the entity
let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
for (let player = 0; player < numPlayers; ++player)
if (this.seen[player] && cmpRangeManager.GetLosVisibility(this.entity, player) != "visible")
this.LoadMirage(player);
}
};
Fogging.prototype.IsActivated = function()
{
return this.activated;
};
Fogging.prototype.LoadMirage = function(player)
{
if (!this.activated)
{
error("LoadMirage called for an entity with fogging deactivated");
return;
}
this.miraged[player] = true;
if (this.mirages[player] == INVALID_ENTITY)
{
var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
var templateName = "mirage|" + cmpTemplateManager.GetCurrentTemplateName(this.entity);
this.mirages[player] = Engine.AddEntity(templateName);
}
var cmpMirage = Engine.QueryInterface(this.mirages[player], IID_Mirage);
if (!cmpMirage)
{
error("Failed to load a mirage for entity " + this.entity);
this.mirages[player] = INVALID_ENTITY;
return;
}
// Copy basic mirage properties
cmpMirage.SetPlayer(player);
cmpMirage.SetParent(this.entity);
// Copy cmpOwnership data
var cmpParentOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
var cmpMirageOwnership = Engine.QueryInterface(this.mirages[player], IID_Ownership);
if (!cmpParentOwnership || !cmpMirageOwnership)
{
error("Failed to copy the ownership data of the fogged entity " + this.entity);
return;
}
cmpMirageOwnership.SetOwner(cmpParentOwnership.GetOwner());
// Copy cmpPosition data
var cmpParentPosition = Engine.QueryInterface(this.entity, IID_Position);
var cmpMiragePosition = Engine.QueryInterface(this.mirages[player], IID_Position);
if (!cmpParentPosition || !cmpMiragePosition)
{
error("Failed to copy the position data of the fogged entity " + this.entity);
return;
}
if (!cmpParentPosition.IsInWorld())
return;
var pos = cmpParentPosition.GetPosition();
cmpMiragePosition.JumpTo(pos.x, pos.z);
var rot = cmpParentPosition.GetRotation();
cmpMiragePosition.SetYRotation(rot.y);
cmpMiragePosition.SetXZRotation(rot.x, rot.z);
// Copy cmpVisualActor data
var cmpParentVisualActor = Engine.QueryInterface(this.entity, IID_Visual);
var cmpMirageVisualActor = Engine.QueryInterface(this.mirages[player], IID_Visual);
if (!cmpParentVisualActor || !cmpMirageVisualActor)
{
error("Failed to copy the visual data of the fogged entity " + this.entity);
return;
}
cmpMirageVisualActor.RecomputeActorName();
cmpMirageVisualActor.SetActorSeed(cmpParentVisualActor.GetActorSeed());
// Store valuable information into the mirage component (especially for the GUI)
var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
if (cmpIdentity)
cmpMirage.CopyIdentity(cmpIdentity);
var cmpFoundation = Engine.QueryInterface(this.entity, IID_Foundation);
if (cmpFoundation)
cmpMirage.CopyFoundation(cmpFoundation);
var cmpRepairable = Engine.QueryInterface(this.entity, IID_Repairable);
if (cmpRepairable && !cmpFoundation)
cmpMirage.CopyRepairable(cmpRepairable);
var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
if (cmpHealth)
cmpMirage.CopyHealth(cmpHealth);
var cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable);
if (cmpCapturable)
cmpMirage.CopyCapturable(cmpCapturable);
var cmpResourceSupply = Engine.QueryInterface(this.entity, IID_ResourceSupply);
if (cmpResourceSupply)
cmpMirage.CopyResourceSupply(cmpResourceSupply);
var cmpMarket = Engine.QueryInterface(this.entity, IID_Market);
if (cmpMarket)
cmpMirage.CopyMarket(cmpMarket);
// Notify the GUI the entity has been replaced by a mirage, in case it is selected at this moment
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
cmpGuiInterface.AddMiragedEntity(player, this.entity, this.mirages[player]);
// Notify the range manager the visibility of this entity must be updated
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
cmpRangeManager.RequestVisibilityUpdate(this.entity);
};
Fogging.prototype.ForceMiraging = function(player)
{
if (!this.activated)
return;
this.seen[player] = true;
this.LoadMirage(player);
};
Fogging.prototype.IsMiraged = function(player)
{
if (player < 0 || player >= this.mirages.length)
return false;
return this.miraged[player];
};
Fogging.prototype.GetMirage = function(player)
{
if (player < 0 || player >= this.mirages.length)
return INVALID_ENTITY;
return this.mirages[player];
};
Fogging.prototype.WasSeen = function(player)
{
if (player < 0 || player >= this.seen.length)
return false;
return this.seen[player];
};
Fogging.prototype.OnOwnershipChanged = function(msg)
{
// Always activate fogging for non-Gaia entities
if (msg.to > 0)
this.Activate();
if (msg.to != -1)
return;
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
for (let player = 0; player < this.mirages.length; ++player)
{
if (this.mirages[player] == INVALID_ENTITY)
continue;
// When this.entity is in the line of sight of the player, its mirage is hidden, rather than destroyed, to save on performance.
// All hidden mirages can be destroyed now (they won't be needed again), and other mirages will destroy themselves when they get out of the fog.
if (cmpRangeManager.GetLosVisibility(this.mirages[player], player) == "hidden")
{
Engine.DestroyEntity(this.mirages[player]);
continue;
}
let cmpMirage = Engine.QueryInterface(this.mirages[player], IID_Mirage);
if (cmpMirage)
cmpMirage.SetParent(INVALID_ENTITY);
}
};
Fogging.prototype.OnVisibilityChanged = function(msg)
{
if (msg.player < 0 || msg.player >= this.mirages.length)
return;
if (msg.newVisibility == VIS_VISIBLE)
{
this.miraged[msg.player] = false;
this.seen[msg.player] = true;
}
if (msg.newVisibility == VIS_FOGGED && this.activated)
this.LoadMirage(msg.player);
};
Engine.RegisterComponentType(IID_Fogging, "Fogging", Fogging);