mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-07-04 05:55:47 -07:00
petra: respond to neutral requests from enemies, patch by Sandarac, refs #4431
This was SVN commit r19161.
This commit is contained in:
parent
8fec942e8a
commit
5725542fc4
4 changed files with 120 additions and 67 deletions
|
|
@ -455,6 +455,26 @@ m.AttackManager.prototype.getEnemyPlayer = function(gameState, attack)
|
|||
return enemyPlayer;
|
||||
};
|
||||
|
||||
/** f.e. if we have changed diplomacy with another player. */
|
||||
m.AttackManager.prototype.cancelAttacksAgainstPlayer = function(player)
|
||||
{
|
||||
for (let attackType in this.upcomingAttacks)
|
||||
for (let attack of this.upcomingAttacks[attackType])
|
||||
if (attack.targetPlayer === player)
|
||||
attack.targetPlayer = undefined;
|
||||
|
||||
for (let attackType in this.startedAttacks)
|
||||
for (let i = 0; i < this.startedAttacks[attackType].length; ++i)
|
||||
{
|
||||
let attack = this.startedAttacks[attackType][i];
|
||||
if (attack.targetPlayer === player)
|
||||
{
|
||||
attack.Abort(gameState);
|
||||
this.startedAttacks[attackType].splice(i--, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
m.AttackManager.prototype.Serialize = function()
|
||||
{
|
||||
let properties = {
|
||||
|
|
|
|||
|
|
@ -63,26 +63,50 @@ m.newDiplomacyMessages = {
|
|||
]
|
||||
};
|
||||
|
||||
m.answerAllyRequestMessages = {
|
||||
"decline": [
|
||||
markForTranslation("I cannot accept your offer to be allies %(_player_)s.")
|
||||
],
|
||||
"declineSuggestNeutral": [
|
||||
markForTranslation("I will not ally with you %(_player_)s, but I will consider a neutrality pact.")
|
||||
],
|
||||
"declineRepeatedOffer": [
|
||||
markForTranslation("%(_player_)s, our previous alliance did not work out, so I must decline your offer.")
|
||||
],
|
||||
"accept": [
|
||||
markForTranslation("I will accept your offer to become allies %(_player_)s. We will both benefit from this alliance.")
|
||||
],
|
||||
"acceptWithTribute": [
|
||||
markForTranslation("I will ally with you %(_player_)s, but only if you send me a tribute of %(_amount_)s %(_resource_)s."),
|
||||
markForTranslation("%(_player_)s, you must send me a tribute of %(_amount_)s %(_resource_)s for me to accept an alliance.")
|
||||
],
|
||||
"waitingForTribute": [
|
||||
markForTranslation("%(_player_)s, my offer still stands. I will ally with you if you send me a tribute of %(_amount_)s %(_resource_)s.")
|
||||
]
|
||||
m.answerDiplomacyRequestMessages = {
|
||||
"ally": {
|
||||
"decline": [
|
||||
markForTranslation("I cannot accept your offer to be allies %(_player_)s.")
|
||||
],
|
||||
"declineSuggestNeutral": [
|
||||
markForTranslation("I will not ally with you %(_player_)s, but I will consider a neutrality pact.")
|
||||
],
|
||||
"declineRepeatedOffer": [
|
||||
markForTranslation("%(_player_)s, our previous alliance did not work out, so I must decline your offer.")
|
||||
],
|
||||
"accept": [
|
||||
markForTranslation("I will accept your offer to become allies %(_player_)s. We will both benefit from this alliance.")
|
||||
],
|
||||
"acceptWithTribute": [
|
||||
markForTranslation("I will ally with you %(_player_)s, but only if you send me a tribute of %(_amount_)s %(_resource_)s."),
|
||||
markForTranslation("%(_player_)s, you must send me a tribute of %(_amount_)s %(_resource_)s for me to accept an alliance.")
|
||||
],
|
||||
"waitingForTribute": [
|
||||
markForTranslation("%(_player_)s, my offer still stands. I will ally with you if you send me a tribute of %(_amount_)s %(_resource_)s."),
|
||||
markForTranslation("%(_player_)s, if you do not send me part of the %(_amount_)s %(_resource_)s tribute soon, I will break off our negotiations.")
|
||||
]
|
||||
},
|
||||
"neutral": {
|
||||
"decline": [
|
||||
markForTranslation("I will not become neutral with you %(_player_)s."),
|
||||
markForTranslation("%(_player_)s, I must decline your request for a neutrality pact.")
|
||||
],
|
||||
"declineRepeatedOffer": [
|
||||
markForTranslation("Our previous neutrality agreement ended in failure %(_player_)s; I will not consider another one.")
|
||||
],
|
||||
"accept": [
|
||||
markForTranslation("I welcome your request for peace between our civilizations %(_player_)s. I will accept."),
|
||||
markForTranslation("%(_player_)s, I will accept your neutrality request. May both our civilizations benefit.")
|
||||
],
|
||||
"acceptWithTribute": [
|
||||
markForTranslation("If you tribute me %(_amount_)s %(_resource_)s, I will accept your neutrality request %(_player_)s."),
|
||||
markForTranslation("%(_player_)s, if you send me %(_amount_)s %(_resource_)s, I will accept a neutrality pact.")
|
||||
],
|
||||
"waitingForTribute": [
|
||||
markForTranslation("%(_player_)s, I will not accept your neutrality request unless you tribute me %(_amount_)s %(_resource_)s soon."),
|
||||
markForTranslation("%(_player_)s, if you do not send me part of the %(_amount_)s %(_resource_)s tribute soon, I will break off our negotiations.")
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
m.chatLaunchAttack = function(gameState, player, type)
|
||||
|
|
@ -162,12 +186,12 @@ m.chatNewDiplomacy = function(gameState, player, newDiplomaticStance)
|
|||
});
|
||||
};
|
||||
|
||||
m.chatAnswerRequestAlly = function(gameState, player, response, requiredTribute)
|
||||
m.chatAnswerRequestDiplomacy = function(gameState, player, requestType, response, requiredTribute)
|
||||
{
|
||||
Engine.PostCommand(PlayerID, {
|
||||
"type": "aichat",
|
||||
"message": "/msg " + gameState.sharedScript.playersData[player].name + " " +
|
||||
pickRandom(this.answerAllyRequestMessages[response]),
|
||||
pickRandom(this.answerDiplomacyRequestMessages[requestType][response]),
|
||||
"translateMessage": true,
|
||||
"translateParameters": requiredTribute ? ["_amount_", "_resource_", "_player_"] : ["_player_"],
|
||||
"parameters": requiredTribute ?
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ var PETRA = function(m)
|
|||
*/
|
||||
|
||||
/**
|
||||
* If a player sends us an ally request, an Object in this.allyRequests will be created
|
||||
* If a player sends us an ally or neutral request, an Object in this.diplomacyRequests will be created
|
||||
* that includes the request status, and the amount and type of the resource tribute (if any)
|
||||
* that they must send in order for us to accept their request.
|
||||
* In addition, a message will be sent if the player has not sent us a tribute within a minute.
|
||||
|
|
@ -24,24 +24,29 @@ m.DiplomacyManager = function(Config)
|
|||
this.nextTributeRequest.set("all", 240);
|
||||
this.betrayLapseTime = -1;
|
||||
this.waitingToBetray = false;
|
||||
this.allyRequests = new Map();
|
||||
this.diplomacyRequests = new Map();
|
||||
};
|
||||
|
||||
/**
|
||||
* If there are any players that are allied with us but we are not allied with them,
|
||||
* treat this situation like an ally request.
|
||||
* If there are any players that are allied/neutral with us but we are not allied/neutral with them,
|
||||
* treat this situation like an ally/neutral request.
|
||||
*/
|
||||
m.DiplomacyManager.prototype.init = function(gameState)
|
||||
{
|
||||
if (!gameState.getAlliedVictory() && !gameState.isCeasefireActive())
|
||||
this.lastManStandingCheck(gameState);
|
||||
|
||||
for (let i = 1; i < gameState.sharedScript.playersData.length; ++i)
|
||||
{
|
||||
if (i === PlayerID)
|
||||
continue;
|
||||
|
||||
if (gameState.isPlayerMutualAlly(i))
|
||||
this.allyRequests.set(i, { "status": "accepted" });
|
||||
this.diplomacyRequests.set(i, { "requestType": "ally", "status": "accepted" });
|
||||
else if (gameState.sharedScript.playersData[i].isAlly[PlayerID])
|
||||
this.handleAllyRequest(gameState, i);
|
||||
this.handleDiplomacyRequest(gameState, i, "ally");
|
||||
else if (gameState.sharedScript.playersData[i].isNeutral[PlayerID] && gameState.isPlayerEnemy(i))
|
||||
this.handleDiplomacyRequest(gameState, i, "neutral");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -114,9 +119,9 @@ m.DiplomacyManager.prototype.checkEvents = function (gameState, events)
|
|||
// or if our allies attack enemies inside our territory
|
||||
for (let evt of events.TributeExchanged)
|
||||
{
|
||||
if (evt.to === PlayerID && !gameState.isPlayerAlly(evt.from) && this.allyRequests.has(evt.from))
|
||||
if (evt.to === PlayerID && !gameState.isPlayerAlly(evt.from) && this.diplomacyRequests.has(evt.from))
|
||||
{
|
||||
let request = this.allyRequests.get(evt.from);
|
||||
let request = this.diplomacyRequests.get(evt.from);
|
||||
if (request.status === "waitingForTribute")
|
||||
{
|
||||
request.wanted -= evt.amounts[request.type];
|
||||
|
|
@ -126,10 +131,10 @@ m.DiplomacyManager.prototype.checkEvents = function (gameState, events)
|
|||
if (this.Config.debug > 1)
|
||||
API3.warn("Player " + uneval(evt.from) + " has sent the required tribute amount");
|
||||
|
||||
this.changePlayerDiplomacy(gameState, evt.from, "ally");
|
||||
this.changePlayerDiplomacy(gameState, evt.from, request.requestType);
|
||||
request.status = "accepted";
|
||||
}
|
||||
else
|
||||
else if (evt.amounts[request.type] > 0)
|
||||
{
|
||||
// Reset the warning sent to the player that reminds them to speed up the tributes
|
||||
request.warnTime = gameState.ai.elapsedTime + 60;
|
||||
|
|
@ -172,31 +177,24 @@ m.DiplomacyManager.prototype.checkEvents = function (gameState, events)
|
|||
if (evt.otherPlayer !== PlayerID)
|
||||
continue;
|
||||
|
||||
if (this.allyRequests.has(evt.player) && !gameState.sharedScript.playersData[evt.player].isAlly[PlayerID])
|
||||
if (this.diplomacyRequests.has(evt.player) && !gameState.sharedScript.playersData[evt.player].isAlly[PlayerID])
|
||||
{
|
||||
// a player that had requested to be allies changed their stance with us
|
||||
let request = this.allyRequests.get(evt.player);
|
||||
let request = this.diplomacyRequests.get(evt.player);
|
||||
if (request.status === "accepted")
|
||||
request.status = "allianceBroken";
|
||||
else if (request.status !== "allianceBroken")
|
||||
request.status = "declinedRequest";
|
||||
}
|
||||
else if (gameState.sharedScript.playersData[evt.player].isAlly[PlayerID] && gameState.isPlayerEnemy(evt.player))
|
||||
m.chatAnswerRequestAlly(gameState, evt.player, "declineSuggestNeutral");
|
||||
m.chatAnswerRequestDiplomacy(gameState, evt.player, "ally", "declineSuggestNeutral");
|
||||
else if (gameState.sharedScript.playersData[evt.player].isAlly[PlayerID] && gameState.isPlayerNeutral(evt.player))
|
||||
this.handleAllyRequest(gameState, evt.player);
|
||||
this.handleDiplomacyRequest(gameState, evt.player, "ally");
|
||||
else if (gameState.sharedScript.playersData[evt.player].isNeutral[PlayerID] && gameState.isPlayerEnemy(evt.player))
|
||||
this.handleDiplomacyRequest(gameState, evt.player, "neutral");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check the diplomacy at the start of the game
|
||||
*/
|
||||
m.DiplomacyManager.prototype.diplomacyCheck = function(gameState)
|
||||
{
|
||||
if (!gameState.getAlliedVictory() && !gameState.isCeasefireActive())
|
||||
this.lastManStandingCheck(gameState);
|
||||
};
|
||||
|
||||
/**
|
||||
* If the "Last Man Standing" option is enabled, check if the only remaining players are allies or neutral.
|
||||
* If so, turn against the strongest first, but be more likely to first turn against neutral players, if there are any.
|
||||
|
|
@ -253,30 +251,39 @@ m.DiplomacyManager.prototype.lastManStandingCheck = function(gameState)
|
|||
}
|
||||
|
||||
if (playerToTurnAgainst)
|
||||
{
|
||||
this.changePlayerDiplomacy(gameState, playerToTurnAgainst, "enemy");
|
||||
let request = this.diplomacyRequests.get(playerToTurnAgainst);
|
||||
if (request && request.status !== "allianceBroken")
|
||||
{
|
||||
if (request.status === "waitingForTribute")
|
||||
m.chatAnswerRequestDiplomacy(gameState, player, request.requestType, "decline");
|
||||
request.status = request.status === "accepted" ? "allianceBroken" : "declinedRequest";
|
||||
}
|
||||
}
|
||||
this.betrayLapseTime = -1;
|
||||
this.waitingToBetray = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Do not become allies with a player if the game would be over.
|
||||
* Overall, be reluctant to become allies with any one player.
|
||||
* Overall, be reluctant to become allies with any one player, but be more likely to accept neutral requests.
|
||||
*/
|
||||
m.DiplomacyManager.prototype.handleAllyRequest = function(gameState, player)
|
||||
m.DiplomacyManager.prototype.handleDiplomacyRequest = function(gameState, player, requestType)
|
||||
{
|
||||
let response;
|
||||
let requiredTribute;
|
||||
let request = this.allyRequests.get(player);
|
||||
let request = this.diplomacyRequests.get(player);
|
||||
let moreEnemiesThanAllies = gameState.getEnemies().length > gameState.getMutualAllies().length;
|
||||
|
||||
// For any given ally request be likely to permanently decline
|
||||
// For any given diplomacy request be likely to permanently decline
|
||||
if (!request && gameState.getPlayerCiv() !== gameState.getPlayerCiv(player) && Math.random() > 0.4 ||
|
||||
gameState.getEnemies().length < gameState.getMutualAllies().length ||
|
||||
gameState.ai.HQ.attackManager.currentEnemyPlayer === player)
|
||||
!moreEnemiesThanAllies || gameState.ai.HQ.attackManager.currentEnemyPlayer === player)
|
||||
{
|
||||
this.allyRequests.set(player, { "status": "declinedRequest" });
|
||||
this.diplomacyRequests.set(player, { "requestType": requestType, "status": "declinedRequest" });
|
||||
response = "decline";
|
||||
}
|
||||
else if (request)
|
||||
else if (request && request.status !== "accepted" && request.requestType !== "ally")
|
||||
{
|
||||
if (request.status === "declinedRequest")
|
||||
response = "decline";
|
||||
|
|
@ -288,30 +295,34 @@ m.DiplomacyManager.prototype.handleAllyRequest = function(gameState, player)
|
|||
requiredTribute = request;
|
||||
}
|
||||
}
|
||||
else if (gameState.getEntities(player).length < gameState.getOwnEntities().length && Math.random() > 0.6)
|
||||
else if (requestType === "ally" && gameState.getEntities(player).length < gameState.getOwnEntities().length &&
|
||||
Math.random() > 0.6 || requestType === "neutral" && moreEnemiesThanAllies && Math.random() > 0.2)
|
||||
{
|
||||
response = "accept";
|
||||
this.changePlayerDiplomacy(gameState, player, "ally");
|
||||
this.allyRequests.set(player, { "status": "accepted" });
|
||||
this.changePlayerDiplomacy(gameState, player, requestType);
|
||||
this.diplomacyRequests.set(player, { "requestType": requestType, "status": "accepted" });
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "acceptWithTribute";
|
||||
requiredTribute = gameState.ai.HQ.pickMostNeededResources(gameState)[0];
|
||||
requiredTribute.wanted = Math.max(1000, gameState.getOwnUnits().length * 10);
|
||||
this.allyRequests.set(player, {
|
||||
requiredTribute.wanted = Math.max(1000, gameState.getOwnUnits().length * requestType === "ally" ? 10 : 5)
|
||||
this.diplomacyRequests.set(player, {
|
||||
"status": "waitingForTribute",
|
||||
"wanted": requiredTribute.wanted,
|
||||
"type": requiredTribute.type,
|
||||
"warnTime": gameState.ai.elapsedTime + 60,
|
||||
"sentWarning": false
|
||||
"sentWarning": false,
|
||||
"requestType": requestType
|
||||
});
|
||||
}
|
||||
m.chatAnswerRequestAlly(gameState, player, response, requiredTribute);
|
||||
m.chatAnswerRequestDiplomacy(gameState, player, requestType, response, requiredTribute);
|
||||
};
|
||||
|
||||
m.DiplomacyManager.prototype.changePlayerDiplomacy = function(gameState, player, newDiplomaticStance)
|
||||
{
|
||||
if (gameState.isPlayerEnemy(player) && (newDiplomaticStance === "ally" || newDiplomaticStance === "neutral"))
|
||||
gameState.ai.HQ.attackManager.cancelAttacksAgainstPlayer(player);
|
||||
Engine.PostCommand(PlayerID, { "type": "diplomacy", "player": player, "to": newDiplomaticStance });
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("diplomacy stance with player " + player + " is now " + newDiplomaticStance);
|
||||
|
|
@ -321,19 +332,19 @@ m.DiplomacyManager.prototype.changePlayerDiplomacy = function(gameState, player,
|
|||
|
||||
m.DiplomacyManager.prototype.checkRequestedTributes = function(gameState)
|
||||
{
|
||||
for (let [player, data] of this.allyRequests.entries())
|
||||
for (let [player, data] of this.diplomacyRequests)
|
||||
if (data.status === "waitingForTribute" && gameState.ai.elapsedTime > data.warnTime)
|
||||
{
|
||||
if (data.sentWarning)
|
||||
{
|
||||
this.allyRequests.delete(player);
|
||||
m.chatAnswerRequestAlly(gameState, player, "decline");
|
||||
this.diplomacyRequests.delete(player);
|
||||
m.chatAnswerRequestDiplomacy(gameState, player, data.requestType, "decline");
|
||||
}
|
||||
else
|
||||
{
|
||||
data.sentWarning = true;
|
||||
data.warnTime = gameState.ai.elapsedTime + 60;
|
||||
m.chatAnswerRequestAlly(gameState, player, "waitingForTribute", {
|
||||
m.chatAnswerRequestDiplomacy(gameState, player, data.requestType, "waitingForTribute", {
|
||||
"wanted": data.wanted,
|
||||
"type": data.type
|
||||
});
|
||||
|
|
@ -361,7 +372,7 @@ m.DiplomacyManager.prototype.Serialize = function()
|
|||
"nextTributeRequest": this.nextTributeRequest,
|
||||
"betrayLapseTime": this.betrayLapseTime,
|
||||
"waitingToBetray": this.waitingToBetray,
|
||||
"allyRequests": this.allyRequests
|
||||
"diplomacyRequests": this.diplomacyRequests
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@ m.HQ.prototype.gameAnalysis = function(gameState)
|
|||
// configure our first base strategy
|
||||
if (this.baseManagers.length > 1)
|
||||
this.configFirstBase(gameState);
|
||||
|
||||
this.diplomacyManager.diplomacyCheck(gameState);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue