Did you create a mod, map, music, or a tool? Present them here and earn feedback!
Note: addon requests do not belong here. Note, everything uploaded to this forum, MUST have a license!
// note: i've not tested this code!
// Get a list of enemy player IDs
const ENEMY_LIST_TTL = 1500; // number of ms the cache lasts for
function getListOfEnemies() {
var player = maxPlayers;
if (getListOfEnemies.TTL < gameTime) {
// always treat scavs as enemy...
getListOfEnemies.cache = [scavengerPlayer];
// add other non-allied players to list...
while (-1<--player) if (!allianceExistsBetween(me,player) getListOfEnemies.cache.push(player);
// make sure we don't do this work again until the cache expires...
getListOfEnemies.TTL = gameTime + ENEMY_LIST_TTL;
}
return getListOfEnemies.cache;
}
// make sure we create cache on first run...
// (also means we don't need to check for null value in first "if" statement above)
getListOfEnemies.TTL = ENEMY_LIST_TTL * -1;
// Get danger level for a given map location
// Defining constants in a function is bit weird, might as well keep them global
const DANGER_RANGE = BASE_SIZE/2; // how far to search from x,y for enemies
// function for 3.1 branch (enumRange not available)
function dangerLevel31(x,y) {
var enemies = getListOfEnemies();
var list = [];
// build list
enemies.forEach(function(enemy) {
// use much more specific enums to reduce size of list
list.concat(enumDroid(enemy,DROID_CYBORG));
list.concat(enumDroid(enemy,DROID_WEAPON));
list.concat(enumStruct(enemy,DEFENCE));
});
// filter to those within range
list = list.filter(function(obj) {
return (distBetweenTwoPoints(obj.x,obj.y,x,y) < DANGER_RANGE);
});
// danger level defined by number of dangerous things
return list.length;
}
// function for 3.2 branch (uses enumRange which is quicker)
function dangerLevel32(x,y) {
var list = enumRange(x,y,DANGER_RANGE,ENEMIES);
// filter out non-dangerous things
list = list.filter(function(obj) {
switch (obj.type) {
case DROID: {
return (obj.droidType == DROID_WEAPON || obj.droidType == DROID_CYBORG);
}
case STRUCTURE: {
return (obj.stattype == DEFENCE);
}
}
return false; // we're not interested in anything else
});
// danger level defined by number of dangerous things
return list.length;
}
// now expose relevant function to code
var dangerLevel = (!!enumRange) ? dangerLevel32 : dangerLevel31;
// use dangerLevel() in remainder of your code
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
It might be worth renaming dangerLevel(x,y) to getThreatsNear(x,y) and have the functions return the list (rather than list length).
That way you have a handy function for getting a list of dangerous objects at a given map point, and can easily do .length to quantify the danger level of that location.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
aubergine: i thought about caching, but it's not worth it. The situation often changes considerably between calls. Probably i did something wrong though ... but anyway your approach doesn't change the complexity: we still have number of enemy units times number of derricks.
const ENEMY_LIST_TTL = 1500; // number of ms the cache lasts for if using dynamic alliances
// get list of enemy player id's at current game tick
function getCurrentEnemies() {
var list = [scavengerPlayer];
var player = maxPlayers;
while (-1<--player) if (!allianceExistsBetween(me,player)) list.push(player);
return list;
}
// your code should use this function, as it caches intelligently
function getListOfEnemies() {
if (alliancesType == ALLIANCES && getListOfEnemies.TTL < gameTime) { // refresh cache
getListOfEnemies.cache = getCurrentEnemies();
getListOfEnemies.TTL = gameTime + ENEMY_LIST_TTL;
}
return getListOfEnemies.cache;
}
// set default cache and TTL
getListOfEnemies.cache = getCurrentEnemies();
getListOfEnemies.TTL = gameTime + ENEMY_LIST_TTL;
Last edited by aubergine on 11 Apr 2012, 13:42, edited 1 time in total.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
Note that the dangerLevel() functions *are not cached*.
The function to get a list of enemy player IDs is what's being cached. I assume you will need to know a list of enemy player IDs for several functions so having a function that despams that processing will a) make code more transparent and b) reduce processing for a large number of functions. With my revised cache of enemy player IDs (see post above) then you'll completely bypass generating lists of enemie player IDs when there are no alliances or fixed alliances. Even with dynamic alliances, I don't think it's worth working out enemy players on a call by call basis. Caching the list of enemy players will decruft that.
In terms of the 3.1 function to get danger level, simply filtering to specific droid/struct types will instantly reduce the list. And using the revised code (in my earlier post) will take advantage of a number of JS compiler optimisations making it faster still.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
BTW, I did consider caching the dangerLevel functions but realised a) the cache would need to be based on x,y location and b) as you mentioned things change considerably in short space of time. I concluded that caching of dangerLevel() functions would be crufty and ineffective and instead focussed on just making them more refined and faster.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
There are some typos in it - let me quickly fix...
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
const ENEMY_ID_LIST_TTL = 5000; // cache TTL for getEnemyPlayerIDs() function
const DANGER_RANGE = Math.ceil(BASE_SIZE/2); // range of getThreatsNear() function
// backport scavengerPlayer global if not present (it's not there in 3.1 branch!)
// https://warzone.atlassian.net/wiki/display/backportjs/Globals
if (!scavengerPlayer) {
// define as const so it doesn't go in to savegames
const scavengerPlayer = (scavengers) ? Math.max(7,maxPlayers) : -1;
}
// getEnemyPlayerIDs() will return an array of enemy player IDs
var getEnemyPlayerIDs = (function() {
var getIDs = function() {
var list = (scavengers) ? [scavengerPlayer] : [];
var player = maxPlayers;
while (-1<--player) if (!allianceExistsBetween(me,player)) list.push(player);
return list;
}
var TTL = gameTime + ENEMY_ID_LIST_TTL;
var cache = getIDs();
return function() {
if (alliancesType == ALLIANCES && TTL < gameTime) { // refresh cache
cache = getIDs();
TTL = gameTime + ENEMY_ID_LIST_TTL;
}
return cache;
}
})();
// getThreatsNear(x,y) will return an array of dangerous enemy objects near x,y
var getThreatsNear = (function() {
var oldApproach = function(x,y) {
var enemies = getEnemyPlayerIDs();
var list = [];
// build list of dangerous enemy objects
enemies.forEach(function(enemy) {
// use specific enums to reduce size of list
list = list.concat(enumDroid(enemy,DROID_CYBORG));
list = list.concat(enumDroid(enemy,DROID_WEAPON));
list = list.concat(enumStruct(enemy,DEFENCE));
});
// filter to those within range
list = list.filter(function(obj) {
return (distBetweenTwoPoints(obj.x,obj.y,x,y) < DANGER_RANGE);
});
return list;
}
var newApproach = function(x,y) {
// get list of all enemy objects within range
var list = enumRange(x,y,DANGER_RANGE,ENEMIES);
// filter to dangerous objects
list = list.filter(function(obj) {
switch (obj.type) {
case DROID: return (obj.droidType == DROID_WEAPON || obj.droidType == DROID_CYBORG);
case STRUCTURE: return (obj.stattype == DEFENCE);
}
return false;
});
return list;
}
// return relevant function based on presence of enumRange function
return (!!enumRange) ? newApproach : oldApproach;
})();
// if you want dangerLevel, use getThreatsNear(x,y).length
Last edited by aubergine on 11 Apr 2012, 14:32, edited 1 time in total.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
// backport scavengerPlayer global if not present (it's not there in 3.1 branch!)
// https://warzone.atlassian.net/wiki/display/backportjs/Globals
if (!scavengerPlayer) {
// define as const so it doesn't go in to savegames
const scavengerPlayer = (scavengers) ? Math.max(7,maxPlayers) : -1;
}
EDIT: I've updated code in previous post to use this.
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO
Anyway, i seriously don't understand this code.
I already have scavengers backported, and check if they are ==-1 is still necessary (or alternatively check the scavengers variable).
where do you backport scavengerPlayer - I couldn't find that anywhere in nullbot?
also, what aspects of the code need more explanation?
"Dedicated to discovering Warzone artefacts, and sharing them freely for the benefit of the community."
-- https://warzone.atlassian.net/wiki/display/GO