From a4e1f3c29268c7e1b7a77e941ed39a54ea46e0d5 Mon Sep 17 00:00:00 2001 From: quantumstate Date: Mon, 2 Jan 2012 21:46:09 +0000 Subject: [PATCH] This was SVN commit r10853. --- binaries/data/config/default.cfg | 2 + .../ai/qbot/attackMoveToLocation.js | 6 +- .../mods/public/simulation/ai/qbot/defence.js | 14 +- .../public/simulation/ai/qbot/military.js | 132 +++++++----------- .../mods/public/simulation/ai/qbot/qbot.js | 17 +-- .../mods/public/simulation/ai/qbot/readme.txt | 2 +- .../simulation2/components/CCmpPosition.cpp | 48 ++++++- .../simulation2/components/ICmpPosition.cpp | 2 + source/simulation2/components/ICmpPosition.h | 13 ++ source/tools/profiler2/profiler2.js | 4 +- 10 files changed, 124 insertions(+), 116 deletions(-) diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg index f6e2fe9c3a..b638e6dec7 100644 --- a/binaries/data/config/default.cfg +++ b/binaries/data/config/default.cfg @@ -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" diff --git a/binaries/data/mods/public/simulation/ai/qbot/attackMoveToLocation.js b/binaries/data/mods/public/simulation/ai/qbot/attackMoveToLocation.js index dc809bcda0..0759792032 100644 --- a/binaries/data/mods/public/simulation/ai/qbot/attackMoveToLocation.js +++ b/binaries/data/mods/public/simulation/ai/qbot/attackMoveToLocation.js @@ -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(); diff --git a/binaries/data/mods/public/simulation/ai/qbot/defence.js b/binaries/data/mods/public/simulation/ai/qbot/defence.js index 1f583d1189..a71476c992 100644 --- a/binaries/data/mods/public/simulation/ai/qbot/defence.js +++ b/binaries/data/mods/public/simulation/ai/qbot/defence.js @@ -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()); } diff --git a/binaries/data/mods/public/simulation/ai/qbot/military.js b/binaries/data/mods/public/simulation/ai/qbot/military.js index fcf5b4094f..bdbeed6468 100755 --- a/binaries/data/mods/public/simulation/ai/qbot/military.js +++ b/binaries/data/mods/public/simulation/ai/qbot/military.js @@ -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); diff --git a/binaries/data/mods/public/simulation/ai/qbot/qbot.js b/binaries/data/mods/public/simulation/ai/qbot/qbot.js index 6d5205c78b..b7e10c5f70 100644 --- a/binaries/data/mods/public/simulation/ai/qbot/qbot.js +++ b/binaries/data/mods/public/simulation/ai/qbot/qbot.js @@ -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{ diff --git a/binaries/data/mods/public/simulation/ai/qbot/readme.txt b/binaries/data/mods/public/simulation/ai/qbot/readme.txt index 0a5521df42..810bdf8c23 100644 --- a/binaries/data/mods/public/simulation/ai/qbot/readme.txt +++ b/binaries/data/mods/public/simulation/ai/qbot/readme.txt @@ -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. diff --git a/source/simulation2/components/CCmpPosition.cpp b/source/simulation2/components/CCmpPosition.cpp index b566c58130..7ccb01121d 100644 --- a/source/simulation2/components/CCmpPosition.cpp +++ b/source/simulation2/components/CCmpPosition.cpp @@ -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 cmpTerrain(GetSimContext(), SYSTEM_ENTITY); + if (!cmpTerrain.null()) + baseY = cmpTerrain->GetGroundLevel(m_PrevX, m_PrevZ); + + if (m_Floating) + { + CmpPtr 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; diff --git a/source/simulation2/components/ICmpPosition.cpp b/source/simulation2/components/ICmpPosition.cpp index 1e3c8b0efb..07f1dcd148 100644 --- a/source/simulation2/components/ICmpPosition.cpp +++ b/source/simulation2/components/ICmpPosition.cpp @@ -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) diff --git a/source/simulation2/components/ICmpPosition.h b/source/simulation2/components/ICmpPosition.h index 4a4b274534..f675d63142 100644 --- a/source/simulation2/components/ICmpPosition.h +++ b/source/simulation2/components/ICmpPosition.h @@ -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. diff --git a/source/tools/profiler2/profiler2.js b/source/tools/profiler2/profiler2.js index 341ac64124..1e16f4db02 100644 --- a/source/tools/profiler2/profiler2.js +++ b/source/tools/profiler2/profiler2.js @@ -146,8 +146,8 @@ function refresh_thread(thread, callback_data) function rebuild_canvases() { - g_data.canvas_frames = $('').get(0); - g_data.canvas_zoom = $('').get(0); + g_data.canvas_frames = $('').get(0); + g_data.canvas_zoom = $('').get(0); g_data.text_output = $('
').get(0);
     
     set_frames_zoom_handlers(g_data.canvas_frames);