Line data Source code
1 : function TerritoryDecay() {} 2 : 3 0 : TerritoryDecay.prototype.Schema = ` 4 : <element name='DecayRate' a:help='Decay rate in capture points per second'> 5 : <choice><ref name='positiveDecimal'/><value>Infinity</value></choice> 6 : </element> 7 : <element name='Territory' a:help='Specifies territory in which this entity will decay.'> 8 : <list> 9 : <oneOrMore> 10 : <choice> 11 : <value>neutral</value> 12 : <value>enemy</value> 13 : </choice> 14 : </oneOrMore> 15 : </list> 16 : </element> 17 : `; 18 : 19 0 : TerritoryDecay.prototype.Init = function() 20 : { 21 0 : this.decaying = false; 22 0 : this.connectedNeighbours = new Array(Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers()).fill(0); 23 0 : this.territoryOwnership = !isFinite(+this.template.DecayRate); 24 : }; 25 : 26 0 : TerritoryDecay.prototype.IsConnected = function() 27 : { 28 0 : this.connectedNeighbours.fill(0); 29 : 30 0 : var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 31 0 : if (!cmpPosition || !cmpPosition.IsInWorld()) 32 0 : return false; 33 : 34 0 : var cmpPlayer = QueryOwnerInterface(this.entity); 35 0 : if (!cmpPlayer) 36 0 : return true;// something without ownership can't decay 37 : 38 0 : const decayTerritory = ApplyValueModificationsToEntity("TerritoryDecay/Territory", this.template.Territory, this.entity); 39 : 40 0 : var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); 41 0 : var pos = cmpPosition.GetPosition2D(); 42 0 : var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); 43 0 : if (tileOwner == 0) 44 : { 45 0 : this.connectedNeighbours[0] = 1; 46 0 : return cmpPlayer.GetPlayerID() == 0 || decayTerritory.indexOf("neutral") === -1; 47 : } 48 : 49 0 : var tileConnected = cmpTerritoryManager.IsConnected(pos.x, pos.y); 50 0 : if (tileConnected && !cmpPlayer.IsMutualAlly(tileOwner)) 51 : { 52 0 : this.connectedNeighbours[tileOwner] = 1; 53 0 : return decayTerritory.indexOf("enemy") === -1; 54 : } 55 : 56 0 : if (tileConnected) 57 0 : return true; 58 : 59 : // Special-case: if the tile is unconnected, non-own territory, decay towards gaia. 60 : // TODO: this is not great, see #4749 61 0 : if (cmpPlayer.GetPlayerID() != tileOwner) 62 : { 63 0 : this.connectedNeighbours[0] = 1; 64 0 : return false; 65 : } 66 : 67 0 : this.connectedNeighbours = cmpTerritoryManager.GetNeighbours(pos.x, pos.y, true); 68 : 69 0 : let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers(); 70 0 : for (var i = 1; i < numPlayers; ++i) 71 0 : if (this.connectedNeighbours[i] > 0 && cmpPlayer.IsMutualAlly(i)) 72 : { 73 : // don't decay if connected to a connected ally; disable blinking 74 0 : cmpTerritoryManager.SetTerritoryBlinking(pos.x, pos.y, false); 75 0 : return true; 76 : } 77 : 78 0 : cmpTerritoryManager.SetTerritoryBlinking(pos.x, pos.y, true); 79 0 : return false; 80 : }; 81 : 82 0 : TerritoryDecay.prototype.IsDecaying = function() 83 : { 84 0 : return this.decaying; 85 : }; 86 : 87 0 : TerritoryDecay.prototype.GetDecayRate = function() 88 : { 89 0 : return ApplyValueModificationsToEntity( 90 : "TerritoryDecay/DecayRate", 91 : +this.template.DecayRate, 92 : this.entity); 93 : }; 94 : 95 : /** 96 : * Get the number of connected bordering tiles to this region 97 : * Only valid when this.IsDecaying() 98 : */ 99 0 : TerritoryDecay.prototype.GetConnectedNeighbours = function() 100 : { 101 0 : return this.connectedNeighbours; 102 : }; 103 : 104 0 : TerritoryDecay.prototype.UpdateDecayState = function() 105 : { 106 0 : let decaying = !this.IsConnected() && this.GetDecayRate() > 0; 107 0 : if (decaying === this.decaying) 108 0 : return; 109 0 : this.decaying = decaying; 110 0 : Engine.PostMessage(this.entity, MT_TerritoryDecayChanged, { "entity": this.entity, "to": decaying, "rate": this.GetDecayRate() }); 111 : }; 112 : 113 0 : TerritoryDecay.prototype.UpdateOwner = function() 114 : { 115 0 : let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 116 0 : let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 117 0 : if (!cmpOwnership || !cmpPosition || !cmpPosition.IsInWorld()) 118 0 : return; 119 0 : let cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); 120 0 : let pos = cmpPosition.GetPosition2D(); 121 0 : let tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); 122 0 : if (tileOwner != cmpOwnership.GetOwner()) 123 0 : cmpOwnership.SetOwner(tileOwner); 124 : }; 125 : 126 0 : TerritoryDecay.prototype.OnTerritoriesChanged = function(msg) 127 : { 128 0 : if (this.territoryOwnership) 129 0 : this.UpdateOwner(); 130 : else 131 0 : this.UpdateDecayState(); 132 : }; 133 : 134 0 : TerritoryDecay.prototype.OnTerritoryPositionChanged = function(msg) 135 : { 136 0 : if (this.territoryOwnership) 137 0 : this.UpdateOwner(); 138 : else 139 0 : this.UpdateDecayState(); 140 : }; 141 : 142 0 : TerritoryDecay.prototype.OnDiplomacyChanged = function(msg) 143 : { 144 : // Can change the connectedness of certain areas 145 0 : if (!this.territoryOwnership) 146 0 : this.UpdateDecayState(); 147 : }; 148 : 149 0 : TerritoryDecay.prototype.OnOwnershipChanged = function(msg) 150 : { 151 : // Update the list of TerritoryDecay components in the manager 152 0 : if (msg.from == INVALID_PLAYER || msg.to == INVALID_PLAYER) 153 : { 154 0 : let cmpTerritoryDecayManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryDecayManager); 155 0 : if (msg.from == INVALID_PLAYER) 156 0 : cmpTerritoryDecayManager.Add(this.entity); 157 : else 158 0 : cmpTerritoryDecayManager.Remove(this.entity); 159 : } 160 : 161 : // if it influences the territory, wait until we get a TerritoriesChanged message 162 0 : if (!this.territoryOwnership && !Engine.QueryInterface(this.entity, IID_TerritoryInfluence)) 163 0 : this.UpdateDecayState(); 164 : }; 165 : 166 0 : TerritoryDecay.prototype.HasTerritoryOwnership = function() 167 : { 168 0 : return this.territoryOwnership; 169 : }; 170 : 171 0 : Engine.RegisterComponentType(IID_TerritoryDecay, "TerritoryDecay", TerritoryDecay);