UNPKG

@aaronjewell/w3-build-order

Version:

Library for configuring a build order in Warcraft 3

1,687 lines (1,486 loc) 138 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['w3-build-order'] = {})); }(this, (function (exports) { 'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function () {}; return { s: F, n: function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (e) { throw e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function () { it = o[Symbol.iterator](); }, n: function () { var step = it.next(); normalCompletion = step.done; return step; }, e: function (e) { didErr = true; err = e; }, f: function () { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } var buildings = [{ id: "altarOfStorms", name: "Altar of Storms", type: "building", gold: 180, lumber: 50, buildTime: 60, supply: 0, dependsOn: [], order: 6, units: ["bladeMaster", "farSeer", "shadowHunter", "taurenChieftain"], upgrades: [], items: [], image: "orc/altarofstorms.png" }, { id: "barracks", name: "Barracks", type: "building", gold: 180, lumber: 50, buildTime: 60, supply: 0, dependsOn: [], order: 2, units: ["grunt"], upgrades: ["trollRegeneration", "berserkerUpgrade", "burningOil"], items: [], image: "orc/barracks.png" }, { id: "beastiary", name: "Beastiary", type: "building", gold: 145, lumber: 140, buildTime: 60, supply: 0, dependsOn: ["stronghold"], order: 8, units: [], upgrades: ["ensnare", "envenomedSpears", "liquidFire"], items: [], image: "orc/beastiary.png" }, { id: "greatHall", name: "Great Hall", type: "building", gold: 385, lumber: 185, buildTime: 150, supply: 11, tier: 1, dependsOn: [], order: 1, units: ["peon"], upgrades: ["pillage", "unitInventory", "stronghold", "fortress"], items: [], image: "orc/greathall.png" }, { id: "orcBurrow", name: "Orc Burrow", type: "building", gold: 160, lumber: 40, buildTime: 50, supply: 10, dependsOn: [], order: 5, units: [], upgrades: [], items: [], image: "orc/orcburrow.png" }, { id: "spiritLodge", name: "Spirit Lodge", type: "building", gold: 150, lumber: 135, buildTime: 70, supply: 0, dependsOn: ["stronghold"], order: 7, units: [], upgrades: ["shamanAdeptTraining", "shamanMasterTraining", "witchDoctorAdeptTraining", "witchDoctorMasterTraining"], items: [], image: "orc/spiritlodge.png" }, { id: "taurenTotem", name: "Tauren Totem", type: "building", gold: 135, lumber: 155, buildTime: 70, supply: 0, dependsOn: ["warMill", "fortress"], order: 9, units: [], upgrades: ["spiritWalkeAdeptTraining", "spiritWalkerMasterTraining", "pulverizeDamageIncrease"], items: [], image: "orc/taurentotem.png" }, { id: "voodooLounge", name: "Voodoo Lounge", type: "building", gold: 130, lumber: 30, buildTime: 60, supply: 0, dependsOn: [], order: 10, units: [], upgrades: [], items: ["healingSalve", "lesserClarityPotion", "orbOfLightning", "potionOfHealing", "potionOfMana", "scrollOfSpeed", "scrollOfTownPortal", "tinyGreatHall"], image: "orc/voodoolounge.png" }, { id: "warMill", name: "War Mill", type: "building", gold: 205, lumber: 0, buildTime: 70, supply: 0, dependsOn: [], order: 3, units: [], upgrades: ["spikedBarricades", "improvedSpikedBarricades", "reinforcedDefenses", "steelMeleeWeapons", "thoriumMeleeWeapons", "arcaniteMeleeWeapons", "steelRangedWeapons", "thoriumRangedWeapons", "arcaniteRangedWeapons"], items: [], image: "orc/warmill.png" }, { id: "watchTower", name: "Watch Tower", type: "building", gold: 110, lumber: 80, buildTime: 60, supply: 0, dependsOn: ["warMill"], order: 4, units: [], upgrades: [], items: [], image: "orc/watchtower.png" }]; var units = [{ id: "peon", name: "Peon", type: "unit", gold: 75, lumber: 0, supply: 1, buildTime: 15, canHarvest: true, canMine: true, canBuild: true, order: 1, image: "orc/peon.png" }, { id: "grunt", name: "Grunt", type: "unit", gold: 200, lumber: 0, supply: 3, buildTime: 30, order: 1, image: "orc/grunt.png" }, { id: "headhunter", name: "Headhunter", type: "unit", gold: 135, lumber: 20, supply: 2, buildTime: 20, order: 2, image: "orc/headhunter.png" }, { id: "demolisher", name: "Demolisher", type: "unit", gold: 220, lumber: 50, supply: 4, buildTime: 40, order: 3, image: "orc/demolisher.png" }, { id: "shaman", name: "Shaman", type: "unit", gold: 130, lumber: 20, supply: 2, buildTime: 30, order: 1, image: "orc/shaman.png" }, { id: "witchDoctor", name: "Witch Doctor", type: "unit", gold: 145, lumber: 25, supply: 2, buildTime: 30, order: 2, image: "orc/witchdoctor.png" }, { id: "raider", name: "Raider", type: "unit", gold: 180, lumber: 40, supply: 3, buildTime: 28, order: 1, image: "orc/wolfrider.png" }, { id: "kodoBeast", name: "Kodo Beast", type: "unit", gold: 255, lumber: 60, supply: 4, buildTime: 30, order: 3, image: "orc/kodobeast.png" }, { id: "windRider", name: "Wind Rider", type: "unit", gold: 265, lumber: 40, supply: 4, buildTime: 35, order: 2, image: "orc/wyvernrider.png" }, { id: "trollBatrider", name: "Troll Batrider", type: "unit", gold: 160, lumber: 40, supply: 2, buildTime: 28, orer: 4, image: "orc/batrider.png" }, { id: "tauren", name: "Tauren", type: "unit", gold: 280, lumber: 80, supply: 5, buildTime: 44, order: 2, image: "orc/tauren.png" }, { id: "bladeMaster", name: "Blade Master", type: "unit", gold: 425, lumber: 100, supply: 5, buildTime: 55, limit: 1, isHero: true, order: 9, image: "orc/blademaster.png" }, { id: "farSeer", name: "Far Seer", type: "unit", gold: 425, lumber: 100, supply: 5, buildTime: 55, limit: 1, isHero: true, order: 10, image: "orc/farseer.png" }, { id: "taurenChieftain", name: "Tuaren Chieftain", type: "unit", gold: 425, lumber: 100, supply: 5, buildTime: 55, limit: 1, isHero: true, order: 11, image: "orc/chieftain.png" }, { id: "shadowHunter", name: "Shadow Hunter", type: "unit", gold: 425, lumber: 100, supply: 5, buildTime: 55, limit: 1, isHero: true, order: 5, image: "orc/shadowhunter.png" }]; var Action = /*#__PURE__*/function () { function Action(_ref) { var type = _ref.type, start = _ref.start, valid = _ref.valid, duration = _ref.duration, meta = _ref.meta; _classCallCheck(this, Action); this._id = Action._id++; this.type = type; this.start = start; this.valid = valid; this.duration = duration; this.meta = meta; } _createClass(Action, null, [{ key: "build", value: function build(start, buildingData, worker) { return new Action({ type: "build", start: start, duration: buildingData.buildTime, valid: true, meta: { worker: worker, building: buildingData } }); } }, { key: "buy", value: function buy(start, itemData, building) { return new Action({ type: "buy", start: start, duration: 0, valid: true, meta: { building: building, item: itemData } }); } }, { key: "train", value: function train(start, unitData, building) { return new Action({ type: "train", start: start, duration: unitData.buildTime || 0, valid: true, meta: { unit: unitData, building: building } }); } }, { key: "upgrade", value: function upgrade(start, upgradeData, building) { return new Action({ type: "upgrade", start: start, duration: upgradeData.buildTime, valid: true, meta: { building: building, upgrade: upgradeData } }); } }, { key: "assignToGold", value: function assignToGold(start, worker) { return new Action({ type: "assignToGold", start: start, duration: 0, valid: true, meta: { worker: worker } }); } }, { key: "removeFromGold", value: function removeFromGold(start, worker) { return new Action({ type: "removeFromGold", start: start, duration: 0, valid: true, meta: { worker: worker } }); } }, { key: "assignToLumber", value: function assignToLumber(start, worker) { return new Action({ type: "assignToLumber", start: start, duration: 0, valid: true, meta: { worker: worker } }); } }, { key: "removeFromLumber", value: function removeFromLumber(start, worker) { return new Action({ type: "removeFromLumber", start: start, duration: 0, valid: true, meta: { worker: worker } }); } }]); return Action; }(); _defineProperty(Action, "_id", 1); var Building = /*#__PURE__*/function () { function Building(_ref) { var id = _ref.id, name = _ref.name, gold = _ref.gold, lumber = _ref.lumber, buildTime = _ref.buildTime, dependsOn = _ref.dependsOn, supply = _ref.supply, type = _ref.type, units = _ref.units, upgrades = _ref.upgrades, items = _ref.items, image = _ref.image; _classCallCheck(this, Building); this._id = Building._id++; this.id = id; this.name = name; this.gold = gold; this.lumber = lumber; this.buildTime = buildTime; this.dependsOn = dependsOn; this.units = units; this.upgrades = upgrades; this.items = items; this.supply = supply; this.image = image; this.type = type; } _createClass(Building, null, [{ key: "resetIds", value: function resetIds() { Building._id = 1; } }]); return Building; }(); _defineProperty(Building, "_id", 1); var Item = /*#__PURE__*/function () { function Item(_ref) { var id = _ref.id, name = _ref.name, gold = _ref.gold, lumber = _ref.lumber, dependsOn = _ref.dependsOn, order = _ref.order, type = _ref.type, image = _ref.image; _classCallCheck(this, Item); this._id = Item._id++; this.id = id; this.name = name; this.gold = gold; this.order = order, this.lumber = lumber; this.dependsOn = dependsOn; this.image = image; this.type = type; } _createClass(Item, null, [{ key: "resetIds", value: function resetIds() { Item._id = 1; } }]); return Item; }(); _defineProperty(Item, "_id", 1); var ResourceList = /*#__PURE__*/function () { function ResourceList() { var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, ResourceList); this.value = value; } _createClass(ResourceList, [{ key: "addValues", value: function addValues(resources) { var resourceList = resources; if (!(resourceList instanceof ResourceList)) { resourceList = new ResourceList(resourceList); } for (var _i = 0, _Object$entries = Object.entries(resourceList.value); _i < _Object$entries.length; _i++) { var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), key = _Object$entries$_i[0], value = _Object$entries$_i[1]; if (key in this.value) { if (Array.isArray(this.value[key])) { if (Array.isArray(value)) { this.value[key] = this.value[key].concat(value); } else { this.value[key].push(value); } } else { this.value[key] += value; } } else { this.value[key] = value; } } } }, { key: "removeValues", value: function removeValues(resources) { var _this = this; var resourceList = resources; if (!(resourceList instanceof ResourceList)) { resourceList = new ResourceList(resourceList); } var _loop = function _loop() { var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2), key = _Object$entries2$_i[0], value = _Object$entries2$_i[1]; if (key in _this.value) { if (Array.isArray(_this.value[key])) { if (Array.isArray(value)) { var _iterator = _createForOfIteratorHelper(value), _step; try { var _loop2 = function _loop2() { var v = _step.value; var index = _this.value[key].findIndex(function (i) { return i._id === v._id; }); _this.value[key].splice(index, 1); }; for (_iterator.s(); !(_step = _iterator.n()).done;) { _loop2(); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } else { var index = _this.value[key].findIndex(function (i) { return i._id === value._id; }); _this.value[key].splice(index, 1); } } else { _this.value[key] -= value; } } else { throw new Error("Unable to lose resource, none accumulated."); } }; for (var _i2 = 0, _Object$entries2 = Object.entries(resourceList.value); _i2 < _Object$entries2.length; _i2++) { _loop(); } } }]); return ResourceList; }(); var ResourceEvent = /*#__PURE__*/function () { function ResourceEvent(tick, actionId) { _classCallCheck(this, ResourceEvent); _defineProperty(this, "resourceLoss", new ResourceList()); _defineProperty(this, "resourceGain", new ResourceList()); this.actionId = actionId; this.tick = tick; } _createClass(ResourceEvent, [{ key: "loseResources", value: function loseResources(resourceList) { var resources = resourceList; if (!(resourceList instanceof ResourceList)) { resources = new ResourceList(resources); } this.resourceLoss.addValues(resourceList); } }, { key: "gainResources", value: function gainResources(resourceList) { var resources = resourceList; if (!(resourceList instanceof ResourceList)) { resources = new ResourceList(resources); } this.resourceGain.addValues(resourceList); } }]); return ResourceEvent; }(); var Unit = /*#__PURE__*/function () { function Unit(_ref) { var id = _ref.id, buildTime = _ref.buildTime, _ref$canBuild = _ref.canBuild, canBuild = _ref$canBuild === void 0 ? false : _ref$canBuild, _ref$canHarvest = _ref.canHarvest, canHarvest = _ref$canHarvest === void 0 ? false : _ref$canHarvest, _ref$canMine = _ref.canMine, canMine = _ref$canMine === void 0 ? false : _ref$canMine, image = _ref.image, _ref$isHero = _ref.isHero, isHero = _ref$isHero === void 0 ? false : _ref$isHero, order = _ref.order, gold = _ref.gold, lumber = _ref.lumber, name = _ref.name, supply = _ref.supply, type = _ref.type; _classCallCheck(this, Unit); this._id = Unit._id++; this.id = id; this.buildTime = buildTime; this.canBuild = canBuild; this.canHarvest = canHarvest; this.canMine = canMine; this.gold = gold; this.isHero = isHero; this.order = order; this.image = image; this.lumber = lumber; this.name = name; this.supply = supply; this.type = type; } _createClass(Unit, null, [{ key: "resetIds", value: function resetIds() { Unit._id = 1; } }]); return Unit; }(); _defineProperty(Unit, "_id", 1); var Upgrade = function Upgrade(_ref) { var id = _ref.id, name = _ref.name, gold = _ref.gold, lumber = _ref.lumber, buildTime = _ref.buildTime, tier = _ref.tier, replaces = _ref.replaces, dependsOn = _ref.dependsOn, image = _ref.image; _classCallCheck(this, Upgrade); this.id = id; this.name = name; this.gold = gold; this.lumber = lumber; this.buildTime = buildTime; this.tier = tier; this.replaces = replaces; this.dependsOn = dependsOn; this.image = image; }; var EventsProcessor = /*#__PURE__*/function () { function EventsProcessor() { _classCallCheck(this, EventsProcessor); } _createClass(EventsProcessor, [{ key: "validateActions", value: function validateActions(actions, resourceList) { var accumulatedActions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; var processedActions = []; var _iterator = _createForOfIteratorHelper(actions), _step; try { var _loop = function _loop() { var action = _step.value; action.valid = true; action.error = null; switch (action.type) { case "build": // Check for sufficient resources if (resourceList.value.gold < action.meta.building.gold || resourceList.value.lumber < action.meta.building.lumber) { action.valid = false; action.error = "not enough resources"; } // Check if builder still exists if (!resourceList.value.units.find(function (u) { return u._id === action.meta.worker._id; })) { action.valid = false; action.error = "worker no longer exists"; } break; case "buy": // Check for sufficient resources if (resourceList.value.gold < action.meta.item.gold || resourceList.value.lumber < action.meta.item.lumber) { action.valid = false; action.error = "not enough resources"; } // Check if shop still exists if (!resourceList.value.buildings.find(function (b) { return b._id === action.meta.building._id; })) { action.valid = false; action.error = "shop no longer exists"; } // Check that we have the dependencies if (typeof action.meta.item.dependsOn !== "undefined" && !action.meta.item.dependsOn.every(function (dependency) { return resourceList.value.upgrades.some(function (completed) { return completed.id === dependency; }); })) { action.valid = false; action.error = "missing required upgrade"; } // Check that we haven't exceeded replenishment if ([].concat(_toConsumableArray(accumulatedActions), processedActions).filter(function (a) { return a.type === "buy" && a.meta.item.id === action.meta.item.id && action.start - a.start < action.meta.item.replenish; }).length >= action.meta.item.max) { action.valid = false; action.error = "exceeded item replenishment"; } break; case "train": if (resourceList.value.gold < action.meta.unit.gold || resourceList.value.lumber < action.meta.unit.lumber || resourceList.value.supply < action.meta.unit.supply) { action.valid = false; action.error = "not enough resources"; } if (action.meta.unit.type !== "neutralUnit" && !resourceList.value.buildings.find(function (b) { return b._id === action.meta.building._id && b.id === action.meta.building.id; })) { action.valid = false; action.error = "building no longer available for training"; } if (action.meta.unit.type !== "neutralUnit" && processedActions.filter(function (a) { return a.type === "train" && a.meta.building._id === action.meta.building._id && a.start + a.duration >= action.start && a.start + a.duration <= action.start + action.duration; }).length) { action.valid = false; action.error = "building is busy training"; } if (action.meta.unit.limit && action.meta.unit.limit <= processedActions.filter(function (a) { return a.type === "train" && a.meta.unit.id === action.meta.unit.id; }).length) { action.valid = false; action.error = "too many of this unit produced"; } // Check that we haven't exceeded replenishment if ([].concat(_toConsumableArray(accumulatedActions), processedActions).filter(function (a) { return a.type === "train" && a.meta.unit.id === action.meta.unit.id && action.start - a.start < action.meta.unit.replenish; }).length >= action.meta.unit.max) { action.valid = false; action.error = "exceeded unit replenishment"; } if (action.meta.unit.availability && action.meta.unit.limit < a.start) { action.valid = false; action.error = "unit being produced before available"; } break; case "assignToGold": if (!resourceList.value.units.find(function (u) { return u._id === action.meta.worker._id && u.id === action.meta.worker.id; })) { action.valid = false; action.error = "worker no longer available for mining"; } break; case "removeFromGold": if (!resourceList.value.miningWorkers.find(function (u) { return u._id === action.meta.worker._id && u.id === action.meta.worker.id; })) { action.valid = false; action.error = "worker no longer mining at this time"; } break; case "assignToLumber": if (!resourceList.value.units.find(function (u) { return u._id === action.meta.worker._id && u.id === action.meta.worker.id; })) { action.valid = false; action.error = "worker no longer available for harvesting"; } break; case "removeFromLumber": if (!resourceList.value.harvestingWorkers.find(function (u) { return u._id === action.meta.worker._id && u.id === action.meta.worker.id; })) { action.valid = false; action.error = "worker no longer harvesting at this time"; } break; case "upgrade": if (resourceList.value.gold < action.meta.upgrade.gold || resourceList.value.lumber < action.meta.upgrade.lumber) { action.valid = false; action.error = "not enough resources for upgrade"; } if (!action.meta.upgrade.dependsOn.buildings.every(function (dependency) { return resourceList.value.buildings.some(function (completed) { return completed.id === dependency; }); }) || !action.meta.upgrade.dependsOn.upgrades.every(function (dependency) { return resourceList.value.upgrades.some(function (completed) { return completed.id === dependency; }); })) { action.valid = false; action.error = "missing required building or upgrade"; } if (!!resourceList.value.upgrades.find(function (u) { return u.id === action.meta.upgrade.id; })) { action.valid = false; action.error = "upgrade already researched"; } if (action.meta.upgrade.replaces && !resourceList.value.upgrades.find(function (u) { return u.id === action.meta.upgrade.replaces; })) { action.valid = false; action.error = "missing earlier version of upgrade"; } } processedActions.push(action); }; for (_iterator.s(); !(_step = _iterator.n()).done;) { _loop(); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } }, { key: "processAction", value: function processAction(action) { var _immediateLoss$loseRe; var resourceEvents = []; switch (action.type) { case "build": var immediateLoss = new ResourceEvent(action.start, action._id); immediateLoss.loseResources({ gold: action.meta.building.gold, lumber: action.meta.building.lumber, units: [action.meta.worker] }); var futureGain = new ResourceEvent(action.start + action.duration, action._id); futureGain.gainResources({ supply: action.meta.building.supply, buildings: [new Building(action.meta.building)], units: [action.meta.worker] }); resourceEvents.push(immediateLoss, futureGain); break; case "buy": var immediateLoss = new ResourceEvent(action.start, action._id); immediateLoss.loseResources({ gold: action.meta.item.gold, lumber: action.meta.item.lumber || 0 // Neutral items do not cost lumber }); var immediateGain = new ResourceEvent(action.start + action.duration, action._id); immediateGain.gainResources({ items: [new Item(action.meta.item)] }); resourceEvents.push(immediateLoss, immediateGain); break; case "train": var immediateLoss = new ResourceEvent(action.start, action._id); immediateLoss.loseResources((_immediateLoss$loseRe = { supply: action.meta.unit.supply, gold: action.meta.unit.gold, lumber: action.meta.unit.lumber }, _defineProperty(_immediateLoss$loseRe, "supply", action.meta.unit.supply), _defineProperty(_immediateLoss$loseRe, "buildings", [action.meta.building]), _immediateLoss$loseRe)); var futureGain = new ResourceEvent(action.start + action.duration, action._id); futureGain.gainResources({ units: [new Unit(action.meta.unit)], buildings: [action.meta.building] }); resourceEvents.push(immediateLoss, futureGain); break; case "assignToGold": var immediateLoss = new ResourceEvent(action.start, action._id); immediateLoss.loseResources({ units: [action.meta.worker] }); var immediateGain = new ResourceEvent(action.start, action._id); immediateGain.gainResources({ miningWorkers: [action.meta.worker] }); resourceEvents.push(immediateGain, immediateLoss); break; case "removeFromGold": var immediateLoss = new ResourceEvent(action.start, action._id); immediateLoss.loseResources({ miningWorkers: [action.meta.worker] }); var immediateGain = new ResourceEvent(action.start, action._id); immediateGain.gainResources({ units: [action.meta.worker] }); resourceEvents.push(immediateGain, immediateLoss); break; case "assignToLumber": var immediateLoss = new ResourceEvent(action.start, action._id); immediateLoss.loseResources({ units: [action.meta.worker] }); var immediateGain = new ResourceEvent(action.start, action._id); immediateGain.gainResources({ harvestingWorkers: [action.meta.worker] }); resourceEvents.push(immediateGain, immediateLoss); break; case "removeFromLumber": var immediateLoss = new ResourceEvent(action.start, action._id); immediateLoss.loseResources({ harvestingWorkers: [action.meta.worker] }); var immediateGain = new ResourceEvent(action.start, action._id); immediateGain.gainResources({ units: [action.meta.worker] }); resourceEvents.push(immediateGain, immediateLoss); break; case "upgrade": var immediateLoss = new ResourceEvent(action.start, action._id); immediateLoss.loseResources({ buildings: [action.meta.building], gold: action.meta.upgrade.gold, lumber: action.meta.upgrade.lumber }); var futureGain = new ResourceEvent(action.start + action.duration, action._id); futureGain.gainResources({ upgrades: [new Upgrade(action.meta.upgrade)], buildings: [action.meta.building] }); resourceEvents.push(immediateLoss, futureGain); break; } return resourceEvents; } }]); return EventsProcessor; }(); var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function createCommonjsModule(fn) { var module = { exports: {} }; return fn(module, module.exports), module.exports; } /** * lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors <https://jquery.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ var lodash_clonedeep = createCommonjsModule(function (module, exports) { /** Used as the size to enable large array optimizations. */ var LARGE_ARRAY_SIZE = 200; /** Used to stand-in for `undefined` hash values. */ var HASH_UNDEFINED = '__lodash_hash_undefined__'; /** Used as references for various `Number` constants. */ var MAX_SAFE_INTEGER = 9007199254740991; /** `Object#toString` result references. */ var argsTag = '[object Arguments]', arrayTag = '[object Array]', boolTag = '[object Boolean]', dateTag = '[object Date]', errorTag = '[object Error]', funcTag = '[object Function]', genTag = '[object GeneratorFunction]', mapTag = '[object Map]', numberTag = '[object Number]', objectTag = '[object Object]', promiseTag = '[object Promise]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', symbolTag = '[object Symbol]', weakMapTag = '[object WeakMap]'; var arrayBufferTag = '[object ArrayBuffer]', dataViewTag = '[object DataView]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]'; /** * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; /** Used to match `RegExp` flags from their coerced string values. */ var reFlags = /\w*$/; /** Used to detect host constructors (Safari). */ var reIsHostCtor = /^\[object .+?Constructor\]$/; /** Used to detect unsigned integer values. */ var reIsUint = /^(?:0|[1-9]\d*)$/; /** Used to identify `toStringTag` values supported by `_.clone`. */ var cloneableTags = {}; cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[mapTag] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[setTag] = cloneableTags[stringTag] = cloneableTags[symbolTag] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** Detect free variable `exports`. */ var freeExports = exports && !exports.nodeType && exports; /** Detect free variable `module`. */ var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module; /** Detect the popular CommonJS extension `module.exports`. */ var moduleExports = freeModule && freeModule.exports === freeExports; /** * Adds the key-value `pair` to `map`. * * @private * @param {Object} map The map to modify. * @param {Array} pair The key-value pair to add. * @returns {Object} Returns `map`. */ function addMapEntry(map, pair) { // Don't return `map.set` because it's not chainable in IE 11. map.set(pair[0], pair[1]); return map; } /** * Adds `value` to `set`. * * @private * @param {Object} set The set to modify. * @param {*} value The value to add. * @returns {Object} Returns `set`. */ function addSetEntry(set, value) { // Don't return `set.add` because it's not chainable in IE 11. set.add(value); return set; } /** * A specialized version of `_.forEach` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns `array`. */ function arrayEach(array, iteratee) { var index = -1, length = array ? array.length : 0; while (++index < length) { if (iteratee(array[index], index, array) === false) { break; } } return array; } /** * Appends the elements of `values` to `array`. * * @private * @param {Array} array The array to modify. * @param {Array} values The values to append. * @returns {Array} Returns `array`. */ function arrayPush(array, values) { var index = -1, length = values.length, offset = array.length; while (++index < length) { array[offset + index] = values[index]; } return array; } /** * A specialized version of `_.reduce` for arrays without support for * iteratee shorthands. * * @private * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @param {boolean} [initAccum] Specify using the first element of `array` as * the initial value. * @returns {*} Returns the accumulated value. */ function arrayReduce(array, iteratee, accumulator, initAccum) { var index = -1, length = array ? array.length : 0; if (initAccum && length) { accumulator = array[++index]; } while (++index < length) { accumulator = iteratee(accumulator, array[index], index, array); } return accumulator; } /** * The base implementation of `_.times` without support for iteratee shorthands * or max array length checks. * * @private * @param {number} n The number of times to invoke `iteratee`. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the array of results. */ function baseTimes(n, iteratee) { var index = -1, result = Array(n); while (++index < n) { result[index] = iteratee(index); } return result; } /** * Gets the value at `key` of `object`. * * @private * @param {Object} [object] The object to query. * @param {string} key The key of the property to get. * @returns {*} Returns the property value. */ function getValue(object, key) { return object == null ? undefined : object[key]; } /** * Checks if `value` is a host object in IE < 9. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a host object, else `false`. */ function isHostObject(value) { // Many host objects are `Object` objects that can coerce to strings // despite having improperly defined `toString` methods. var result = false; if (value != null && typeof value.toString != 'function') { try { result = !!(value + ''); } catch (e) {} } return result; } /** * Converts `map` to its key-value pairs. * * @private * @param {Object} map The map to convert. * @returns {Array} Returns the key-value pairs. */ function mapToArray(map) { var index = -1, result = Array(map.size); map.forEach(function(value, key) { result[++index] = [key, value]; }); return result; } /** * Creates a unary function that invokes `func` with its argument transformed. * * @private * @param {Function} func The function to wrap. * @param {Function} transform The argument transform. * @returns {Function} Returns the new function. */ function overArg(func, transform) { return function(arg) { return func(transform(arg)); }; } /** * Converts `set` to an array of its values. * * @private * @param {Object} set The set to convert. * @returns {Array} Returns the values. */ function setToArray(set) { var index = -1, result = Array(set.size); set.forEach(function(value) { result[++index] = value; }); return result; } /** Used for built-in method references. */ var arrayProto = Array.prototype, funcProto = Function.prototype, objectProto = Object.prototype; /** Used to detect overreaching core-js shims. */ var coreJsData = root['__core-js_shared__']; /** Used to detect methods masquerading as native. */ var maskSrcKey = (function() { var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); return uid ? ('Symbol(src)_1.' + uid) : ''; }()); /** Used to resolve the decompiled source of functions. */ var funcToString = funcProto.toString; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /** Used to detect if a method is native. */ var reIsNative = RegExp('^' + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); /** Built-in value references. */ var Buffer = moduleExports ? root.Buffer : undefined, Symbol = root.Symbol, Uint8Array = root.Uint8Array, getPrototype = overArg(Object.getPrototypeOf, Object), objectCreate = Object.create, propertyIsEnumerable = objectProto.propertyIsEnumerable, splice = arrayProto.splice; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeGetSymbols = Object.getOwnPropertySymbols, nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, nativeKeys