diff --git a/multiplay/skirmish/cobra_includes/adaption.js b/multiplay/skirmish/cobra_includes/adaption.js index 39c2d32..cbcd4f6 100644 --- a/multiplay/skirmish/cobra_includes/adaption.js +++ b/multiplay/skirmish/cobra_includes/adaption.js @@ -14,21 +14,6 @@ function switchOffMG() } } -//Don't get too riled up until we get a formidable army. -function restraint() -{ - const COOLDOWN = 6000; - const LOW_COUNT = enumDroid(me).length < 20; - var peacefulTime = false; - - if (LOW_COUNT && ((lastAttackedTime + COOLDOWN) < gameTime)) - { - peacefulTime = true; //Calm down and gather more strength. - haltAttackDroids(); - } - - return peacefulTime; -} //Choose the personality as described in the global SUB_PERSONALITIES. //When called from chat it will switch to that one directly. diff --git a/multiplay/skirmish/cobra_includes/build.js b/multiplay/skirmish/cobra_includes/build.js index 74d4824..34f2ada 100644 --- a/multiplay/skirmish/cobra_includes/build.js +++ b/multiplay/skirmish/cobra_includes/build.js @@ -7,7 +7,7 @@ function needPowerGenerator() return ((countStruct(structures.derricks) - (countStruct(structures.gens) * 4)) > 0); } - return cacheThis(uncached, [], undefined, 4000); + return cacheThis(uncached, [], undefined, 8000); } //Determine if this is a constructor droid. Specify and optional second paramter @@ -100,26 +100,6 @@ function countAndBuild(stat, count) return false; } -//Return the best available artillery defense structure. -function getDefenseStructure() -{ - function uncached() - { - var templates = SUB_PERSONALITIES[personality].artillery.defenses; - for (var i = templates.length - 1; i > 0; --i) - { - if (isStructureAvailable(templates[i].stat)) - { - return templates[i].stat; - } - } - //Fallback onto the hmg tower. - return "GuardTower1"; - } - - return cacheThis(uncached, []); -} - //Find the closest derrick that is not guarded a defense or ECM tower. function protectUnguardedDerricks(droid) { @@ -128,7 +108,7 @@ function protectUnguardedDerricks(droid) if (isDefined(droid)) { - if (buildStructure(droid, getDefenseStructure(), droid, 0)) + if (buildStructure(droid, returnDefense(), droid, 0)) { return true; } @@ -163,7 +143,7 @@ function protectUnguardedDerricks(droid) if (isDefined(undefended[0])) { - if (buildStuff(getDefenseStructure(), undefined, undefended[0], 0, true)) + if (buildStuff(returnDefense(), undefined, undefended[0], 0, true)) { return true; } @@ -232,14 +212,14 @@ function buildStuff(struc, module, defendThis, blocking, oilGroup) freeTrucks = freeTrucks.sort(distanceToBase); var truck = freeTrucks[0]; - if (isDefined(struc) && isDefined(module) && isDefined(truck)) + if (isDefined(module) && isDefined(truck)) { if (orderDroidBuild(truck, DORDER_BUILD, module, struc.x, struc.y)) { return true; } } - if (isDefined(truck) && isDefined(struc)) + if (isDefined(truck)) { if (isDefined(defendThis)) { @@ -298,7 +278,7 @@ function lookForOil() for (var j = 0, drLen = droids.length; j < drLen; j++) { var dist = distBetweenTwoPoints(droids[j].x, droids[j].y, oils[i].x, oils[i].y); - var unsafe = enumRange(oils[i].x, oils[i].y, 9, ENEMIES, false); + var unsafe = enumRange(oils[i].x, oils[i].y, 6, ENEMIES, false); unsafe = unsafe.filter(isUnsafeEnemyObject); if (!isDefined(unsafe[0]) && conCanHelp(droids[j], oils[i].x, oils[i].y)) { @@ -307,7 +287,7 @@ function lookForOil() } } - if (bestDroid) + if (bestDroid && !stopExecution("oil" + oils[i].y * mapWidth * oils[i].x, 50000)) { bestDroid.busy = true; orderDroidBuild(bestDroid, DORDER_BUILD, structures.derricks, oils[i].x, oils[i].y); @@ -376,17 +356,94 @@ function buildAAForPersonality() return false; } -//Build defense systems. -function buildDefenses() +// type refers to either a hardpoint like structure or an artillery emplacement. +// returns undefined if no structure it can build can be built. +function returnDefense(type) +{ + if (!isDefined(type)) + { + type = random(2); + } + + const ELECTRONIC_CHANCE = 67; + var defenses = (type === 0) ? SUB_PERSONALITIES[personality].primaryWeapon.defenses : SUB_PERSONALITIES[personality].artillery.defenses; + var bestDefense = "Emplacement-MortarEMP"; //default + + //Choose a random electronic warfare defense if possible. + if (random(101) < ELECTRONIC_CHANCE) + { + var avail = 0; + for (var i = 0, t = ELECTRONIC_DEFENSES.length; i < t; ++i) + { + if(isStructureAvailable(ELECTRONIC_DEFENSES[i])) + { + avail += 1; + } + } + + if (avail > 0) + { + defenses = []; + defenses.push(ELECTRONIC_DEFENSES[random(avail)]); + } + } + + for (var i = defenses.length - 1; i > -1; --i) + { + var def = isDefined(defenses[i].stat); + if (def && isStructureAvailable(defenses[i].stat)) + { + bestDefense = defenses[i].stat; + break; + } + else if (!def && isStructureAvailable(defenses[i])) + { + bestDefense = defenses[i]; + break; + } + } + + return bestDefense; +} + +// Immediately try building a defense near this truck. +function buildDefenseNearTruck(truck, type) +{ + if (!isDefined(type)) + { + type = 0; + } + + var defense = returnDefense(type); + + if (isDefined(defense)) + { + var result = pickStructLocation(truck, defense, truck.x, truck.y, 1); + if (result) + { + return orderDroidBuild(truck, DORDER_BUILD, defense, result.x, result.y); + } + } + + return false; +} + +// Passing a truck will instruct that truck to pick +// a location to build a defense structure near it. +function buildDefenses(truck) { - const MIN_POWER = 180; if (buildAAForPersonality()) { return true; } - if ((gameTime > 240000) && (getRealPower() > MIN_POWER)) + if ((gameTime > 180000) && (getRealPower() > MIN_BUILD_POWER)) { + if (isDefined(truck)) + { + return buildDefenseNearTruck(truck, 0); + } + if (buildSensors()) { return true; @@ -396,6 +453,12 @@ function buildDefenses() { return true; } + + var def = returnDefense(); + if (isDefined(def)) + { + return countAndBuild(def, Infinity); + } } return false; @@ -439,21 +502,24 @@ function factoryBuildOrder() { for (var x = 0; x < 2; ++x) { + //Always build at least one of each factory, if allowed. + if (x && (getRealPower() < MIN_BUILD_POWER)) + { + break; + } + var num = (!x) ? 1 : 5; for (var i = 0; i < 3; ++i) { var fac = SUB_PERSONALITIES[personality].factoryOrder[i]; - if (fac === VTOL_FACTORY && !useVtol) + if ((fac === VTOL_FACTORY && !useVtol) || (fac === CYBORG_FACTORY && (turnOffCyborgs || forceHover))) { continue; } - if (!((fac === CYBORG_FACTORY) && turnOffCyborgs && !forceHover)) + if (countAndBuild(fac, num)) { - if (countAndBuild(fac, num)) - { - return true; - } + return true; } } } @@ -465,21 +531,22 @@ function factoryBuildOrder() //Build repair bays when possible. function buildPhase2() { - const MIN_POWER = 230; - - if (!countStruct(structures.gens) || (getRealPower() < MIN_POWER)) + if (!countStruct(structures.gens)) { return true; } - if (!researchComplete && countAndBuild(structures.labs, 5)) + if (!(getRealPower() < MIN_BUILD_POWER)) { - return true; - } + if (!researchComplete && countAndBuild(structures.labs, 5)) + { + return true; + } - if (countAndBuild(structures.extras[0], 5)) - { - return true; + if (countAndBuild(structures.extras[0], 5)) + { + return true; + } } if (factoryBuildOrder()) @@ -527,20 +594,20 @@ function buildExtras() //Cobra's unique build decisions function buildOrderCobra() { + var turtling = !confidenceThreshold(); if(checkUnfinishedStructures()) { return; } if(maintenance()) { return; } if(buildPhase1()) { return; } - if(enemyUnitsInBase()) { return; } if(buildSpecialStructures()) { return; } - buildDefenses(); + (turtling && buildDefenses()); if(buildExtras()) { return; } if(buildPhase2()) { return; } + (!turtling && buildDefenses()); } //Check if a building has modules to be built function maintenance() { - const MIN_POWER = 160; const LIST = ["A0PowMod1", "A0FacMod1", "A0ResearchModule1", "A0FacMod1"]; const MODS = [1, 2, 1, 2]; //Number of modules paired with list above var struct = null, module = "", structList = []; @@ -570,14 +637,6 @@ function maintenance() { if (structList[c].modules < MODS[i]) { - //Only build the last factory module if we have a heavy body - if (structList[c].modules === 1) - { - if ((i === 1) && !componentAvailable("Body11ABT")) - { - continue; - } - } struct = structList[c]; module = LIST[i]; break; diff --git a/multiplay/skirmish/cobra_includes/chat.js b/multiplay/skirmish/cobra_includes/chat.js index de9fbb7..1921ac1 100644 --- a/multiplay/skirmish/cobra_includes/chat.js +++ b/multiplay/skirmish/cobra_includes/chat.js @@ -133,7 +133,7 @@ function freeForAll() if (won === true) { const FRIENDS = playerAlliance(true); - var CACHE_FRIENDS = FRIENDS.length; + const CACHE_FRIENDS = FRIENDS.length; if (CACHE_FRIENDS) { diff --git a/multiplay/skirmish/cobra_includes/events.js b/multiplay/skirmish/cobra_includes/events.js index b639d54..9b7d0b9 100644 --- a/multiplay/skirmish/cobra_includes/events.js +++ b/multiplay/skirmish/cobra_includes/events.js @@ -6,7 +6,6 @@ function eventGameInit() { attackGroup = newGroup(); vtolGroup = newGroup(); - cyborgGroup = newGroup(); sensorGroup = newGroup(); repairGroup = newGroup(); artilleryGroup = newGroup(); @@ -15,7 +14,7 @@ function eventGameInit() lastMsg = "eventGameInit"; addDroidsToGroup(attackGroup, enumDroid(me, DROID_WEAPON).filter(function(obj) { return !obj.isCB; })); - addDroidsToGroup(cyborgGroup, enumDroid(me, DROID_CYBORG)); + addDroidsToGroup(attackGroup, enumDroid(me, DROID_CYBORG)); addDroidsToGroup(vtolGroup, enumDroid(me).filter(function(obj) { return isVTOL(obj); })); addDroidsToGroup(sensorGroup, enumDroid(me, DROID_SENSOR)); addDroidsToGroup(repairGroup, enumDroid(me, DROID_REPAIR)); @@ -26,7 +25,7 @@ function eventGameInit() { if (l < MIN_TRUCKS) { - baseType === CAMP_CLEAN ? groupAdd(constructGroup, cons[i]) : groupAdd(oilGrabberGroup, cons[i]); + !countStruct(FACTORY) ? groupAdd(constructGroup, cons[i]) : groupAdd(oilGrabberGroup, cons[i]); } else { @@ -46,37 +45,30 @@ function eventGameInit() function eventStartLevel() { researchComplete = false; - throttleTime = []; - lastAttackedTime = 0; initializeGrudgeCounter(); - - for (var i = 0; i < 4; ++i) - { - throttleTime.push(0); - } - diffPerks(); forceHover = checkIfSeaMap(); turnOffCyborgs = forceHover; personality = choosePersonality(); turnOffMG = CheckStartingBases(); initializeResearchLists(); - useArti = personality !== "AL" && random(101) < 50; - useVtol = random(101) < 50; + useArti = true; + useVtol = true; recycleForHoverCobra(); buildOrderCobra(); //Start building right away. const THINK_LONGER = (difficulty === EASY) ? 4000 + ((1 + random(4)) * random(1200)) : 0; - setTimer("researchCobra", THINK_LONGER + 700 + 3 * random(70)); + setTimer("CobraProduce", THINK_LONGER + 700 + 3 * random(70)); setTimer("buildOrderCobra", THINK_LONGER + 1100 + 3 * random(60)); - setTimer("CobraProduce", THINK_LONGER + 1400 + 3 * random(70)); - setTimer("switchOffMG", THINK_LONGER + 1800 + 3 * random(70)); - setTimer("lookForOil", THINK_LONGER + 2000 + 3 * random(60)) + setTimer("researchCobra", THINK_LONGER + 1200 + 3 * random(70)); + setTimer("lookForOil", THINK_LONGER + 1600 + 3 * random(60)) + setTimer("checkAllForRepair", THINK_LONGER + 2000 + 3 * random(60)); setTimer("repairDroidTacticsCobra", THINK_LONGER + 2500 + 4 * random(60)); setTimer("artilleryTacticsCobra", THINK_LONGER + 4500 + 4 * random(60)); setTimer("vtolTacticsCobra", THINK_LONGER + 5600 + 3 * random(70)); setTimer("battleTacticsCobra", THINK_LONGER + 7000 + 5 * random(60)); + setTimer("switchOffMG", THINK_LONGER + 10000 + 3 * random(70)); setTimer("recycleForHoverCobra", THINK_LONGER + 15000 + 2 * random(60)); setTimer("stopTimersCobra", THINK_LONGER + 100000 + 5 * random(70)); } @@ -133,7 +125,8 @@ function eventDroidBuilt(droid, struct) { if (isConstruct(droid)) { - if (enumGroup(oilGrabberGroup).length < 4) + //Combat engineesr are always base builders. + if (droid.body !== "CyborgLightBody" && enumGroup(oilGrabberGroup).length < 4) { groupAdd(oilGrabberGroup, droid); } @@ -155,11 +148,7 @@ function eventDroidBuilt(droid, struct) { groupAdd(vtolGroup, droid); } - else if (droid.droidType === DROID_CYBORG) - { - groupAdd(cyborgGroup, droid); - } - else if (droid.droidType === DROID_WEAPON) + else if (droid.droidType === DROID_WEAPON || droid.droidType === DROID_CYBORG) { //Anything with splash damage or CB abiliities go here. if (droid.isCB || droid.hasIndirect) @@ -191,17 +180,16 @@ function eventAttacked(victim, attacker) } } - if (stopExecution(0, 100000) === false) + if (stopExecution("throttleEventAttacked1", 20000)) { - attackStuff(getScavengerNumber()); + return; } - return; + attackStuff(getScavengerNumber()); } if (attacker && victim && (attacker.player !== me) && !allianceExistsBetween(attacker.player, victim.player)) { - lastAttackedTime = gameTime; if (grudgeCount[attacker.player] < MAX_GRUDGE) { @@ -231,7 +219,7 @@ function eventAttacked(victim, attacker) } } - if (stopExecution(0, 210) || restraint()) + if (stopExecution("throttleEventAttacked2", 750) || !shouldCobraAttack()) { return; } @@ -247,14 +235,14 @@ function eventAttacked(victim, attacker) return (d.type === DROID) && ((d.droidType === DROID_WEAPON) || (d.droidType === DROID_CYBORG) || isVTOL(d)); }); - if (!isDefined(units[2])) + if (units.length < 2) { units = chooseGroup(); } } units = units.filter(function(dr) { - return ((dr.id !== victim.id) + return (dr.id !== victim.id && ((isVTOL(dr) && droidReady(dr)) || (!repairDroid(dr)) && droidCanReach(dr, attacker.x, attacker.y)) ); @@ -287,17 +275,19 @@ function eventGroupLoss(droid, group, size) { if (droid.order !== DORDER_RECYCLE) { - if (stopExecution(3, 12000) === false) + if (stopExecution("throttleGroupLoss", 12000)) { - addBeacon(droid.x, droid.y, ALLIES); + return; } + + addBeacon(droid.x, droid.y, ALLIES); } } //Better check what is going on over there. function eventBeacon(x, y, from, to, message) { - if (stopExecution(2, 13000) === true) + if (stopExecution("throttleBeacon", 13000) || !shouldCobraAttack()) { return; } @@ -310,10 +300,8 @@ function eventBeacon(x, y, from, to, message) return; //not close enough to the beacon. } - //Now uses only one of the ground groups since telling every attack - //group has intense consequences on performance. const UNITS = chooseGroup().filter(function(dr) { - return (!repairDroid(dr) && droidCanReach(dr, x, y)); + return droidCanReach(dr, x, y); }); for (var i = 0, c = UNITS.length; i < c; i++) { @@ -370,10 +358,10 @@ function eventStructureReady(structure) } } - const ENEMY_FACTORY = returnClosestEnemyFactory(); - if (isDefined(ENEMY_FACTORY)) + var fac = returnClosestEnemyFactory(); + if (isDefined(fac)) { - activateStructure(structure, ENEMY_FACTORY); + activateStructure(structure, getObject(fac.typeInfo, fac.playerInfo, fac.idInfo)); } else { diff --git a/multiplay/skirmish/cobra_includes/globalVariables.js b/multiplay/skirmish/cobra_includes/globalVariables.js index ff13eba..ffd70d3 100644 --- a/multiplay/skirmish/cobra_includes/globalVariables.js +++ b/multiplay/skirmish/cobra_includes/globalVariables.js @@ -6,6 +6,14 @@ const VTOL_FACTORY = "A0VTolFactory1"; const MY_BASE = startPositions[me]; const MIN_TRUCKS = 6; const OIL_RES = "OilResource"; +const MIN_POWER = 180; +const MIN_BUILD_POWER = 230; + +const ELECTRONIC_DEFENSES = [ + "Sys-SpyTower", + "WallTower-EMP", + "Emplacement-MortarEMP", +]; //Research constants const TANK_ARMOR = [ @@ -22,11 +30,12 @@ const ESSENTIALS = [ "R-Struc-PowerModuleMk1", "R-Struc-Research-Upgrade09", "R-Struc-Power-Upgrade03a", +]; +const ESSENTIALS_2 = [ "R-Vehicle-Prop-Halftracks", "R-Vehicle-Body05", "R-Struc-RprFac-Upgrade01", "R-Vehicle-Prop-Hover", - "R-Vehicle-Body04", ]; const SYSTEM_UPGRADES = [ "R-Sys-Sensor-Upgrade03", @@ -59,13 +68,14 @@ const BODY_RESEARCH = [ "R-Vehicle-Body14", ]; const VTOL_RES = [ + "R-Wpn-Bomb02", "R-Wpn-Bomb-Accuracy03", - "R-Wpn-Bomb04", "R-Struc-VTOLPad-Upgrade06", + "R-Wpn-Bomb04", "R-Wpn-Bomb06", ]; const LATE_EARLY_GAME_TECH = [ - "R-Vehicle-Body11", + "R-Vehicle-Body12", "R-Vehicle-Prop-Tracks", ]; @@ -75,16 +85,14 @@ const TANK_BODY = [ "Body13SUP", // Wyvern "Body10MBT", // Vengeance "Body7ABT", // Retribution - "Body6SUPP", // Panther - "Body11ABT", // Python "Body12SUP", // Mantis + "Body6SUPP", // Panther "Body8MBT", // Scorpion "Body5REC", // Cobra "Body1REC", // Viper ]; const SYSTEM_BODY = [ "Body3MBT", // Retaliation -// "Body2SUP", // Leopard "Body4ABT", // Bug "Body1REC", // Viper ]; @@ -126,7 +134,7 @@ const SUB_PERSONALITIES = "defensePriority": 10, "vtolPriority": 20, "systemPriority": 30, - "alloyPriority": 10, + "alloyPriority": 20, "res": [ "R-Wpn-Cannon-Damage02", "R-Wpn-Cannon-ROF02", @@ -138,14 +146,14 @@ const SUB_PERSONALITIES = "secondaryWeapon": weaponStats.gauss, "artillery": weaponStats.mortars, "antiAir": weaponStats.AA, - "factoryOrder": [FACTORY, VTOL_FACTORY, CYBORG_FACTORY], + "factoryOrder": [FACTORY, CYBORG_FACTORY, VTOL_FACTORY], "defensePriority": 20, "vtolPriority": 40, "systemPriority": 20, "alloyPriority": 25, "res": [ "R-Wpn-Flamer-Damage03", - "R-Wpn-Flamer-ROF03", + "R-Wpn-Flamer-ROF01", ], }, AB: @@ -153,14 +161,16 @@ const SUB_PERSONALITIES = "primaryWeapon": weaponStats.rockets_AT, "secondaryWeapon": weaponStats.gauss, "artillery": weaponStats.rockets_Arty, - "antiAir": weaponStats.AA, - "factoryOrder": [CYBORG_FACTORY, VTOL_FACTORY, FACTORY], + "antiAir": weaponStats.rockets_AA, + "factoryOrder": [FACTORY, VTOL_FACTORY, CYBORG_FACTORY], "defensePriority": 60, "vtolPriority": 90, "systemPriority": 15, "alloyPriority": 15, "res": [ "R-Wpn-MG2Mk1", + "R-Wpn-Rocket02-MRL", + "R-Wpn-Rocket01-LtAT", ], }, AM: @@ -188,8 +198,9 @@ const SUB_PERSONALITIES = "defensePriority": 10, "vtolPriority": 100, "systemPriority": 40, - "alloyPriority": 5, + "alloyPriority": 10, "res": [ + "R-Wpn-Mortar-Incenediary", "R-Wpn-Laser01", ], }, @@ -198,7 +209,6 @@ const SUB_PERSONALITIES = // Groups var attackGroup; var vtolGroup; -var cyborgGroup; var sensorGroup; var repairGroup; var artilleryGroup; @@ -211,9 +221,7 @@ var lastMsg; //The last Cobra chat message. var forceHover; //Use hover propulsion only. var seaMapWithLandEnemy; //Hover map with an enemy sharing land with Cobra. var turnOffCyborgs; //Turn of cyborgs (hover maps/chat). -var throttleTime; //For events so that some do not trigger their code too fast. More details in stopExecution() in miscFunctions. var researchComplete; //Check if done with research. -var lastAttackedTime; var turnOffMG; //This is only used for when the personalities don't have their weapons researched. var useArti; var useVtol; @@ -233,3 +241,4 @@ var extremeLaserTech; var secondaryWeaponTech; var secondaryWeaponExtra; var defenseTech; +var standardDefenseTech; diff --git a/multiplay/skirmish/cobra_includes/mapDynamics.js b/multiplay/skirmish/cobra_includes/mapDynamics.js index 5dab7ac..8ad87dc 100644 --- a/multiplay/skirmish/cobra_includes/mapDynamics.js +++ b/multiplay/skirmish/cobra_includes/mapDynamics.js @@ -1,23 +1,7 @@ -//Need to search for scavenger player number. Keep undefined if there are no scavengers. + function getScavengerNumber() { - function uncached() - { - var scavNumber; - for (var x = maxPlayers; x < 11; ++x) - { - var structs = enumStruct(x); - if (isDefined(structs[0])) - { - scavNumber = x; - break; - } - } - - return scavNumber; - } - - return cacheThis(uncached, [], undefined, Infinity); + return scavengerPlayer; } //Figure out if we are on a hover map. This is determined by checking if a @@ -62,7 +46,7 @@ function checkIfSeaMap() if ((i !== me) && !allianceExistsBetween(i, me) && propulsionCanReach("wheeled01", MY_BASE.x, MY_BASE.y, startPositions[i].x, startPositions[i].y)) { //Check to see if it is a closed player slot - if (enumDroid(i).length) + if (countDroid(DROID_ANY, i).length) { seaMapWithLandEnemy = true; break; diff --git a/multiplay/skirmish/cobra_includes/miscFunctions.js b/multiplay/skirmish/cobra_includes/miscFunctions.js index 2df3e33..cf86b30 100644 --- a/multiplay/skirmish/cobra_includes/miscFunctions.js +++ b/multiplay/skirmish/cobra_includes/miscFunctions.js @@ -10,25 +10,25 @@ function random(max) // Returns true if something is defined function isDefined(data) { - return (typeof(data) !== "undefined"); + return typeof(data) !== "undefined"; } //Determine if a game object is destroyed or not. function isObjectAlive(object) { - return (isDefined(object) && object && (object.id !== 0)); + return object && isDefined(object) && (object.id !== 0); } //Sort an array from smallest to largest in value. function sortArrayNumeric(a, b) { - return (a - b); + return a - b; } //Sort an array from smallest to largest in terms of droid health. function sortDroidsByHealth(a, b) { - return (a.health - b.health); + return a.health - b.health; } //Used for deciding if a truck will capture oil. @@ -88,7 +88,7 @@ function distanceToBase(obj1, obj2) { var dist1 = distBetweenTwoPoints(MY_BASE.x, MY_BASE.y, obj1.x, obj1.y); var dist2 = distBetweenTwoPoints(MY_BASE.x, MY_BASE.y, obj2.x, obj2.y); - return (dist1 - dist2); + return dist1 - dist2; } //Push list elements into another. @@ -119,31 +119,36 @@ function addDroidsToGroup(group, droids) //Returns closest enemy object. function rangeStep(player) { - if (!isDefined(player)) + function uncached(player) { - player = getMostHarmfulPlayer(); - } + if (!isDefined(player)) + { + player = getMostHarmfulPlayer(); + } - var targets = []; - var closestStructure = findNearestEnemyStructure(player); - var closestDroid = findNearestEnemyDroid(player); + var targets = []; + var struc = findNearestEnemyStructure(player); + var droid = findNearestEnemyDroid(player); - if (isDefined(closestStructure)) - { - targets.push(closestStructure); - } - if (isDefined(closestDroid)) - { - targets.push(closestDroid); - } + if (isDefined(struc)) + { + targets.push(getObject(struc.typeInfo, struc.playerInfo, struc.idInfo)); + } + if (isDefined(droid)) + { + targets.push(getObject(droid.typeInfo, droid.playerInfo, droid.idInfo)); + } - if (isDefined(targets[0])) - { - targets = targets.sort(distanceToBase); - return targets[0]; + if (isDefined(targets[0])) + { + targets = targets.sort(distanceToBase); + return objectInformation(targets[0]); + } + + return undefined; } - return undefined; + return cacheThis(uncached, [player]); } //Ally is false for checking for enemy players @@ -246,7 +251,7 @@ function findLivingEnemies() var alive = []; for (var x = 0; x < maxPlayers; ++x) { - if ((x !== me) && !allianceExistsBetween(x, me) && (enumDroid(x).length || enumStruct(x).length)) + if ((x !== me) && !allianceExistsBetween(x, me) && (countDroid(DROID_ANY, x).length || enumStruct(x).length)) { alive.push(x); } @@ -345,7 +350,7 @@ function donateFromGroup(from, group) switch (group) { case "ATTACK": chosenGroup = enumGroup(attackGroup); break; - case "CYBORG": chosenGroup = enumGroup(cyborgGroup); break; + case "CYBORG": chosenGroup = enumGroup(attackGroup).filter(function(dr) { return dr.droidType === DROID_CYBORG; }); break; case "VTOL": chosenGroup = enumGroup(vtolGroup); break; default: chosenGroup = enumGroup(attackGroup); break; } diff --git a/multiplay/skirmish/cobra_includes/performance.js b/multiplay/skirmish/cobra_includes/performance.js index e9c1563..1f218bb 100644 --- a/multiplay/skirmish/cobra_includes/performance.js +++ b/multiplay/skirmish/cobra_includes/performance.js @@ -33,7 +33,10 @@ function cacheThis(func, funcParameters, cachedItem, time) var t = arguments.callee.caller.cachedTimes[cachedItem]; var obj = arguments.callee.caller.cachedValues[cachedItem]; - if (!isDefined(obj) || ((gameTime - t) >= REFRESH_TIME)) + var def = isDefined(obj); + if (!def + || (def && isDefined(obj.typeInfo) && (getObject(obj.typeInfo, obj.playerInfo, obj.idInfo) === null)) + || ((gameTime - t) >= REFRESH_TIME)) { arguments.callee.caller.cachedValues[cachedItem] = callFuncWithArgs(func, funcParameters); arguments.callee.caller.cachedTimes[cachedItem] = gameTime; @@ -42,31 +45,41 @@ function cacheThis(func, funcParameters, cachedItem, time) return arguments.callee.caller.cachedValues[cachedItem]; } -//TODO: Implement this better -//Determine if something (namely events) should be skipped momentarily. -//0 - eventAttacked(). -//1 - eventChat(). -//2 - eventBeacon(). -//3 - eventGroupLoss(). (the addBeacon call). -//ms is a delay value. -//Defaults to checking eventAttacked timer. -function stopExecution(throttleNumber, ms) +//A simple throttle function to make sure something is not executed too much. +function stopExecution(throttleThis, time) { - if (!isDefined(throttleNumber)) + if (!isDefined(time)) { - throttleNumber = 0; - } + time = 2000; + } - if (!isDefined(ms)) + if (!isDefined(arguments.callee.caller.throttleTimes)) { - ms = 1000; - } + arguments.callee.caller.throttleTimes = {}; + } - if (gameTime > (throttleTime[throttleNumber] + ms)) + if (!isDefined(arguments.callee.caller.throttleTimes[throttleThis])) { - throttleTime[throttleNumber] = gameTime + (4 * random(500)); + arguments.callee.caller.throttleTimes[throttleThis] = gameTime; return false; } - return true; + if (gameTime - arguments.callee.caller.throttleTimes[throttleThis] < time) + { + return true; + } + + arguments.callee.caller.throttleTimes[throttleThis] = gameTime; + return false; +} + +//This way we can pass around DROID/STRUCTURE/FEATURE object information in cacheThis by using getObject() +//in the calling functions since assigning a variable only keeps a snapshot of the object as it was at the time. +function objectInformation(object) +{ + return { + "typeInfo": object.type, + "playerInfo": object.player, + "idInfo": object.id + }; } diff --git a/multiplay/skirmish/cobra_includes/production.js b/multiplay/skirmish/cobra_includes/production.js index 9f83cf9..bcbaedc 100644 --- a/multiplay/skirmish/cobra_includes/production.js +++ b/multiplay/skirmish/cobra_includes/production.js @@ -358,11 +358,13 @@ function analyzeQueuedSystems() //Produce a unit when factories allow it. function CobraProduce() { - const MIN_POWER = 160; - const MIN_COM_ENG = 3; + if (countDroid(DROID_ANY) >= 150) + { + return; //Stop spamming about having the droid limit reached. + } const MIN_SENSORS = 2; const MIN_REPAIRS = 3; - var useCybEngineer = false; //countStruct(CYBORG_FACTORY) && !componentAvailable("hover01"); + var useCybEngineer = countStruct(CYBORG_FACTORY) && (enumGroup(constructGroup).length < 4); var systems = analyzeQueuedSystems(); var attackers = enumGroup(attackGroup); @@ -409,7 +411,7 @@ function CobraProduce() //Do not produce weak body units if we can give this factory a module. if (!countStruct(structures.gens) || (FC.modules < 1 - && componentAvailable("Body11ABT"))) + && componentAvailable("Body12SUP"))) { continue; } @@ -421,7 +423,7 @@ function CobraProduce() { if (countStruct(structures.gens)) { - if (facType === CYBORG_FACTORY) + if (facType === CYBORG_FACTORY && (!turnOffCyborgs || !forceHover)) { buildCyborg(FC, useCybEngineer); } diff --git a/multiplay/skirmish/cobra_includes/research.js b/multiplay/skirmish/cobra_includes/research.js index b804e55..b7100e6 100644 --- a/multiplay/skirmish/cobra_includes/research.js +++ b/multiplay/skirmish/cobra_includes/research.js @@ -33,6 +33,7 @@ function initializeResearchLists() secondaryWeaponTech = updateResearchList(SUB_PERSONALITIES[personality].secondaryWeapon.weapons); secondaryWeaponExtra = updateResearchList(SUB_PERSONALITIES[personality].secondaryWeapon.extras); defenseTech = updateResearchList(SUB_PERSONALITIES[personality].artillery.defenses); + standardDefenseTech = updateResearchList(SUB_PERSONALITIES[personality].primaryWeapon.defenses) cyborgWeaps = updateResearchList(SUB_PERSONALITIES[personality].primaryWeapon.templates); } @@ -42,26 +43,20 @@ function initializeResearchLists() //one is not completed... so lets help it a bit. function evalResearch(lab, list) { - var found = false; - for (var i = 0, a = list.length; i < a; ++i) { - found = pursueResearch(lab, list[i]); - if (found) + if (pursueResearch(lab, list[i])) { - break; + return true; } } - return found; + return false; } function researchCobra() { - const MIN_POWER = 170; - if (!countDroid(DROID_CONSTRUCT) - || getRealPower() < MIN_POWER - || !(isDefined(techlist) && isDefined(turnOffCyborgs))) + if (!countDroid(DROID_CONSTRUCT) || !(isDefined(techlist) && isDefined(turnOffCyborgs))) { return; } @@ -73,22 +68,26 @@ function researchCobra() for (var i = 0, a = labList.length; i < a; ++i) { var lab = labList[i]; - var found = evalResearch(lab, ESSENTIALS); + var found = found = evalResearch(lab, ESSENTIALS); - if (!found && (getRealPower() > MIN_POWER)) + if (!found && getRealPower() > MIN_POWER) { if (!found) found = evalResearch(lab, techlist); + if (!found) + found = evalResearch(lab, ESSENTIALS_2); if (!found) - found = evalResearch(lab, weaponTech); + found = evalResearch(lab, LATE_EARLY_GAME_TECH); + if (!found && !turnOffCyborgs) + found = evalResearch(lab, cyborgWeaps); if (!found) found = evalResearch(lab, SYSTEM_UPGRADES); if (!found) - found = evalResearch(lab, LATE_EARLY_GAME_TECH); + found = evalResearch(lab, weaponTech); //Use default AA until stormbringer. - if (countEnemyVTOL() && !isStructureAvailable("P0-AASite-Laser")) + if (!random(2) && countEnemyVTOL() && !isStructureAvailable("P0-AASite-Laser")) { if (!found) found = evalResearch(lab, antiAirTech); @@ -96,6 +95,11 @@ function researchCobra() found = evalResearch(lab, antiAirExtras); } + if (!found && useArti && returnArtilleryAlias() !== "rkta") + found = evalResearch(lab, artillExtra); + if (!found) + found = evalResearch(lab, extraTech); + if (!found && (random(101) < SUB_PERSONALITIES[personality].alloyPriority)) { found = evalResearch(lab, TANK_ARMOR); @@ -105,19 +109,15 @@ function researchCobra() } } - if (!found && !turnOffCyborgs) - found = evalResearch(lab, cyborgWeaps); + if (!found && useArti) + found = evalResearch(lab, defenseTech); if (!found) - found = evalResearch(lab, extraTech); + found = evalResearch(lab, standardDefenseTech); + if (!found && useArti) found = evalResearch(lab, artilleryTech); - if (!found && useArti) - found = evalResearch(lab, artillExtra); - if (!found && (random(101) < SUB_PERSONALITIES[personality].systemPriority)) found = evalResearch(lab, SENSOR_TECH); - if (!found && useArti) - found = evalResearch(lab, defenseTech); if (!found && useVtol && (random(101) < SUB_PERSONALITIES[personality].vtolPriority)) found = evalResearch(lab, VTOL_RES); @@ -127,21 +127,17 @@ function researchCobra() if (!found) found = evalResearch(lab, BODY_RESEARCH); - //Late game weapon. - if (random(3)) - { - var cyborgSecondary = appendListElements(cyborgSecondary, updateResearchList(SUB_PERSONALITIES[personality].secondaryWeapon.templates)); - var len = SUB_PERSONALITIES[personality].primaryWeapon.weapons.length - 1; - if (isDesignable(SUB_PERSONALITIES[personality].primaryWeapon.weapons[len].stat)) - { - if(!found && !turnOffCyborgs && isDefined(cyborgSecondary[0])) - found = pursueResearch(lab, cyborgSecondary); - if(!found) - found = evalResearch(lab, secondaryWeaponExtra); - if(!found) - found = evalResearch(lab, secondaryWeaponTech); - } + var cyborgSecondary = appendListElements(cyborgSecondary, updateResearchList(SUB_PERSONALITIES[personality].secondaryWeapon.templates)); + var len = SUB_PERSONALITIES[personality].primaryWeapon.weapons.length - 1; + if (isDesignable(SUB_PERSONALITIES[personality].primaryWeapon.weapons[len].stat)) + { + if(!found && !turnOffCyborgs && isDefined(cyborgSecondary[0])) + found = pursueResearch(lab, cyborgSecondary); + if(!found) + found = evalResearch(lab, secondaryWeaponExtra); + if(!found) + found = evalResearch(lab, secondaryWeaponTech); } // Lasers diff --git a/multiplay/skirmish/cobra_includes/tactics.js b/multiplay/skirmish/cobra_includes/tactics.js index d77f1c9..6008ba5 100644 --- a/multiplay/skirmish/cobra_includes/tactics.js +++ b/multiplay/skirmish/cobra_includes/tactics.js @@ -4,9 +4,9 @@ function droidReady(droid) { return (!repairDroid(droid, false) - && (droid.order !== DORDER_ATTACK) - && (droid.order !== DORDER_RTR) - && (droid.order !== DORDER_RECYCLE) + && droid.order !== DORDER_ATTACK + && droid.order !== DORDER_RTR + && droid.order !== DORDER_RECYCLE && vtolReady(droid) //True for non-VTOL units ); } @@ -14,27 +14,14 @@ function droidReady(droid) //Check if a passed in weapon name is a plasma cannon. function isPlasmaCannon(weaponName) { - if (!isDefined(weaponName)) - { - return false; - } - - return (weaponName.name === "Laser4-PlasmaCannon"); + return isDefined(weaponName) && (weaponName.name === "Laser4-PlasmaCannon"); } //Modified from Nullbot. //Returns true if the VTOL has ammo. False if empty. function vtolArmed(obj, percent) { - for (var i = 0, p = obj.weapons.length; i < p; ++i) - { - if (obj.weapons[i].armed >= percent) - { - return true; - } - } - - return false; + return obj.weapons[0].armed >= percent; } //Count how many Enemy VTOL units are on the map. @@ -57,54 +44,64 @@ function countEnemyVTOL() return cacheThis(uncached, []); } -//Return the closest factory for an enemy. Undefined if none. +//Return information about the closest factory for an enemy. Undefined if none. function returnClosestEnemyFactory(enemyNumber) { - if (!isDefined(enemyNumber)) + function uncached(enemyNumber) { - enemyNumber = getMostHarmfulPlayer(); - } + if (!isDefined(enemyNumber)) + { + enemyNumber = getMostHarmfulPlayer(); + } - var facs = enumStruct(enemyNumber, FACTORY); - facs = appendListElements(facs, enumStruct(enemyNumber, CYBORG_FACTORY)); - facs = appendListElements(facs, enumStruct(enemyNumber, VTOL_FACTORY)); + var facs = enumStruct(enemyNumber, FACTORY); + facs = appendListElements(facs, enumStruct(enemyNumber, CYBORG_FACTORY)); + facs = appendListElements(facs, enumStruct(enemyNumber, VTOL_FACTORY)); - if (isDefined(facs[0])) - { - facs = facs.sort(distanceToBase); - return facs[0]; + if (isDefined(facs[0])) + { + facs = facs.sort(distanceToBase); + return objectInformation(facs[0]); + } + + return undefined; } - return undefined; + return cacheThis(uncached, [enemyNumber]); } -//Return the closest enemy truck for an enemy. Undefined if none. +//Return information about the closest enemy truck for an enemy. Undefined if none. function getClosestEnemyTruck(enemyNumber) { - if (!isDefined(enemyNumber)) + function uncached(enemyNumber) { - enemyNumber = getMostHarmfulPlayer(); - } + if (!isDefined(enemyNumber)) + { + enemyNumber = getMostHarmfulPlayer(); + } - var trucks = enumDroid(enemyNumber, DROID_CONSTRUCT); - if (isDefined(trucks[0])) - { - trucks.sort(distanceToBase); - return trucks[0]; + var trucks = enumDroid(enemyNumber, DROID_CONSTRUCT); + if (isDefined(trucks[0])) + { + trucks.sort(distanceToBase); + return objectInformation(trucks[0]); + } + + return undefined; } - return undefined; + return cacheThis(uncached, [enemyNumber]); } //Should the vtol attack when ammo is high enough? function vtolReady(droid) { - const ARMED_PERCENT = 1; if (!isVTOL(droid)) { return true; //See droidReady(droid). } + const ARMED_PERCENT = 1; if ((droid.order === DORDER_ATTACK) || (droid.order === DORDER_REARM)) { return false; @@ -124,7 +121,7 @@ function vtolReady(droid) //Repair a droid with the option of forcing it to. function repairDroid(droid, force) { - const FORCE_REPAIR_PERCENT = 40; + const FORCE_REPAIR_PERCENT = 48; const EXPERIENCE_DIVISOR = 22; const HEALTH_TO_REPAIR = 58 + Math.floor(droid.experience / EXPERIENCE_DIVISOR); @@ -152,16 +149,29 @@ function repairDroid(droid, force) return false; } -//choose either cyborgs or tanks. -function chooseGroup() +//Continuously check a random ground group for repair +function checkAllForRepair() { - var grp = random(2) ? enumGroup(attackGroup) : enumGroup(cyborgGroup); - grp = grp.filter(function(dr) { return droidReady(dr); }); + if (!countStruct(structures.extras[0])) + { + return; + } - return !isDefined(grp[MIN_ATTACK_DROIDS]) ? enumGroup(attackGroup) : grp; + var droids = enumGroup(attackGroup); + for (var i = 0, l = droids.length; i < l; ++i) + { + var droid = droids[i]; + repairDroid(droid, Math.floor(droid.health) < 48); + } } -//Find the derricks of all enemy players, or just a specific one. +//choose land attackers. +function chooseGroup() +{ + return enumGroup(attackGroup).filter(function(dr) { return droidReady(dr); }); +} + +//Find the closest enemy derrick information. If no player is defined, then all of them are checked. function findEnemyDerricks(playerNumber) { function uncached(playerNumber) @@ -186,58 +196,74 @@ function findEnemyDerricks(playerNumber) derr = enumStruct(playerNumber, structures.derricks); } - return derr; + derrs = derrs.sort(distanceToBase); + if (isDefined(derrs[0])) + { + return objectInformation(derrs[0]); + } + + return undefined; } - return cacheThis(uncached, [playerNumber], undefined, 3000); + return cacheThis(uncached, [playerNumber]); } -//Find closest enemy droid. Returns undefined otherwise. Do not target VTOLs +//Find information about the closest enemy droid. Returns undefined otherwise. Do not target VTOLs //unless they are the only remaining droids. function findNearestEnemyDroid(enemy) { - if (!isDefined(enemy)) + function uncached(enemy) { - enemy = getMostHarmfulPlayer(); - } + if (!isDefined(enemy)) + { + enemy = getMostHarmfulPlayer(); + } - var badDroids = enumDroid(enemy); - if (isDefined(badDroids[0])) - { - var temp = badDroids.filter(function(dr) { return !isVTOL(dr); }); - if (!isDefined(temp[0])) + var badDroids = enumDroid(enemy); + if (isDefined(badDroids[0])) { - temp = badDroids; + var temp = badDroids.filter(function(dr) { return !isVTOL(dr); }); + if (!isDefined(temp[0])) + { + temp = badDroids; + } + + temp = temp.sort(distanceToBase); + return objectInformation(temp[0]); } - temp = temp.sort(distanceToBase); - return temp[0]; + return undefined; } - return undefined; + return cacheThis(uncached, [enemy], enemy, 16000); } -//Return the closest structure of an enemy. Returns undefined otherwise. +//Return information about the closest structure of an enemy. Returns undefined otherwise. function findNearestEnemyStructure(enemy) { - if (!isDefined(enemy)) + function uncached(enemy) { - enemy = getMostHarmfulPlayer(); - } + if (!isDefined(enemy)) + { + enemy = getMostHarmfulPlayer(); + } - var s = enumStruct(enemy).filter(function(obj) { return (obj.stattype !== WALL); }); - if (!isDefined(s[0])) - { - s = enumStruct(enemy); - } + var s = enumStruct(enemy).filter(function(obj) { return (obj.stattype !== WALL); }); + if (!isDefined(s[0])) + { + s = enumStruct(enemy); + } - if (isDefined(s[0])) - { - s = s.sort(distanceToBase); - return s[0]; + if (isDefined(s[0])) + { + s = s.sort(distanceToBase); + return objectInformation(s[0]); + } + + return undefined; } - return undefined; + return cacheThis(uncached, [enemy], enemy, 16000); } //Attack something. @@ -261,7 +287,11 @@ function attackWithGroup(enemy, targets) } else { - target = getCloseEnemyObject(); + target = rangeStep(); + if (isDefined(target)) + { + target = getObject(target.typeInfo, target.playerInfo, target.idInfo); + } } for (var j = 0; j < LEN; j++) @@ -289,7 +319,7 @@ function chatTactic(enemy) //attacker is a player number. Attack a specific player. function attackStuff(attacker) { - if (restraint()) + if (!shouldCobraAttack() || stopExecution("attackStuff", 5000)) { return; } @@ -307,13 +337,11 @@ function attackStuff(attacker) //Sensors know all your secrets. They will observe what is closest to Cobra base. function artilleryTacticsCobra() { - if (restraint()) + if (!shouldCobraAttack()) { return; } - - var sensors = enumGroup(sensorGroup).filter(function(dr) - { + var sensors = enumGroup(sensorGroup).filter(function(dr) { return droidReady(dr); }); const ARTILLERY_UNITS = enumGroup(artilleryGroup); @@ -327,6 +355,7 @@ function artilleryTacticsCobra() if (isDefined(obj)) { + obj = getObject(obj.typeInfo, obj.playerInfo, obj.idInfo); orderDroidObj(sensors[0], DORDER_OBSERVE, obj); for (var i = 0; i < ARTI_LEN; ++i) { @@ -345,12 +374,12 @@ function attackEnemyOil() if (LEN >= MIN_ATTACK_DROIDS) { var derr = findEnemyDerricks(); - if (isDefined(derr[0])) + derr = getObject(derr.typeInfo, derr.playerInfo, derr.idInfo); + if (isDefined(derr)) { - derr = derr.sort(distanceToBase); for (var i = 0; i < LEN; ++i) { - attackThisObject(WHO[i], derr[0]); + attackThisObject(WHO[i], derr); } } } @@ -359,55 +388,20 @@ function attackEnemyOil() //Defend or attack. function battleTacticsCobra() { - if (restraint()) - { - return; - } - - const MIN_DERRICKS = averageOilPerPlayer(); const ENEMY = getMostHarmfulPlayer(); - const MIN_GRUDGE = 300; donateSomePower(); + enemyUnitsInBase() - if ((countStruct(structures.derricks) < MIN_DERRICKS) || (getRealPower() < -50)) - { - attackEnemyOil(); - } - else if (grudgeCount[ENEMY] > MIN_GRUDGE) + if (shouldCobraAttack()) { - const ENEMY_FACTORY = returnClosestEnemyFactory(); - if (random(101) < 5) + var target = rangeStep(); + if (isDefined(target)) { - chatTactic(ENEMY); //Tell players to attack this enemy. - } - - if (isDefined(ENEMY_FACTORY)) - { - attackWithGroup(ENEMY, ENEMY_FACTORY); - } - else - { - const ENEMY_TRUCK = getClosestEnemyTruck(); - if (isDefined(ENEMY_TRUCK)) - { - attackWithGroup(ENEMY, ENEMY_TRUCK); - } - else + target = getObject(target.typeInfo, target.playerInfo, target.idInfo); + const WHO = chooseGroup(); + for (var i = 0, l = WHO.length; i < l; ++i) { - grudgeCount[ENEMY] = 0; //they dead. - } - } - } - else - { - const WHO = chooseGroup(); - const LEN = WHO.length; - if (LEN >= MIN_ATTACK_DROIDS) - { - var nearestTarget = getCloseEnemyObject(); - for (var i = 0; i < LEN; ++i) - { - attackThisObject(WHO[i], nearestTarget); + attackThisObject(WHO[i], target); } } } @@ -417,10 +411,14 @@ function battleTacticsCobra() function recycleForHoverCobra() { const MIN_FACTORY = 1; - var systems = enumDroid(me).filter(function(dr) { return isConstruct(dr); }); + var systems = enumDroid(me).filter(function(dr) { + return isConstruct(dr); + }); systems = appendListElements(systems, enumDroid(me, DROID_SENSOR)); systems = appendListElements(systems, enumDroid(me, DROID_REPAIR)); - systems = systems.filter(function(dr) { return (dr.propulsion !== "hover01"); }); + systems = systems.filter(function(dr) { + return (dr.body !== "CyborgLightBody" && dr.propulsion !== "hover01"); + }); var unfinished = unfinishedStructures(); const NON_HOVER_SYSTEMS = systems.length; @@ -465,7 +463,9 @@ function repairDroidTacticsCobra() if (LEN) { - var myDroids = random(2) ? enumGroup(attackGroup) : enumGroup(cyborgGroup); + var myDroids = enumGroup(attackGroup).filter(function(dr) { + return dr.order !== DORDER_RTR; + }); if (isDefined(myDroids[0])) { @@ -504,21 +504,22 @@ function targetPlayer(playerNumber) //VTOL units do there own form of tactics. function vtolTacticsCobra() { - if (restraint()) - { - return; - } - const MIN_VTOLS = 5; - var vtols = enumGroup(vtolGroup).filter(function(dr) { return droidReady(dr); }); + var vtols = enumGroup(vtolGroup).filter(function(dr) { + return droidReady(dr); + }); const LEN = vtols.length; if (LEN >= MIN_VTOLS) { - var target = getCloseEnemyObject(); - for (var i = 0; i < LEN; ++i) + var target = rangeStep(); + if (isDefined(target)) { - attackThisObject(vtols[i], target); + target = getObject(target.typeInfo, target.playerInfo, target.idInfo); + for (var i = 0; i < LEN; ++i) + { + attackThisObject(vtols[i], target); + } } } } @@ -533,7 +534,11 @@ function attackThisObject(droid, target) if (!isDefined(target)) { - target = getCloseEnemyObject(); + target = rangeStep(); + if (isDefined(target)) + { + target = getObject(target.typeInfo, target.playerInfo, target.idInfo); + } } if (isDefined(droid) && droidReady(droid) && isDefined(target) && droidCanReach(droid, target.x, target.y)) @@ -552,73 +557,105 @@ function attackThisObject(droid, target) } } -//Return the closest enemy player structure or droid. Undefined if none. -function getCloseEnemyObject(enemy) +//Check if enemy units are in or around Cobra base. +function enemyUnitsInBase() { - if (!isDefined(enemy)) + var area = initialTerritory(); + var enemyUnits = enumArea(area.x1, area.y1, area.x2, area.y2, ENEMIES, false).filter(function(obj) { + return (obj.type === DROID + && (obj.droidType === DROID_WEAPON + || obj.droidType === DROID_CYBORG) + ); + }); + + var enemyNearBase = enemyUnits.sort(distanceToBase); + + //The attack code automatically chooses the closest object of the + //most harmful player anyway so this should suffice for defense. + if (enemyNearBase.length) { - enemy = getMostHarmfulPlayer(); + targetPlayer(enemyUnits[0].player); //play rough. } - var target = findNearestEnemyStructure(enemy); - if (!isDefined(target)) + return isDefined(enemyNearBase); +} + +//Donate my power to allies if I have too much. +function donateSomePower() +{ + const ALLY_PLAYERS = playerAlliance(true); + const LEN = ALLY_PLAYERS.length; + const ALIVE_ENEMIES = findLivingEnemies().length; + + if (LEN && ALIVE_ENEMIES) { - target = findNearestEnemyDroid(enemy); - if (!isDefined(target)) + var ally = ALLY_PLAYERS[random(LEN)] + if (getRealPower() > 100 && (playerPower(me) > 2 * playerPower(ally))) { - return undefined; + donatePower(playerPower(me) / 2, ally); } } - - return target; } -//Check if enemy units are in or around Cobra base. -function enemyUnitsInBase() +//Flee! Flee for your lives! +function runAway() { - var enemyUnits = enumRange(MY_BASE.x, MY_BASE.y, 16, ENEMIES, true).filter(function(dr) { - return (dr.type === DROID && dr.droidType === DROID_WEAPON); + var droids = enumDroid(me).filter(function(dr) { + return ((dr.droidType === DROID_WEAPON + || dr.droidType === DROID_CYBORG) + && !isVTOL(dr)); }); - var enemyNearBase = isDefined(enemyUnits[0]); - - //The attack code automatically chooses the closest object of the - //most harmful player anyway so this should suffice for defense. - if (enemyNearBase) + for (var i = 0, l = droids.length; i < l; ++i) { - targetPlayer(enemyUnits[0].player); //play rough. + var droid = droids[i]; + if (droid.order !== DORDER_RTR) + { + orderDroidLoc(droid, DORDER_MOVE, MY_BASE.x, MY_BASE.y); + } } - - return enemyNearBase; } -//Stop all attacker droids from attacking. Repairs are initiated in addition to that. -function haltAttackDroids() +//Does Cobra believe it is winning or could win? +function confidenceThreshold() { - const DROIDS = enumDroid(me).filter(function(dr) { - return (dr.droidType !== DROID_CONSTRUCT - && dr.droidType !== DROID_REPAIR - && !isVTOL(dr) - ); - }); + const DERR_COUNT = countStruct(structures.derricks); + var points = 0; + var derrRatio = Math.floor(DERR_COUNT / countAllResources()) * 100; - for (var i = 0, l = DROIDS.length; i < l; ++i) + //Owning ~half the oils or more is a good signal of winning + if (derrRatio >= 40) { - const DROID = DROIDS[i]; - orderDroid(DROID, DORDER_STOP); - repairDroid(DROID, false); + return true; } + + points = (DERR_COUNT >= countStruct(structures.derricks, getMostHarmfulPlayer())) ? (points + 12) : (points - 12); + points = (countDroid(DROID_ANY) >= countDroid(DROID_ANY, getMostHarmfulPlayer()) - 4) ? (points + 21) : (points - 7); + //team stuff + if (playerAlliance(true).length) + { + points = (findLivingEnemies().length <= playerAlliance(true).length + 1) ? (points + 15) : (points - 15); + } + //more + points = random(2) ? (points + random(8)) : (points - random(4)); + points += Math.floor(DERR_COUNT / 2.5); + if (enumGroup(attackGroup).length < MIN_ATTACK_DROIDS) + { + points -= 6; + } + + return (points > -1); } -//Donate my power to allies if I have too much. -function donateSomePower() +//Check if our forces are large enough to take on the most harmful player. +function shouldCobraAttack() { - const ALLY_PLAYERS = playerAlliance(true); - const LEN = ALLY_PLAYERS.length; - const ALIVE_ENEMIES = findLivingEnemies().length; - - if (LEN && ALIVE_ENEMIES && (getRealPower() > 3000)) + if (confidenceThreshold() && countDroid(DROID_ANY) > 15) { - donatePower(playerPower(me) / 2, ALLY_PLAYERS[random(LEN)]); + return true; + } + else { + runAway(); + return false; } } diff --git a/multiplay/skirmish/cobra_rulesets/CobraStandard.js b/multiplay/skirmish/cobra_rulesets/CobraStandard.js index bba0187..8e27529 100644 --- a/multiplay/skirmish/cobra_rulesets/CobraStandard.js +++ b/multiplay/skirmish/cobra_rulesets/CobraStandard.js @@ -360,8 +360,7 @@ const weaponStats = alias: "rkta", weapons: [ { res: "R-Wpn-Rocket02-MRL", stat: "Rocket-MRL" }, // mra - //{ res: "R-Wpn-Rocket03-HvAT", stat: "Rocket-BB" }, // bb - //{ res: "R-Wpn-Rocket06-IDF", stat: "Rocket-IDF" }, // ripple + { res: "R-Wpn-Rocket06-IDF", stat: "Rocket-IDF" }, // ripple { res: "R-Wpn-MdArtMissile", stat: "Missile-MdArt" }, // seraph { res: "R-Wpn-HvArtMissile", stat: "Missile-HvyArt" }, // archie ], @@ -508,8 +507,8 @@ const weaponStats = alias: "bomb", weapons: [], vtols: [ - { res: "R-Wpn-Bomb01", stat: "Bomb1-VTOL-LtHE" }, // cluster bomb - { res: "R-Wpn-Bomb03", stat: "Bomb3-VTOL-LtINC" }, // Phosphor bomb + // { res: "R-Wpn-Bomb01", stat: "Bomb1-VTOL-LtHE" }, // cluster bomb + //{ res: "R-Wpn-Bomb03", stat: "Bomb3-VTOL-LtINC" }, // Phosphor bomb { res: "R-Wpn-Bomb02", stat: "Bomb2-VTOL-HvHE" }, // HEAP bomb { res: "R-Wpn-Bomb04", stat: "Bomb4-VTOL-HvyINC" }, // Thermite bomb //{ res: "R-Wpn-Bomb05", stat: "Bomb5-VTOL-Plasmite" }, // Plasmite bomb