Line data Source code
1 0 : const VIS_HIDDEN = 0; 2 0 : const VIS_FOGGED = 1; 3 0 : const VIS_VISIBLE = 2; 4 : 5 : function Fogging() {} 6 : 7 0 : Fogging.prototype.Schema = 8 : "<a:help>Allows this entity to be replaced by mirage entities in the fog-of-war.</a:help>" + 9 : "<empty/>"; 10 : 11 : /** 12 : * The components that we want to mirage when present. 13 : * Assumes that a function "Mirage()" is present. 14 : */ 15 0 : Fogging.prototype.componentsToMirage = [ 16 : IID_Capturable, 17 : IID_Foundation, 18 : IID_Health, 19 : IID_Identity, 20 : IID_Market, 21 : IID_Repairable, 22 : IID_Resistance, 23 : IID_ResourceSupply 24 : ]; 25 : 26 0 : Fogging.prototype.Init = function() 27 : { 28 0 : this.activated = false; 29 0 : this.mirages = []; 30 0 : this.miraged = []; 31 0 : this.seen = []; 32 : 33 0 : let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); 34 0 : for (let player = 0; player < numPlayers; ++player) 35 : { 36 0 : this.mirages.push(INVALID_ENTITY); 37 0 : this.miraged.push(false); 38 0 : this.seen.push(false); 39 : } 40 : }; 41 : 42 0 : Fogging.prototype.Activate = function() 43 : { 44 0 : let mustUpdate = !this.activated; 45 0 : this.activated = true; 46 : 47 0 : if (mustUpdate) 48 : { 49 : // Load a mirage for each player who has already seen the entity. 50 0 : let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); 51 0 : let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 52 0 : for (let player = 0; player < numPlayers; ++player) 53 0 : if (this.seen[player] && cmpRangeManager.GetLosVisibility(this.entity, player) != "visible") 54 0 : this.LoadMirage(player); 55 : } 56 : }; 57 : 58 0 : Fogging.prototype.IsActivated = function() 59 : { 60 0 : return this.activated; 61 : }; 62 : 63 0 : Fogging.prototype.LoadMirage = function(player) 64 : { 65 0 : if (!this.activated) 66 : { 67 0 : error("LoadMirage called for an entity with fogging deactivated"); 68 0 : return; 69 : } 70 : 71 0 : this.miraged[player] = true; 72 : 73 0 : if (this.mirages[player] == INVALID_ENTITY) 74 0 : this.mirages[player] = Engine.AddEntity("mirage|" + Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager).GetCurrentTemplateName(this.entity)); 75 : 76 0 : let cmpMirage = Engine.QueryInterface(this.mirages[player], IID_Mirage); 77 0 : if (!cmpMirage) 78 : { 79 0 : error("Failed to load a mirage for entity " + this.entity); 80 0 : this.mirages[player] = INVALID_ENTITY; 81 0 : return; 82 : } 83 : 84 : // Copy basic mirage properties. 85 0 : cmpMirage.SetPlayer(player); 86 0 : cmpMirage.SetParent(this.entity); 87 : 88 0 : let cmpParentOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 89 0 : let cmpMirageOwnership = Engine.QueryInterface(this.mirages[player], IID_Ownership); 90 0 : if (!cmpParentOwnership || !cmpMirageOwnership) 91 : { 92 0 : error("Failed to copy the ownership data of the fogged entity " + this.entity); 93 0 : return; 94 : } 95 0 : cmpMirageOwnership.SetOwner(cmpParentOwnership.GetOwner()); 96 : 97 0 : let cmpParentPosition = Engine.QueryInterface(this.entity, IID_Position); 98 0 : let cmpMiragePosition = Engine.QueryInterface(this.mirages[player], IID_Position); 99 0 : if (!cmpParentPosition || !cmpMiragePosition) 100 : { 101 0 : error("Failed to copy the position data of the fogged entity " + this.entity); 102 0 : return; 103 : } 104 0 : if (!cmpParentPosition.IsInWorld()) 105 0 : return; 106 0 : let pos = cmpParentPosition.GetPosition(); 107 0 : cmpMiragePosition.JumpTo(pos.x, pos.z); 108 0 : let rot = cmpParentPosition.GetRotation(); 109 0 : cmpMiragePosition.SetYRotation(rot.y); 110 0 : cmpMiragePosition.SetXZRotation(rot.x, rot.z); 111 : 112 0 : let cmpParentVisualActor = Engine.QueryInterface(this.entity, IID_Visual); 113 0 : let cmpMirageVisualActor = Engine.QueryInterface(this.mirages[player], IID_Visual); 114 0 : if (!cmpParentVisualActor || !cmpMirageVisualActor) 115 : { 116 0 : error("Failed to copy the visual data of the fogged entity " + this.entity); 117 0 : return; 118 : } 119 : 120 0 : cmpMirageVisualActor.RecomputeActorName(); 121 0 : cmpMirageVisualActor.SetActorSeed(cmpParentVisualActor.GetActorSeed()); 122 : 123 : // Store valuable information into the mirage component (especially for the GUI). 124 0 : for (let component of this.componentsToMirage) 125 0 : cmpMirage.CopyComponent(component); 126 : 127 : // Notify the GUI the entity has been replaced by a mirage, in case it is selected at this moment. 128 0 : Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).AddMiragedEntity(player, this.entity, this.mirages[player]); 129 : 130 : // Notify the range manager the visibility of this entity must be updated. 131 0 : Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).RequestVisibilityUpdate(this.entity); 132 : }; 133 : 134 : /** 135 : * Should only be called for entities that are currently explored, but not visible or 136 : * things will 'bug out' (double entities and such). 137 : */ 138 0 : Fogging.prototype.ForceMiraging = function(player) 139 : { 140 0 : this.seen[player] = true; 141 : 142 0 : if (!this.activated) 143 0 : return; 144 : 145 0 : this.LoadMirage(player); 146 : }; 147 : 148 0 : Fogging.prototype.IsMiraged = function(player) 149 : { 150 0 : if (player < 0 || player >= this.mirages.length) 151 0 : return false; 152 : 153 0 : return this.miraged[player]; 154 : }; 155 : 156 0 : Fogging.prototype.GetMirage = function(player) 157 : { 158 0 : if (player < 0 || player >= this.mirages.length) 159 0 : return INVALID_ENTITY; 160 : 161 0 : return this.mirages[player]; 162 : }; 163 : 164 0 : Fogging.prototype.WasSeen = function(player) 165 : { 166 0 : if (player < 0 || player >= this.seen.length) 167 0 : return false; 168 : 169 0 : return this.seen[player]; 170 : }; 171 : 172 0 : Fogging.prototype.OnOwnershipChanged = function(msg) 173 : { 174 : // Always activate fogging for non-Gaia entities. 175 0 : if (msg.to > 0) 176 0 : this.Activate(); 177 : 178 0 : if (msg.to != -1) 179 0 : return; 180 : 181 0 : let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 182 0 : for (let player = 0; player < this.mirages.length; ++player) 183 : { 184 0 : if (this.mirages[player] == INVALID_ENTITY) 185 0 : continue; 186 : 187 : // When this.entity is in the line of sight of the player, its mirage is hidden, rather than destroyed, to save on performance. 188 : // 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. 189 0 : if (cmpRangeManager.GetLosVisibility(this.mirages[player], player) == "hidden") 190 : { 191 0 : Engine.DestroyEntity(this.mirages[player]); 192 0 : continue; 193 : } 194 : 195 0 : let cmpMirage = Engine.QueryInterface(this.mirages[player], IID_Mirage); 196 0 : if (cmpMirage) 197 0 : cmpMirage.SetParent(INVALID_ENTITY); 198 : } 199 : }; 200 : 201 0 : Fogging.prototype.OnVisibilityChanged = function(msg) 202 : { 203 0 : if (msg.player < 0 || msg.player >= this.mirages.length) 204 0 : return; 205 : 206 0 : if (msg.newVisibility == VIS_VISIBLE) 207 : { 208 0 : this.miraged[msg.player] = false; 209 0 : this.seen[msg.player] = true; 210 : } 211 : 212 0 : if (msg.newVisibility == VIS_FOGGED && this.activated) 213 0 : this.LoadMirage(msg.player); 214 : }; 215 : 216 0 : Engine.RegisterComponentType(IID_Fogging, "Fogging", Fogging);