Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/ai/petra/gameTypeManager.js
var PETRA = function(m) | var PETRA = function(m) | ||||
{ | { | ||||
/** | /** | ||||
* Handle events that are important to specific gameTypes | * Handle events that are important to specific gameTypes | ||||
* In regicide, train and manage healer guards and military guards for the hero. | * In regicide, train and manage healer guards and military guards for the hero. | ||||
*/ | */ | ||||
m.GameTypeManager = function(Config) | m.GameTypeManager = function(Config) | ||||
{ | { | ||||
this.Config = Config; | this.Config = Config; | ||||
this.criticalEnts = new Map(); | this.criticalEnts = new Map(); | ||||
// Holds ids of all ents who are (or can be) guarding and if the ent is currently guarding | // Holds ids of all ents who are (or can be) guarding and if the ent is currently guarding | ||||
this.guardEnts = new Map(); | this.guardEnts = new Map(); | ||||
this.healersPerCriticalEnt = 2 + Math.round(this.Config.personality.defensive * 2); | this.healersPerCriticalEnt = 2 + Math.round(this.Config.personality.defensive * 2); | ||||
this.tryCaptureGaiaRelic = false; | |||||
this.tryCaptureGaiaRelicLapseTime = -1; | |||||
}; | }; | ||||
/** | /** | ||||
* Cache the ids of any inital gameType-critical entities. | * Cache the ids of any inital gameType-critical entities. | ||||
* In regicide, these are the inital heroes that the player starts with. | * In regicide, these are the inital heroes that the player starts with. | ||||
*/ | */ | ||||
m.GameTypeManager.prototype.init = function(gameState) | m.GameTypeManager.prototype.init = function(gameState) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 215 Lines • ▼ Show 20 Lines | for (let evt of events.OwnershipChanged) | ||||
let ent = gameState.getEntityById(evt.entity); | let ent = gameState.getEntityById(evt.entity); | ||||
if (ent && (gameState.getGameType() === "wonder" && ent.hasClass("Wonder") || | if (ent && (gameState.getGameType() === "wonder" && ent.hasClass("Wonder") || | ||||
gameState.getGameType() === "capture_the_relic" && ent.hasClass("Relic"))) | gameState.getGameType() === "capture_the_relic" && ent.hasClass("Relic"))) | ||||
{ | { | ||||
this.criticalEnts.set(ent.id(), { "guardsAssigned": 0, "guards": new Map() }); | this.criticalEnts.set(ent.id(), { "guardsAssigned": 0, "guards": new Map() }); | ||||
// Move captured relics to the closest base | // Move captured relics to the closest base | ||||
if (ent.hasClass("Unit")) | if (ent.hasClass("Unit")) | ||||
{ | |||||
this.pickCriticalEntRetreatLocation(gameState, ent, false); | this.pickCriticalEntRetreatLocation(gameState, ent, false); | ||||
if (evt.from === 0) | |||||
gameState.ai.HQ.attackManager.cancelAttacksAgainstPlayer(gameState, evt.from); | |||||
} | |||||
} | } | ||||
} | } | ||||
}; | }; | ||||
m.GameTypeManager.prototype.removeGuardsFromCriticalEnt = function(gameState, criticalEntId) | m.GameTypeManager.prototype.removeGuardsFromCriticalEnt = function(gameState, criticalEntId) | ||||
{ | { | ||||
for (let [guardId, role] of this.criticalEnts.get(criticalEntId).guards) | for (let [guardId, role] of this.criticalEnts.get(criticalEntId).guards) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
gameState.ai.HQ.defenseManager.garrisonAttackedUnit(gameState, criticalEnt, emergency); | gameState.ai.HQ.defenseManager.garrisonAttackedUnit(gameState, criticalEnt, emergency); | ||||
let plan = criticalEnt.getMetadata(PlayerID, "plan"); | let plan = criticalEnt.getMetadata(PlayerID, "plan"); | ||||
if (plan === -2 || plan === -3) | if (plan === -2 || plan === -3) | ||||
return; | return; | ||||
// Couldn't find a place to garrison, so the ent will flee from attacks | // Couldn't find a place to garrison, so the ent will flee from attacks | ||||
if (!criticalEnt.hasClass("Relic")) | |||||
criticalEnt.setStance("passive"); | criticalEnt.setStance("passive"); | ||||
let accessIndex = gameState.ai.accessibility.getAccessValue(criticalEnt.position()); | let accessIndex = gameState.ai.accessibility.getAccessValue(criticalEnt.position()); | ||||
let basePos = m.getBestBase(gameState, criticalEnt, true); | let basePos = m.getBestBase(gameState, criticalEnt, true); | ||||
if (basePos && basePos.accessIndex == accessIndex) | if (basePos && basePos.accessIndex == accessIndex) | ||||
criticalEnt.move(basePos.anchor.position()[0], basePos.anchor.position()[1]); | criticalEnt.move(basePos.anchor.position()[0], basePos.anchor.position()[1]); | ||||
}; | }; | ||||
/** | /** | ||||
* The number of healers trained per critical ent (dependent on the defensive trait) | * The number of healers trained per critical ent (dependent on the defensive trait) | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | for (let [id, data] of this.criticalEnts) | ||||
if (data.healersAssigned < this.healersPerCriticalEnt && | if (data.healersAssigned < this.healersPerCriticalEnt && | ||||
this.guardEnts.size < Math.min(gameState.getPopulationMax() / 10, gameState.getPopulation() / 4)) | this.guardEnts.size < Math.min(gameState.getPopulationMax() / 10, gameState.getPopulation() / 4)) | ||||
this.trainCriticalEntHealer(gameState, queues, id); | this.trainCriticalEntHealer(gameState, queues, id); | ||||
} | } | ||||
this.manageCriticalEntGuards(gameState); | this.manageCriticalEntGuards(gameState); | ||||
} | } | ||||
if (gameState.getGameType() === "capture_the_relic" && gameState.ai.playedTurn % 10 === 0) | if (gameState.getGameType() === "capture_the_relic" && gameState.ai.playedTurn % 10 === 0) | ||||
{ | |||||
this.manageCriticalEntGuards(gameState); | this.manageCriticalEntGuards(gameState); | ||||
// Do not capture gaia relics frequently, as the ai has access to the entire map | |||||
if (gameState.ai.elapsedTime > this.tryCaptureGaiaRelicLapseTime && !this.tryCaptureGaiaRelic) | |||||
mimo: playedTurn%400 is not ok as it depends on SP (0.2 * 8 * 400 = 640s) or MP (0.5 * 8 * 400 =… | |||||
Not Done Inline ActionsI don't know if I fully understand what is meant by "variant of tryCaptureGaiaRelic". Sandarac: I don't know if I fully understand what is meant by "variant of tryCaptureGaiaRelic". | |||||
Not Done Inline ActionsSorry, i forgot to answer that one: my idea was to have two timers to look for relics:
but this distinction can be in another patch. mimo: Sorry, i forgot to answer that one: my idea was to have two timers to look for relics:
- the… | |||||
Not Done Inline ActionsAh, okay I see :) Sandarac: Ah, okay I see :) | |||||
{ | |||||
this.tryCaptureGaiaRelic = true; | |||||
this.tryCaptureGaiaRelicLapseTime = gameState.ai.elapsedTime + (5 - 0.5 * (this.Config.difficulty - 3) * 60); | |||||
Not Done Inline ActionsI've the impression this line would be better in attackManager with line 385 where we put tryCaptureGaiaRelic to false as it can take some time to start the attack. What's your opinion? mimo: I've the impression this line would be better in attackManager with line 385 where we put… | |||||
Not Done Inline ActionsYes, I agree, that sounds like a good idea. Sandarac: Yes, I agree, that sounds like a good idea. | |||||
} | |||||
} | |||||
}; | }; | ||||
m.GameTypeManager.prototype.Serialize = function() | m.GameTypeManager.prototype.Serialize = function() | ||||
{ | { | ||||
return { | return { | ||||
"criticalEnts": this.criticalEnts, | "criticalEnts": this.criticalEnts, | ||||
"guardEnts": this.guardEnts, | "guardEnts": this.guardEnts, | ||||
"healersPerCriticalEnt": this.healersPerCriticalEnt | "healersPerCriticalEnt": this.healersPerCriticalEnt, | ||||
"tryCaptureGaiaRelic": this.tryCaptureGaiaRelic, | |||||
"tryCaptureGaiaRelicLapseTime": this.tryCaptureGaiaRelicLapseTime | |||||
}; | }; | ||||
}; | }; | ||||
m.GameTypeManager.prototype.Deserialize = function(data) | m.GameTypeManager.prototype.Deserialize = function(data) | ||||
{ | { | ||||
for (let key in data) | for (let key in data) | ||||
this[key] = data[key]; | this[key] = data[key]; | ||||
}; | }; | ||||
return m; | return m; | ||||
}(PETRA); | }(PETRA); |
Wildfire Games · Phabricator
playedTurn%400 is not ok as it depends on SP (0.2 * 8 * 400 = 640s) or MP (0.5 * 8 * 400 = 1600s). Rather use gameState.ai.elapsedTime, caching the time of the last try.
Although i've not yet tried this "capture the relics", these delays seem too much to me. What about 5 mn for both SP and MP ? and even maybe (5 - 0.5*(aidifficulty-3)) mn?
In addition, we can have a variant of tryCaptureGaiaRelic which would not wait for relics inside the player's territory (as the ai would certainly be able to see it) or those the ai already tried to capture but failed.