Ticket #4431: petra_ally_requests_v0.4.patch
File petra_ally_requests_v0.4.patch, 11.0 KB (added by , 7 years ago) |
---|
-
binaries/data/mods/public/gui/session/messages.js
185 185 g_IsObserver, 186 186 187 187 "/msg": (senderID, addresseeGUID) => 188 addresseeGUID == Engine.GetPlayerGUID()188 addresseeGUID == (Engine.GetPlayerGUID() || "local") 189 189 }; 190 190 191 191 /** -
binaries/data/mods/public/simulation/ai/common-api/gamestate.js
384 384 return ret; 385 385 }; 386 386 387 m.GameState.prototype.getExclusiveMutualAllies = function() 388 { // Player is not included 389 let ret = []; 390 for (let i in this.playerData.isAlly) 391 if (this.playerData.isAlly[i] && 392 this.sharedScript.playersData[i].isAlly[this.player] && +i !== this.player) 393 ret.push(+i); 394 return ret; 395 }; 396 387 397 m.GameState.prototype.isEntityAlly = function(ent) 388 398 { 389 399 if (!ent) -
binaries/data/mods/public/simulation/ai/petra/chatHelper.js
63 63 ] 64 64 }; 65 65 66 m.chatAnswerAllyRequestMessages = { 67 "decline": [ 68 markForTranslation("I cannot accept your offer to be allies %(_player_)s.") 69 ], 70 "declineSuggestNeutral": [ 71 markForTranslation("I will not ally with you %(_player_)s, but I will consider a neutrality pact.") 72 ], 73 "declineRepeatedOffer": [ 74 markForTranslation("%(_player_)s, our previous alliance did not work out, so I must decline your offer.") 75 ], 76 "accept": [ 77 markForTranslation("I will accept your offer to become allies %(_player_)s. We will both benefit from this alliance.") 78 ], 79 "acceptWithTribute": [ 80 markForTranslation("I will ally with you %(_player_)s, but only if you send me a tribute of %(_amount_)s %(_resource_)s."), 81 markForTranslation("%(_player_)s, you must send me a tribute of %(_amount_)s %(_resource_)s for me to accept an alliance.") 82 ], 83 "waitingForTribute": [ 84 markForTranslation("%(_player_)s, my offer still stands. I will ally with you if you send me a tribute of %(_amount_)s %(_resource_)s.") 85 ] 86 }; 87 66 88 m.chatLaunchAttack = function(gameState, player, type) 67 89 { 68 90 Engine.PostCommand(PlayerID, { 69 91 "type": "aichat", 70 "message": "/allies " + pickRandom(this.launchAttackMessages[type === "HugeAttack" ? type: "other"]),92 "message": "/allies " + pickRandom(this.launchAttackMessages[type === "HugeAttack" ? "hugeAttack" : "other"]), 71 93 "translateMessage": true, 72 94 "translateParameters": ["_player_"], 73 95 "parameters": { "_player_": player } … … 140 162 }); 141 163 }; 142 164 165 m.chatAnswerRequestAlly = function(gameState, player, response, requiredTribute) 166 { 167 Engine.PostCommand(PlayerID, { 168 "type": "aichat", 169 "message": "/msg " + gameState.sharedScript.playersData[player].name + " " + 170 pickRandom(this.chatAnswerAllyRequestMessages[response]), 171 "translateMessage": true, 172 "translateParameters": requiredTribute ? ["_amount_", "_resource_", "_player_"] : ["_player_"], 173 "parameters": requiredTribute ? 174 { "_amount_": requiredTribute.wanted, "_resource_": requiredTribute.type, "_player_": player } : 175 { "_player_": player } 176 }); 177 }; 178 143 179 return m; 144 180 }(PETRA); -
binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js
5 5 * Manage the diplomacy: 6 6 * update our cooperative trait 7 7 * sent tribute to allies 8 * decide which player to turn against in "Last Man Standing" mode 9 * respond to diplomacy requests 8 10 */ 9 11 12 /** 13 * If a player sends us an ally request, an Object in this.allyRequests will be created 14 * that includes the request status, and the amount and type of the resource tribute (if any) 15 * that they must send in order for us to accept their request. 16 * In addition, a message will be sent if the player has not sent us a tribute within a minute. 17 * If two minutes pass without a tribute, we will decline their request. 18 */ 10 19 m.DiplomacyManager = function(Config) 11 20 { 12 21 this.Config = Config; … … 15 24 this.nextTributeRequest.set("all", 240); 16 25 this.betrayLapseTime = -1; 17 26 this.waitingToBetray = false; 27 this.allyRequests = new Map(); 18 28 }; 19 29 30 m.DiplomacyManager.prototype.init = function(gameState) 31 { 32 for (let ally of gameState.getExclusiveMutualAllies()) 33 this.allyRequests.set(ally, { "status": "accepted" }); 34 }; 35 20 36 /** 21 37 * Check if any allied needs help (tribute) and sent it if we have enough resource 22 38 * or ask for a tribute if we are in need and one ally can help … … 86 102 // or if our allies attack enemies inside our territory 87 103 for (let evt of events.TributeExchanged) 88 104 { 105 if (evt.to === PlayerID && !gameState.isPlayerAlly(evt.from) && this.allyRequests.has(evt.from)) 106 { 107 let request = this.allyRequests.get(evt.from); 108 if (request.status === "waitingForTribute") 109 { 110 request.wanted -= evt.amounts[request.type]; 111 112 if (request.wanted <= 0) 113 { 114 if (this.Config.debug > 1) 115 API3.warn("Player " + uneval(evt.from) + " has sent the required tribute amount"); 116 117 this.changePlayerDiplomacy(gameState, evt.from, "ally"); 118 request.status = "accepted"; 119 } 120 else 121 { 122 // Reset the warning sent to the player that reminds them to speed up the tributes 123 request.warnTime = gameState.ai.elapsedTime + 60; 124 request.sentWarning = false; 125 } 126 } 127 } 128 89 129 if (evt.to !== PlayerID || !gameState.isPlayerAlly(evt.from)) 90 130 continue; 91 131 let tributes = 0; … … 114 154 115 155 if (events.DiplomacyChanged.length || events.PlayerDefeated.length || events.CeasefireEnded.length) 116 156 this.lastManStandingCheck(gameState); 157 158 for (let evt of events.DiplomacyChanged) 159 { 160 if (evt.otherPlayer !== PlayerID) 161 continue; 162 163 if (this.allyRequests.has(evt.player) && !gameState.sharedScript.playersData[evt.player].isAlly[PlayerID]) 164 { 165 // a player that had requested to be allies changed their stance with us 166 let request = this.allyRequests.get(evt.player); 167 if (request.status === "accepted") 168 request.status = "allianceBroken"; 169 else if (request.status !== "allianceBroken") 170 request.status = "declinedRequest"; 171 } 172 else if (gameState.sharedScript.playersData[evt.player].isAlly[PlayerID] && gameState.isPlayerEnemy(evt.player)) 173 m.chatAnswerRequestAlly(gameState, evt.player, "declineSuggestNeutral"); 174 else if (gameState.sharedScript.playersData[evt.player].isAlly[PlayerID] && gameState.isPlayerNeutral(evt.player)) 175 this.handleAllyRequest(gameState, evt.player); 176 } 117 177 }; 118 178 119 179 /** … … 186 246 this.waitingToBetray = false; 187 247 }; 188 248 249 /** 250 * Do not become allies with a player if the game would be over. 251 * Overall, be reluctant to become allies with any one player. 252 */ 253 m.DiplomacyManager.prototype.handleAllyRequest = function(gameState, player) 254 { 255 let response; 256 let requiredTribute; 257 let request = this.allyRequests.get(player); 258 259 // For any given ally request be likely to permanently decline 260 if (!request && gameState.getPlayerCiv() !== gameState.getPlayerCiv(player) && Math.random() > 0.4 || 261 gameState.getEnemies().length < gameState.getExclusiveMutualAllies().length || 262 gameState.ai.HQ.attackManager.currentEnemyPlayer === player) 263 { 264 this.allyRequests.set(player, { "status": "declinedRequest" }); 265 response = "decline"; 266 } 267 else if (request) 268 { 269 if (request.status === "declinedRequest") 270 response = "decline"; 271 else if (request.status === "allianceBroken") // Previous alliance was broken, so decline 272 response = "declineRepeatedOffer"; 273 else if (request.status === "waitingForTribute") 274 { 275 response = "waitingForTribute"; 276 requiredTribute = request; 277 } 278 } 279 else if (gameState.getEntities(player).length < gameState.getOwnEntities().length && Math.random() > 0.6) 280 { 281 response = "accept"; 282 this.changePlayerDiplomacy(gameState, player, "ally"); 283 this.allyRequests.set(player, { "status": "accepted" }); 284 } 285 else 286 { 287 response = "acceptWithTribute"; 288 requiredTribute = gameState.ai.HQ.pickMostNeededResources(gameState)[0]; 289 requiredTribute.wanted = Math.max(1000, gameState.getOwnUnits().length * 10); 290 this.allyRequests.set(player, { 291 "status": "waitingForTribute", 292 "wanted": requiredTribute.wanted, 293 "type": requiredTribute.type, 294 "warnTime": gameState.ai.elapsedTime + 60, 295 "sentWarning": false 296 }); 297 } 298 m.chatAnswerRequestAlly(gameState, player, response, requiredTribute); 299 }; 300 189 301 m.DiplomacyManager.prototype.changePlayerDiplomacy = function(gameState, player, newDiplomaticStance) 190 302 { 191 303 Engine.PostCommand(PlayerID, { "type": "diplomacy", "player": player, "to": newDiplomaticStance }); … … 195 307 m.chatNewDiplomacy(gameState, player, newDiplomaticStance); 196 308 }; 197 309 310 m.DiplomacyManager.prototype.allyRequestsTributesCheck = function(gameState) 311 { 312 for (let [player, data] of this.allyRequests.entries()) 313 if (data.status === "waitingForTribute" && gameState.ai.elapsedTime > data.warnTime) 314 { 315 if (data.sentWarning) 316 { 317 this.allyRequests.delete(player); 318 m.chatAnswerRequestAlly(gameState, player, "decline"); 319 } 320 else 321 { 322 data.sentWarning = true; 323 data.warnTime = gameState.ai.elapsedTime + 60; 324 m.chatAnswerRequestAlly(gameState, player, "waitingForTribute", { 325 "wanted": data.wanted, 326 "type": data.type 327 }); 328 } 329 } 330 }; 331 198 332 m.DiplomacyManager.prototype.update = function(gameState, events) 199 333 { 200 334 this.checkEvents(gameState, events); … … 204 338 205 339 if (this.waitingToBetray && gameState.ai.elapsedTime > this.betrayLapseTime) 206 340 this.lastManStandingCheck(gameState); 341 342 this.allyRequestsTributesCheck(gameState); 207 343 }; 208 344 209 345 m.DiplomacyManager.prototype.Serialize = function() … … 212 348 "nextTributeUpdate": this.nextTributeUpdate, 213 349 "nextTributeRequest": this.nextTributeRequest, 214 350 "betrayLapseTime": this.betrayLapseTime, 215 "waitingToBetray": this.waitingToBetray 351 "waitingToBetray": this.waitingToBetray, 352 "allyRequests": this.allyRequests 216 353 }; 217 354 }; 218 355 -
binaries/data/mods/public/simulation/ai/petra/startingStrategy.js
13 13 this.attackManager.init(gameState); 14 14 this.navalManager.init(gameState); 15 15 this.tradeManager.init(gameState); 16 this.diplomacyManager.init(gameState); 16 17 17 18 // Make a list of buildable structures from the config file 18 19 this.structureAnalysis(gameState);