Skip to content

Instantly share code, notes, and snippets.

@mpolyak
Last active July 25, 2016 21:44
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpolyak/8af627cbdf596b5e294a to your computer and use it in GitHub Desktop.
Save mpolyak/8af627cbdf596b5e294a to your computer and use it in GitHub Desktop.
/*
Copyright (c) 2014 Michael Polyak. All Rights Reserved.
mpolyak@gmail.com
HighSea v2.7.6
*/
if (this.queue === undefined)
{
this.queue = [];
this.friendMinion = this.buildables.peasant ? "peasant" : "peon";
this.friendMelee = this.buildables.soldier ? "soldier" : "munchkin";
this.friendRange = this.buildables.librarian ? "librarian" : "shaman";
this.enemyMinion = this.buildables.peasant ? "peon" : "peasant";
this.units =
{
"soldier": {melee: true, power: 45.0},
"munchkin": {melee: true, power: 45.0},
"knight": {melee: true, power: 51.2},
"ogre": {melee: true, power: 51.2},
"librarian": {range: true, power: 75.0},
"shaman": {range: true, power: 75.0},
"griffin-rider":{range: true, power: 150.0},
"fangrider": {range: true, power: 150.0},
"captain": {melee: true, power: 32.4},
"brawler": {melee: true, power: 32.4}
};
}
var FRIEND_MINION = this.friendMinion;
var FRIEND_MELEE = this.friendMelee;
var FRIEND_RANGE = this.friendRange;
var ENEMY_MINION = this.enemyMinion;
var BASE = "base";
var UNITS = this.units;
var WIDTH = 85;
var HEIGHT = 70;
var MAX_MINIONS = 6;
var GRAB_DISTANCE = 20;
var MAX_HEADINGS = 8;
var MIN_HEADINGS = 4;
var DEFEND_DISTANCE = 50;
var ATTACK_DISTANCE = 30;
var ATTACK_TIME = 120;
var MELEE_RANGE_RATIO = 3 / 2;
var base = this;
this.lootGrid = function (index, sectors, width, height)
{
var rows = Math.floor(Math.sqrt(sectors)); var cols = Math.floor(sectors / rows);
var hsize = width / cols;
var vsize = height / rows;
if (index >= rows * cols)
{
return {left: (width / 2) - hsize, right: (width / 2) + hsize,
top: (height / 2) + vsize, bottom: (height / 2) - vsize};
}
var row = Math.floor(index / cols); var col = index % cols;
return {left: hsize * col, right: hsize * (col + 1),
top: vsize * (row + 1), bottom: vsize * row};
};
this.lootItem = function (minion, grid, items, taken, headings)
{
var compass = [];
var i;
for (i = 0; i < headings; i ++)
compass.push(null);
var point = -1; var wealth = 0;
for (i = 0; i < items.length; i ++)
{
var item = items[i];
if (taken && taken.indexOf(item.id) !== -1)
continue;
var direction = Vector.subtract(item.pos, minion.pos); var distance = direction.magnitude();
if (grid && distance > GRAB_DISTANCE)
{
if (item.pos.x < grid.left || item.pos.x > grid.right || item.pos.y < grid.bottom || item.pos.y > grid.top)
continue;
}
var heading = Math.round(headings * Vector.normalize(direction).heading() / (2 * Math.PI) + headings) % headings;
if (!compass[heading])
compass[heading] = {wealth: 0, worth: 0, distance: 0, item: null};
var worth = item.bountyGold / distance;
if (compass[heading].worth < worth) {
compass[heading].worth = worth; compass[heading].distance = distance; compass[heading].item = item;
}
compass[heading].wealth += item.bountyGold / (distance * distance);
if (compass[heading].wealth > wealth) {
point = heading; wealth = compass[heading].wealth;
}
}
return point !== -1 ? {distance: compass[point].distance, item: compass[point].item} : null;
};
this.lootGold = function (items, minions, enemies)
{
if (!minions.length)
return;
var headings = Math.max(MIN_HEADINGS, Math.min(MAX_HEADINGS,
Math.floor((items.length / (minions.length + enemies.length)) / 2) * 2));
var grid;
var loot;
var i;
var looted = []; var taken = [];
for (i = 0; i < minions.length; i ++)
{
grid = base.lootGrid(i, minions.length, WIDTH, HEIGHT);
loot = base.lootItem(minions[i], grid, items, null, headings);
if (loot)
taken.push(loot.item.id);
looted.push({grid: grid, loot: loot});
}
if (looted.length > 1)
{
var index;
var reloot = [];
for (i = 0; i < looted.length - 1; i ++)
{
if (!looted[i].loot)
continue;
for (var j = i + 1; j < looted.length; j ++)
{
if (!looted[j].loot || looted[j].loot.item.id !== looted[i].loot.item.id)
continue;
index = looted[j].loot.distance < looted[i].loot.distance ? i : j;
if (reloot.indexOf(index) === -1)
reloot.push(index);
if (index === i)
break;
}
}
for (i = 0; i < reloot.length; i ++)
{
index = reloot[i];
looted[index].loot = base.lootItem(minions[index], looted[index].grid, items, taken, headings);
}
}
for (i = 0; i < looted.length; i ++)
{
var minion = minions[i];
grid = looted[i].grid;
loot = looted[i].loot;
if (loot) {
base.command(minion, "move", loot.item.pos);
}
else if (grid)
base.command(minion, "move", {x: (grid.left + grid.right) / 2, y: (grid.top + grid.bottom) / 2});
}
};
this.balanceOfPower = function (friends, enemies)
{
var target = null;
var melee = 0;
var range = 0;
var friendsDistance = -1;
var enemiesDistance = -1;
var distance;
var type;
var unit;
var i;
for (i = 0; i < enemies.length; i ++)
{
type = enemies[i].type;
if (type === BASE) {
target = enemies[i];
}
else if (type !== ENEMY_MINION)
{
unit = UNITS[type];
if (unit.melee) {
melee -= unit.power;
}
else
range -= unit.power;
distance = base.distance(enemies[i].pos);
if (enemiesDistance === -1 || distance < enemiesDistance)
enemiesDistance = distance;
}
}
for (i = 0; i < friends.length; i ++)
{
type = friends[i].type;
if (type !== BASE && type !== FRIEND_MINION)
{
unit = UNITS[type];
if (unit.melee) {
melee += unit.power;
}
else
range += unit.power;
if (target)
{
distance = friends[i].distance(target.pos);
if (friendsDistance === -1 || distance < friendsDistance)
friendsDistance = distance;
}
}
}
return {target: target, melee: melee, range: range, friendsDistance: friendsDistance, enemiesDistance: enemiesDistance};
};
this.timeToAttack = function (bop)
{
if (base.now() > ATTACK_TIME)
{
if (bop.enemiesDistance === -1 && bop.target && bop.target.gold < base.gold)
return true;
}
else
{
if (bop.enemiesDistance === -1 && bop.target && bop.target.gold < base.gold / 2 &&
base.gold > ((base.buildables[FRIEND_MELEE].goldCost * MELEE_RANGE_RATIO) + base.buildables[FRIEND_RANGE].goldCost))
{
return true;
}
}
return false;
};
this.buildUnit = function (type, count)
{
for (var i = 0; i < count; i ++)
base.queue.push(type);
};
this.buildBattleArmy = function (bop)
{
if (!bop.target)
return false;
var melee = bop.melee < 0 ? Math.ceil(Math.abs(bop.melee) / UNITS[FRIEND_MELEE].power) : 0;
var range = bop.range < 0 ? Math.ceil(Math.abs(bop.range) / UNITS[FRIEND_RANGE].power) : 0;
var meleeCost = melee * base.buildables[FRIEND_MELEE].goldCost;
var rangeCost = range * base.buildables[FRIEND_RANGE].goldCost;
if (meleeCost + rangeCost > base.gold || meleeCost + rangeCost > bop.target.gold)
return false;
if (melee)
base.buildUnit(FRIEND_MELEE, melee);
if (range)
base.buildUnit(FRIEND_RANGE, range);
return true;
};
this.buildAttackArmy = function ()
{
var units = Math.floor(base.gold / ((base.buildables[FRIEND_MELEE].goldCost * MELEE_RANGE_RATIO) + base.buildables[FRIEND_RANGE].goldCost));
if (units)
{
base.buildUnit(FRIEND_MELEE, units * MELEE_RANGE_RATIO);
base.buildUnit(FRIEND_RANGE, units);
}
};
this.buildDefenceArmy = function ()
{
base.buildUnit(FRIEND_MELEE, base.gold / base.buildables[FRIEND_MELEE].goldCost);
};
var friendsMinions = this.getByType(FRIEND_MINION);
var enemiesMinions = this.getByType(ENEMY_MINION);
this.lootGold(this.getItems(), friendsMinions, enemiesMinions);
if (!this.queue.length)
{
var bop = this.balanceOfPower(this.getFriends(), this.getEnemies());
if ((bop.friendsDistance !== -1 && bop.friendsDistance < ATTACK_DISTANCE) ||
(bop.enemiesDistance !== -1 && bop.enemiesDistance < DEFEND_DISTANCE) || this.timeToAttack(bop))
{
if (bop.enemiesDistance !== -1 && bop.enemiesDistance < ATTACK_DISTANCE) {
this.buildDefenceArmy();
}
else
{
if (bop.enemiesDistance === -1 || !this.buildBattleArmy(bop))
this.buildAttackArmy();
}
}
else if (bop.melee >= 0 && bop.range >= 0 && friendsMinions.length < enemiesMinions.length + 1 && friendsMinions.length < MAX_MINIONS)
{
if (this.gold >= this.buildables[FRIEND_MINION].goldCost)
this.queue.push(FRIEND_MINION);
}
}
if (this.queue.length && this.gold >= this.buildables[this.queue[0]].goldCost)
this.build(this.queue.shift());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment