Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Incremental Zoo II Bot
- // @namespace YudaiNao-2aefd016eda566ee92d6911705ece4ca
- // @description Automates portions of the game; last updated at game version 0.44
- // @include http://magicaweb.com/zooII/
- // @include http://magicaweb.com/zooII/#
- // @version 2.0
- // @grant none
- // ==/UserScript==
- var Zookeeper = function ()
- {
- var self = this;
- self.load = function ()
- {
- if (typeof unsafeWindow == 'undefined')
- {
- self.state = IZ.Zoo;
- self.commands = IZ;
- }
- else
- {
- self.state = unsafeWindow.IZ.Zoo;
- self.commands = unsafeWindow.IZ;
- }
- createInterfacePanel();
- for (var rName in routines)
- {
- if (!routines.hasOwnProperty(rName))
- continue;
- if (routines[rName].obj.load)
- routines[rName].obj.load();
- }
- self.tick();
- intervalObj = setInterval(self.tick, options.updateInterval);
- }
- self.tick = function ()
- {
- for (var rName in routines)
- {
- if (!routines.hasOwnProperty(rName))
- continue;
- if (routines[rName].enabled)
- routines[rName].obj.tick();
- }
- }
- self.register = function (routine)
- {
- var rName = routine.getName();
- routines[rName] = {
- obj : routine,
- enabled : false
- };
- }
- self.toggleHandler = function (event)
- {
- var regs = event.target.name.match(/routine_(.+)_toggle/);
- if (!regs)
- return;
- var routineName = regs[1];
- var newState = (event.target.value == 'on' ? true : false);
- routines[routineName].enabled = newState;
- }
- self.createElem = function (tagName, opts)
- {
- //(opts) = { properties : {...}, style : {...}, text : str, parent : elem }
- var elem = document.createElement(tagName);
- if (opts)
- {
- if (opts.properties)
- {
- for (var pKey in opts.properties)
- {
- if (opts.properties.hasOwnProperty(pKey))
- elem.setAttribute(pKey, opts.properties[pKey]);
- }
- }
- if (opts.style)
- {
- for (var sKey in opts.style)
- {
- if (opts.style.hasOwnProperty(sKey))
- elem.style[sKey] = opts.style[sKey];
- }
- }
- if (opts.text !== undefined)
- {
- var textNode = document.createTextNode(opts.text);
- elem.appendChild(textNode);
- }
- if (opts.parent)
- opts.parent.appendChild(elem);
- }
- return elem;
- }
- self.getRoutine = function (rName)
- {
- if (routines[rName])
- return routines[rName].obj;
- }
- self.isRoutineEnabled = function (rName)
- {
- return routines[rName].enabled;
- }
- self.getAnimalName = function (animal)
- {
- if (typeof animal == 'number')
- return self.commands.animals[animal].name;
- }
- self.alterValue = function (value, alteration)
- {
- if (typeof alteration == 'string')
- {
- var regs = alteration.match(/^([^0-9])([0-9.]+)$/);
- if (!regs)
- return;
- var operator = regs[1];
- var num = regs[2];
- if (operator == '+' || operator == '-')
- return value + parseFloat(num);
- else if (operator == '*')
- return value * parseFloat(num);
- else if (operator == '/')
- return value / parseFloat(num);
- }
- else if (typeof alteration == 'number')
- return alteration;
- }
- self.formatNumber = function (rawNum, decimalPad)
- {
- var magnitude = Math.log(Math.abs(rawNum)) / Math.LN10;
- if (magnitude % 1 > 0.99)
- magnitude = Math.round(magnitude);
- var unit = '';
- var power = 0;
- if (magnitude >= 3)
- {
- for (var _i = 3; _i < 100; _i += 3)
- {
- if (!numericUnits[_i])
- break;
- if (magnitude < _i + 3)
- {
- unit = numericUnits[_i];
- power = _i;
- break;
- }
- }
- }
- var formatNumber = Math.round(rawNum / Math.pow(10, power) * 100) / 100;
- formatNumber = formatNumber.toString();
- if (decimalPad)
- {
- if (formatNumber.indexOf('.') == -1)
- formatNumber += '.00';
- else if (formatNumber.indexOf('.') == formatNumber.length - 2)
- formatNumber += '0';
- }
- return formatNumber + unit;
- }
- self.unformatNumber = function (formatNum)
- {
- var regs = formatNum.match(/^([0-9-,.]+)([A-Za-z]+)?$/)
- if (!regs)
- return;
- var num = parseFloat(regs[1].replace(/,/, ''));
- var unit = regs[2];
- if (!unit)
- return num;
- var power = numericUnits[unit];
- if (!power)
- return;
- return num * Math.pow(10, power);
- }
- var createInterfacePanel = function ()
- {
- var panel = self.createElem(
- 'div',
- {
- style : {
- position : 'absolute',
- top : '1em',
- right : '1em',
- zIndex : 1000,
- fontFamily : 'Trebuchet, Arial, sans-serif',
- lineHeight : '150%'
- },
- parent : document.querySelector('body > div.container')
- }
- );
- for (var rName in routines)
- {
- if (!routines.hasOwnProperty(rName))
- continue;
- var container = self.createElem(
- 'div',
- {
- style : {
- marginBottom : '0.5em',
- border : '1px solid ' + options.borderColor,
- backgroundColor : 'white'
- },
- parent : panel
- }
- );
- self.createElem(
- 'div',
- {
- text : rName,
- style : {
- textAlign : 'center',
- color : '#444488',
- backgroundColor : options.borderColor,
- fontFamily : 'Georgia, serif',
- fontWeight : 'bold'
- },
- parent : container
- }
- );
- var onLabel = self.createElem(
- 'label',
- {
- text : 'On',
- style : {
- backgroundColor : '#D0F0D0',
- padding : '0.25em 0.5em 0.25em 0',
- borderColor : options.borderColor,
- borderStyle : 'solid',
- borderWidth : '2px 0 2px 2px'
- }
- }
- );
- var onRadio = self.createElem(
- 'input',
- {
- properties : {
- type : 'radio',
- name : 'routine_' + rName + '_toggle',
- value : 'on'
- }
- }
- );
- onRadio.addEventListener('change', self.toggleHandler);
- onLabel.insertBefore(onRadio, onLabel.childNodes[0]);
- var offLabel = self.createElem(
- 'label',
- {
- text : 'Off',
- style : {
- backgroundColor : '#F0D0D0',
- padding : '0.25em 0 0.25em 0.5em',
- borderColor : options.borderColor,
- borderStyle : 'solid',
- borderWidth : '2px 2px 2px 0'
- }
- }
- );
- var offRadio = self.createElem(
- 'input',
- {
- properties : {
- type : 'radio',
- name : 'routine_' + rName + '_toggle',
- value : 'off',
- checked : 'checked'
- }
- }
- );
- offRadio.addEventListener('change', self.toggleHandler);
- offLabel.appendChild(offRadio);
- var toggle = self.createElem(
- 'div',
- {
- style : {
- textAlign : 'center',
- fontSize : '10pt'
- },
- parent : container
- }
- );
- toggle.appendChild(onLabel);
- toggle.appendChild(offLabel);
- var opts = routines[rName].obj.createOptionsDOM();
- if (opts)
- {
- opts.style.fontSize = '10pt';
- opts.style.margin = '0.5em';
- container.appendChild(opts);
- }
- }
- }
- var routines = {};
- var options = {
- updateInterval : 1000, //ms
- borderColor : '#CCCCCC'
- };
- var intervalObj;
- var numericUnits = {
- 'k' : 3, 3 : 'k',
- 'm' : 6, 6 : 'm',
- 'b' : 9, 9 : 'b',
- 't' : 12, 12 : 't',
- 'qa' : 15, 15 : 'qa',
- 'qi' : 18, 18 : 'qi'
- };
- }
- var SellerRoutine = function (controller)
- {
- var self = this;
- self.load = function ()
- {
- updateDetails();
- }
- self.tick = function ()
- {
- checkAnimalPopulations();
- checkTrade();
- updateDetails();
- }
- self.getName = function ()
- {
- return routineName;
- }
- self.createOptionsDOM = function ()
- {
- var container = controller.createElem('div');
- var simpleRadios = {
- hybrid : { label : 'Hybrid strategy', title : 'Minimal for newest ' + options.hybridThreshold + ' species, optimal for older ones', checked : true },
- minimal : { label : 'Minimal population', title : '100 Meerkets, 200 Peacocks, 300 Chameleons, etc' },
- optimal : { label : 'Optimal population', title : 'Maximizes growth rate' }
- };
- for (var key in simpleRadios)
- {
- var radioDiv = controller.createElem('div', { parent : container });
- var radioLabel = controller.createElem('label', { parent : radioDiv });
- var radioInput = controller.createElem(
- 'input',
- {
- properties : {
- type : 'radio',
- name : 'seller_strategy',
- value : key
- },
- parent: radioLabel
- }
- );
- var radioSpan = controller.createElem(
- 'span',
- {
- text : simpleRadios[key].label,
- parent : radioLabel
- }
- );
- if (simpleRadios[key].title)
- {
- radioSpan.setAttribute('title', simpleRadios[key].title);
- radioSpan.style.cursor = 'help';
- }
- if (simpleRadios[key].checked)
- radioInput.setAttribute('checked', 'checked');
- radioInput.addEventListener('change', self.optionsHandler);
- }
- var fixedDiv = controller.createElem('div', { parent : container });
- var fixedLabel = controller.createElem('label', { parent : fixedDiv });
- var fixedRadio = controller.createElem(
- 'input',
- {
- properties : {
- type : 'radio',
- name : 'seller_strategy',
- value : 'fixed'
- },
- parent : fixedLabel
- }
- );
- fixedRadio.addEventListener('change', self.optionsHandler);
- controller.createElem('span', { text : 'Keep ', parent : fixedLabel });
- var fixedInput = controller.createElem(
- 'input',
- {
- properties : {
- type : 'text',
- name : 'seller_fixedpop',
- size : 3,
- value : options.fixedPop,
- title : '1500, 10k, 1.2m, 5b, etc'
- },
- style : { cursor : 'help' },
- parent : fixedDiv
- }
- );
- fixedInput.addEventListener('change', self.optionsHandler);
- controller.createElem('span', { text : ' population', parent : fixedDiv });
- var tradeDiv = controller.createElem('div', { parent : container });
- var tradeLabel = controller.createElem('label', { parent : tradeDiv });
- var tradeInput = controller.createElem(
- 'input',
- {
- properties : {
- type : 'checkbox',
- name : 'seller_trade',
- value : key,
- checked : 'checked'
- },
- parent: tradeLabel
- }
- );
- var tradeSpan = controller.createElem(
- 'span',
- {
- text : 'Accept profitable trades',
- parent : tradeLabel
- }
- );
- tradeInput.addEventListener('change', self.optionsHandler);
- var detailsContainer = controller.createElem(
- 'div',
- {
- style : {
- textAlign : 'center',
- marginTop : '0.5em'
- },
- parent : container
- }
- );
- var detailsLink = controller.createElem(
- 'span',
- {
- text : 'Details',
- style : {
- border : '1px dashed #CCCCCC',
- padding : '0.25em 0.5em',
- cursor : 'pointer'
- },
- parent : detailsContainer
- }
- );
- detailsLink.addEventListener('click', self.toggleDetails);
- detailsElems.container = controller.createElem(
- 'div',
- {
- style : {
- border : '1px dashed #CCCCCC',
- display : 'none',
- textAlign : 'left',
- padding : '0.25em 0.5em'
- },
- parent : detailsContainer
- }
- );
- detailsElems.income = controller.createElem('div', { parent : detailsElems.container });
- detailsElems.trade = controller.createElem('div', { parent : detailsElems.container });
- detailsElems.popFloor = controller.createElem('div', { parent : detailsElems.container });
- return container;
- }
- self.optionsHandler = function (event)
- {
- if (event.target.name == 'seller_strategy')
- {
- var newStrategy = event.target.value;
- options.strategy = newStrategy;
- updateDetails();
- }
- else if (event.target.name == 'seller_fixedpop')
- {
- var newVal = controller.unformatNumber(event.target.value);
- options.fixedPop = newVal;
- updateDetails();
- }
- else if (event.target.name == 'seller_trade')
- {
- options.acceptTrades = event.target.checked;
- }
- }
- self.getPopulationFloor = function (animal, strategy)
- {
- if (!strategy)
- strategy = options.strategy;
- if (strategy == 'minimal')
- {
- return (animal + 1) * 100;
- }
- else if (strategy == 'optimal')
- {
- var calc = new AnimalCalc(animal, controller);
- var lastGrowth;
- for (var pop = 50; pop < 100000; pop += 50)
- {
- calc.alter({ own : pop });
- if (lastGrowth && (calc.getValue('growth') < lastGrowth || lastGrowth / calc.getValue('growth') > 0.99))
- return pop - 50;
- lastGrowth = calc.getValue('growth');
- }
- return self.getPopulationFloor(animal, 'minimal'); //failsafe
- }
- else if (strategy == 'hybrid')
- {
- var newestAnimal;
- for (var _i = 0, _len_i = controller.state.animalsN; _i < _len_i; _i++)
- {
- var owned = controller.state.animals[_i].own;
- if (owned == 0)
- break;
- else
- newestAnimal = _i;
- }
- if (newestAnimal - animal < options.hybridThreshold)
- return self.getPopulationFloor(animal, 'minimal');
- else
- return self.getPopulationFloor(animal, 'optimal');
- }
- else if (strategy == 'fixed')
- {
- return options.fixedPop;
- }
- }
- self.toggleDetails = function (event)
- {
- detailsElems.container.style.display = (detailsElems.container.style.display == 'none' ? 'block' : 'none');
- }
- var checkAnimalPopulations = function ()
- {
- for (var _i = 0, _len_i = controller.state.animalsN; _i < _len_i; _i++)
- {
- var owned = controller.state.animals[_i].own;
- if (owned == 0)
- break;
- var populationFloor = self.getPopulationFloor(_i);
- var populationCeiling = controller.state.animals[_i].maxPop;
- if (owned - 100 >= populationFloor)
- sellAnimals(_i, 100, owned);
- else if (owned - 10 >= populationFloor)
- sellAnimals(_i, 10, owned);
- else if (owned + 10 >= populationCeiling)
- sellAnimals(_i, 10, owned);
- }
- }
- var sellAnimals = function (animal, amount, owned)
- {
- if (owned - amount < options.hardFloor)
- return;
- var elem = document.getElementById('sell' + amount + animal);
- if (elem)
- controller.commands.sell(elem, amount);
- }
- var checkTrade = function ()
- {
- if (!options.acceptTrades || !controller.state.offerActive)
- return;
- var lossAnimal = controller.state.offerGiveSpecies;
- var lossAmount = controller.state.offerGiveNumber;
- var lossValue = controller.state.animals[lossAnimal].buyPrice * lossAmount;
- var gainAnimal = controller.state.offerGetSpecies;
- var gainAmount = controller.state.offerGetNumber;
- var gainValue = controller.state.animals[gainAnimal].buyPrice * gainAmount;
- if (lossValue > gainValue)
- controller.commands.offerRejected();
- else
- {
- controller.commands.offerAccepted();
- lastTrade = { lossAnimal : lossAnimal, lossAmount : lossAmount, gainAnimal : gainAnimal, gainAmount : gainAmount, profit : gainValue - lossValue };
- }
- }
- var updateDetails = function ()
- {
- for (var _i = 0, _len_i = controller.state.animalsN; _i < _len_i; _i++)
- {
- if (controller.state.animals[_i].own == 0)
- break;
- if (!detailsElems.popFloor.childNodes[_i])
- controller.createElem('div', { parent : detailsElems.popFloor });
- detailsElems.popFloor.childNodes[_i].textContent = controller.getAnimalName(_i) + ' - ' + controller.formatNumber(self.getPopulationFloor(_i));
- }
- var calc = new IncomeCalc(controller);
- detailsElems.income.textContent = 'Est. income: $' + controller.formatNumber(calc.getIncome(), true) + '/s';
- if (lastTrade)
- {
- detailsElems.trade.textContent = 'Last trade: $' + controller.formatNumber(lastTrade.profit);
- detailsElems.trade.title = controller.getAnimalName(lastTrade.lossAnimal) + ' (x' + lastTrade.lossAmount + ') -> ' + controller.getAnimalName(lastTrade.gainAnimal) + ' (x' + lastTrade.gainAmount + ')';
- detailsElems.trade.style.cursor = 'help';
- }
- else
- {
- detailsElems.trade.textContent = '';
- detailsElems.trade.title = '';
- detailsElems.trade.style.cursor = 'auto';
- }
- }
- var controller;
- var routineName = 'Seller';
- var options = {
- hardFloor : 10, //never sell animals to below this threshold (failsafe)
- hybridThreshold : 3, //threshold before which minimal strategy is used, after which optimal strategy
- fixedPop : 10000,
- strategy : 'hybrid',
- acceptTrades : true
- };
- var detailsElems = {};
- var lastTrade;
- };
- var SpenderRoutine = function (controller)
- {
- var self = this;
- self.tick = function ()
- {
- //pays debt in full and terminates
- // or pays debt partially and continues
- //buys an enclosure and terminates
- // or buys an economy upgrade preemptively and terminates
- // or continues
- //seeds a new animal and terminates
- // or buys an economy upgrade preemptively and terminates
- // or continues
- //buys an economy upgrade and terminates
- try
- {
- if (options.strategies.debt)
- {
- if (controller.state.debt > 0)
- {
- var paidInFull = payDebt();
- if (paidInFull)
- throw { entryType : 'debt' };
- }
- }
- if (options.strategies.enclosure)
- {
- var upgrade = checkEnclosures();
- if (upgrade)
- {
- var purchased = buyUpgrade(upgrade);
- if (typeof purchased == 'number')
- {
- logDetailsEntry({ entryType : 'saving', pType : 'enclosure', pAnimal : upgrade.animal, pCost : purchased });
- var preUpgrade = evaluatePreemptiveUpgrade(purchased);
- if (preUpgrade)
- {
- var prePurchase = buyUpgrade(preUpgrade);
- if (typeof prePurchase == 'number')
- throw { entryType : 'saving', pType : preUpgrade.type, pAnimal : preUpgrade.animal, pCost : prePurchase };
- else if (prePurchase)
- throw { entryType : 'bought', pType : preUpgrade.type, pAnimal : preUpgrade.animal };
- }
- throw '';
- }
- else if (purchased)
- throw { entryType : 'bought', pType : 'enclosure', pAnimal : upgrade.animal };
- }
- }
- if (options.strategies.seed)
- {
- var purchase = checkNewAnimals();
- if (purchase)
- {
- if (purchase.type == 'seed')
- var purchased = seedNewAnimal(purchase.animal);
- else if (purchase.type == 'own')
- var purchased = buyAnimals(purchase.animal, 1);
- else
- var purchased = buyUpgrade(purchase);
- if (typeof purchased == 'number')
- {
- logDetailsEntry({ entryType : 'saving', pType : purchase.type, pAnimal : purchase.animal, pCost : purchased });
- var preUpgrade = evaluatePreemptiveUpgrade(purchased);
- if (preUpgrade)
- {
- var prePurchase = buyUpgrade(preUpgrade);
- if (typeof prePurchase == 'number')
- throw { entryType : 'saving', pType : preUpgrade.type, pAnimal : preUpgrade.animal, pCost : prePurchase };
- else if (prePurchase)
- throw { entryType : 'bought', pType : preUpgrade.type, pAnimal : preUpgrade.animal };
- }
- throw '';
- }
- else if (purchased)
- throw { entryType : 'bought', pType : purchase.type, pAnimal : purchase.animal };
- }
- }
- if (options.strategies.growth || options.strategies.price || options.strategies.visitor)
- {
- var types = [];
- if (options.strategies.growth)
- types.push('birthRate', 'deathRate');
- if (options.strategies.price)
- types.push('buyPrice');
- if (options.strategies.visitor)
- types.push('visitorsBuy', 'visitorsTime');
- var upgrade = findBestPurchase(types);
- if (upgrade !== false)
- {
- var purchase = buyUpgrade(upgrade);
- if (typeof purchase == 'number')
- throw { entryType : 'saving', pType : upgrade.type, pAnimal : upgrade.animal, pCost : purchase };
- else if (purchase)
- throw { entryType : 'bought', pType : upgrade.type, pAnimal : upgrade.animal };
- }
- }
- logDetailsEntry({ entryType : 'saving' });
- }
- catch (logMessage)
- {
- if (logMessage)
- logDetailsEntry(logMessage);
- }
- updateDetails();
- }
- self.getName = function ()
- {
- return routineName;
- }
- self.createOptionsDOM = function ()
- {
- var container = controller.createElem('div');
- var simpleChecks = {
- growth : { label : 'Buy growth upgrades' },
- price : { label : 'Buy price upgrades', title : "Only bought when population exceeds seller's threshold" },
- visitor : { label : 'Buy visitor upgrades' },
- enclosure : { label : 'Buy enclosure upgrades', title : "Only bought when population nears limit" },
- debt : { label : 'Pay off debt', title : "Pays " + options.debtPaymentRate + "% per tick if debt can't be paid in full" },
- seed : { label : 'Seed new animal types', title : "Buys animals and upgrades for new species to get growth rate above " + options.seedMinGrowth + "%" }
- }
- for (var key in simpleChecks)
- {
- var checkDiv = controller.createElem('div', { parent : container });
- var checkLabel = controller.createElem('label', { parent : checkDiv });
- var checkInput = controller.createElem(
- 'input',
- {
- properties : {
- type : 'checkbox',
- name : 'spender_' + key,
- checked : 'checked'
- },
- parent: checkLabel
- }
- );
- var checkSpan = controller.createElem(
- 'span',
- {
- text : simpleChecks[key].label,
- parent : checkLabel
- }
- );
- if (simpleChecks[key].title)
- {
- checkSpan.setAttribute('title', simpleChecks[key].title);
- checkSpan.style.cursor = 'help';
- }
- checkInput.addEventListener('change', self.optionsHandler);
- }
- controller.createElem('span', { text : 'Reserve $', parent : container });
- var reserveInput = controller.createElem(
- 'input',
- {
- properties : {
- type : 'text',
- name : 'spender_reserve',
- size : 5,
- value : options.reserve,
- title : '1500, 10k, 1.2m, 5b, etc'
- },
- style : { cursor : 'help' },
- parent : container
- }
- );
- reserveInput.addEventListener('change', self.optionsHandler);
- var detailsContainer = controller.createElem(
- 'div',
- {
- style : {
- textAlign : 'center',
- marginTop : '0.5em'
- },
- parent : container
- }
- );
- var detailsLink = controller.createElem(
- 'span',
- {
- text : 'Details',
- style : {
- border : '1px dashed #CCCCCC',
- padding : '0.25em 0.5em',
- cursor : 'pointer'
- },
- parent : detailsContainer
- }
- );
- detailsLink.addEventListener('click', self.toggleDetails);
- detailsElems.container = controller.createElem(
- 'div',
- {
- style : {
- border : '1px dashed #CCCCCC',
- display : 'none',
- textAlign : 'left',
- padding : '0.25em 0.5em'
- },
- parent : detailsContainer
- }
- );
- detailsElems.saving = controller.createElem('div', { parent : detailsElems.container });
- detailsElems.spent = controller.createElem('div', { parent : detailsElems.container });
- return container;
- }
- self.optionsHandler = function (event)
- {
- if (!event.target.name.match(/^spender_[a-z]+$/))
- return;
- var optName = event.target.name.match(/^spender_([a-z]+)$/)[1];
- if (optName == 'reserve')
- {
- var newVal = controller.unformatNumber(event.target.value);
- if (newVal !== undefined)
- options.reserve = newVal;
- }
- else if (options.strategies[optName] !== undefined)
- {
- options.strategies[optName] = event.target.checked;
- }
- }
- self.toggleDetails = function (event)
- {
- detailsElems.container.style.display = (detailsElems.container.style.display == 'none' ? 'block' : 'none');
- }
- var payDebt = function ()
- {
- var money = availableMoney();
- var debt = controller.state.debt;
- if (debt == 0 || money < 10)
- return;
- if (debt < money)
- {
- controller.commands.debtClick('max');
- return true;
- }
- else
- {
- var paymentAmount = money * options.debtPaymentRate / 100;
- var paymentIncrement = (paymentAmount < 1000 ? 10 : 1000);
- var paymentCount = Math.max(Math.floor(paymentAmount / paymentIncrement), 1);
- for (var _i = 0; _i < paymentCount; _i++)
- controller.commands.debtClick(paymentIncrement);
- return false;
- }
- }
- var checkEnclosures = function ()
- {
- for (var _i = 0, _len_i = controller.state.animalsN; _i < _len_i; _i++)
- {
- var popLimit = controller.state.animals[_i].maxPop;
- var popCurrent = controller.state.animals[_i].own;
- if (popCurrent >= popLimit - options.enclosureBuyMargin)
- return { animal : _i, type : 'enclosure' };
- }
- return false;
- }
- var checkNewAnimals = function ()
- {
- for (var _i = 0, _len_i = controller.state.animalsN; _i < _len_i; _i++)
- {
- if (_i == controller.state.speciesShown)
- break;
- if (!animalPrereqMet(_i))
- continue;
- var calc = new AnimalCalc(_i, controller);
- if (calc.getValue('own') == 0)
- return { animal : _i, type : 'seed' };
- else if (calc.getValue('growth') < options.seedMinGrowth / 100)
- return findBestPurchase(['birthRate', 'deathRate', 'own'], _i);
- }
- return false;
- }
- var seedNewAnimal = function (animal)
- {
- var startPop = options.seedStartPop(animal) - controller.state.animals[animal].own;
- var startBirth = options.seedStartBirth(animal) - controller.state.animals[animal].brCount;
- var startDeath = options.seedStartDeath(animal) - controller.state.animals[animal].drCount;
- var singlePop = controller.state.animals[animal].buyPrice;
- var firstBirth = controller.state.animals[animal].brPrice;
- var firstDeath = controller.state.animals[animal].drPrice;
- var costPop = singlePop * startPop;
- var costBirth = 0;
- for (var _i = 0; _i < startBirth; _i++)
- costBirth += firstBirth * Math.pow(1.5, _i);
- var costDeath = 0;
- for (var _i = 0; _i < startDeath; _i++)
- costDeath += firstDeath * Math.pow(1.5, _i);
- var costTotal = costPop + costBirth + costDeath;
- if (availableMoney() < costTotal)
- return costTotal;
- var result = buyAnimals(animal, startPop);
- for (var _i = 0; _i < startBirth; _i++)
- result *= buyUpgrade({ animal : animal, type : 'birthRate' });
- for (var _i = 0; _i < startDeath; _i++)
- result *= buyUpgrade({ animal : animal, type : 'deathRate' });
- return (result == 1 ? true : false);
- }
- var findBestPurchase = function (pTypes, pAnimal)
- {
- //pTypes [ 'birthRate'|'deathRate'|'buyPrice'|'own'|'visitorsBuy'|'visitorsTime' ]
- if (pTypes.length == 0)
- return false;
- var startIndex = (pAnimal !== undefined ? pAnimal : 0);
- var endIndex = (pAnimal !== undefined ? pAnimal + 1 : controller.state.animalsN);
- var bestPurchase = { efficiency : 0 };
- for (var _i = startIndex, _len_i = endIndex; _i < _len_i; _i++)
- {
- var calc = new AnimalCalc(_i, controller);
- var owned = calc.getValue('own');
- if (owned == 0)
- break;
- for (var _j = 0, _len_j = pTypes.length; _j < _len_j; _j++)
- {
- var pType = pTypes[_j];
- if (pType == 'visitorsBuy' || pType == 'visitorsTime')
- continue;
- else if (pType == 'own')
- {
- if (owned == controller.state.animals[_i].maxPop)
- continue;
- var pCost = calc.getValue('buyPrice');
- var pEfficiency = calc.measureChange({ own : '+1' }, 'value') / pCost;
- }
- else
- {
- var upPrefix = upgradePrefixes[pType];
- if (controller.state.animals[_i][upPrefix + 'Count'] == options.upgradeLimit)
- continue;
- if (pType == 'buyPrice')
- {
- var saleThreshold = controller.getRoutine('Seller').getPopulationFloor(_i);
- if (owned < saleThreshold)
- continue;
- }
- var changeArg = {};
- changeArg[pType] = '*' + controller.state[upPrefix + 'BoostEffect'];
- var pCost = calc.getValue(upPrefix + 'Price');
- var pEfficiency = calc.measureChange(changeArg, 'value') / pCost;
- }
- if (bestPurchase.efficiency < pEfficiency)
- bestPurchase = { animal : _i, type : pType, efficiency : pEfficiency, cost : pCost };
- }
- }
- if (pTypes.indexOf('visitorsBuy') > -1)
- {
- var pCost = controller.state.visitorsBuyCost;
- var pValue = controller.state.visitorsBuy / controller.state.visitorsTime;
- var pEfficiency = pValue / pCost;
- if (bestPurchase.efficiency < pEfficiency)
- bestPurchase = { animal : false, type : 'visitorsBuy', efficiency : pEfficiency, cost : pCost };
- }
- if (pTypes.indexOf('visitorsTime') > -1 && controller.state.visitorsTime > 1)
- {
- var pCost = controller.state.visitorsTimeCost;
- var pValue = controller.state.visitorsTotal / (controller.state.visitorsTime - 1) - controller.state.visitorsTotal / controller.state.visitorsTime;
- var pEfficiency = pValue / pCost;
- if (bestPurchase.efficiency < pEfficiency)
- bestPurchase = { animal : false, type : 'visitorsTime', efficiency : pEfficiency, cost : pCost };
- }
- if (bestPurchase.animal === undefined)
- return false;
- return bestPurchase;
- }
- var buyUpgrade = function (upgrade)
- {
- //{ animal : int|false, type : 'birthRate'|'deathRate'|'buyPrice'|'enclosure'|'visitorsBuy'|'visitorsTime',( cost : float) }
- if (upgrade.type == 'visitorsBuy' || upgrade.type == 'visitorsTime')
- return buyVisitorUpgrade(upgrade);
- var upPrefix = upgradePrefixes[upgrade.type];
- if (!upgrade.cost)
- upgrade.cost = controller.state.animals[upgrade.animal][upPrefix + 'Price']
- if (availableMoney() < upgrade.cost)
- return upgrade.cost;
- var elem = document.getElementById(upPrefix + upgrade.animal);
- if (elem)
- {
- if (upgrade.type == 'birthRate')
- controller.commands.buyBRBoost(elem);
- else if (upgrade.type == 'deathRate')
- controller.commands.buyDRBoost(elem);
- else if (upgrade.type == 'buyPrice')
- controller.commands.buyBSBoost(elem);
- else if (upgrade.type == 'enclosure')
- controller.commands.buyENBoost(elem);
- else
- return false;
- return true;
- }
- return false;
- }
- var buyAnimals = function (animal, amount)
- {
- if (animal >= controller.state.speciesShown)
- return false;
- if (!animalPrereqMet(animal))
- return false;
- var cost = controller.state.animals[animal].buyPrice;
- if (cost * amount > availableMoney())
- return cost * amount;
- var countOne = amount % 10;
- var countTen = Math.floor(amount / 10);
- var elemOne = document.getElementById('buy' + animal);
- var elemTen = document.getElementById('buy10' + animal);
- if (elemOne && elemTen)
- {
- for (var _i = 0; _i < countOne; _i++)
- controller.commands.buy(elemOne, 1);
- for (var _i = 0; _i < countTen; _i++)
- controller.commands.buy(elemTen, 10);
- return true;
- }
- return false;
- }
- var evaluatePreemptiveUpgrade = function (goal)
- {
- if (!options.strategies.growth && !options.strategies.price && !options.strategies.visitor)
- return false;
- var types = [];
- if (options.strategies.growth)
- types.push('birthRate', 'deathRate');
- if (options.strategies.price)
- types.push('buyPrice');
- if (options.strategies.visitor)
- types.push('visitorsBuy', 'visitorsTime');
- var bestUpgrade = findBestPurchase(types);
- var calc = new IncomeCalc(controller);
- var currentIncome = calc.getIncome();
- if (currentIncome == 0)
- return;
- var alterArg = {};
- if (bestUpgrade.type == 'visitorsBuy')
- alterArg.visitorsTotal = '+' + controller.state.visitorsBuy;
- else if (bestUpgrade.type == 'visitorsTime')
- alterArg.visitorsTime = '-1';
- else
- alterArg[bestUpgrade.type] = '*' + controller.state[upgradePrefixes[bestUpgrade.type] + 'BoostEffect'];
- calc.alter(alterArg);
- var upgradeIncome = calc.getIncome();
- var currentGoal = goal - availableMoney();
- var upgradeGoal = currentGoal + bestUpgrade.cost;
- var currentTime = currentGoal / currentIncome;
- var upgradeTime = upgradeGoal / upgradeIncome;
- if (upgradeTime < currentTime)
- return bestUpgrade;
- return false;
- }
- var buyVisitorUpgrade = function (upgrade)
- {
- if (!upgrade.cost)
- {
- if (upgrade.type == 'visitorsBuy')
- upgrade.cost = controller.state.visitorsBuyCost;
- else if (upgrade.type == 'visitorsTime')
- upgrade.cost = controller.state.visitorsTimeCost;
- }
- if (availableMoney() < upgrade.cost)
- return upgrade.cost;
- if (upgrade.type == 'visitorsBuy')
- controller.commands.buyVisitors();
- else if (upgrade.type == 'visitorsTime')
- controller.commands.buyVisitorsTime();
- else
- return false;
- return true;
- }
- var logDetailsEntry = function (entry)
- {
- //{ entryType : 'bought'|'debt'|'saving'(, pType : str, pAnimal : int, pCost : float) }
- if (logDisplayNames[entry.pType])
- entry.pType = logDisplayNames[entry.pType];
- if (entry.entryType == 'saving' || entry.entryType == 'bought')
- {
- var purchaseStr = (entry.pAnimal !== false ? controller.getAnimalName(entry.pAnimal) + ' ' : '') + entry.pType;
- if (entry.entryType == 'saving')
- {
- if (!entry.pType)
- detailsLog.saving = undefined;
- else
- detailsLog.saving = purchaseStr + ' ($' + controller.formatNumber(entry.pCost) + ')';
- }
- else if (entry.entryType == 'bought')
- {
- if (detailsLog.saving && detailsLog.saving.indexOf(purchaseStr) === 0)
- detailsLog.saving = undefined;
- if (detailsLog.spent[0] && detailsLog.spent[0].indexOf(purchaseStr) === 0)
- {
- var regs = detailsLog.spent[0].match(/ \(x([0-9]+)\)$/);
- var messageCount = (regs ? parseInt(regs[1]) + 1 : 2);
- detailsLog.spent[0] = purchaseStr + ' (x' + messageCount + ')';
- }
- else
- detailsLog.spent.unshift(purchaseStr);
- }
- }
- else if (entry.entryType == 'debt')
- detailsLog.spent.unshift('paid off debt');
- }
- var updateDetails = function ()
- {
- if (detailsLog.spent.length > 10)
- detailsLog.spent.splice(10);
- for (var _i = 0, _len_i = detailsLog.spent.length; _i < _len_i; _i++)
- {
- if (!detailsElems.spent.childNodes[_i])
- controller.createElem('div', { parent : detailsElems.spent });
- detailsElems.spent.childNodes[_i].textContent = (_i + 1) + '. ' + detailsLog.spent[_i];
- }
- detailsElems.saving.textContent = (detailsLog.saving ? 'Next: ' + detailsLog.saving : '\u00A0');
- }
- var availableMoney = function ()
- {
- var money = controller.state.money - options.reserve;
- return (money < 0 ? 0 : money);
- }
- var animalPrereqMet = function (animal)
- {
- if (animal < 2)
- return true;
- var prereqAnimal = animal - 2;
- var prereqAmount = (animal - 1) * 100;
- return (controller.state.animals[prereqAnimal].own >= prereqAmount);
- }
- var controller;
- var routineName = 'Spender';
- var options = {
- strategies : {
- growth : true,
- price : true,
- visitor : true,
- enclosure : true,
- debt : true,
- seed : true
- },
- upgradeLimit : 20,
- debtPaymentRate : 1, //percentage of funds to spend on debt payment if debt can't be paid off entirely
- enclosureBuyMargin : 20, //number below limit that population must reach before an enclosure is purchased
- seedStartPop : function (animal) { return (animal + 3) * 2; }, //number of animals to buy at once when first starting up
- seedStartBirth : function (animal) { return Math.round((animal + 2) / 3); },
- seedStartDeath : function (animal) { return Math.round((animal + 2) / 6); },
- seedMinGrowth : 8, //growth rate to establish before new species is no longer prioritized
- reserve : 0
- };
- var upgradePrefixes = {
- birthRate : 'br',
- deathRate : 'dr',
- buyPrice : 'bs',
- enclosure : 'en'
- };
- var logDisplayNames = {
- own : 'animal',
- visitorsBuy : 'visitorCount',
- visitorsTime : 'visitorFrequency',
- buyPrice : 'price'
- };
- var detailsLog = { spent : [] };
- var detailsElems = {};
- };
- var AnimalCalc = function (animalData, controller)
- {
- var self = this;
- self.clone = function ()
- {
- var copyData = JSON.parse(JSON.stringify(animalData));
- return new AnimalCalc(copyData, controller);
- }
- self.alter = function (alterations)
- {
- for (var key in alterations)
- {
- if (!alterations.hasOwnProperty(key) || !animalData.hasOwnProperty(key))
- continue;
- var newValue = controller.alterValue(animalData[key], alterations[key]);
- if (newValue === undefined)
- continue;
- animalData[key] = newValue;
- }
- }
- self.getValue = function (key)
- {
- if (key == 'birthRate')
- {
- var br = animalData.birthRate;
- var pop = animalData.own;
- return pop / (br + pop);
- }
- else if (key == 'deathRate')
- {
- var dr = animalData.deathRate;
- var pop = animalData.own;
- return pop / (dr + pop * 2);
- }
- else if (key == 'growth' || key == 'growthRate')
- {
- return self.getValue('birthRate') - self.getValue('deathRate');
- }
- else if (key == 'value' || key == 'productionValue')
- {
- var sellPrice = animalData.buyPrice * controller.state.sellPrice;
- var growthRate = self.getValue('growth');
- return sellPrice * growthRate;
- }
- else if (animalData.hasOwnProperty(key))
- return animalData[key];
- }
- self.measureChange = function (alterations, values)
- {
- var altered = self.clone();
- altered.alter(alterations);
- if (typeof values != 'object')
- values = [values];
- var difference = {};
- for (var _i = 0, _len_i = values.length; _i < _len_i; _i++)
- {
- var value = values[_i];
- difference[value] = altered.getValue(value) - self.getValue(value);
- }
- if (values.length == 1)
- return difference[values[0]];
- return difference;
- }
- var construct = function ()
- {
- if (typeof animalData == 'number')
- {
- var copyData = JSON.parse(JSON.stringify(controller.state.animals[animalData]));
- animalData = copyData;
- }
- }
- var animalData;
- var controller;
- construct();
- };
- var IncomeCalc = function (controller, incomeData)
- {
- var self = this;
- self.clone = function ()
- {
- var incomeData = { animalCalcs : [] };
- for (var _i = 0, _len_i = animalCalcs.length; _i < _len_i; _i++)
- incomeData.animalCalcs.push(animalCalcs[_i].clone());
- var copyData = JSON.parse(JSON.stringify(visitorData));
- incomeData.visitorData = copyData;
- return new IncomeCalc(controller, incomeData);
- }
- self.alter = function (alterations, animal)
- {
- if (alterations.visitorsTotal !== undefined || alterations.visitorsTime !== undefined)
- {
- for (var type in alterations)
- {
- if (!alterations.hasOwnProperty(type) || !visitorData.hasOwnProperty(type))
- continue;
- var newValue = controller.alterValue(visitorData[type], alterations[type]);
- if (newValue === undefined)
- continue;
- visitorData[type] = newValue;
- }
- }
- if (animal)
- {
- if (typeof animal != 'object')
- animal = [animal];
- for (var _i = 0, _len_i = animal.length; _i < _len_i; _i++)
- animalCalcs[animal[_i]].alter(alterations);
- }
- else
- {
- for (var _i = 0, _len_i = animalCalcs.length; _i < _len_i; _i++)
- animalCalcs[_i].alter(alterations);
- }
- }
- self.getIncome = function ()
- {
- var income = 0;
- if (controller.isRoutineEnabled('Seller'))
- {
- for (var _i = 0, _len_i = animalCalcs.length; _i < _len_i; _i++)
- {
- var owned = animalCalcs[_i].getValue('own');
- if (owned < controller.getRoutine('Seller').getPopulationFloor(_i))
- continue;
- income += animalCalcs[_i].getValue('value');
- }
- }
- income += visitorData.visitorsTotal / visitorData.visitorsTime;
- return income;
- }
- self.measureChange = function (alterations)
- {
- var altered = self.clone();
- altered.alter(alterations);
- var difference = altered.getIncome() - self.getIncome();
- return difference;
- }
- var construct = function ()
- {
- for (var _i = 0, _len_i = controller.state.animalsN; _i < _len_i; _i++)
- {
- var owned = controller.state.animals[_i].own;
- if (owned == 0)
- break;
- animalCalcs.push(new AnimalCalc(_i, controller));
- }
- visitorData.visitorsTotal = controller.state.visitorsTotal;
- visitorData.visitorsTime = controller.state.visitorsTime;
- }
- var controller;
- var animalCalcs = [];
- var visitorData = {};
- construct();
- };
- var keeper = new Zookeeper();
- keeper.register(new SellerRoutine(keeper));
- keeper.register(new SpenderRoutine(keeper));
- setTimeout(keeper.load, 2000); //delayed start to allow propagation of game state object (IZ & IZ.Zoo)
Advertisement
Add Comment
Please, Sign In to add comment