diff --git a/css/style.css b/css/style.css index d4e0cd2..080b59c 100644 --- a/css/style.css +++ b/css/style.css @@ -326,6 +326,9 @@ h1 br { padding: 1px; z-index: 50; } +.element.empty { + opacity: 0.2; +} #observationsContent { font-size: 24px; } diff --git a/index.html b/index.html index 34d85d3..0301be6 100644 --- a/index.html +++ b/index.html @@ -78,18 +78,24 @@ -
-
+
+
-
+
{{r.key}} @@ -108,9 +114,33 @@
- - +
+ + {{r.key}} + +
+ +
+ + diff --git a/js/app.js b/js/app.js index 3880ca7..fd67122 100644 --- a/js/app.js +++ b/js/app.js @@ -21,46 +21,9 @@ var app = (function () { // directives - /** Change scope values on window resize **/ - app.directive('resize', function ($window) { - return function (scope, element, attr) { - // make window into an angular element - var w = angular.element($window); - // watch window h&w, onchange scope - scope.$watch( - function () { - return { - 'h': w.height(), - 'w': w.width() - }; - }, - function (newValue, oldValue) { - // update scope values - scope.windowHeight = newValue.h; - scope.windowWidth = newValue.w; - - // new function - scope.resizeWithOffset = function (offsetH) { - scope.$eval(attr.notifier); - return { - 'height': (newValue.h - offsetH) + 'px' - //,'width': (newValue.w - 100) + 'px' - }; - }; - - }, - true - ); - - // update scope on resize event - w.bind('resize', function () { - scope.$apply(); - }); - } - }); - // factories to provide game objects + // factories to provide services. They serve shared game objects app.factory('elements', function () { var elements = Helpers.loadFile('json/elements.json'); elements = elements.map( @@ -103,37 +66,74 @@ var app = (function () { }; }]); - - // controllers - app.controller('DetectorController', ['$scope','game','detector', function ($scope,game,detector) { - // this.detector.init(400); - this.dropOptions = { + app.controller('ElementController', ['$scope', '$compile', 'game', 'detector', function ($scope, $compile, game, detector) { + var vs = this; + vs.dragOptions = { + revert: true, //"invalid", + zIndex: 100, + // helper: "clone", // drags a clone + // opacity: 0.75, + // start: vs.onRuneDrop.bind(vs), + // stop: vs.onRuneDrop.bind(vs), + cancel: false, + // containment:false + }; + vs.elements = game.elements; + vs.isVisible = function (item) { + return item.isVisible(game.lab); + }; + vs.isAvailable = function (item) { + return item.isAvailable(game.lab); + }; + vs.onDrop = function (event, ui) { + // store the dropped element + var draggable = angular.element(ui.draggable); + var key = draggable.data('element'); + if (!draggable.hasClass('element-icon')) { + var elementStore = vs.elements.filter(function (e) { + return e.key === key; + })[0]; + var hashKey=draggable.data('hashkey'); + var found=false; + for (var i = 0; i < detector.elements.length; i++) { + if (detector.elements[i].$$hashKey===hashKey){ + // delete detector.elements[i]; + detector.elements.splice(i,1); + var found=true; + break; + } + } + if (!found) console.warn('Could not find dragged element in detector.elements',draggable); + else elementStore.state.amount+=1; + } + } + vs.doElement = function (item) { + var cost = item.element(game.lab); + if (cost > 0) { + UI.showUpdateValue("#update-data", -cost); + UI.showUpdateValue("#update-reputation", item.state.reputation); + } + }; + vs.showInfo = function (r) { + UI.showModal(r.name, r.getInfo()); + UI.showLevels(r.state.level); + }; + }]); + + app.controller('DetectorController', ['$scope', 'game', 'detector', function ($scope, game, detector) { + var vm = this; + vm.elements = detector.elements; + vm.dropOptions = { // accept: ".rune", addClasses: true, // greedy: true, // tolerance: "pointer", activeClass: "ui-state-hover", hoverClass: "ui-state-active", - } - this.onDrop = function (event, ui) { - detector.onDrop(event, ui, game); - } - this.click = function () { - game.lab.clickDetector(); - detector.addEvent(); - UI.showUpdateValue("#update-data", game.lab.state.detector); - return false; }; - this.toggleFlameFuel = function () { - console.log('toggleFlameFuel'); - detector.flame.toggleFuel(); - } - }]); - - app.controller('ElementController', ['$scope', '$compile','game','detector', function ($scope, $compile,game,detector) { - this.dragOptions = { - revert: true, //"invalid", + vm.dragOptions = { + revert: "invalid", zIndex: 100, // helper: "clone", // drags a clone // opacity: 0.75, @@ -142,27 +142,22 @@ var app = (function () { cancel: false, // containment:false }; - this.elements = game.elements; - this.isVisible = function (item) { - return item.isVisible(game.lab); + vm.onDrop = function (event, ui) { + detector.onDrop(event, ui, game); }; - this.isAvailable = function (item) { - return item.isAvailable(game.lab); + vm.click = function () { + game.lab.clickDetector(); + detector.addEvent(); + UI.showUpdateValue("#update-data", game.lab.state.detector); + return false; }; - this.doElement = function (item) { - var cost = item.element(game.lab); - if (cost > 0) { - UI.showUpdateValue("#update-data", -cost); - UI.showUpdateValue("#update-reputation", item.state.reputation); - } - }; - this.showInfo = function (r) { - UI.showModal(r.name, r.getInfo()); - UI.showLevels(r.state.level); + vm.toggleFlameFuel = function () { + console.log('toggleFlameFuel'); + detector.flamer.toggleFuel(); }; }]); - app.controller('LabController', ['$interval','game','detector', function ($interval,game,detector) { + app.controller('LabController', ['$interval', 'game', 'detector', function ($interval, game, detector) { this.lab = game.lab; this.showDetectorInfo = function () { if (!this._detectorInfo) { @@ -189,7 +184,7 @@ var app = (function () { }, 1000); }]); - app.controller('HRController', ['$scope','game', function ($scope,game) { + app.controller('HRController', ['$scope', 'game', function ($scope, game) { this.workers = game.workers; this.isVisible = function (worker) { return worker.isVisible(game.lab); @@ -205,7 +200,7 @@ var app = (function () { }; }]); - app.controller('UpgradesController', ['$scope','game', function ($scope,game) { + app.controller('UpgradesController', ['$scope', 'game', function ($scope, game) { this.upgrades = game.upgrades; this.isVisible = function (upgrade) { return upgrade.isVisible(game.lab, game.allObjects); @@ -220,7 +215,7 @@ var app = (function () { } }]); - app.controller('AchievementsController', function ($scope,game) { + app.controller('AchievementsController', function ($scope, game) { $scope.achievements = game.achievements; $scope.progress = function () { return game.achievements.filter(function (a) { @@ -229,7 +224,7 @@ var app = (function () { }; }); - app.controller('SaveController', ['$scope', '$interval','game', function ($scope, $interval,game) { + app.controller('SaveController', ['$scope', '$interval', 'game', function ($scope, $interval, game) { game.lastSaved = new Date().getTime(); $scope.lastSaved = game.lastSaved; $scope.saveNow = function () { @@ -250,7 +245,7 @@ var app = (function () { $interval($scope.saveNow, 10000); }]); - app.controller('StatsController', ['$scope','game',function ($scope, game) { + app.controller('StatsController', ['$scope', 'game', function ($scope, game) { $scope.lab = game.lab; }]); diff --git a/js/detector/detector.js b/js/detector/detector.js index d1ccc27..c143922 100644 --- a/js/detector/detector.js +++ b/js/detector/detector.js @@ -23,6 +23,8 @@ var Detector = function(){ ctx: null }, + elements: [], + visible: true, width: 400, @@ -80,34 +82,34 @@ var Detector = function(){ $(window).on('resize',this.onResize.bind(this)); }, - onResize: function(){ - // TODO, do one, schedule a check and then prevent firing until then - if ($(window).width() >= 1200) { - if (this.width != 500) { - $('#detector').width(500).height(500); - this.init(500); - } - } else if ($(window).width() < 768 && $(window).height() - 90 < 300) { - var newWidth = $(window).width() - Math.max($(window).width() - ($(window).height() - 90 + 10), 300) - 10; - if (this.width != newWidth) { - $('#detector').width(newWidth).height(newWidth); - this.init(newWidth); - } - } else if ($(window).width() < 992) { - if (this.width != 300) { - $('#detector').width(300).height(300); - this.init(300); - } - } else { - if (this.width != 400) { - $('#detector').width(400).height(400); - this.init(400); - } - } - - this.bubblr.onResize(); - this.flamer.onResize(); - }, + // onResize: function(){ + // // TODO, do one, schedule a check and then prevent firing until then + // if ($(window).width() >= 1200) { + // if (this.width != 500) { + // $('#detector').width(500).height(500); + // this.init(500); + // } + // } else if ($(window).width() < 768 && $(window).height() - 90 < 300) { + // var newWidth = $(window).width() - Math.max($(window).width() - ($(window).height() - 90 + 10), 300) - 10; + // if (this.width != newWidth) { + // $('#detector').width(newWidth).height(newWidth); + // this.init(newWidth); + // } + // } else if ($(window).width() < 992) { + // if (this.width != 300) { + // $('#detector').width(300).height(300); + // this.init(300); + // } + // } else { + // if (this.width != 400) { + // $('#detector').width(400).height(400); + // this.init(400); + // } + // } + // + // this.bubblr.onResize(); + // this.flamer.onResize(); + // }, /** When a user clicks the detector **/ addEvent: function() @@ -128,59 +130,92 @@ var Detector = function(){ }, onDrop: function(event, ui, game){ - // TODO tidy this, attach new runes to something better - // FIXME at the moment it duplicates runes, but we need a better system var self=this; console.debug('onDrop',arguments); - var $draggable = $(ui.draggable), - $droppable = $(event.target); + var $draggable = angular.element(ui.draggable), + $droppable = angular.element(event.target); // if the dragger came from the elements panels, clone it to here - var newElement = $draggable.clone(); - var $detector = $droppable.parent() - $detector.append(newElement); - // also set position to that of droppable - newElement.offset($draggable.offset()) + if ($draggable.hasClass('element-icon')){ + var elementStore = game.elements.filter(function(e){return e.key==$draggable.data('element');})[0]; + elementStore.state.amount-=1; + var newElement = angular.copy(elementStore); + newElement.state.top=$draggable.offset().top; + newElement.state.left=$draggable.offset().left; + this.elements.push(newElement); + } - var elementStore = game.elements.filter(function(e){return e.key==$draggable.data('element')}); - elementStore[0].state.amount-=1; // get everything intersecting the drop - var draggableTop = $draggable.offset().top; var draggableHeight = $draggable.height(); var draggableBottom = draggableTop + draggableHeight; var draggableLeft = $draggable.offset().left; var draggableWidth = $draggable.height(); var draggableRight = draggableLeft + draggableWidth; - var $droppables = $(".ui-droppable"); - var $droppablesCoveredByDraggable = $droppables.filter( function() { - var $droppable = $(this); - var top = $droppable.offset().top; - var height = $droppable.height(); + var $draggables = angular.element('#detector').find('.element').not('.element-icon'); // replace with detector.elements + var inputs = $draggables.filter( function() { + var $elem = angular.element(this); + var top = $elem.offset().top; + var height = $elem.height(); var bottom = top + height; - var left = $droppable.offset().left; - var width = $droppable.width(); + var left = $elem.offset().left; + var width = $elem.width(); var right = left + width; var isCoveredByDraggable = top <= draggableBottom && bottom >= draggableTop && left <= draggableRight && right >= draggableLeft; return isCoveredByDraggable; }); - // TODO also get draggable covered by droppable - for (var i = 0; i < $droppablesCoveredByDraggable.length; i++) { + var reaction = this.experiment({inputs:inputs},game); + console.log('droppables', inputs.length); + + + }, + + /** Run an experiment depending on ingredients and conditions **/ + experiment: function(options,game) { + var inputs = options.inputs || []; + var inputKeys = inputs.map(function(i,e){return $(e).data('element')}); + inputKeys.sort(); // this makes reaction be independant of order + + var result = game.rules[inputKeys] + if (result) { + return this.reaction(result.ingredients,result.rune,game) } - // just get one thes with a data-element attribute - var inputs = $droppablesCoveredByDraggable.filter(function(e){ - return $(e).data('element'); - }) - inputs.push($draggable); - var reaction = game.experiment({inputs:inputs}); - console.log('droppables', $droppablesCoveredByDraggable.length); + return result; + }, + /** Remove ingredients and make results with animations **/ + reaction: function(ingredients,results,game){ + + // remove ingredients from detector + for (var i = 0; i < ingredients.length; i++) { + var ingredient = ingredients[i]; + } + + // TODO use angular effects to remove in puff of fade + + // add results and discover them + for (var i = 0; i < results.length; i++) { + var resultKey = results[i]; + + // make sure it's discovered + var elementStore = this.elements.filter(function(e){return e.key===resultKey;}); + elementStore.state.discovered=true; + + // add new element to beaker + detector.elements.push(); + // var newElement = $('#elementContent').find('.'+resultKey).clone(); + // $('#detector').append(newElement); + newElement.offset($draggable.offset()); + } + + // effects + this.bubblr.start(1500); }, } diff --git a/js/detector/flame.js b/js/detector/flame.js index 073a95f..d4614ec 100644 --- a/js/detector/flame.js +++ b/js/detector/flame.js @@ -182,10 +182,10 @@ /** Toggle fuel and the flame will burn down or up again **/ Flame.prototype.toggleFuel = function (state) { if (state===undefined) - detector.flame.state.on=!detector.flame.state.on; + this.state.on=!this.state.on; else - detector.flame.state.on=state; - return detector.flame.state.on; + this.state.on=state; + return this.state.on; } Flame.prototype.animate = function(){ diff --git a/js/game.js b/js/game.js index bec4758..ac2a892 100644 --- a/js/game.js +++ b/js/game.js @@ -98,50 +98,6 @@ var Game = (function(Helpers,GameObjects,ObjectStorage) { } return rules; }, - - /** Run an experiment depending on ingredients and conditions **/ - Game.prototype.experiment = function(options) { - var inputs = options.inputs || []; - var inputKeys = inputs.map(function(i,e){return $(e).data('element')}); - inputKeys.sort(); // this makes reaction be independant of order - - var result = this.rules[inputKeys] - if (result) { - return this.reaction(result.ingredients,result.rune) - } - return result; - }, - - /** Remove ingredients and make results with animations **/ - Game.prototype.reaction= function(ingredients,results){ - - // remove ingredients - for (var i = 0; i < ingredients.length; i++) { - var ingredient = ingredients[i]; - - } - - // TODO use angular effects to remove in puff of fade - $(aElem).remove(); - $(bElem).remove(); - - // if the dragger came from the elements panels, clone it to here - for (var i = 0; i < results.length; i++) { - // make sure it's discovered - var resultKey = results[i]; - var elementStore = this.elements.filter(function(e){return e.key===resultKey;}); - elementStore.state.discovered=true; - - // add new element to beaker - var newElement = $('#elementContent').find('.'+resultKey).clone(); - $('#detector').append(newElement); - newElement.offset($draggable.offset()) - } - - // effects - this.bubblr.start(1500); - - }, Game.prototype.save = function() { // Save every object's state to local storage for (var key in this.allObjects) { diff --git a/js/gameobjects.js b/js/gameobjects.js index a66ba5f..45fe717 100644 --- a/js/gameobjects.js +++ b/js/gameobjects.js @@ -2,279 +2,283 @@ * Game objects such as workers, research, upgrades, and achievements. */ -var GameObjects = (function() { - 'use strict'; - var GLOBAL_VISIBILITY_THRESHOLD = 0.5; +var GameObjects = (function () { + 'use strict'; + var GLOBAL_VISIBILITY_THRESHOLD = 0.5; - /** @class GameObject - * Base class for all objects in the game. This works together with the - * saving mechanism. - */ - var GameObject = function(obj) { - this.state = {}; - $.extend(this, obj); - if (!this.key) { - throw 'Error: GameObject has to have a key!'; - } - }; - GameObject.prototype.loadState = - function(state) { $.extend(this.state, state); }; + /** @class GameObject + * Base class for all objects in the game. This works together with the + * saving mechanism. + */ + var GameObject = function (obj) { + this.state = {}; + $.extend(this, obj); + if (!this.key) { + throw 'Error: GameObject has to have a key!'; + } + }; + GameObject.prototype.loadState = + function (state) { + $.extend(this.state, state); + }; - /** @class Lab - */ - var Lab = function() { - GameObject.apply(this, [{ - key : 'lab', - state : { - name : 'Click here to give your lab an awesome name!', - detector : 1, - factor : 5, - data : 0, - money : 0, - reputation : 0, - clicks : 0, - moneyCollected : 0, - moneySpent : 0, - dataCollected : 0, - dataSpent : 0, - time: 0 - } - }]); + /** @class Lab + */ + var Lab = function () { + GameObject.apply(this, [{ + key: 'lab', + state: { + name: 'Click here to give your lab an awesome name!', + detector: 1, + factor: 5, + data: 0, + money: 0, + reputation: 0, + clicks: 0, + moneyCollected: 0, + moneySpent: 0, + dataCollected: 0, + dataSpent: 0, + time: 0 + } + }]); - }; + }; - Lab.prototype = Object.create(GameObject.prototype); + Lab.prototype = Object.create(GameObject.prototype); - Lab.prototype.constructor = Lab; + Lab.prototype.constructor = Lab; - Lab.prototype.getGrant = function() { - var addition = this.state.reputation * this.state.factor; - this.state.money += addition; - this.state.moneyCollected += addition; - return addition; - }; + Lab.prototype.getGrant = function () { + var addition = this.state.reputation * this.state.factor; + this.state.money += addition; + this.state.moneyCollected += addition; + return addition; + }; - Lab.prototype.acquireData = function(amount) { - this.state.data += amount; - this.state.dataCollected += amount; - }; + Lab.prototype.acquireData = function (amount) { + this.state.data += amount; + this.state.dataCollected += amount; + }; - Lab.prototype.clickDetector = function() { - this.state.clicks += 1; - this.acquireData(this.state.detector); - }; + Lab.prototype.clickDetector = function () { + this.state.clicks += 1; + this.acquireData(this.state.detector); + }; - Lab.prototype.research = function(cost, reputation) { - if (this.state.data >= cost) { - this.state.data -= cost; - this.state.dataSpent += cost; - this.state.reputation += reputation; - return true; - } - return false; - }; - - - Lab.prototype.buy = function(cost) { - if (this.state.money >= cost) { - this.state.money -= cost; - this.state.moneySpent += cost; - return true; - } - return false; - }; - - /** @class Element - */ - var Element = function(obj) { - GameObject.apply(this, [obj]); - this.state.amount = Math.round(Math.random()*2); - this.state.discovered = Math.random()<0.1; - this.state.interesting = Math.random()<0.1; - this.state.color = Math.round(Math.random()*12); - }; - - Element.prototype = Object.create(GameObject.prototype); - - Element.prototype.constructor = Element; - - Element.prototype.isVisible = function(lab) { - if (!lab) { - return false; - } - return this.state.discovered; - }; - - Element.prototype.isAvailable = function(lab) { - if (!lab) { - return false; - } - return this.state.amount>0; - }; - - Element.prototype.research = function(lab) { - if (lab && lab.research(this.state.cost, this.state.reputation)) { - this.state.level++; - if (this.state.info_levels.length > 0 && - this.state.level === this.state.info_levels[0]) { - this.state.interesting = true; - this.state.info_levels.splice(0, 1); - } - var old_cost = this.state.cost; - this.state.cost = Math.floor(this.state.cost * this.cost_increase); - return old_cost; - } - return -1; - }; - - Element.prototype.getInfo = function() { - if (!this._info) { - this._info = Helpers.loadFile(this.info); - } - this.state.interesting = false; - return this._info; - }; - - /** @class Worker - * Implement an auto-clicker in the game. - */ - var Worker = function(obj) { - GameObject.apply(this, [obj]); - this.state.hired = 0; - }; - - Worker.prototype = Object.create(GameObject.prototype); - - Worker.prototype.constructor = Worker; - - Worker.prototype.isVisible = function(lab) { - if (!lab) { - return false; - } - return this.state.hired > 0 || - lab.state.money >= this.state.cost * GLOBAL_VISIBILITY_THRESHOLD; - }; - - Worker.prototype.isAvailable = function(lab) { - if (!lab) { - return false; - } - return lab.state.money >= this.state.cost; - }; - - Worker.prototype.hire = function(lab) { - if (lab && lab.buy(this.state.cost)) { - this.state.hired++; - var cost = this.state.cost; - this.state.cost = Math.floor(cost * this.cost_increase); - return cost; - } - return -1; // not enough money - }; - - Worker.prototype.getTotal = - function() { return this.state.hired * this.state.rate; }; - - /** @class Upgrade - */ - var Upgrade = function(obj) { - GameObject.apply(this, [obj]); - this.state.visible = false; - this.state.used = false; - }; - - Upgrade.prototype = Object.create(GameObject.prototype); - - Upgrade.prototype.constructor = Upgrade; - - Upgrade.prototype.meetsRequirements = function(allObjects) { - if (!allObjects) { - return false; - } - for (var i = 0; i < this.requirements.length; i++) { - var req = this.requirements[i]; - if (allObjects[req.key].state[req.property] < req.threshold) { + Lab.prototype.research = function (cost, reputation) { + if (this.state.data >= cost) { + this.state.data -= cost; + this.state.dataSpent += cost; + this.state.reputation += reputation; + return true; + } return false; - } - } - return true; - }; - - Upgrade.prototype.isAvailable = function(lab, allObjects) { - if (!lab || !allObjects) { - return false; - } - return !this.state.used && lab.state.money >= this.cost && - this.meetsRequirements(allObjects); - }; - - Upgrade.prototype.isVisible = function(lab, allObjects) { - if (!lab || !allObjects) { - return false; - } - if (!this.state.used && - (this.state.visible || - lab.state.money >= this.cost * GLOBAL_VISIBILITY_THRESHOLD && - this.meetsRequirements(allObjects))) { - this._visible = true; - return true; - } - return false; - }; - - Upgrade.prototype.buy = function(lab, allObjects) { - if (lab && allObjects && !this.state.used && lab.buy(this.cost)) { - for (var i = 0; i < this.targets.length; i++) { - var t = this.targets[i]; - allObjects[t.key].state[t.property] *= this.factor || 1; - allObjects[t.key].state[t.property] += this.constant || 0; - } - this.state.used = true; // How about actually REMOVING used upgrades? - this.state.visible = false; - return this.cost; - } - return -1; - }; + }; - /** @class Achievement - */ - var Achievement = function(obj) { - GameObject.apply(this, [obj]); - this.state.timeAchieved = null; - }; + Lab.prototype.buy = function (cost) { + if (this.state.money >= cost) { + this.state.money -= cost; + this.state.moneySpent += cost; + return true; + } + return false; + }; - Achievement.prototype = Object.create(GameObject.prototype); + /** @class Element + */ + var Element = function (obj) { + GameObject.apply(this, [obj]); + this.state.amount = Math.round(Math.random() * 2); + this.state.discovered = Math.random() < 0.1; + this.state.interesting = Math.random() < 0.1; + this.state.color = Math.round(Math.random() * 11); + }; - Achievement.prototype.validate = function(lab, allObjects, saveTime) { - if (this.state.timeAchieved) { - return true; - } - if (allObjects.hasOwnProperty(this.targetKey) && - allObjects[this.targetKey].state.hasOwnProperty(this.targetProperty) && - allObjects[this.targetKey].state[this.targetProperty] >= this.threshold) { - this.state.timeAchieved = lab.state.time + new Date().getTime() - saveTime; - UI.showAchievement(this); - return true; - } - return false; - }; + Element.prototype = Object.create(GameObject.prototype); - Achievement.prototype.isAchieved = function() { - if (this.state.timeAchieved) { - return true; - } else { - return false; - } - }; + Element.prototype.constructor = Element; + + Element.prototype.isVisible = function (lab) { + if (!lab) { + return false; + } + return this.state.discovered; + }; + + Element.prototype.isAvailable = function (lab) { + if (!lab) { + return false; + } + return this.state.amount > 0; + }; + + Element.prototype.research = function (lab) { + if (lab && lab.research(this.state.cost, this.state.reputation)) { + this.state.level++; + if (this.state.info_levels.length > 0 && + this.state.level === this.state.info_levels[0]) { + this.state.interesting = true; + this.state.info_levels.splice(0, 1); + } + var old_cost = this.state.cost; + this.state.cost = Math.floor(this.state.cost * this.cost_increase); + return old_cost; + } + return -1; + }; + + Element.prototype.getInfo = function () { + if (!this._info) { + this._info = Helpers.loadFile(this.info); + } + this.state.interesting = false; + return this._info; + }; + + /** @class Worker + * Implement an auto-clicker in the game. + */ + var Worker = function (obj) { + GameObject.apply(this, [obj]); + this.state.hired = 0; + }; + + Worker.prototype = Object.create(GameObject.prototype); + + Worker.prototype.constructor = Worker; + + Worker.prototype.isVisible = function (lab) { + if (!lab) { + return false; + } + return this.state.hired > 0 || + lab.state.money >= this.state.cost * GLOBAL_VISIBILITY_THRESHOLD; + }; + + Worker.prototype.isAvailable = function (lab) { + if (!lab) { + return false; + } + return lab.state.money >= this.state.cost; + }; + + Worker.prototype.hire = function (lab) { + if (lab && lab.buy(this.state.cost)) { + this.state.hired++; + var cost = this.state.cost; + this.state.cost = Math.floor(cost * this.cost_increase); + return cost; + } + return -1; // not enough money + }; + + Worker.prototype.getTotal = + function () { + return this.state.hired * this.state.rate; + }; + + /** @class Upgrade + */ + var Upgrade = function (obj) { + GameObject.apply(this, [obj]); + this.state.visible = false; + this.state.used = false; + }; + + Upgrade.prototype = Object.create(GameObject.prototype); + + Upgrade.prototype.constructor = Upgrade; + + Upgrade.prototype.meetsRequirements = function (allObjects) { + if (!allObjects) { + return false; + } + for (var i = 0; i < this.requirements.length; i++) { + var req = this.requirements[i]; + if (allObjects[req.key].state[req.property] < req.threshold) { + return false; + } + } + return true; + }; + + Upgrade.prototype.isAvailable = function (lab, allObjects) { + if (!lab || !allObjects) { + return false; + } + return !this.state.used && lab.state.money >= this.cost && + this.meetsRequirements(allObjects); + }; + + Upgrade.prototype.isVisible = function (lab, allObjects) { + if (!lab || !allObjects) { + return false; + } + if (!this.state.used && + (this.state.visible || + lab.state.money >= this.cost * GLOBAL_VISIBILITY_THRESHOLD && + this.meetsRequirements(allObjects))) { + this._visible = true; + return true; + } + return false; + }; + + Upgrade.prototype.buy = function (lab, allObjects) { + if (lab && allObjects && !this.state.used && lab.buy(this.cost)) { + for (var i = 0; i < this.targets.length; i++) { + var t = this.targets[i]; + allObjects[t.key].state[t.property] *= this.factor || 1; + allObjects[t.key].state[t.property] += this.constant || 0; + } + this.state.used = true; // How about actually REMOVING used upgrades? + this.state.visible = false; + return this.cost; + } + return -1; + }; - // Expose classes in module. - return { - Lab: Lab, - Element: Element, - Worker: Worker, - Upgrade: Upgrade, - Achievement: Achievement - }; + /** @class Achievement + */ + var Achievement = function (obj) { + GameObject.apply(this, [obj]); + this.state.timeAchieved = null; + }; + + Achievement.prototype = Object.create(GameObject.prototype); + + Achievement.prototype.validate = function (lab, allObjects, saveTime) { + if (this.state.timeAchieved) { + return true; + } + if (allObjects.hasOwnProperty(this.targetKey) && + allObjects[this.targetKey].state.hasOwnProperty(this.targetProperty) && + allObjects[this.targetKey].state[this.targetProperty] >= this.threshold) { + this.state.timeAchieved = lab.state.time + new Date().getTime() - saveTime; + UI.showAchievement(this); + return true; + } + return false; + }; + + Achievement.prototype.isAchieved = function () { + if (this.state.timeAchieved) { + return true; + } else { + return false; + } + }; + + + // Expose classes in module. + return { + Lab: Lab, + Element: Element, + Worker: Worker, + Upgrade: Upgrade, + Achievement: Achievement + }; }());