1
0
forked from 0ad/0ad

Implement emergency recognition for PetraAI.

First patch for an emergency mode. This implements a rudimentary
detection strategy.
The current effect is a shout-out for help.

Patch by: @JCWasmx86
Differential revision: https://code.wildfiregames.com/D4645
Refs. #2195

This was SVN commit r27141.
This commit is contained in:
Freagarach 2022-10-10 05:09:23 +00:00
parent 4e52613ca2
commit a315f90980
4 changed files with 152 additions and 0 deletions

View File

@ -132,6 +132,15 @@ PETRA.sendDiplomacyRequestMessages = {
}
};
PETRA.emergencyMessages = {
"enter": [
markForTranslation("My armies failed while defending my empire. Please honor our alliance and send help!")
],
"exit": [
markForTranslation("My empire regained its old strength, now it is time to seek revenge together!")
]
};
PETRA.chatLaunchAttack = function(gameState, player, type)
{
Engine.PostCommand(PlayerID, {
@ -234,3 +243,12 @@ PETRA.chatNewRequestDiplomacy = function(gameState, player, requestType, status)
"parameters": { "_player_": player }
});
};
PETRA.chatEmergency = function(gameState, enable)
{
Engine.PostCommand(PlayerID, {
"type": "aichat",
"message": "/allies " + pickRandom(this.emergencyMessages[enable ? "enter" : "exit"]),
"translateMessage": true
});
};

View File

@ -175,6 +175,33 @@ PETRA.Config = function(difficulty = PETRA.DIFFICULTY_MEDIUM, behavior)
"Market/InternationalBonus",
"Player/sharedDropsites"
];
this.criticalPopulationFactors = [
0.8,
0.8,
0.7,
0.6,
0.5,
0.35
];
this.criticalStructureFactors = [
0.8,
0.8,
0.7,
0.6,
0.5,
0.35
];
this.criticalRootFactors = [
0.8,
0.8,
0.67,
0.5,
0.35,
0.2
];
};
PETRA.Config.prototype.setConfig = function(gameState)
@ -287,6 +314,12 @@ PETRA.Config.prototype.setConfig = function(gameState)
if (this.difficulty < PETRA.DIFFICULTY_EASY)
this.Economy.workPhase3 = Infinity; // prevent the phasing to city phase
this.emergencyValues = {
"population": this.criticalPopulationFactors[this.difficulty],
"structures": this.criticalStructureFactors[this.difficulty],
"roots": this.criticalRootFactors[this.difficulty],
};
if (this.debug < 2)
return;
API3.warn(" >>> Petra bot: personality = " + uneval(this.personality));

View File

@ -0,0 +1,93 @@
/**
* Checks for emergencies and acts accordingly
*/
PETRA.EmergencyManager = function(Config)
{
this.Config = Config;
this.referencePopulation = 0;
this.referenceStructureCount = 0;
this.numRoots = 0;
this.hasEmergency = false;
};
PETRA.EmergencyManager.prototype.init = function(gameState)
{
this.referencePopulation = gameState.getPopulation();
this.referenceStructureCount = gameState.getOwnStructures().length;
this.numRoots = this.rootCount(gameState);
};
PETRA.EmergencyManager.prototype.update = function(gameState)
{
if (this.hasEmergency)
{
this.emergencyUpdate(gameState);
return;
}
const pop = gameState.getPopulation();
const nStructures = gameState.getOwnStructures().length;
const nRoots = this.rootCount(gameState);
const factors = this.Config.emergencyValues;
if (((pop / this.referencePopulation) < factors.population || pop == 0) &&
((nStructures / this.referenceStructureCount) < factors.structures || nStructures == 0))
this.setEmergency(gameState, true);
else if ((nRoots / this.numRoots) <= factors.roots || (nRoots == 0 && this.numRoots != 0))
this.setEmergency(gameState, true);
if (pop > this.referencePopulation || this.hasEmergency)
this.referencePopulation = pop;
if (nStructures > this.referenceStructureCount || this.hasEmergency)
this.referenceStructureCount = nStructures;
if (nRoots > this.numRoots || this.hasEmergency)
this.numRoots = nRoots;
};
PETRA.EmergencyManager.prototype.emergencyUpdate = function(gameState)
{
const pop = gameState.getPopulation();
const nStructures = gameState.getOwnStructures().length;
const nRoots = this.rootCount(gameState);
const factors = this.Config.emergencyValues;
if ((pop > this.referencePopulation * 1.2 &&
nStructures > this.referenceStructureCount * 1.2) ||
nRoots > this.numRoots)
{
this.setEmergency(gameState, false);
this.referencePopulation = pop;
this.referenceStructureCount = nStructures;
this.numRoots = nRoots;
}
};
PETRA.EmergencyManager.prototype.rootCount = function(gameState)
{
let roots = 0;
gameState.getOwnStructures().toEntityArray().forEach(ent => {
if (ent?.get("TerritoryInfluence")?.Root === "true")
roots++;
});
return roots;
};
PETRA.EmergencyManager.prototype.setEmergency = function(gameState, enable)
{
this.hasEmergency = enable;
PETRA.chatEmergency(gameState, enable);
};
PETRA.EmergencyManager.prototype.Serialize = function()
{
return {
"referencePopulation": this.referencePopulation,
"referenceStructureCount": this.referenceStructureCount,
"numRoots": this.numRoots,
"hasEmergency": this.hasEmergency
};
};
PETRA.EmergencyManager.prototype.Deserialize = function(data)
{
for (const key in data)
this[key] = data[key];
};

View File

@ -44,6 +44,7 @@ PETRA.HQ = function(Config)
this.diplomacyManager = new PETRA.DiplomacyManager(this.Config);
this.garrisonManager = new PETRA.GarrisonManager(this.Config);
this.victoryManager = new PETRA.VictoryManager(this.Config);
this.emergencyManager = new PETRA.EmergencyManager(this.Config);
this.capturableTargets = new Map();
this.capturableTargetsTime = 0;
@ -66,6 +67,7 @@ PETRA.HQ.prototype.init = function(gameState, queues)
this.treasures.registerUpdates();
this.currentPhase = gameState.currentPhase();
this.decayingStructures = new Set();
this.emergencyManager.init(gameState);
};
/**
@ -2190,6 +2192,7 @@ PETRA.HQ.prototype.baseAtIndex = function(territoryIndex)
PETRA.HQ.prototype.update = function(gameState, queues, events)
{
Engine.ProfileStart("Headquarters update");
this.emergencyManager.update(gameState);
this.turnCache = {};
this.territoryMap = PETRA.createTerritoryMap(gameState);
this.canBarter = gameState.getOwnEntitiesByClass("Market", true).filter(API3.Filters.isBuilt()).hasEntities();
@ -2337,6 +2340,7 @@ PETRA.HQ.prototype.Serialize = function()
API3.warn(" diplomacyManager " + uneval(this.diplomacyManager.Serialize()));
API3.warn(" garrisonManager " + uneval(this.garrisonManager.Serialize()));
API3.warn(" victoryManager " + uneval(this.victoryManager.Serialize()));
API3.warn(" emergencyManager " + uneval(this.emergencyManager.Serialize()));
}
return {
@ -2352,6 +2356,7 @@ PETRA.HQ.prototype.Serialize = function()
"diplomacyManager": this.diplomacyManager.Serialize(),
"garrisonManager": this.garrisonManager.Serialize(),
"victoryManager": this.victoryManager.Serialize(),
"emergencyManager": this.emergencyManager.Serialize(),
};
};
@ -2395,4 +2400,7 @@ PETRA.HQ.prototype.Deserialize = function(gameState, data)
this.victoryManager = new PETRA.VictoryManager(this.Config);
this.victoryManager.Deserialize(data.victoryManager);
this.emergencyManager = new PETRA.EmergencyManager(this.Config);
this.emergencyManager.Deserialize(data.emergencyManager);
};