Dragging back and forth between elements and test-tube workds

This commit is contained in:
2016-02-23 16:47:55 +08:00
parent 8840634f6f
commit f01955571d
7 changed files with 474 additions and 451 deletions
+3
View File
@@ -326,6 +326,9 @@ h1 br {
padding: 1px;
z-index: 50;
}
.element.empty {
opacity: 0.2;
}
#observationsContent {
font-size: 24px;
}
+38 -8
View File
@@ -78,18 +78,24 @@
</h4>
</div>
<div class="panel-body large" id="elementLarge">
<div id="elementContent" ng-controller="ElementController as rc">
<div class="panel-body large" id="elementLarge"
data-drop="true"
jqyoui-droppable="{onDrop: 'rc.onDrop'}"
data-jqyoui-options="{{rc.dropOptions}}"
ng-controller="ElementController as rc"
>
<div id="elementContent">
<div class="row" ng-cloak>
<div class="col-md-3" ng-repeat="r in rc.elements" ng-show="rc.isVisible(r)">
<div class="col-md-4" ng-repeat="r in rc.elements" ng-show="rc.isVisible(r)">
<span
id="{{r.key}}"
class="{{r.key}} element element-icon {{ r.state.interesting ? 'blink' : '' }} {{'q'+r.state.color+'-12'}}"
class="{{r.key}} element element-icon {{ r.state.interesting ? 'blink' : '' }} {{'q'+r.state.color+'-12'}} {{r.state.amount>0 ? '': 'empty'}}"
data-element="{{r.key}}"
data-drag="true"
data-drag="{{r.state.amount>0}}"
jqyoui-draggable="{containment:'offset'}"
data-jqyoui-options="{{rc.dragOptions}}"
data-hashkey={{r.$$hashKey}}
>
{{r.key}}
</span>
@@ -108,9 +114,33 @@
<div id="detector-holder">
<div id="detector" ng-controller="DetectorController as dc">
<!-- <canvas id="detector-core" class="test-tube center-block " width="400"
height="400" style=""></canvas> -->
<canvas ng-click="dc.click()" id="detector-core" width="400" height="400" class="test-tube prevent-select center-block " data-drop="true"
<div id="detector-element-container" ng-cloak>
<div ng-repeat="r in dc.elements">
<span
class="{{r.key}} element q{{r.state.color}}-12"
data-element="{{r.key}}"
data-drag="true"
jqyoui-draggable="{containment:'offset'}"
data-jqyoui-options="{{rc.dragOptions}}"
aria-disabled="false"
style="position: fixed; z-index: 9999; left: {{r.state.left}}px; top: {{r.state.top}}px;"
data-hashkey={{r.$$hashKey}}
>
{{r.key}}
</span>
</div>
</div>
<canvas
ng-click="dc.click()"
id="detector-core"
width="400"
height="400"
class="test-tube prevent-select center-block "
data-drop="true"
jqyoui-droppable="{onDrop: 'dc.onDrop'}"
data-jqyoui-options="{{dc.dropOptions}}"
>
+77 -82
View File
@@ -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;
}]);
+91 -56
View File
@@ -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);
},
}
+3 -3
View File
@@ -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(){
-44
View File
@@ -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) {
+262 -258
View File
@@ -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
};
}());