Last active
July 25, 2016 21:44
Revisions
-
mpolyak renamed this gist
Jun 13, 2014 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
mpolyak created this gist
Jun 13, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,355 @@ /* Copyright (c) 2014 Michael Polyak. All Rights Reserved. [email protected] 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());