1
0
forked from 0ad/0ad

This was SVN commit r10853.

This commit is contained in:
Jonathan Waller 2012-01-02 21:46:09 +00:00
parent 97c847c4d9
commit a4e1f3c292
10 changed files with 124 additions and 116 deletions

View File

@ -216,6 +216,8 @@ profiler2.gpu.arb.enable = true ; Allow GL_ARB_timer_query timing mo
profiler2.gpu.ext.enable = true ; Allow GL_EXT_timer_query timing mode when available
profiler2.gpu.intel.enable = true ; Allow GL_INTEL_performance_queries timing mode when available
hotkey.attackmove = Super
; > QUICKSAVE
hotkey.quicksave = "Shift+F5"
hotkey.quickload = "Shift+F8"

View File

@ -1,6 +1,6 @@
function AttackMoveToLocation(gameState, militaryManager, minAttackSize, maxAttackSize, targetFinder){
this.minAttackSize = minAttackSize || 20;
this.maxAttackSize = maxAttackSize || 60;
this.minAttackSize = minAttackSize || Config.attack.minAttackSize;
this.maxAttackSize = maxAttackSize || Config.attack.maxAttackSize;
this.idList=[];
this.previousTime = 0;
@ -17,7 +17,7 @@ AttackMoveToLocation.prototype.canExecute = function(gameState, militaryManager)
var enemyCount = militaryManager.measureEnemyCount(gameState);
// We require our army to be >= this strength
var targetStrength = enemyStrength * 1.5;
var targetStrength = enemyStrength * Config.attack.enemyRatio;
var availableCount = militaryManager.countAvailableUnits();
var availableStrength = militaryManager.measureAvailableStrength();

View File

@ -1,12 +1,12 @@
function Defence(){
this.AQUIRE_DIST = 220;
this.RELEASE_DIST = 250;
this.ACQUIRE_DIST = Config.defence.acquireDistance;
this.RELEASE_DIST = Config.defence.releaseDistance;
this.GROUP_RADIUS = 20; // units will be added to a group if they are within this radius
this.GROUP_BREAK_RADIUS = 40; // units will leave a group if they are outside of this radius
this.GROUP_MERGE_RADIUS = 10; // Two groups with centres this far apart will be merged
this.GROUP_RADIUS = Config.defence.groupRadius; // units will be added to a group if they are within this radius
this.GROUP_BREAK_RADIUS = Config.defence.groupBreakRadius; // units will leave a group if they are outside of this radius
this.GROUP_MERGE_RADIUS = Config.defence.groupMergeRadius; // Two groups with centres this far apart will be merged
this.DEFENCE_RATIO = 2; // How many defenders we want per attacker. Need to balance fewer losses vs. lost economy
this.DEFENCE_RATIO = Config.defence.defenderRatio; // How many defenders we want per attacker. Need to balance fewer losses vs. lost economy
// These are objects with the keys being entity ids and values being the entity objects
// NOTE: It is assumed that all attackers have a valid position, the attackers list must be kept up to date so this
@ -172,7 +172,7 @@ Defence.prototype.updateAttackers = function(gameState, events, enemyTroops){
self.attackers[ent.id()] = ent;
}
}else{
if (minDist < self.AQUIRE_DIST){
if (minDist < self.ACQUIRE_DIST){
self.attackers[ent.id()] = ent;
self.newAttackers.push(ent.id());
}

View File

@ -7,9 +7,6 @@
*/
var MilitaryAttackManager = function() {
this.targetSquadSize = 10;
this.targetScoutTowers = 10;
// these use the structure soldiers[unitId] = true|false to register the units
this.soldiers = {};
this.assigned = {};
@ -26,21 +23,48 @@ var MilitaryAttackManager = function() {
this.lastAttackTime = 0;
this.defenceManager = new Defence();
this.defineUnitsAndBuildings();
};
MilitaryAttackManager.prototype.init = function(gameState) {
var civ = gameState.playerData.civ;
if (civ in this.uCivCitizenSoldier) {
this.uCitizenSoldier = this.uCivCitizenSoldier[civ];
this.uAdvanced = this.uCivAdvanced[civ];
this.uSiege = this.uCivSiege[civ];
this.bAdvanced = this.bCivAdvanced[civ];
this.bFort = this.bCivFort[civ];
// load units and buildings from the config files
if (civ in Config.units.citizenSoldier){
this.uCitizenSoldier = Config.units.citizenSoldier[civ];
}else{
this.uCitizenSoldier = Config.units.citizenSoldier['default'];
}
if (civ in Config.units.advanced){
this.uAdvanced = Config.units.advanced[civ];
}else{
this.uAdvanced = Config.units.advanced['default'];
}
if (civ in Config.units.siege){
this.uSiege = Config.units.siege[civ];
}else{
this.uSiege = Config.units.siege['default'];
}
if (civ in Config.buildings.moderate){
this.bModerate = Config.buildings.moderate[civ];
}else{
this.bModerate = Config.buildings.moderate['default'];
}
if (civ in Config.buildings.advanced){
this.bAdvanced = Config.buildings.advanced[civ];
}else{
this.bAdvanced = Config.buildings.advanced['default'];
}
if (civ in Config.buildings.fort){
this.bFort = Config.buildings.fort[civ];
}else{
this.bFort = Config.buildings.fort['default'];
}
for (var i in this.uCitizenSoldier){
this.uCitizenSoldier[i] = gameState.applyCiv(this.uCitizenSoldier[i]);
}
@ -50,6 +74,9 @@ MilitaryAttackManager.prototype.init = function(gameState) {
for (var i in this.uSiege){
this.uSiege[i] = gameState.applyCiv(this.uSiege[i]);
}
for (var i in this.bAdvanced){
this.bAdvanced[i] = gameState.applyCiv(this.bAdvanced[i]);
}
for (var i in this.bFort){
this.bFort[i] = gameState.applyCiv(this.bFort[i]);
}
@ -59,61 +86,13 @@ MilitaryAttackManager.prototype.init = function(gameState) {
};
// TODO: figure out how to make this generic
for (var i in this.attackManagers){
this.availableAttacks[i] = new this.attackManagers[i](gameState, this, 10, 10, this.getEconomicTargets);
this.availableAttacks[i] = new this.attackManagers[i](gameState, this);
}
var filter = Filters.and(Filters.isEnemy(), Filters.byClassesOr(["CitizenSoldier", "Super", "Siege"]));
this.enemySoldiers = new EntityCollection(gameState.ai, gameState.entities._entities, filter, gameState);
};
MilitaryAttackManager.prototype.defineUnitsAndBuildings = function(){
// units
this.uCivCitizenSoldier= {};
this.uCivAdvanced = {};
this.uCivSiege = {};
this.uCivCitizenSoldier.hele = [ "units/hele_infantry_spearman_b", "units/hele_infantry_javelinist_b", "units/hele_infantry_archer_b" ];
this.uCivAdvanced.hele = [ "units/hele_cavalry_swordsman_b", "units/hele_cavalry_javelinist_b", "units/hele_champion_cavalry_mace", "units/hele_champion_infantry_mace", "units/hele_champion_infantry_polis", "units/hele_champion_ranged_polis" , "units/thebes_sacred_band_hoplitai", "units/thespian_melanochitones","units/sparta_hellenistic_phalangitai", "units/thrace_black_cloak"];
this.uCivSiege.hele = [ "units/hele_mechanical_siege_oxybeles", "units/hele_mechanical_siege_lithobolos" ];
this.uCivCitizenSoldier.cart = [ "units/cart_infantry_spearman_b", "units/cart_infantry_archer_b" ];
this.uCivAdvanced.cart = [ "units/cart_cavalry_javelinist_b", "units/cart_champion_cavalry", "units/cart_infantry_swordsman_2_b", "units/cart_cavalry_spearman_b", "units/cart_infantry_javelinist_b", "units/cart_infantry_slinger_b", "units/cart_cavalry_swordsman_b", "units/cart_infantry_swordsman_b", "units/cart_cavalry_swordsman_2_b", "units/cart_sacred_band_cavalry"];
this.uCivSiege.cart = ["units/cart_mechanical_siege_ballista", "units/cart_mechanical_siege_oxybeles"];
this.uCivCitizenSoldier.celt = [ "units/celt_infantry_spearman_b", "units/celt_infantry_javelinist_b" ];
this.uCivAdvanced.celt = [ "units/celt_cavalry_javelinist_b", "units/celt_cavalry_swordsman_b", "units/celt_champion_cavalry_gaul", "units/celt_champion_infantry_gaul", "units/celt_champion_cavalry_brit", "units/celt_champion_infantry_brit", "units/celt_fanatic" ];
this.uCivSiege.celt = ["units/celt_mechanical_siege_ram"];
this.uCivCitizenSoldier.iber = [ "units/iber_infantry_spearman_b", "units/iber_infantry_slinger_b", "units/iber_infantry_swordsman_b", "units/iber_infantry_javelinist_b" ];
this.uCivAdvanced.iber = ["units/iber_cavalry_spearman_b", "units/iber_champion_cavalry", "units/iber_champion_infantry" ];
this.uCivSiege.iber = ["units/iber_mechanical_siege_ram"];
this.uCivCitizenSoldier.pers = [ "units/pers_infantry_spearman_b", "units/pers_infantry_archer_b", "units/pers_infantry_javelinist_b" ];
this.uCivAdvanced.pers = ["units/pers_cavalry_javelinist_b", "units/pers_champion_infantry", "units/pers_champion_cavalry", "units/pers_cavalry_spearman_b", "units/pers_cavalry_swordsman_b", "units/pers_cavalry_javelinist_b", "units/pers_cavalry_archer_b", "pers_kardakes_hoplite", "units/pers_kardakes_skirmisher", "units/pers_war_elephant" ];
this.uCivSiege.pers = ["units/pers_mechanical_siege_ram"];
//defaults
this.uCitizenSoldier = ["units/{civ}_infantry_spearman_b", "units/{civ}_infantry_slinger_b", "units/{civ}_infantry_swordsman_b", "units/{civ}_infantry_javelinist_b", "units/{civ}_infantry_archer_b" ];
this.uAdvanced = ["units/{civ}_cavalry_spearman_b", "units/{civ}_cavalry_javelinist_b", "units/{civ}_champion_cavalry", "units/{civ}_champion_infantry"];
this.uSiege = ["units/{civ}_mechanical_siege_oxybeles", "units/{civ}_mechanical_siege_lithobolos", "units/{civ}_mechanical_siege_ballista","units/{civ}_mechanical_siege_ram"];
// buildings
this.bModerate = [ "structures/{civ}_barracks" ]; //same for all civs
this.bCivAdvanced = {};
this.bCivAdvanced.hele = [ "structures/{civ}_gymnasion", "structures/{civ}_fortress" ];
this.bCivAdvanced.cart = [ "structures/{civ}_fortress", "structures/{civ}_embassy_celtic", "structures/{civ}_embassy_iberian", "structures/{civ}_embassy_italiote" ];
this.bCivAdvanced.celt = [ "structures/{civ}_kennel", "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ];
this.bCivAdvanced.iber = [ "structures/{civ}_fortress" ];
this.bCivAdvanced.pers = [ "structures/{civ}_fortress", "structures/{civ}_stables", "structures/{civ}_apadana" ];
this.bCivFort = {};
this.bCivFort.hele = [ "structures/{civ}_fortress" ];
this.bCivFort.cart = [ "structures/{civ}_fortress" ];
this.bCivFort.celt = [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ];
this.bCivFort.iber = [ "structures/{civ}_fortress" ];
this.bCivFort.pers = [ "structures/{civ}_fortress" ];
};
/**
* @param (GameState) gameState
* @returns array of soldiers for which training buildings exist
@ -565,32 +544,15 @@ MilitaryAttackManager.prototype.update = function(gameState, queues, events) {
}
// Look for attack plans which can be executed, only do this once every minute
if (gameState.getTimeElapsed() < 6.5*60*1000){
if (gameState.getTimeElapsed() - 60*1000 > this.lastAttackTime){
this.lastAttackTime = gameState.getTimeElapsed();
for (var i = 0; i < this.availableAttacks.length; i++){
if (this.availableAttacks[i].canExecute(gameState, this)){
// Make it so raids happen a bit randomly
if (Math.random() < 0.35){
this.availableAttacks[i].execute(gameState, this);
this.currentAttacks.push(this.availableAttacks[i]);
debug("Raiding!");
this.availableAttacks.splice(i, 1, new this.attackManagers[i](gameState, this, 10, 10, this.getEconomicTargets));
}
}
}
}
}else{
for (var i = 0; i < this.availableAttacks.length; i++){
if (this.availableAttacks[i].canExecute(gameState, this)){
this.availableAttacks[i].execute(gameState, this);
this.currentAttacks.push(this.availableAttacks[i]);
debug("Attacking!");
}
this.availableAttacks.splice(i, 1, new this.attackManagers[i](gameState, this, 20, 60));
for (var i = 0; i < this.availableAttacks.length; i++){
if (this.availableAttacks[i].canExecute(gameState, this)){
this.availableAttacks[i].execute(gameState, this);
this.currentAttacks.push(this.availableAttacks[i]);
debug("Attacking!");
}
this.availableAttacks.splice(i, 1, new this.attackManagers[i](gameState, this));
}
// Keep current attacks updated
for (i in this.currentAttacks){
this.currentAttacks[i].update(gameState, this, events);

View File

@ -22,18 +22,7 @@ function QBotAI(settings) {
this.productionQueues = [];
this.priorities = {
house : 500,
citizenSoldier : 100,
villager : 100,
economicBuilding : 30,
field: 20,
advancedSoldier : 30,
siege : 10,
militaryBuilding : 50,
defenceBuilding: 17,
civilCentre: 1000
};
this.priorities = Config.priorities;
this.queueManager = new QueueManager(this.queues, this.priorities);
@ -132,10 +121,8 @@ QBotAI.prototype.Deserialize = function(data)
this._entityMetadata = {};
};
var debugOn = false;
function debug(output){
if (debugOn){
if (Config.debug){
if (typeof output === "string"){
warn(output);
}else{

View File

@ -1,4 +1,4 @@
This is an AI for 0 AD based on the testBot.
This is an AI for 0 A.D. (http://wildfiregames.com/0ad/) based on the testBot.
Install by placing the files into the data/mods/public/simulation/ai/qbot folder.

View File

@ -66,7 +66,7 @@ public:
// Dynamic state:
bool m_InWorld;
entity_pos_t m_X, m_Z, m_LastX, m_LastZ; // these values contain undefined junk if !InWorld
entity_pos_t m_X, m_Z, m_LastX, m_LastZ, m_PrevX, m_PrevZ; // these values contain undefined junk if !InWorld
entity_pos_t m_YOffset;
bool m_RelativeToGround; // whether m_YOffset is relative to terrain/water plane, or an absolute height
@ -203,6 +203,8 @@ public:
m_InWorld = true;
m_LastX = m_X;
m_LastZ = m_Z;
m_PrevX = m_X;
m_PrevZ = m_Z;
}
AdvertisePositionChanges();
@ -210,8 +212,8 @@ public:
virtual void JumpTo(entity_pos_t x, entity_pos_t z)
{
m_LastX = m_X = x;
m_LastZ = m_Z = z;
m_LastX = m_PrevX = m_X = x;
m_LastZ = m_PrevZ = m_Z = z;
m_InWorld = true;
AdvertisePositionChanges();
@ -278,6 +280,43 @@ public:
return CFixedVector2D(m_X, m_Z);
}
virtual CFixedVector3D GetPreviousPosition()
{
if (!m_InWorld)
{
LOGERROR(L"CCmpPosition::GetPreviousPosition called on entity when IsInWorld is false");
return CFixedVector3D();
}
entity_pos_t baseY;
if (m_RelativeToGround)
{
CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY);
if (!cmpTerrain.null())
baseY = cmpTerrain->GetGroundLevel(m_PrevX, m_PrevZ);
if (m_Floating)
{
CmpPtr<ICmpWaterManager> cmpWaterMan(GetSimContext(), SYSTEM_ENTITY);
if (!cmpWaterMan.null())
baseY = std::max(baseY, cmpWaterMan->GetWaterLevel(m_PrevX, m_PrevZ));
}
}
return CFixedVector3D(m_PrevX, baseY + m_YOffset, m_PrevZ);
}
virtual CFixedVector2D GetPreviousPosition2D()
{
if (!m_InWorld)
{
LOGERROR(L"CCmpPosition::GetPreviousPosition2D called on entity when IsInWorld is false");
return CFixedVector2D();
}
return CFixedVector2D(m_PrevX, m_PrevZ);
}
virtual void TurnTo(entity_angle_t y)
{
m_RotY = y;
@ -408,6 +447,9 @@ public:
}
case MT_TurnStart:
{
m_PrevX = m_LastX;
m_PrevZ = m_LastZ;
m_LastX = m_X;
m_LastZ = m_Z;

View File

@ -32,6 +32,8 @@ DEFINE_INTERFACE_METHOD_1("SetHeightFixed", void, ICmpPosition, SetHeightFixed,
DEFINE_INTERFACE_METHOD_0("IsFloating", bool, ICmpPosition, IsFloating)
DEFINE_INTERFACE_METHOD_0("GetPosition", CFixedVector3D, ICmpPosition, GetPosition)
DEFINE_INTERFACE_METHOD_0("GetPosition2D", CFixedVector2D, ICmpPosition, GetPosition2D)
DEFINE_INTERFACE_METHOD_0("GetPreviousPosition", CFixedVector3D, ICmpPosition, GetPreviousPosition)
DEFINE_INTERFACE_METHOD_0("GetPreviousPosition2D", CFixedVector2D, ICmpPosition, GetPreviousPosition2D)
DEFINE_INTERFACE_METHOD_1("TurnTo", void, ICmpPosition, TurnTo, entity_angle_t)
DEFINE_INTERFACE_METHOD_1("SetYRotation", void, ICmpPosition, SetYRotation, entity_angle_t)
DEFINE_INTERFACE_METHOD_2("SetXZRotation", void, ICmpPosition, SetXZRotation, entity_angle_t, entity_angle_t)

View File

@ -108,6 +108,19 @@ public:
*/
virtual CFixedVector2D GetPosition2D() = 0;
/**
* Returns the previous turn's x,y,z position (no interpolation).
* Depends on the current terrain heightmap.
* Must not be called unless IsInWorld is true.
*/
virtual CFixedVector3D GetPreviousPosition() = 0;
/**
* Returns the previous turn's x,z position (no interpolation).
* Must not be called unless IsInWorld is true.
*/
virtual CFixedVector2D GetPreviousPosition2D() = 0;
/**
* Rotate smoothly to the given angle around the upwards axis.
* @param y clockwise radians from the +Z axis.

View File

@ -146,8 +146,8 @@ function refresh_thread(thread, callback_data)
function rebuild_canvases()
{
g_data.canvas_frames = $('<canvas width="1600" height="128"></canvas>').get(0);
g_data.canvas_zoom = $('<canvas width="1600" height="128"></canvas>').get(0);
g_data.canvas_frames = $('<canvas width="1400" height="180"></canvas>').get(0);
g_data.canvas_zoom = $('<canvas width="1400" height="180"></canvas>').get(0);
g_data.text_output = $('<pre></pre>').get(0);
set_frames_zoom_handlers(g_data.canvas_frames);