mirror of
https://github.com/wassname/cardsforscience.git
synced 2026-09-11 12:00:40 +08:00
Converted to es6 imports and exports
This commit is contained in:
+4
-2
@@ -1,5 +1,5 @@
|
||||
/** Custom google analystics events **/
|
||||
var Helpers = require("js/helpers");
|
||||
import Helpers from "js/helpers";
|
||||
|
||||
// google analystics async code
|
||||
(function (i, s, o, g, r, a, m) {
|
||||
@@ -14,7 +14,7 @@ var Helpers = require("js/helpers");
|
||||
m.parentNode.insertBefore(a, m);
|
||||
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
|
||||
|
||||
var analytics = module.exports =
|
||||
var analytics =
|
||||
{
|
||||
enabled: true,
|
||||
|
||||
@@ -95,3 +95,5 @@ var analytics = module.exports =
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default analytics
|
||||
|
||||
+487
-485
@@ -1,485 +1,487 @@
|
||||
/**
|
||||
* Define the angular app
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
//deps
|
||||
var jquery = require("jquery");
|
||||
var jqueryUi = require("jquery-ui");
|
||||
var jqueryUiTouchPunch = require("jquery-ui-touch-punch");
|
||||
var jsCookie = require("js-cookie");
|
||||
|
||||
var angular = require("angular");
|
||||
var angularDragdrop = require("angular-dragdrop");
|
||||
var angularAnimate = require("angular-animate");
|
||||
var angulartics = require('angulartics');
|
||||
var angularticsGoogleAnalytics = require('angulartics-google-analytics');
|
||||
var ngAlertify = require("alertify.js/dist/js/ngAlertify.js");
|
||||
|
||||
//app
|
||||
var ObjectStorage = require("js/storage");
|
||||
var Helpers = require("js/helpers");
|
||||
var GameObjects = require("js/gameobjects");
|
||||
var analytics = require("js/analytics");
|
||||
var Game = require("js/game");
|
||||
var Rules = require("js/rules.js");
|
||||
var UI = require("js/ui.js");
|
||||
|
||||
var app = (function (Helpers,analytics,Game,Rules) {
|
||||
Helpers.validateSaveVersion();
|
||||
|
||||
var app = angular.module('cardsForScience', ['ngDragDrop','ngAnimate','angulartics', angularticsGoogleAnalytics,"ngAlertify"]);
|
||||
|
||||
// config
|
||||
app.config(function ($analyticsProvider) {
|
||||
$analyticsProvider.firstPageview(true); /* Records pages that don't use $state or $route */
|
||||
$analyticsProvider.withAutoBase(true); /* Records full path */
|
||||
});
|
||||
|
||||
// directives
|
||||
|
||||
|
||||
/**
|
||||
* Make little "+2" "-1" score animations when score changes requires ng-model="score"
|
||||
* Associated css:
|
||||
* ```
|
||||
* .update-value { // set constant height, and the position
|
||||
position: relative;
|
||||
right: -2em;
|
||||
top: -1.42857em;
|
||||
height: 1.42857em;
|
||||
}
|
||||
.update-plus { // if the change is +ve
|
||||
color: green;
|
||||
position: relative;
|
||||
}
|
||||
.update-minus {
|
||||
color: red;
|
||||
position: relative;
|
||||
}
|
||||
*/
|
||||
function cfsScoreChange($compile) {
|
||||
return {
|
||||
link: function (scope, element, attrs) {
|
||||
scope.$watch(attrs.ngModel, function (newValue, oldValue) {
|
||||
// showUpdateValue
|
||||
var num = newValue-oldValue;
|
||||
var formatted = Helpers.formatNumberPostfix(num);
|
||||
var insert;
|
||||
if (num > 0) {
|
||||
insert = angular.element("<div class=''></div>")
|
||||
.attr("class", "update-plus")
|
||||
.html("+" + formatted);
|
||||
} else {
|
||||
insert = angular.element("<div></div>")
|
||||
.attr("class", "update-minus")
|
||||
.html(formatted);
|
||||
}
|
||||
|
||||
// TODO it would be better to use an ::after element for this
|
||||
// showUpdate
|
||||
element.append(insert);
|
||||
insert.animate({
|
||||
"bottom":"+=30px",
|
||||
"opacity": 0
|
||||
}, { duration: 500, complete: function() {
|
||||
angular.element(this).remove();
|
||||
}});
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
};
|
||||
cfsScoreChange.$inject = ['$compile'];
|
||||
app.directive('cfsScoreChange', cfsScoreChange);
|
||||
|
||||
|
||||
/**
|
||||
* Directive to render a rule and bind it's option with select boxes
|
||||
* This expects ng-model="rule" as an attribute
|
||||
*/
|
||||
// function cfsRule($compile) {
|
||||
// return {
|
||||
// link: function (scope, element, attrs) {
|
||||
// var rule = scope.$eval(attrs.ngModel);
|
||||
//
|
||||
// // first generate a select box for each option (using lodash templating)
|
||||
// _.templateSettings.interpolate = /<%=([\s\S]+?)%>/g;
|
||||
// var optionTmpl = '' +
|
||||
// '<select \n' +
|
||||
// ' name="<%=option%>" \n' +
|
||||
// ' convert-to-number="{{rule.optionDesc.<%=option%>.type===\'Number\'}}" \n' +
|
||||
// ' ng-model="rule.options.<%=option%>" \n' +
|
||||
// ' class="form-control input-sm" \n' +
|
||||
// ' ng-options="v for v in rule.optionDesc.<%=option%>.possibleVals track by v" \n' +
|
||||
// '>\n' +
|
||||
// '</select>\n';
|
||||
//
|
||||
// var tmplParams = _.defaults({},rule.options,rule.otherOptions);
|
||||
// for (var option in rule.optionDesc) {
|
||||
// if (rule.optionDesc.hasOwnProperty(option)) {
|
||||
// var vals = rule.optionDesc[option].possibleVals;
|
||||
// if (vals) {
|
||||
// tmplParams[option] = _.template(optionTmpl)({
|
||||
// option: option
|
||||
// });
|
||||
// } else {
|
||||
// // if there are no options replace '{{color}}' with 'color'
|
||||
// tmplParams[option] = option;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // now put each select box into description
|
||||
// // replace '{{color}}' with '<select name="color"...'
|
||||
// var template = _.template(rule.description)(tmplParams);
|
||||
//
|
||||
// // now compile with angular
|
||||
// element.html(template).show();
|
||||
// $compile(element.contents())(scope);
|
||||
// }
|
||||
// };
|
||||
// };
|
||||
// cfsRule.$inject = ['$compile'];
|
||||
// app.directive('cfsRule', cfsRule);
|
||||
|
||||
|
||||
// factories to provide services. They serve shared game objects
|
||||
// app.factory('cards', function () {
|
||||
// var cards = Helpers.loadFile('json/cards.json');
|
||||
// cards = cards.map(
|
||||
// function (r) {
|
||||
// return new GameObjects.Card(r);
|
||||
// });
|
||||
// // put in extended array with helper methods
|
||||
// Cards = new GameObjects.Cards();
|
||||
// Cards.push.apply(Cards,cards);
|
||||
// return Cards;
|
||||
// });
|
||||
|
||||
|
||||
function game($http, $q, lab) {
|
||||
var game = new Game();
|
||||
game.lab = lab;
|
||||
game.allObjects.lab = lab;
|
||||
var promise = game.load($http, $q);
|
||||
game.reset();
|
||||
// return promise;
|
||||
return game;
|
||||
};
|
||||
game.$inject = ['$http', '$q', 'lab'];
|
||||
app.factory('game', game);
|
||||
|
||||
function lab() {
|
||||
if (!this.lab) this.lab = new GameObjects.Lab();
|
||||
return this.lab;
|
||||
};
|
||||
app.factory('lab', lab);
|
||||
|
||||
// add helpers as filters
|
||||
function niceNumber($filter) {
|
||||
return Helpers.formatNumberPostfix;
|
||||
};
|
||||
niceNumber.$inject = ['$filter'];
|
||||
app.filter('niceNumber', niceNumber);
|
||||
|
||||
/** transpose data for a table **/
|
||||
// function transpose($filter) {
|
||||
// return function (input) {
|
||||
// return _.zip(input);
|
||||
// };
|
||||
// };
|
||||
// transpose.$inject = ['$filter'];
|
||||
// app.filter('transpose', transpose);
|
||||
|
||||
function boolToTick($filter) {
|
||||
return function (input) {
|
||||
if (input===true) return '✓';
|
||||
else if (input===false) return '❌';
|
||||
else return input;
|
||||
};
|
||||
};
|
||||
boolToTick.$inject = ['$filter'];
|
||||
app.filter('boolToTick', boolToTick);
|
||||
|
||||
function niceTime($filter) {
|
||||
return Helpers.formatTime;
|
||||
};
|
||||
niceTime.$inject = ['$filter'];
|
||||
app.filter('niceTime', niceTime);
|
||||
|
||||
function currency($filter) {
|
||||
return function (input) {
|
||||
return 'JTN ' + $filter('niceNumber')(input);
|
||||
};
|
||||
};
|
||||
currency.$inject = ['$filter'];
|
||||
app.filter('currency', currency);
|
||||
|
||||
function reverse($filter) {
|
||||
return function (items) {
|
||||
if (items instanceof Array)
|
||||
return items.slice().reverse();
|
||||
else
|
||||
return items;
|
||||
};
|
||||
};
|
||||
reverse.$inject = ['$filter'];
|
||||
app.filter('reverse', reverse);
|
||||
|
||||
// controllers
|
||||
app.controller('CardController', CardController);
|
||||
CardController.$inject = ['$scope', '$compile', 'game', 'lab'];
|
||||
|
||||
function CardController($scope, $compile, game, lab) {
|
||||
var vm = this;
|
||||
vm.dataJqyouiOptions = {
|
||||
revert: "invalid",
|
||||
zIndex: 100,
|
||||
cancel: false,
|
||||
};
|
||||
vm.jqyouiDraggable = {
|
||||
containment:'offset',
|
||||
onStart:'rc.dragStart(r)',
|
||||
onStop:'rc.dragStop(r)',
|
||||
animate:true,
|
||||
};
|
||||
vm.onClick = function (card) {
|
||||
// don't click if it was dragged within .222 seconds
|
||||
// (to prevent double firing)
|
||||
if (!card.state.lastDragged || new Date()-new Date(card.state.lastDragged)>300)
|
||||
game.play(card);
|
||||
else
|
||||
console.log('clickprevent',card.state.lastDragged);
|
||||
};
|
||||
vm.dragStart = function(event, ui,card){
|
||||
card.state.lastDragged=new Date();
|
||||
console.log('startDrag');
|
||||
};
|
||||
vm.dragStop = function(event, ui,card){
|
||||
card.state.lastDragged=new Date();
|
||||
console.log('endDrag');
|
||||
};
|
||||
vm.cards = game.cards;
|
||||
vm.isVisible = function (item) {
|
||||
return item.isVisible(lab);
|
||||
};
|
||||
vm.isAvailable = function (item) {
|
||||
return item.isAvailable(lab);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function TableController($scope, game, lab, $filter) {
|
||||
var vm = this;
|
||||
vm.cards = detector.cards;
|
||||
vm.ruleInfo = game.ruleInfo;
|
||||
vm.hints = game.hints;
|
||||
vm.limit = -12;
|
||||
vm.hintCost = 10;
|
||||
vm.ruleCost = 300;
|
||||
vm.lastCards = game.lastCards;
|
||||
vm.incorrectCards = game.incorrectCards;
|
||||
vm.dataJqyouiOptions = {
|
||||
// accept: ".rune",
|
||||
addClasses: true,
|
||||
// greedy: true,
|
||||
// tolerance: "pointer",
|
||||
activeClass: "ui-state-hover",
|
||||
hoverClass: "ui-state-active",
|
||||
};
|
||||
vm.jqyouiDroppable={onDrop: 'dc.onDrop',multiple:true};
|
||||
vm.onDrop = function (event, ui) {
|
||||
var result = game.onDrop(event, ui, game);
|
||||
};
|
||||
vm.revealRule = function () {
|
||||
if (vm.ruleInfo.length===0){
|
||||
vm.ruleInfo.push(game.rule.describe());
|
||||
lab.state.score -= vm.ruleCost;
|
||||
};
|
||||
};
|
||||
vm.revealHint = function () {
|
||||
var hint = game.rule.nextHint();
|
||||
if (hint) {
|
||||
vm.hints.push(hint);
|
||||
lab.state.score -= vm.hintCost;
|
||||
}
|
||||
};
|
||||
};
|
||||
TableController.$inject = ['$scope', 'game', 'lab', '$filter'];
|
||||
app.controller('TableController', TableController);
|
||||
|
||||
|
||||
function RulesController($scope, game, lab,$analytics,alertify) {
|
||||
var vm = this;
|
||||
// present just a few hypothesis
|
||||
|
||||
// emit event track (with category and label properties for GA)
|
||||
$analytics.eventTrack('rule', {
|
||||
category: 'rule', label: game.rule.describe()
|
||||
});
|
||||
|
||||
|
||||
vm.hypotheses = game.hypotheses;
|
||||
|
||||
vm.upgrades = game.upgrades;
|
||||
vm.isVisible = function (upgrade) {
|
||||
return upgrade.isVisible(lab, game.allObjects);
|
||||
};
|
||||
vm.isAvailable = function (upgrade) {
|
||||
return upgrade.isAvailable(lab, game.allObjects);
|
||||
};
|
||||
/** return a class based on none right or wrong guessed **/
|
||||
vm.isGuessed = function(rule){
|
||||
if (rule.guessed===true) return 'bg-success';
|
||||
else if (rule.guessed===false) return 'bg-danger';
|
||||
else return '';
|
||||
|
||||
};
|
||||
vm.guess = function (e, rule) {
|
||||
var params = angular.element(e.target).parent('form').serializeArray();
|
||||
|
||||
var sameRule = rule.description == game.rule.description;
|
||||
var sameOpts = angular.equals(rule.options, game.rule.options);
|
||||
if (sameRule && sameOpts) {
|
||||
// right!
|
||||
lab.state.score += 200;
|
||||
lab.state.rulesGuessed.push({
|
||||
key: game.rule.key,
|
||||
options: game.rule.options,
|
||||
description: game.rule.describe(),
|
||||
});
|
||||
if (!rule.state) rule.state={};
|
||||
rule.guessed=true;
|
||||
|
||||
alertify.alert(
|
||||
'You have won using inductive logic! <p> <p> Play again?',
|
||||
function(event){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
},function(){}
|
||||
);
|
||||
} else {
|
||||
lab.state.score -= 200;
|
||||
rule.guessed=false;
|
||||
lab.state.rulesFailed.push({
|
||||
key: rule.key,
|
||||
options: rule.options,
|
||||
description: rule.describe(),
|
||||
});
|
||||
}
|
||||
console.log('guess', arguments);
|
||||
|
||||
|
||||
// vm.winDialouge = function () {
|
||||
// if (!vm._winDialouge) {
|
||||
// vm._winDialouge = Helpers.loadFile('html/win.html');
|
||||
// }
|
||||
// UI.showModal('Win', vm._winDialouge);
|
||||
// };
|
||||
};
|
||||
};
|
||||
RulesController.$inject = ['$scope', 'game', 'lab','$analytics','alertify'];
|
||||
app.controller('RulesController', RulesController);
|
||||
|
||||
function AchievementsController($scope, game, lab) {
|
||||
var vm = this;
|
||||
vm.achievements = game.achievements;
|
||||
vm.progress = function () {
|
||||
return game.achievements.filter(function (a) {
|
||||
return a.validate(lab, game.allObjects, game.lastSaved);
|
||||
}).length;
|
||||
};
|
||||
};
|
||||
AchievementsController.$inject = ['$scope', 'game', 'lab'];
|
||||
app.controller('AchievementsController', AchievementsController);
|
||||
|
||||
function SaveController($scope, $interval, $window, alertify, game, lab) {
|
||||
var vm = this;
|
||||
game.lastSaved = new Date().getTime();
|
||||
vm.lastSaved = game.lastSaved;
|
||||
;
|
||||
|
||||
vm.saveNow = function () {
|
||||
var saveTime = new Date().getTime();
|
||||
lab.state.time += saveTime - game.lastSaved;
|
||||
game.save();
|
||||
game.lastSaved = saveTime;
|
||||
vm.lastSaved = game.lastSaved;
|
||||
|
||||
// if (lab.state.score<0){
|
||||
// alertify.alert(
|
||||
// 'Your score is below zero, so you lost :( Want to try a different rule?',
|
||||
// function(event){
|
||||
// event.preventDefault();
|
||||
// // ObjectStorage.clear();
|
||||
// // $window.location.reload(true); /// reloads are better for ads?
|
||||
// game.reset();
|
||||
// // since this confirmation was away from the dom we need to
|
||||
// // manually refresh
|
||||
// $scope.$apply();
|
||||
// },function(){}
|
||||
// );
|
||||
// }
|
||||
|
||||
};
|
||||
vm.restart = function () {
|
||||
console.log('restart');
|
||||
alertify.confirm(
|
||||
'Do you really want to restart the game? All progress will be lost.',
|
||||
function(event){
|
||||
alertify.alert('Restarting. <p> The rule was: <p>"'+game.rule.describe(),function(){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
});
|
||||
},function(){}
|
||||
);
|
||||
};
|
||||
$interval(vm.saveNow, 10000);
|
||||
};
|
||||
SaveController.$inject = ['$scope', '$interval', '$window', 'alertify', 'game', 'lab'];
|
||||
app.controller('SaveController', SaveController);
|
||||
|
||||
function StatsController($scope, lab,game,alertify) {
|
||||
var vm = this;
|
||||
vm.lab = lab;
|
||||
vm.lost=false;
|
||||
|
||||
|
||||
$scope.$watch('lc.lab.state.score', function (newValue, oldValue) {
|
||||
if (newValue<0&&!vm.lost){
|
||||
vm.lost=true;
|
||||
alertify.alert(
|
||||
'<p>You lost :( Play again? <p><p> The rule was: <p>"'+game.rule.describe()+'"',
|
||||
function(event){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
vm.lost=false;
|
||||
|
||||
},function(){}
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
};
|
||||
StatsController.$inject = ['$scope', 'lab','game','alertify'];
|
||||
app.controller('StatsController', StatsController);
|
||||
|
||||
analytics.init();
|
||||
analytics.sendScreen(analytics.screens.main);
|
||||
})(Helpers,analytics,Game,Rules);
|
||||
module.exports=app;
|
||||
/**
|
||||
* Define the angular app
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
//deps
|
||||
import jquery from "jquery";
|
||||
import jqueryUi from "jquery-ui";
|
||||
import jqueryUiTouchPunch from "jquery-ui-touch-punch";
|
||||
import jsCookie from "js-cookie";
|
||||
|
||||
import angular from "angular";
|
||||
import angularDragdrop from "angular-dragdrop";
|
||||
import angularAnimate from "angular-animate";
|
||||
import angulartics from 'angulartics';
|
||||
import angularticsGoogleAnalytics from 'angulartics-google-analytics';
|
||||
import ngAlertify from "alertify.js/dist/js/ngAlertify.js";
|
||||
|
||||
//app
|
||||
import ObjectStorage from "js/storage";
|
||||
import Helpers from "js/helpers";
|
||||
import GameObjects from "js/gameobjects";
|
||||
import analytics from "js/analytics";
|
||||
import Game from "js/game";
|
||||
import Rules from "js/rules.js";
|
||||
import UI from "js/ui.js";
|
||||
|
||||
|
||||
var app = (function (Helpers,analytics,Game,Rules) {
|
||||
Helpers.validateSaveVersion();
|
||||
|
||||
var app = angular.module('cardsForScience', ['ngDragDrop','ngAnimate','angulartics', angularticsGoogleAnalytics,"ngAlertify"]);
|
||||
|
||||
// config
|
||||
app.config(function ($analyticsProvider) {
|
||||
$analyticsProvider.firstPageview(true); /* Records pages that don't use $state or $route */
|
||||
$analyticsProvider.withAutoBase(true); /* Records full path */
|
||||
});
|
||||
|
||||
// directives
|
||||
|
||||
|
||||
/**
|
||||
* Make little "+2" "-1" score animations when score changes requires ng-model="score"
|
||||
* Associated css:
|
||||
* ```
|
||||
* .update-value { // set constant height, and the position
|
||||
position: relative;
|
||||
right: -2em;
|
||||
top: -1.42857em;
|
||||
height: 1.42857em;
|
||||
}
|
||||
.update-plus { // if the change is +ve
|
||||
color: green;
|
||||
position: relative;
|
||||
}
|
||||
.update-minus {
|
||||
color: red;
|
||||
position: relative;
|
||||
}
|
||||
*/
|
||||
function cfsScoreChange($compile) {
|
||||
return {
|
||||
link: function (scope, element, attrs) {
|
||||
scope.$watch(attrs.ngModel, function (newValue, oldValue) {
|
||||
// showUpdateValue
|
||||
var num = newValue-oldValue;
|
||||
var formatted = Helpers.formatNumberPostfix(num);
|
||||
var insert;
|
||||
if (num > 0) {
|
||||
insert = angular.element("<div class=''></div>")
|
||||
.attr("class", "update-plus")
|
||||
.html("+" + formatted);
|
||||
} else {
|
||||
insert = angular.element("<div></div>")
|
||||
.attr("class", "update-minus")
|
||||
.html(formatted);
|
||||
}
|
||||
|
||||
// TODO it would be better to use an ::after element for this
|
||||
// showUpdate
|
||||
element.append(insert);
|
||||
insert.animate({
|
||||
"bottom":"+=30px",
|
||||
"opacity": 0
|
||||
}, { duration: 500, complete: function() {
|
||||
angular.element(this).remove();
|
||||
}});
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
};
|
||||
cfsScoreChange.$inject = ['$compile'];
|
||||
app.directive('cfsScoreChange', cfsScoreChange);
|
||||
|
||||
|
||||
/**
|
||||
* Directive to render a rule and bind it's option with select boxes
|
||||
* This expects ng-model="rule" as an attribute
|
||||
*/
|
||||
// function cfsRule($compile) {
|
||||
// return {
|
||||
// link: function (scope, element, attrs) {
|
||||
// var rule = scope.$eval(attrs.ngModel);
|
||||
//
|
||||
// // first generate a select box for each option (using lodash templating)
|
||||
// _.templateSettings.interpolate = /<%=([\s\S]+?)%>/g;
|
||||
// var optionTmpl = '' +
|
||||
// '<select \n' +
|
||||
// ' name="<%=option%>" \n' +
|
||||
// ' convert-to-number="{{rule.optionDesc.<%=option%>.type===\'Number\'}}" \n' +
|
||||
// ' ng-model="rule.options.<%=option%>" \n' +
|
||||
// ' class="form-control input-sm" \n' +
|
||||
// ' ng-options="v for v in rule.optionDesc.<%=option%>.possibleVals track by v" \n' +
|
||||
// '>\n' +
|
||||
// '</select>\n';
|
||||
//
|
||||
// var tmplParams = _.defaults({},rule.options,rule.otherOptions);
|
||||
// for (var option in rule.optionDesc) {
|
||||
// if (rule.optionDesc.hasOwnProperty(option)) {
|
||||
// var vals = rule.optionDesc[option].possibleVals;
|
||||
// if (vals) {
|
||||
// tmplParams[option] = _.template(optionTmpl)({
|
||||
// option: option
|
||||
// });
|
||||
// } else {
|
||||
// // if there are no options replace '{{color}}' with 'color'
|
||||
// tmplParams[option] = option;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // now put each select box into description
|
||||
// // replace '{{color}}' with '<select name="color"...'
|
||||
// var template = _.template(rule.description)(tmplParams);
|
||||
//
|
||||
// // now compile with angular
|
||||
// element.html(template).show();
|
||||
// $compile(element.contents())(scope);
|
||||
// }
|
||||
// };
|
||||
// };
|
||||
// cfsRule.$inject = ['$compile'];
|
||||
// app.directive('cfsRule', cfsRule);
|
||||
|
||||
|
||||
// factories to provide services. They serve shared game objects
|
||||
// app.factory('cards', function () {
|
||||
// var cards = Helpers.loadFile('json/cards.json');
|
||||
// cards = cards.map(
|
||||
// function (r) {
|
||||
// return new GameObjects.Card(r);
|
||||
// });
|
||||
// // put in extended array with helper methods
|
||||
// Cards = new GameObjects.Cards();
|
||||
// Cards.push.apply(Cards,cards);
|
||||
// return Cards;
|
||||
// });
|
||||
|
||||
|
||||
function game($http, $q, lab) {
|
||||
var game = new Game();
|
||||
game.lab = lab;
|
||||
game.allObjects.lab = lab;
|
||||
var promise = game.load($http, $q);
|
||||
game.reset();
|
||||
// return promise;
|
||||
return game;
|
||||
};
|
||||
game.$inject = ['$http', '$q', 'lab'];
|
||||
app.factory('game', game);
|
||||
|
||||
function lab() {
|
||||
if (!this.lab) this.lab = new GameObjects.Lab();
|
||||
return this.lab;
|
||||
};
|
||||
app.factory('lab', lab);
|
||||
|
||||
// add helpers as filters
|
||||
function niceNumber($filter) {
|
||||
return Helpers.formatNumberPostfix;
|
||||
};
|
||||
niceNumber.$inject = ['$filter'];
|
||||
app.filter('niceNumber', niceNumber);
|
||||
|
||||
/** transpose data for a table **/
|
||||
// function transpose($filter) {
|
||||
// return function (input) {
|
||||
// return _.zip(input);
|
||||
// };
|
||||
// };
|
||||
// transpose.$inject = ['$filter'];
|
||||
// app.filter('transpose', transpose);
|
||||
|
||||
function boolToTick($filter) {
|
||||
return function (input) {
|
||||
if (input===true) return '✓';
|
||||
else if (input===false) return '❌';
|
||||
else return input;
|
||||
};
|
||||
};
|
||||
boolToTick.$inject = ['$filter'];
|
||||
app.filter('boolToTick', boolToTick);
|
||||
|
||||
function niceTime($filter) {
|
||||
return Helpers.formatTime;
|
||||
};
|
||||
niceTime.$inject = ['$filter'];
|
||||
app.filter('niceTime', niceTime);
|
||||
|
||||
function currency($filter) {
|
||||
return function (input) {
|
||||
return 'JTN ' + $filter('niceNumber')(input);
|
||||
};
|
||||
};
|
||||
currency.$inject = ['$filter'];
|
||||
app.filter('currency', currency);
|
||||
|
||||
function reverse($filter) {
|
||||
return function (items) {
|
||||
if (items instanceof Array)
|
||||
return items.slice().reverse();
|
||||
else
|
||||
return items;
|
||||
};
|
||||
};
|
||||
reverse.$inject = ['$filter'];
|
||||
app.filter('reverse', reverse);
|
||||
|
||||
// controllers
|
||||
app.controller('CardController', CardController);
|
||||
CardController.$inject = ['$scope', '$compile', 'game', 'lab'];
|
||||
|
||||
function CardController($scope, $compile, game, lab) {
|
||||
var vm = this;
|
||||
vm.dataJqyouiOptions = {
|
||||
revert: "invalid",
|
||||
zIndex: 100,
|
||||
cancel: false,
|
||||
};
|
||||
vm.jqyouiDraggable = {
|
||||
containment:'offset',
|
||||
onStart:'rc.dragStart(r)',
|
||||
onStop:'rc.dragStop(r)',
|
||||
animate:true,
|
||||
};
|
||||
vm.onClick = function (card) {
|
||||
// don't click if it was dragged within .222 seconds
|
||||
// (to prevent double firing)
|
||||
if (!card.state.lastDragged || new Date()-new Date(card.state.lastDragged)>300)
|
||||
game.play(card);
|
||||
else
|
||||
console.log('clickprevent',card.state.lastDragged);
|
||||
};
|
||||
vm.dragStart = function(event, ui,card){
|
||||
card.state.lastDragged=new Date();
|
||||
console.log('startDrag');
|
||||
};
|
||||
vm.dragStop = function(event, ui,card){
|
||||
card.state.lastDragged=new Date();
|
||||
console.log('endDrag');
|
||||
};
|
||||
vm.cards = game.cards;
|
||||
vm.isVisible = function (item) {
|
||||
return item.isVisible(lab);
|
||||
};
|
||||
vm.isAvailable = function (item) {
|
||||
return item.isAvailable(lab);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function TableController($scope, game, lab, $filter) {
|
||||
var vm = this;
|
||||
vm.cards = detector.cards;
|
||||
vm.ruleInfo = game.ruleInfo;
|
||||
vm.hints = game.hints;
|
||||
vm.limit = -12;
|
||||
vm.hintCost = 10;
|
||||
vm.ruleCost = 300;
|
||||
vm.lastCards = game.lastCards;
|
||||
vm.incorrectCards = game.incorrectCards;
|
||||
vm.dataJqyouiOptions = {
|
||||
// accept: ".rune",
|
||||
addClasses: true,
|
||||
// greedy: true,
|
||||
// tolerance: "pointer",
|
||||
activeClass: "ui-state-hover",
|
||||
hoverClass: "ui-state-active",
|
||||
};
|
||||
vm.jqyouiDroppable={onDrop: 'dc.onDrop',multiple:true};
|
||||
vm.onDrop = function (event, ui) {
|
||||
var result = game.onDrop(event, ui, game);
|
||||
};
|
||||
vm.revealRule = function () {
|
||||
if (vm.ruleInfo.length===0){
|
||||
vm.ruleInfo.push(game.rule.describe());
|
||||
lab.state.score -= vm.ruleCost;
|
||||
};
|
||||
};
|
||||
vm.revealHint = function () {
|
||||
var hint = game.rule.nextHint();
|
||||
if (hint) {
|
||||
vm.hints.push(hint);
|
||||
lab.state.score -= vm.hintCost;
|
||||
}
|
||||
};
|
||||
};
|
||||
TableController.$inject = ['$scope', 'game', 'lab', '$filter'];
|
||||
app.controller('TableController', TableController);
|
||||
|
||||
|
||||
function RulesController($scope, game, lab,$analytics,alertify) {
|
||||
var vm = this;
|
||||
// present just a few hypothesis
|
||||
|
||||
// emit event track (with category and label properties for GA)
|
||||
$analytics.eventTrack('rule', {
|
||||
category: 'rule', label: game.rule.describe()
|
||||
});
|
||||
|
||||
|
||||
vm.hypotheses = game.hypotheses;
|
||||
|
||||
vm.upgrades = game.upgrades;
|
||||
vm.isVisible = function (upgrade) {
|
||||
return upgrade.isVisible(lab, game.allObjects);
|
||||
};
|
||||
vm.isAvailable = function (upgrade) {
|
||||
return upgrade.isAvailable(lab, game.allObjects);
|
||||
};
|
||||
/** return a class based on none right or wrong guessed **/
|
||||
vm.isGuessed = function(rule){
|
||||
if (rule.guessed===true) return 'bg-success';
|
||||
else if (rule.guessed===false) return 'bg-danger';
|
||||
else return '';
|
||||
|
||||
};
|
||||
vm.guess = function (e, rule) {
|
||||
var params = angular.element(e.target).parent('form').serializeArray();
|
||||
|
||||
var sameRule = rule.description == game.rule.description;
|
||||
var sameOpts = angular.equals(rule.options, game.rule.options);
|
||||
if (sameRule && sameOpts) {
|
||||
// right!
|
||||
lab.state.score += 200;
|
||||
lab.state.rulesGuessed.push({
|
||||
key: game.rule.key,
|
||||
options: game.rule.options,
|
||||
description: game.rule.describe(),
|
||||
});
|
||||
if (!rule.state) rule.state={};
|
||||
rule.guessed=true;
|
||||
|
||||
alertify.alert(
|
||||
'You have won using inductive logic! <p> <p> Play again?',
|
||||
function(event){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
},function(){}
|
||||
);
|
||||
} else {
|
||||
lab.state.score -= 200;
|
||||
rule.guessed=false;
|
||||
lab.state.rulesFailed.push({
|
||||
key: rule.key,
|
||||
options: rule.options,
|
||||
description: rule.describe(),
|
||||
});
|
||||
}
|
||||
console.log('guess', arguments);
|
||||
|
||||
|
||||
// vm.winDialouge = function () {
|
||||
// if (!vm._winDialouge) {
|
||||
// vm._winDialouge = Helpers.loadFile('html/win.html');
|
||||
// }
|
||||
// UI.showModal('Win', vm._winDialouge);
|
||||
// };
|
||||
};
|
||||
};
|
||||
RulesController.$inject = ['$scope', 'game', 'lab','$analytics','alertify'];
|
||||
app.controller('RulesController', RulesController);
|
||||
|
||||
function AchievementsController($scope, game, lab) {
|
||||
var vm = this;
|
||||
vm.achievements = game.achievements;
|
||||
vm.progress = function () {
|
||||
return game.achievements.filter(function (a) {
|
||||
return a.validate(lab, game.allObjects, game.lastSaved);
|
||||
}).length;
|
||||
};
|
||||
};
|
||||
AchievementsController.$inject = ['$scope', 'game', 'lab'];
|
||||
app.controller('AchievementsController', AchievementsController);
|
||||
|
||||
function SaveController($scope, $interval, $window, alertify, game, lab) {
|
||||
var vm = this;
|
||||
game.lastSaved = new Date().getTime();
|
||||
vm.lastSaved = game.lastSaved;
|
||||
;
|
||||
|
||||
vm.saveNow = function () {
|
||||
var saveTime = new Date().getTime();
|
||||
lab.state.time += saveTime - game.lastSaved;
|
||||
game.save();
|
||||
game.lastSaved = saveTime;
|
||||
vm.lastSaved = game.lastSaved;
|
||||
|
||||
// if (lab.state.score<0){
|
||||
// alertify.alert(
|
||||
// 'Your score is below zero, so you lost :( Want to try a different rule?',
|
||||
// function(event){
|
||||
// event.preventDefault();
|
||||
// // ObjectStorage.clear();
|
||||
// // $window.location.reload(true); /// reloads are better for ads?
|
||||
// game.reset();
|
||||
// // since this confirmation was away from the dom we need to
|
||||
// // manually refresh
|
||||
// $scope.$apply();
|
||||
// },function(){}
|
||||
// );
|
||||
// }
|
||||
|
||||
};
|
||||
vm.restart = function () {
|
||||
console.log('restart');
|
||||
alertify.confirm(
|
||||
'Do you really want to restart the game? All progress will be lost.',
|
||||
function(event){
|
||||
alertify.alert('Restarting. <p> The rule was: <p>"'+game.rule.describe(),function(){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
});
|
||||
},function(){}
|
||||
);
|
||||
};
|
||||
$interval(vm.saveNow, 10000);
|
||||
};
|
||||
SaveController.$inject = ['$scope', '$interval', '$window', 'alertify', 'game', 'lab'];
|
||||
app.controller('SaveController', SaveController);
|
||||
|
||||
function StatsController($scope, lab,game,alertify) {
|
||||
var vm = this;
|
||||
vm.lab = lab;
|
||||
vm.lost=false;
|
||||
|
||||
|
||||
$scope.$watch('lc.lab.state.score', function (newValue, oldValue) {
|
||||
if (newValue<0&&!vm.lost){
|
||||
vm.lost=true;
|
||||
alertify.alert(
|
||||
'<p>You lost :( Play again? <p><p> The rule was: <p>"'+game.rule.describe()+'"',
|
||||
function(event){
|
||||
event.preventDefault();
|
||||
// ObjectStorage.clear();
|
||||
// $window.location.reload(true); /// reloads are better for ads?
|
||||
game.reset();
|
||||
// since this confirmation was away from the dom we need to
|
||||
// manually refresh
|
||||
$scope.$apply();
|
||||
vm.lost=false;
|
||||
|
||||
},function(){}
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
};
|
||||
StatsController.$inject = ['$scope', 'lab','game','alertify'];
|
||||
app.controller('StatsController', StatsController);
|
||||
|
||||
analytics.init();
|
||||
analytics.sendScreen(analytics.screens.main);
|
||||
})(Helpers,analytics,Game,Rules);
|
||||
|
||||
export default app;
|
||||
|
||||
+269
-267
@@ -1,267 +1,269 @@
|
||||
/**
|
||||
* Game object load/saves game resources and stores game objects
|
||||
*/
|
||||
var ObjectStorage = require("js/storage.js");
|
||||
var Helpers = require("js/helpers.js");
|
||||
var GameObjects = require("js/gameobjects.js");
|
||||
var Rules = require("js/rules.js");
|
||||
var cards = require("json/cards.json");
|
||||
var achievements = require("json/achievements.json");
|
||||
var ruleSimulations = require("json/simulations.json");
|
||||
|
||||
var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules,cards,achievements) {
|
||||
'use strict';
|
||||
|
||||
var Game = function () {
|
||||
this.lab = null;
|
||||
this.cards = null;
|
||||
this.workers = null;
|
||||
this.upgrades = null;
|
||||
this.achievements = null;
|
||||
this.allObjects = {
|
||||
// lab: this.lab
|
||||
};
|
||||
this.loaded = false;
|
||||
|
||||
this.hypotheses = [];
|
||||
this.lastCards= [];
|
||||
this.hints=[];
|
||||
this.ruleInfo=[];
|
||||
this.incorrectCards= [];
|
||||
this.rule=undefined;
|
||||
this.rules=Rules.rules;
|
||||
this.Rule=Rules.Rule;
|
||||
};
|
||||
|
||||
Game.prototype.load = function ($http, $q) {
|
||||
var self = this;
|
||||
if (this.loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cards = cards; //Helpers.loadFile('json/cards.json');
|
||||
this.achievements = require("json/achievements.json"); //Helpers.loadFile('./json/achievements.json');
|
||||
|
||||
// Turn JSON files into actual game objects and fill map of all objects
|
||||
var makeGameObject = function (type, object) {
|
||||
// It's okay to define this function here since load is only called
|
||||
// once anyway...
|
||||
var o = new type(object);
|
||||
self.allObjects[o.key] = o;
|
||||
return o;
|
||||
};
|
||||
self.cards = self.cards.map(
|
||||
function (r) {
|
||||
return makeGameObject(GameObjects.Card, r);
|
||||
});
|
||||
self.achievements = self.achievements.map(
|
||||
function (a) {
|
||||
return makeGameObject(GameObjects.Achievement, a);
|
||||
});
|
||||
|
||||
|
||||
// put cards in extended array with utility methods
|
||||
self.Card = new GameObjects.Cards();
|
||||
self.Card.push.apply(self.Card, self.cards);
|
||||
self.cards = self.Card;
|
||||
|
||||
// add rules to load and save states
|
||||
self.rules.map(function(o){
|
||||
self.allObjects[o.key] = o;
|
||||
});
|
||||
|
||||
// TODO save and load lastCards and incorrectCards
|
||||
|
||||
// Load states from local store
|
||||
for (var key in self.allObjects) {
|
||||
var o = self.allObjects[key];
|
||||
o.loadState(ObjectStorage.load(key));
|
||||
}
|
||||
|
||||
self.loaded = true;
|
||||
return self;
|
||||
};
|
||||
|
||||
Game.prototype.reset = function () {
|
||||
// setup game
|
||||
this.rule = this.newRule();
|
||||
|
||||
this.dealHand();
|
||||
|
||||
// deal new initial cards that follow the rule
|
||||
this.lastCards.splice(0,this.lastCards.length);
|
||||
this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
var error,i;
|
||||
for (i = 0; i < 52; i++) {
|
||||
if (this.lastCards.length>2) break; // stop here
|
||||
var card = angular.copy(_.sample(this.cards));
|
||||
var res;
|
||||
try{
|
||||
res = this.rule.test(card,this.lastCards,this.cards);
|
||||
} catch(e){
|
||||
error=e;
|
||||
// in case of an error just add a random card
|
||||
// this is probobly because it is looking back 2 or 3 cards
|
||||
// yet we only have 1
|
||||
this.lastCards.push(card);
|
||||
}
|
||||
if (res) this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
}
|
||||
if (this.lastCards.length<3) {
|
||||
console.warn(
|
||||
'Could not deal cards for rule after:',
|
||||
i,
|
||||
this.rule.key,
|
||||
this.rule.options,
|
||||
this.rule.describe(),
|
||||
_.map(this.lastCards,'key'),
|
||||
error?error.message:''
|
||||
);
|
||||
// feck, just deal 3 random then
|
||||
this.lastCards.splice(0,this.lastCards.length);
|
||||
this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
|
||||
}
|
||||
// this.lastCards.push.apply(this.lastCards,_.sampleSize(this.cards,3));
|
||||
|
||||
this.ruleInfo.splice(0,this.ruleInfo.length);
|
||||
this.hints.splice(0,this.hints.length);
|
||||
|
||||
// empty incorrect cards
|
||||
this.incorrectCards.splice(0,this.incorrectCards.length);
|
||||
this.incorrectCards.push([]);
|
||||
this.incorrectCards.push([]);
|
||||
this.incorrectCards.push([]);
|
||||
|
||||
// reset score
|
||||
this.lab.state.score = 200;
|
||||
|
||||
// new set of hypothes
|
||||
this.hypotheses=this.genHypotheses();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Game.prototype.genHypotheses = function () {
|
||||
// get some hypotheses
|
||||
var hypo=[];
|
||||
|
||||
// a random 2, 2 variations of each
|
||||
for (var i = 0; i < 1; i++) {
|
||||
var rule = _.sample(this.rules);
|
||||
rule = angular.copy(rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
rule = angular.copy(rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
}
|
||||
|
||||
// add the real rule
|
||||
var rule = angular.copy(this.rule);
|
||||
hypo.push(rule);
|
||||
|
||||
// and a variation of the real rule
|
||||
var rule = angular.copy(this.rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
|
||||
// clean and remember
|
||||
hypo = _.uniq(hypo);
|
||||
hypo = _.shuffle(hypo);
|
||||
|
||||
// empty old ones
|
||||
this.hypotheses.splice(0,this.hypotheses.length);
|
||||
// put in new ones
|
||||
for (var i = 0; i < hypo.length; i++) {
|
||||
this.hypotheses.push(hypo[i]);
|
||||
}
|
||||
return this.hypotheses;
|
||||
};
|
||||
|
||||
Game.prototype.newRule = function () {
|
||||
// FIXME
|
||||
var okRules = _.filter(ruleSimulations,function(s){
|
||||
return s.ratioRight>0.1&&s.ratioRight<0.6;
|
||||
});
|
||||
// var okRules = this.rules;
|
||||
// _.map(this.rules,function(r){return r.randomize();});
|
||||
// choose and ok rule
|
||||
var ruleConfig = _.sample(okRules);
|
||||
// now find the rule and set these options
|
||||
var rule = _.find(this.rules,{key:ruleConfig.key});
|
||||
var options = ruleConfig.options;
|
||||
if (typeof options==="string") options = JSON.parse(options);
|
||||
rule.setOptions(options);
|
||||
return this.rule = rule;
|
||||
};
|
||||
|
||||
Game.prototype.dealHand = function (n) {
|
||||
n=n||12;
|
||||
|
||||
var sample=_.sampleSize(this.cards,n);
|
||||
|
||||
// empty all cards
|
||||
this.cards.map(function(card){
|
||||
card.state.amount=0;
|
||||
});
|
||||
// now increase the value of our sample
|
||||
for (var i = 0; i < sample.length; i++) {
|
||||
var card = sample[i];
|
||||
this.cards.get(card.key).state.amount++;
|
||||
}
|
||||
};
|
||||
Game.prototype.onClick = function (event, ui) {
|
||||
var self=this;
|
||||
console.debug('onClick',arguments);
|
||||
|
||||
var cardType = angular.element(ui.draggable).data('cards');
|
||||
var card = _.find(this.cards,{key:cardType});
|
||||
return this.play(card);
|
||||
};
|
||||
Game.prototype.onDrop = function (event, ui) {
|
||||
var self=this;
|
||||
console.debug('onDrop',arguments);
|
||||
|
||||
var cardType = angular.element(ui.draggable).data('cards');
|
||||
var card = _.find(this.cards,{key:cardType});
|
||||
return this.play(card);
|
||||
};
|
||||
Game.prototype.play = function (card) {
|
||||
var self=this;
|
||||
card.state.amount-=1;
|
||||
|
||||
var turn = this.lastCards.length-1;
|
||||
var correct = this.test(card);
|
||||
if (correct){
|
||||
if(!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
|
||||
this.lastCards.push(angular.copy(card));
|
||||
if(!this.incorrectCards[turn+1]) this.incorrectCards[turn+1]=[];
|
||||
this.lab.state.score+=1;
|
||||
} else {
|
||||
// add incorrect one to sidelines
|
||||
if (!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
|
||||
this.incorrectCards[turn].push(angular.copy(card));
|
||||
|
||||
// deal 2 random cards
|
||||
_.sample(this.cards).state.amount+=1;
|
||||
_.sample(this.cards).state.amount+=1;
|
||||
this.lab.state.score-=2;
|
||||
}
|
||||
return correct;
|
||||
};
|
||||
/** Test the rule **/
|
||||
Game.prototype.test = function (card) {
|
||||
return this.rule.test(card,this.lastCards,this.cards);
|
||||
};
|
||||
Game.prototype.save = function () {
|
||||
// Save every object's state to local storage
|
||||
for (var key in this.allObjects) {
|
||||
ObjectStorage.save(key, this.allObjects[key].state);
|
||||
}
|
||||
};
|
||||
|
||||
return Game;
|
||||
}(Helpers, GameObjects, ObjectStorage,Rules,cards,achievements));
|
||||
/**
|
||||
* Game object load/saves game resources and stores game objects
|
||||
*/
|
||||
import ObjectStorage from 'js/storage.js';
|
||||
import * as Helpers from './helpers'
|
||||
import GameObjects from './gameobjects';
|
||||
import * as Rules from './rules.js';
|
||||
import cards from 'json/cards.json';
|
||||
import achievements from 'json/achievements.json';
|
||||
import ruleSimulations from 'json/simulations.json';
|
||||
|
||||
var Game = (function (Helpers, GameObjects, ObjectStorage,Rules,cards,achievements) {
|
||||
'use strict';
|
||||
|
||||
var Game = function () {
|
||||
this.lab = null;
|
||||
this.cards = null;
|
||||
this.workers = null;
|
||||
this.upgrades = null;
|
||||
this.achievements = null;
|
||||
this.allObjects = {
|
||||
// lab: this.lab
|
||||
};
|
||||
this.loaded = false;
|
||||
|
||||
this.hypotheses = [];
|
||||
this.lastCards= [];
|
||||
this.hints=[];
|
||||
this.ruleInfo=[];
|
||||
this.incorrectCards= [];
|
||||
this.rule=undefined;
|
||||
this.rules=Rules.rules;
|
||||
this.Rule=Rules.Rule;
|
||||
};
|
||||
|
||||
Game.prototype.load = function ($http, $q) {
|
||||
var self = this;
|
||||
if (this.loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cards = cards; //Helpers.loadFile('json/cards.json');
|
||||
this.achievements = require("json/achievements.json"); //Helpers.loadFile('./json/achievements.json');
|
||||
|
||||
// Turn JSON files into actual game objects and fill map of all objects
|
||||
var makeGameObject = function (type, object) {
|
||||
// It's okay to define this function here since load is only called
|
||||
// once anyway...
|
||||
var o = new type(object);
|
||||
self.allObjects[o.key] = o;
|
||||
return o;
|
||||
};
|
||||
self.cards = self.cards.map(
|
||||
function (r) {
|
||||
return makeGameObject(GameObjects.Card, r);
|
||||
});
|
||||
self.achievements = self.achievements.map(
|
||||
function (a) {
|
||||
return makeGameObject(GameObjects.Achievement, a);
|
||||
});
|
||||
|
||||
|
||||
// put cards in extended array with utility methods
|
||||
self.Card = new GameObjects.Cards();
|
||||
self.Card.push.apply(self.Card, self.cards);
|
||||
self.cards = self.Card;
|
||||
|
||||
// add rules to load and save states
|
||||
self.rules.map(function(o){
|
||||
self.allObjects[o.key] = o;
|
||||
});
|
||||
|
||||
// TODO save and load lastCards and incorrectCards
|
||||
|
||||
// Load states from local store
|
||||
for (var key in self.allObjects) {
|
||||
var o = self.allObjects[key];
|
||||
o.loadState(ObjectStorage.load(key));
|
||||
}
|
||||
|
||||
self.loaded = true;
|
||||
return self;
|
||||
};
|
||||
|
||||
Game.prototype.reset = function () {
|
||||
// setup game
|
||||
this.rule = this.newRule();
|
||||
|
||||
this.dealHand();
|
||||
|
||||
// deal new initial cards that follow the rule
|
||||
this.lastCards.splice(0,this.lastCards.length);
|
||||
this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
var error,i;
|
||||
for (i = 0; i < 52; i++) {
|
||||
if (this.lastCards.length>2) break; // stop here
|
||||
var card = angular.copy(_.sample(this.cards));
|
||||
var res;
|
||||
try{
|
||||
res = this.rule.test(card,this.lastCards,this.cards);
|
||||
} catch(e){
|
||||
error=e;
|
||||
// in case of an error just add a random card
|
||||
// this is probobly because it is looking back 2 or 3 cards
|
||||
// yet we only have 1
|
||||
this.lastCards.push(card);
|
||||
}
|
||||
if (res) this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
}
|
||||
if (this.lastCards.length<3) {
|
||||
console.warn(
|
||||
'Could not deal cards for rule after:',
|
||||
i,
|
||||
this.rule.key,
|
||||
this.rule.options,
|
||||
this.rule.describe(),
|
||||
_.map(this.lastCards,'key'),
|
||||
error?error.message:''
|
||||
);
|
||||
// feck, just deal 3 random then
|
||||
this.lastCards.splice(0,this.lastCards.length);
|
||||
this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
this.lastCards.push(angular.copy(_.sample(this.cards)));
|
||||
|
||||
}
|
||||
// this.lastCards.push.apply(this.lastCards,_.sampleSize(this.cards,3));
|
||||
|
||||
this.ruleInfo.splice(0,this.ruleInfo.length);
|
||||
this.hints.splice(0,this.hints.length);
|
||||
|
||||
// empty incorrect cards
|
||||
this.incorrectCards.splice(0,this.incorrectCards.length);
|
||||
this.incorrectCards.push([]);
|
||||
this.incorrectCards.push([]);
|
||||
this.incorrectCards.push([]);
|
||||
|
||||
// reset score
|
||||
this.lab.state.score = 200;
|
||||
|
||||
// new set of hypothes
|
||||
this.hypotheses=this.genHypotheses();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Game.prototype.genHypotheses = function () {
|
||||
// get some hypotheses
|
||||
var hypo=[];
|
||||
|
||||
// a random 2, 2 variations of each
|
||||
for (var i = 0; i < 1; i++) {
|
||||
var rule = _.sample(this.rules);
|
||||
rule = angular.copy(rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
rule = angular.copy(rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
}
|
||||
|
||||
// add the real rule
|
||||
var rule = angular.copy(this.rule);
|
||||
hypo.push(rule);
|
||||
|
||||
// and a variation of the real rule
|
||||
var rule = angular.copy(this.rule);
|
||||
rule.randomize();
|
||||
hypo.push(rule);
|
||||
|
||||
// clean and remember
|
||||
hypo = _.uniq(hypo);
|
||||
hypo = _.shuffle(hypo);
|
||||
|
||||
// empty old ones
|
||||
this.hypotheses.splice(0,this.hypotheses.length);
|
||||
// put in new ones
|
||||
for (var i = 0; i < hypo.length; i++) {
|
||||
this.hypotheses.push(hypo[i]);
|
||||
}
|
||||
return this.hypotheses;
|
||||
};
|
||||
|
||||
Game.prototype.newRule = function () {
|
||||
// FIXME
|
||||
var okRules = _.filter(ruleSimulations,function(s){
|
||||
return s.ratioRight>0.1&&s.ratioRight<0.6;
|
||||
});
|
||||
// var okRules = this.rules;
|
||||
// _.map(this.rules,function(r){return r.randomize();});
|
||||
// choose and ok rule
|
||||
var ruleConfig = _.sample(okRules);
|
||||
// now find the rule and set these options
|
||||
var rule = _.find(this.rules,{key:ruleConfig.key});
|
||||
var options = ruleConfig.options;
|
||||
if (typeof options==="string") options = JSON.parse(options);
|
||||
rule.setOptions(options);
|
||||
return this.rule = rule;
|
||||
};
|
||||
|
||||
Game.prototype.dealHand = function (n) {
|
||||
n=n||12;
|
||||
|
||||
var sample=_.sampleSize(this.cards,n);
|
||||
|
||||
// empty all cards
|
||||
this.cards.map(function(card){
|
||||
card.state.amount=0;
|
||||
});
|
||||
// now increase the value of our sample
|
||||
for (var i = 0; i < sample.length; i++) {
|
||||
var card = sample[i];
|
||||
this.cards.get(card.key).state.amount++;
|
||||
}
|
||||
};
|
||||
Game.prototype.onClick = function (event, ui) {
|
||||
var self=this;
|
||||
console.debug('onClick',arguments);
|
||||
|
||||
var cardType = angular.element(ui.draggable).data('cards');
|
||||
var card = _.find(this.cards,{key:cardType});
|
||||
return this.play(card);
|
||||
};
|
||||
Game.prototype.onDrop = function (event, ui) {
|
||||
var self=this;
|
||||
console.debug('onDrop',arguments);
|
||||
|
||||
var cardType = angular.element(ui.draggable).data('cards');
|
||||
var card = _.find(this.cards,{key:cardType});
|
||||
return this.play(card);
|
||||
};
|
||||
Game.prototype.play = function (card) {
|
||||
var self=this;
|
||||
card.state.amount-=1;
|
||||
|
||||
var turn = this.lastCards.length-1;
|
||||
var correct = this.test(card);
|
||||
if (correct){
|
||||
if(!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
|
||||
this.lastCards.push(angular.copy(card));
|
||||
if(!this.incorrectCards[turn+1]) this.incorrectCards[turn+1]=[];
|
||||
this.lab.state.score+=1;
|
||||
} else {
|
||||
// add incorrect one to sidelines
|
||||
if (!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
|
||||
this.incorrectCards[turn].push(angular.copy(card));
|
||||
|
||||
// deal 2 random cards
|
||||
_.sample(this.cards).state.amount+=1;
|
||||
_.sample(this.cards).state.amount+=1;
|
||||
this.lab.state.score-=2;
|
||||
}
|
||||
return correct;
|
||||
};
|
||||
/** Test the rule **/
|
||||
Game.prototype.test = function (card) {
|
||||
return this.rule.test(card,this.lastCards,this.cards);
|
||||
};
|
||||
Game.prototype.save = function () {
|
||||
// Save every object's state to local storage
|
||||
for (var key in this.allObjects) {
|
||||
ObjectStorage.save(key, this.allObjects[key].state);
|
||||
}
|
||||
};
|
||||
|
||||
return Game;
|
||||
}(Helpers, GameObjects, ObjectStorage,Rules,cards,achievements));
|
||||
|
||||
export default Game
|
||||
|
||||
+299
-297
@@ -1,297 +1,299 @@
|
||||
/**
|
||||
* Game objects such as workers, research, upgrades, and achievements.
|
||||
*/
|
||||
|
||||
var GameObjects = module.exports = (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);
|
||||
};
|
||||
GameObject.prototype.guid = function () {
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||
s4() + '-' + s4() + s4() + s4();
|
||||
};
|
||||
|
||||
/** @class Lab
|
||||
*/
|
||||
var Lab = function () {
|
||||
GameObject.apply(this, [{
|
||||
key: 'lab',
|
||||
state: {
|
||||
name: 'Write your name here',
|
||||
detector: 1,
|
||||
factor: 5,
|
||||
data: 0,
|
||||
money: 0,
|
||||
reputation: 0,
|
||||
clicks: 0,
|
||||
moneyCollected: 0,
|
||||
moneySpent: 0,
|
||||
dataCollected: 0,
|
||||
dataSpent: 0,
|
||||
time: 0,
|
||||
observations: [],
|
||||
score: 0,
|
||||
highScore: 0,
|
||||
hints: 0,
|
||||
rulesGuessed: [],
|
||||
rulesFailed: [],
|
||||
}
|
||||
}]);
|
||||
|
||||
};
|
||||
|
||||
Lab.prototype = Object.create(GameObject.prototype);
|
||||
|
||||
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.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.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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes in a rule/observation object and records observation in journal
|
||||
* with reactants, inputs, catalysts, conditions, results
|
||||
**/
|
||||
Lab.prototype.observe = function (observation) {
|
||||
// join the arrays into strings for display
|
||||
var obsText = {};
|
||||
for (var k in observation) {
|
||||
if (observation.hasOwnProperty(k)) {
|
||||
obsText[k] = observation[k].sort().join('');
|
||||
}
|
||||
}
|
||||
obsText.amount=1;
|
||||
// check if an obs with all the attributes matching (extra attribs are ok)
|
||||
var index = _.findIndex(this.state.observations,obsText);
|
||||
if (index>-1)
|
||||
this.state.observations[index].amount+=1;
|
||||
else
|
||||
this.state.observations.push(obsText);
|
||||
};
|
||||
|
||||
|
||||
Lab.prototype.buy = function (cost) {
|
||||
if (this.state.money >= cost) {
|
||||
this.state.money -= cost;
|
||||
this.state.moneySpent += cost;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var Cards = function (obj) {
|
||||
this.push.apply(this, obj);
|
||||
};
|
||||
|
||||
Cards.prototype = Object.create(Array.prototype);
|
||||
|
||||
Cards.prototype.constructor = Array.constructor;
|
||||
|
||||
Cards.prototype.pushAll = function (items) {
|
||||
this.push.apply(this, items);
|
||||
};
|
||||
|
||||
/** Add a random element or specify it's key **/
|
||||
Cards.prototype.addToStore = function (element) {
|
||||
if (element) this.get(element);
|
||||
if (!element) element = this.select();
|
||||
return element.state.amount += 1;
|
||||
};
|
||||
|
||||
/** Add a random discovered element or specify it's key **/
|
||||
Cards.prototype.addKnownToStore = function (element) {
|
||||
var discovered = this.filter(function (e) {
|
||||
return e.state.discovered;
|
||||
});
|
||||
discovered = new GameObjects.Cards(discovered);
|
||||
if (element) discovered.get(element);
|
||||
if (!element) element = discovered.select();
|
||||
return element.state.amount += 1;
|
||||
};
|
||||
|
||||
/** Select random element from store **/
|
||||
Cards.prototype.select = function () {
|
||||
var i = Math.round((this.length - 1) * Math.random());
|
||||
return this[i];
|
||||
};
|
||||
/** Get element by key **/
|
||||
Cards.prototype.get = function (key) {
|
||||
return this.filter(function (e) {
|
||||
return e.key === key;
|
||||
})[0];
|
||||
};
|
||||
|
||||
/** Get element by hashid **/
|
||||
Cards.prototype.getByHashKey = function (hashKey) {
|
||||
if (hashKey === undefined) {
|
||||
console.warn('GetByHashKey given an undefined hashkey', hashKey)
|
||||
return;
|
||||
}
|
||||
var res = this.filter(function (e) {
|
||||
return e.$$hashKey === hashKey;
|
||||
});
|
||||
if (res.length == 1) return res[0];
|
||||
else if (res.length) {
|
||||
console.warn('Got multiple results when filtering on hashKey', hashKey);
|
||||
return res[0];
|
||||
} else {
|
||||
console.warn('Got no results when filtering on hashKey', hashKey);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/** @class Card
|
||||
*/
|
||||
var Card = function (obj) {
|
||||
// load from localStorage by obj.key
|
||||
GameObject.apply(this, [obj]);
|
||||
|
||||
// apply defaults to undefined values
|
||||
this.state = _.defaults(this.state,{
|
||||
amount: 0,
|
||||
discovered: false,
|
||||
interesting: false,
|
||||
});
|
||||
|
||||
// generate uuid
|
||||
this.uuid = this.uuid || this.guid();
|
||||
};
|
||||
|
||||
Card.prototype = Object.create(GameObject.prototype);
|
||||
|
||||
Card.prototype.constructor = Card;
|
||||
|
||||
Card.prototype.isVisible = function (lab) {
|
||||
if (!lab) {
|
||||
return false;
|
||||
}
|
||||
return this.state.discovered;
|
||||
};
|
||||
|
||||
Card.prototype.isAvailable = function (lab) {
|
||||
if (!lab) {
|
||||
return false;
|
||||
}
|
||||
return this.state.amount > 0;
|
||||
};
|
||||
|
||||
Card.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;
|
||||
};
|
||||
|
||||
Card.prototype.getInfo = function () {
|
||||
if (!this._info) {
|
||||
this._info = Helpers.loadFile(this.info);
|
||||
}
|
||||
this.state.interesting = false;
|
||||
return this._info;
|
||||
};
|
||||
|
||||
/** Create a new element for the test tube from this Card **/
|
||||
Card.prototype.spawn = function () {
|
||||
var element = angular.copy(this);
|
||||
element.uuid = element.guid();
|
||||
element.state = undefined;
|
||||
// this.state.amount -= 1;
|
||||
return element;
|
||||
};
|
||||
|
||||
Card.prototype.decreaseStore = function () {
|
||||
return this.state.amount -= 1;
|
||||
};
|
||||
|
||||
|
||||
/** @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,
|
||||
Card: Card,
|
||||
Achievement: Achievement,
|
||||
Cards: Cards
|
||||
};
|
||||
}());
|
||||
/**
|
||||
* Game objects such as workers, research, upgrades, and achievements.
|
||||
*/
|
||||
|
||||
|
||||
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);
|
||||
};
|
||||
GameObject.prototype.guid = function () {
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||
s4() + '-' + s4() + s4() + s4();
|
||||
};
|
||||
|
||||
/** @class Lab
|
||||
*/
|
||||
var Lab = function () {
|
||||
GameObject.apply(this, [{
|
||||
key: 'lab',
|
||||
state: {
|
||||
name: 'Write your name here',
|
||||
detector: 1,
|
||||
factor: 5,
|
||||
data: 0,
|
||||
money: 0,
|
||||
reputation: 0,
|
||||
clicks: 0,
|
||||
moneyCollected: 0,
|
||||
moneySpent: 0,
|
||||
dataCollected: 0,
|
||||
dataSpent: 0,
|
||||
time: 0,
|
||||
observations: [],
|
||||
score: 0,
|
||||
highScore: 0,
|
||||
hints: 0,
|
||||
rulesGuessed: [],
|
||||
rulesFailed: [],
|
||||
}
|
||||
}]);
|
||||
|
||||
};
|
||||
|
||||
Lab.prototype = Object.create(GameObject.prototype);
|
||||
|
||||
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.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.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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes in a rule/observation object and records observation in journal
|
||||
* with reactants, inputs, catalysts, conditions, results
|
||||
**/
|
||||
Lab.prototype.observe = function (observation) {
|
||||
// join the arrays into strings for display
|
||||
var obsText = {};
|
||||
for (var k in observation) {
|
||||
if (observation.hasOwnProperty(k)) {
|
||||
obsText[k] = observation[k].sort().join('');
|
||||
}
|
||||
}
|
||||
obsText.amount=1;
|
||||
// check if an obs with all the attributes matching (extra attribs are ok)
|
||||
var index = _.findIndex(this.state.observations,obsText);
|
||||
if (index>-1)
|
||||
this.state.observations[index].amount+=1;
|
||||
else
|
||||
this.state.observations.push(obsText);
|
||||
};
|
||||
|
||||
|
||||
Lab.prototype.buy = function (cost) {
|
||||
if (this.state.money >= cost) {
|
||||
this.state.money -= cost;
|
||||
this.state.moneySpent += cost;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var Cards = function (obj) {
|
||||
this.push.apply(this, obj);
|
||||
};
|
||||
|
||||
Cards.prototype = Object.create(Array.prototype);
|
||||
|
||||
Cards.prototype.constructor = Array.constructor;
|
||||
|
||||
Cards.prototype.pushAll = function (items) {
|
||||
this.push.apply(this, items);
|
||||
};
|
||||
|
||||
/** Add a random element or specify it's key **/
|
||||
Cards.prototype.addToStore = function (element) {
|
||||
if (element) this.get(element);
|
||||
if (!element) element = this.select();
|
||||
return element.state.amount += 1;
|
||||
};
|
||||
|
||||
/** Add a random discovered element or specify it's key **/
|
||||
Cards.prototype.addKnownToStore = function (element) {
|
||||
var discovered = this.filter(function (e) {
|
||||
return e.state.discovered;
|
||||
});
|
||||
discovered = new GameObjects.Cards(discovered);
|
||||
if (element) discovered.get(element);
|
||||
if (!element) element = discovered.select();
|
||||
return element.state.amount += 1;
|
||||
};
|
||||
|
||||
/** Select random element from store **/
|
||||
Cards.prototype.select = function () {
|
||||
var i = Math.round((this.length - 1) * Math.random());
|
||||
return this[i];
|
||||
};
|
||||
/** Get element by key **/
|
||||
Cards.prototype.get = function (key) {
|
||||
return this.filter(function (e) {
|
||||
return e.key === key;
|
||||
})[0];
|
||||
};
|
||||
|
||||
/** Get element by hashid **/
|
||||
Cards.prototype.getByHashKey = function (hashKey) {
|
||||
if (hashKey === undefined) {
|
||||
console.warn('GetByHashKey given an undefined hashkey', hashKey)
|
||||
return;
|
||||
}
|
||||
var res = this.filter(function (e) {
|
||||
return e.$$hashKey === hashKey;
|
||||
});
|
||||
if (res.length == 1) return res[0];
|
||||
else if (res.length) {
|
||||
console.warn('Got multiple results when filtering on hashKey', hashKey);
|
||||
return res[0];
|
||||
} else {
|
||||
console.warn('Got no results when filtering on hashKey', hashKey);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/** @class Card
|
||||
*/
|
||||
var Card = function (obj) {
|
||||
// load from localStorage by obj.key
|
||||
GameObject.apply(this, [obj]);
|
||||
|
||||
// apply defaults to undefined values
|
||||
this.state = _.defaults(this.state,{
|
||||
amount: 0,
|
||||
discovered: false,
|
||||
interesting: false,
|
||||
});
|
||||
|
||||
// generate uuid
|
||||
this.uuid = this.uuid || this.guid();
|
||||
};
|
||||
|
||||
Card.prototype = Object.create(GameObject.prototype);
|
||||
|
||||
Card.prototype.constructor = Card;
|
||||
|
||||
Card.prototype.isVisible = function (lab) {
|
||||
if (!lab) {
|
||||
return false;
|
||||
}
|
||||
return this.state.discovered;
|
||||
};
|
||||
|
||||
Card.prototype.isAvailable = function (lab) {
|
||||
if (!lab) {
|
||||
return false;
|
||||
}
|
||||
return this.state.amount > 0;
|
||||
};
|
||||
|
||||
Card.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;
|
||||
};
|
||||
|
||||
Card.prototype.getInfo = function () {
|
||||
if (!this._info) {
|
||||
this._info = Helpers.loadFile(this.info);
|
||||
}
|
||||
this.state.interesting = false;
|
||||
return this._info;
|
||||
};
|
||||
|
||||
/** Create a new element for the test tube from this Card **/
|
||||
Card.prototype.spawn = function () {
|
||||
var element = angular.copy(this);
|
||||
element.uuid = element.guid();
|
||||
element.state = undefined;
|
||||
// this.state.amount -= 1;
|
||||
return element;
|
||||
};
|
||||
|
||||
Card.prototype.decreaseStore = function () {
|
||||
return this.state.amount -= 1;
|
||||
};
|
||||
|
||||
|
||||
/** @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,
|
||||
Card: Card,
|
||||
Achievement: Achievement,
|
||||
Cards: Cards
|
||||
};
|
||||
}());
|
||||
export default GameObjects
|
||||
|
||||
+106
-106
@@ -1,106 +1,106 @@
|
||||
/** @module Helpers
|
||||
* Define some useful helpers that are used throughout the game.
|
||||
*/
|
||||
var ObjectStorage = require("js/storage");
|
||||
var jquery = require("jquery");
|
||||
var Helpers = (function ($,ObjectStorage) {
|
||||
'use strict';
|
||||
/** Load a file (usually JSON).
|
||||
*/
|
||||
var loadFile = function (filename) {
|
||||
var res;
|
||||
$.ajax({
|
||||
async: false,
|
||||
url: filename,
|
||||
success: function (data) {
|
||||
res = data;
|
||||
}
|
||||
});
|
||||
return res;
|
||||
};
|
||||
|
||||
/** Format a number with proper postfix.
|
||||
*/
|
||||
var formatNumberPostfix = function (number) {
|
||||
if (typeof number !== "number") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var prefixes = [{
|
||||
magnitude: 1e24,
|
||||
label: 'Y'
|
||||
}, {
|
||||
magnitude: 1e21,
|
||||
label: 'Z'
|
||||
}, {
|
||||
magnitude: 1e18,
|
||||
label: 'E'
|
||||
}, {
|
||||
magnitude: 1e15,
|
||||
label: 'P'
|
||||
}, {
|
||||
magnitude: 1e12,
|
||||
label: 'T'
|
||||
}, {
|
||||
magnitude: 1e9,
|
||||
label: 'B'
|
||||
}, {
|
||||
magnitude: 1e6,
|
||||
label: 'M'
|
||||
}, {
|
||||
magnitude: 1e3,
|
||||
label: 'k'
|
||||
}];
|
||||
|
||||
var abs = Math.abs(number);
|
||||
for (var i = 0; i < prefixes.length; i++) {
|
||||
if (abs >= prefixes[i].magnitude) {
|
||||
return (number / prefixes[i].magnitude).toFixed(1) + prefixes[i].label;
|
||||
}
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
var formatTime = function (msec) {
|
||||
var totals = Math.ceil(msec / 1000);
|
||||
var days = Math.floor(totals / (24 * 60 * 60));
|
||||
var hours = Math.floor((totals % (24 * 60 * 60)) / (60 * 60));
|
||||
var totalmin = (totals % (24 * 60 * 60)) % (60 * 60);
|
||||
var mins = Math.floor(totalmin / 60);
|
||||
var secs = totalmin % 60;
|
||||
|
||||
var str = [];
|
||||
if (days > 0) {
|
||||
str.push(days + ' day' + (days % 100 == 1 ? '' : 's'));
|
||||
}
|
||||
if (hours > 0) {
|
||||
str.push(hours + ' h');
|
||||
}
|
||||
if (mins > 0) {
|
||||
str.push(mins + ' min');
|
||||
}
|
||||
if (secs > 0) {
|
||||
str.push(secs + ' s');
|
||||
}
|
||||
|
||||
return str.join(', ');
|
||||
};
|
||||
|
||||
var saveVersion = '1.0';
|
||||
var validateSaveVersion = function () {
|
||||
var ver = ObjectStorage.load('saveVersion');
|
||||
if (typeof ver === 'undefined' || ver != saveVersion) {
|
||||
ObjectStorage.clear();
|
||||
ObjectStorage.save('saveVersion', saveVersion);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loadFile: loadFile,
|
||||
formatNumberPostfix: formatNumberPostfix,
|
||||
formatTime: formatTime,
|
||||
validateSaveVersion: validateSaveVersion,
|
||||
analytics: 'UA-51809277-5'
|
||||
};
|
||||
})(jquery, ObjectStorage);
|
||||
module.exports=Helpers;
|
||||
/** @module Helpers
|
||||
* Define some useful helpers that are used throughout the game.
|
||||
*/
|
||||
import ObjectStorage from "js/storage";
|
||||
import jquery from "jquery";
|
||||
var Helpers = (function ($,ObjectStorage) {
|
||||
'use strict';
|
||||
/** Load a file (usually JSON).
|
||||
*/
|
||||
var loadFile = function (filename) {
|
||||
var res;
|
||||
$.ajax({
|
||||
async: false,
|
||||
url: filename,
|
||||
success: function (data) {
|
||||
res = data;
|
||||
}
|
||||
});
|
||||
return res;
|
||||
};
|
||||
|
||||
/** Format a number with proper postfix.
|
||||
*/
|
||||
var formatNumberPostfix = function (number) {
|
||||
if (typeof number !== "number") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var prefixes = [{
|
||||
magnitude: 1e24,
|
||||
label: 'Y'
|
||||
}, {
|
||||
magnitude: 1e21,
|
||||
label: 'Z'
|
||||
}, {
|
||||
magnitude: 1e18,
|
||||
label: 'E'
|
||||
}, {
|
||||
magnitude: 1e15,
|
||||
label: 'P'
|
||||
}, {
|
||||
magnitude: 1e12,
|
||||
label: 'T'
|
||||
}, {
|
||||
magnitude: 1e9,
|
||||
label: 'B'
|
||||
}, {
|
||||
magnitude: 1e6,
|
||||
label: 'M'
|
||||
}, {
|
||||
magnitude: 1e3,
|
||||
label: 'k'
|
||||
}];
|
||||
|
||||
var abs = Math.abs(number);
|
||||
for (var i = 0; i < prefixes.length; i++) {
|
||||
if (abs >= prefixes[i].magnitude) {
|
||||
return (number / prefixes[i].magnitude).toFixed(1) + prefixes[i].label;
|
||||
}
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
var formatTime = function (msec) {
|
||||
var totals = Math.ceil(msec / 1000);
|
||||
var days = Math.floor(totals / (24 * 60 * 60));
|
||||
var hours = Math.floor((totals % (24 * 60 * 60)) / (60 * 60));
|
||||
var totalmin = (totals % (24 * 60 * 60)) % (60 * 60);
|
||||
var mins = Math.floor(totalmin / 60);
|
||||
var secs = totalmin % 60;
|
||||
|
||||
var str = [];
|
||||
if (days > 0) {
|
||||
str.push(days + ' day' + (days % 100 == 1 ? '' : 's'));
|
||||
}
|
||||
if (hours > 0) {
|
||||
str.push(hours + ' h');
|
||||
}
|
||||
if (mins > 0) {
|
||||
str.push(mins + ' min');
|
||||
}
|
||||
if (secs > 0) {
|
||||
str.push(secs + ' s');
|
||||
}
|
||||
|
||||
return str.join(', ');
|
||||
};
|
||||
|
||||
var saveVersion = '1.0';
|
||||
var validateSaveVersion = function () {
|
||||
var ver = ObjectStorage.load('saveVersion');
|
||||
if (typeof ver === 'undefined' || ver != saveVersion) {
|
||||
ObjectStorage.clear();
|
||||
ObjectStorage.save('saveVersion', saveVersion);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loadFile: loadFile,
|
||||
formatNumberPostfix: formatNumberPostfix,
|
||||
formatTime: formatTime,
|
||||
validateSaveVersion: validateSaveVersion,
|
||||
analytics: 'UA-51809277-5'
|
||||
};
|
||||
})(jquery, ObjectStorage);
|
||||
export default Helpers;
|
||||
|
||||
+707
-718
File diff suppressed because it is too large
Load Diff
+73
-73
@@ -1,73 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Simulate rules</title>
|
||||
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> -->
|
||||
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> -->
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.11/css/jquery.dataTables.min.css">
|
||||
<link rel="stylesheet" href="../../../clientApp.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Simulate rules</h1>
|
||||
<textarea rows="10" style="width: 1000px; height: 400px" id="summary"></textarea>
|
||||
<textarea rows="3" style="width: 1000px; height: 100px" id="oks"></textarea>
|
||||
<div id="export"></div>
|
||||
<table id="results" class="table">
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.10.11/js/jquery.dataTables.min.js"></script>
|
||||
<!-- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> -->
|
||||
<script src="../../../clientApp.bundle.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
var simulation = new clientApp.Rules.Simulation(clientApp.Rules.rules,clientApp.cards);
|
||||
var results=simulation.run();
|
||||
var summary = simulation.summarize()
|
||||
// var results = [];
|
||||
// for (var i = 0; i < clientApp.Rules.rules.length; i++) {
|
||||
// var rule = clientApp.Rules.rules[i];
|
||||
// var res = rule.simulate(clientApp.cards);
|
||||
// results.push.apply(results,res);
|
||||
// }
|
||||
|
||||
$('#oks').text('ok: '+_.map(results,'ok').reduce(_.add)+'/'+results.length);
|
||||
|
||||
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(results));
|
||||
$('<a class="btn btn-default" href="data:' + data + '" download="data.json">export table as JSON</a>').appendTo('#export');
|
||||
|
||||
|
||||
results=_.map(results,function(r){
|
||||
r.options=JSON.stringify(r.options);
|
||||
return r;
|
||||
})
|
||||
// just get keys we want and in order
|
||||
var keys = [ "n","time", "ratioRight","ok", "right", "wrong", "error", "key", "options", "rule", "description","rights","wrongs","errors", ]
|
||||
|
||||
var table=$('#results');
|
||||
var ts='';
|
||||
ts+='<thead><tr><th>'+keys.join('</th><th>')+'</th></tr></thead><tbody>';
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
// order them into an array
|
||||
var result = _.map(keys,function(key){return results[i][key];});
|
||||
// make table row
|
||||
ts+='<tr><td>'+result.join('</td><td>')+'</td></tr>';
|
||||
}
|
||||
ts+='</tbody>';
|
||||
table.append(ts);
|
||||
$('#results').dataTable();
|
||||
|
||||
var summaryJson = JSON.stringify(summary,null,4);
|
||||
$('#summary').text(summaryJson);
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Simulate rules</title>
|
||||
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> -->
|
||||
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> -->
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.11/css/jquery.dataTables.min.css">
|
||||
<link rel="stylesheet" href="../../../clientApp.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Simulate rules</h1>
|
||||
<textarea rows="10" style="width: 1000px; height: 400px" id="summary"></textarea>
|
||||
<textarea rows="3" style="width: 1000px; height: 100px" id="oks"></textarea>
|
||||
<div id="export"></div>
|
||||
<table id="results" class="table">
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.10.11/js/jquery.dataTables.min.js"></script>
|
||||
<!-- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> -->
|
||||
<script src="../../../clientApp.bundle.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
var simulation = new clientApp.Rules.Simulation(clientApp.Rules.rules,clientApp.cards);
|
||||
var results=simulation.run();
|
||||
var summary = simulation.summarize()
|
||||
// var results = [];
|
||||
// for (var i = 0; i < clientApp.Rules.rules.length; i++) {
|
||||
// var rule = clientApp.Rules.rules[i];
|
||||
// var res = rule.simulate(clientApp.cards);
|
||||
// results.push.apply(results,res);
|
||||
// }
|
||||
|
||||
$('#oks').text('ok: '+_.map(results,'ok').reduce(_.add)+'/'+results.length);
|
||||
|
||||
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(results));
|
||||
$('<a class="btn btn-default" href="data:' + data + '" download="data.json">export table as JSON</a>').appendTo('#export');
|
||||
|
||||
|
||||
results=_.map(results,function(r){
|
||||
r.options=JSON.stringify(r.options);
|
||||
return r;
|
||||
})
|
||||
// just get keys we want and in order
|
||||
var keys = [ "n","time", "ratioRight","ok", "right", "wrong", "error", "key", "options", "rule", "description","rights","wrongs","errors", ]
|
||||
|
||||
var table=$('#results');
|
||||
var ts='';
|
||||
ts+='<thead><tr><th>'+keys.join('</th><th>')+'</th></tr></thead><tbody>';
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
// order them into an array
|
||||
var result = _.map(keys,function(key){return results[i][key];});
|
||||
// make table row
|
||||
ts+='<tr><td>'+result.join('</td><td>')+'</td></tr>';
|
||||
}
|
||||
ts+='</tbody>';
|
||||
table.append(ts);
|
||||
$('#results').dataTable();
|
||||
|
||||
var summaryJson = JSON.stringify(summary,null,4);
|
||||
$('#summary').text(summaryJson);
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</html>
|
||||
|
||||
+32
-30
@@ -1,30 +1,32 @@
|
||||
/** Allows to save objects to HTML5 local storage.
|
||||
* However, it can only save properties, not functions.
|
||||
*/
|
||||
var ObjectStorage = module.exports = (function() {
|
||||
'use strict';
|
||||
try {
|
||||
var _s = localStorage;
|
||||
return {
|
||||
save :
|
||||
function(key, item) {
|
||||
_s.setItem(key, JSON.stringify(item, function(key, val) {
|
||||
if (key == '$$hashKey') {
|
||||
return undefined;
|
||||
}
|
||||
return val;
|
||||
}));
|
||||
},
|
||||
load : function(key) { return JSON.parse(_s.getItem(key)); },
|
||||
clear : function() { _s.clear(); }
|
||||
};
|
||||
} catch (e) {
|
||||
alert('There is no local storage for you.' +
|
||||
' If you refresh the page, all progress will be lost');
|
||||
return {
|
||||
save : function(key, item) {},
|
||||
load : function(key) { return null; },
|
||||
clear : function() {}
|
||||
};
|
||||
};
|
||||
}());
|
||||
/** Allows to save objects to HTML5 local storage.
|
||||
* However, it can only save properties, not functions.
|
||||
*/
|
||||
|
||||
var ObjectStorage = (function() {
|
||||
'use strict';
|
||||
try {
|
||||
var _s = localStorage;
|
||||
return {
|
||||
save :
|
||||
function(key, item) {
|
||||
_s.setItem(key, JSON.stringify(item, function(key, val) {
|
||||
if (key == '$$hashKey') {
|
||||
return undefined;
|
||||
}
|
||||
return val;
|
||||
}));
|
||||
},
|
||||
load : function(key) { return JSON.parse(_s.getItem(key)); },
|
||||
clear : function() { _s.clear(); }
|
||||
};
|
||||
} catch (e) {
|
||||
alert('There is no local storage for you.' +
|
||||
' If you refresh the page, all progress will be lost');
|
||||
return {
|
||||
save : function(key, item) {},
|
||||
load : function(key) { return null; },
|
||||
clear : function() {}
|
||||
};
|
||||
};
|
||||
}());
|
||||
export default ObjectStorage
|
||||
|
||||
+163
-162
@@ -1,162 +1,163 @@
|
||||
'use strict';
|
||||
|
||||
/** Define UI specific stuff.
|
||||
*/
|
||||
var FastClick = require("fastclick");
|
||||
var Cookies = require("js-cookie");
|
||||
var UI = module.exports = (function (FastClick,Cookies) {
|
||||
/** Introduce FastClick for faster clicking on mobile.
|
||||
*/
|
||||
$(function() {
|
||||
FastClick.attach(document.body);
|
||||
});
|
||||
|
||||
// $('.prevent-select').on('mousedown', function(e) {
|
||||
// e.preventDefault();
|
||||
// });
|
||||
|
||||
|
||||
/** Show a bootstrap modal with dynamic content e.g. background info **/
|
||||
var showModal = function(title, text, level) {
|
||||
var $modal = $('#infoBox');
|
||||
$modal.find('#infoBoxLabel').html(title);
|
||||
$modal.find('.modal-body').html(text);
|
||||
$modal.modal({show: true});
|
||||
};
|
||||
|
||||
/** Display only the cards with data-min-level above a certain
|
||||
* threshold.
|
||||
*/
|
||||
var showLevels = function(level) {
|
||||
$('#infoBox').find('[data-min-level]').each(function() {
|
||||
if (level >= $(this).data('min-level')) {
|
||||
$(this).show();
|
||||
} else {
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var showUpdateValue = function(ident, num) {
|
||||
if (num != 0) {
|
||||
var formatted = Helpers.formatNumberPostfix(num);
|
||||
var insert;
|
||||
if (num > 0) {
|
||||
insert = $("<div></div>")
|
||||
.attr("class", "update-plus")
|
||||
.html("+" + formatted);
|
||||
} else {
|
||||
insert = $("<div></div>")
|
||||
.attr("class", "update-minus")
|
||||
.html(formatted);
|
||||
}
|
||||
showUpdate(ident, insert);
|
||||
}
|
||||
}
|
||||
|
||||
var showUpdate = function(ident, insert) {
|
||||
var elem = $(ident);
|
||||
elem.append(insert);
|
||||
insert.animate({
|
||||
"bottom":"+=30px",
|
||||
"opacity": 0
|
||||
}, { duration: 500, complete: function() {
|
||||
$(this).remove();
|
||||
}});
|
||||
}
|
||||
|
||||
var showAchievement = function(obj) {
|
||||
var alert = '<div class="alert alert-success alert-dismissible" role="alert">';
|
||||
alert += '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>';
|
||||
alert += '<span class="fa ' + obj.icon + ' alert-glyph"></span> <span class="alert-text">' + obj.description + '</span>';
|
||||
alert += '</div>';
|
||||
|
||||
alert = $(alert);
|
||||
|
||||
$('#achievements-container').prepend(alert);
|
||||
var remove = function(a)
|
||||
{
|
||||
return function()
|
||||
{
|
||||
a.slideUp(300, function() { a.remove(); });
|
||||
};
|
||||
};
|
||||
|
||||
window.setTimeout(remove(alert), 2000);
|
||||
}
|
||||
|
||||
// display cookie warning
|
||||
if (typeof Cookies.get('cookielaw') === 'undefined') {
|
||||
var alert = '<div id="cookielaw" class="alert alert-info" role="alert">';
|
||||
alert += '<button type="button" class="btn btn-primary">OK</button>';
|
||||
alert += '<i class="fa fa-info-circle alert-glyph"></i> <span class="alert-text">Cards for science uses local storage to store your current progress.</span>';
|
||||
alert += '</div>';
|
||||
alert = $(alert);
|
||||
alert.find('button').click(function ()
|
||||
{
|
||||
Cookies.set('cookielaw', 'informed', { expires: 365 });
|
||||
$('#cookielaw').slideUp(300, function() { $('#cookielaw').remove(); });
|
||||
})
|
||||
|
||||
$('#messages-container').append(alert);
|
||||
}
|
||||
|
||||
// display new user alert
|
||||
// if (typeof Cookies.get('cern60') === 'undefined') {
|
||||
// var alert = '<div id="cern60" class="alert alert-info" role="alert">';
|
||||
// alert += '<button type="button" class="btn btn-primary">Close</button>';
|
||||
// alert += '<i class="fa fa-area-chart alert-glyph"></i> <span class="alert-text"><a class="alert-link" href="http://home.web.cern.ch/about/updates/2014/12/take-part-cern-60-public-computing-challenge" target="_blank">Join the CERN 60 computing challenge!</a></span>';
|
||||
// alert += '</div>';
|
||||
// alert = $(alert);
|
||||
// alert.find('button').click(function ()
|
||||
// {
|
||||
// Cookies.set('cern60', 'closed', { expires: 365 });
|
||||
// $('#cern60').slideUp(300, function() { $('#cern60').remove(); });
|
||||
// })
|
||||
//
|
||||
// $('#messages-container').append(alert);
|
||||
// }
|
||||
|
||||
return {
|
||||
showAchievement: showAchievement,
|
||||
showModal: showModal,
|
||||
showLevels: showLevels,
|
||||
showUpdateValue: showUpdateValue
|
||||
};
|
||||
})(FastClick,Cookies);
|
||||
|
||||
//
|
||||
// // I don't know what this is for, so I leave it here for the moment...
|
||||
// (function() {
|
||||
// var hidden = "hidden";
|
||||
//
|
||||
// // Standards:
|
||||
// if (hidden in document)
|
||||
// document.addEventListener("visibilitychange", onchange);
|
||||
// else if ((hidden = "mozHidden") in document)
|
||||
// document.addEventListener("mozvisibilitychange", onchange);
|
||||
// else if ((hidden = "webkitHidden") in document)
|
||||
// document.addEventListener("webkitvisibilitychange", onchange);
|
||||
// else if ((hidden = "msHidden") in document)
|
||||
// document.addEventListener("msvisibilitychange", onchange);
|
||||
// // IE 9 and lower:
|
||||
// else if ('onfocusin' in document)
|
||||
// document.onfocusin = document.onfocusout = onchange;
|
||||
// // All others:
|
||||
// else
|
||||
// window.onpageshow = window.onpagehide
|
||||
// = window.onfocus = window.onblur = onchange;
|
||||
//
|
||||
// function onchange (evt) {
|
||||
// var v = 'visible', h = 'hidden',
|
||||
// evtMap = {
|
||||
// focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
|
||||
// };
|
||||
//
|
||||
// evt = evt || window.event;
|
||||
// if (evt.type in evtMap)
|
||||
// detector.visible = evtMap[evt.type] == 'visible';
|
||||
// else
|
||||
// detector.visible = !this[hidden];
|
||||
// }
|
||||
// })();
|
||||
'use strict';
|
||||
|
||||
/** Define UI specific stuff.
|
||||
*/
|
||||
var FastClick = require("fastclick");
|
||||
var Cookies = require("js-cookie");
|
||||
export default UI
|
||||
var UI = (function (FastClick,Cookies) {
|
||||
/** Introduce FastClick for faster clicking on mobile.
|
||||
*/
|
||||
$(function() {
|
||||
FastClick.attach(document.body);
|
||||
});
|
||||
|
||||
// $('.prevent-select').on('mousedown', function(e) {
|
||||
// e.preventDefault();
|
||||
// });
|
||||
|
||||
|
||||
/** Show a bootstrap modal with dynamic content e.g. background info **/
|
||||
var showModal = function(title, text, level) {
|
||||
var $modal = $('#infoBox');
|
||||
$modal.find('#infoBoxLabel').html(title);
|
||||
$modal.find('.modal-body').html(text);
|
||||
$modal.modal({show: true});
|
||||
};
|
||||
|
||||
/** Display only the cards with data-min-level above a certain
|
||||
* threshold.
|
||||
*/
|
||||
var showLevels = function(level) {
|
||||
$('#infoBox').find('[data-min-level]').each(function() {
|
||||
if (level >= $(this).data('min-level')) {
|
||||
$(this).show();
|
||||
} else {
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var showUpdateValue = function(ident, num) {
|
||||
if (num != 0) {
|
||||
var formatted = Helpers.formatNumberPostfix(num);
|
||||
var insert;
|
||||
if (num > 0) {
|
||||
insert = $("<div></div>")
|
||||
.attr("class", "update-plus")
|
||||
.html("+" + formatted);
|
||||
} else {
|
||||
insert = $("<div></div>")
|
||||
.attr("class", "update-minus")
|
||||
.html(formatted);
|
||||
}
|
||||
showUpdate(ident, insert);
|
||||
}
|
||||
}
|
||||
|
||||
var showUpdate = function(ident, insert) {
|
||||
var elem = $(ident);
|
||||
elem.append(insert);
|
||||
insert.animate({
|
||||
"bottom":"+=30px",
|
||||
"opacity": 0
|
||||
}, { duration: 500, complete: function() {
|
||||
$(this).remove();
|
||||
}});
|
||||
}
|
||||
|
||||
var showAchievement = function(obj) {
|
||||
var alert = '<div class="alert alert-success alert-dismissible" role="alert">';
|
||||
alert += '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>';
|
||||
alert += '<span class="fa ' + obj.icon + ' alert-glyph"></span> <span class="alert-text">' + obj.description + '</span>';
|
||||
alert += '</div>';
|
||||
|
||||
alert = $(alert);
|
||||
|
||||
$('#achievements-container').prepend(alert);
|
||||
var remove = function(a)
|
||||
{
|
||||
return function()
|
||||
{
|
||||
a.slideUp(300, function() { a.remove(); });
|
||||
};
|
||||
};
|
||||
|
||||
window.setTimeout(remove(alert), 2000);
|
||||
}
|
||||
|
||||
// display cookie warning
|
||||
if (typeof Cookies.get('cookielaw') === 'undefined') {
|
||||
var alert = '<div id="cookielaw" class="alert alert-info" role="alert">';
|
||||
alert += '<button type="button" class="btn btn-primary">OK</button>';
|
||||
alert += '<i class="fa fa-info-circle alert-glyph"></i> <span class="alert-text">Cards for science uses local storage to store your current progress.</span>';
|
||||
alert += '</div>';
|
||||
alert = $(alert);
|
||||
alert.find('button').click(function ()
|
||||
{
|
||||
Cookies.set('cookielaw', 'informed', { expires: 365 });
|
||||
$('#cookielaw').slideUp(300, function() { $('#cookielaw').remove(); });
|
||||
})
|
||||
|
||||
$('#messages-container').append(alert);
|
||||
}
|
||||
|
||||
// display new user alert
|
||||
// if (typeof Cookies.get('cern60') === 'undefined') {
|
||||
// var alert = '<div id="cern60" class="alert alert-info" role="alert">';
|
||||
// alert += '<button type="button" class="btn btn-primary">Close</button>';
|
||||
// alert += '<i class="fa fa-area-chart alert-glyph"></i> <span class="alert-text"><a class="alert-link" href="http://home.web.cern.ch/about/updates/2014/12/take-part-cern-60-public-computing-challenge" target="_blank">Join the CERN 60 computing challenge!</a></span>';
|
||||
// alert += '</div>';
|
||||
// alert = $(alert);
|
||||
// alert.find('button').click(function ()
|
||||
// {
|
||||
// Cookies.set('cern60', 'closed', { expires: 365 });
|
||||
// $('#cern60').slideUp(300, function() { $('#cern60').remove(); });
|
||||
// })
|
||||
//
|
||||
// $('#messages-container').append(alert);
|
||||
// }
|
||||
|
||||
return {
|
||||
showAchievement: showAchievement,
|
||||
showModal: showModal,
|
||||
showLevels: showLevels,
|
||||
showUpdateValue: showUpdateValue
|
||||
};
|
||||
})(FastClick,Cookies);
|
||||
|
||||
//
|
||||
// // I don't know what this is for, so I leave it here for the moment...
|
||||
// (function() {
|
||||
// var hidden = "hidden";
|
||||
//
|
||||
// // Standards:
|
||||
// if (hidden in document)
|
||||
// document.addEventListener("visibilitychange", onchange);
|
||||
// else if ((hidden = "mozHidden") in document)
|
||||
// document.addEventListener("mozvisibilitychange", onchange);
|
||||
// else if ((hidden = "webkitHidden") in document)
|
||||
// document.addEventListener("webkitvisibilitychange", onchange);
|
||||
// else if ((hidden = "msHidden") in document)
|
||||
// document.addEventListener("msvisibilitychange", onchange);
|
||||
// // IE 9 and lower:
|
||||
// else if ('onfocusin' in document)
|
||||
// document.onfocusin = document.onfocusout = onchange;
|
||||
// // All others:
|
||||
// else
|
||||
// window.onpageshow = window.onpagehide
|
||||
// = window.onfocus = window.onblur = onchange;
|
||||
//
|
||||
// function onchange (evt) {
|
||||
// var v = 'visible', h = 'hidden',
|
||||
// evtMap = {
|
||||
// focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
|
||||
// };
|
||||
//
|
||||
// evt = evt || window.event;
|
||||
// if (evt.type in evtMap)
|
||||
// detector.visible = evtMap[evt.type] == 'visible';
|
||||
// else
|
||||
// detector.visible = !this[hidden];
|
||||
// }
|
||||
// })();
|
||||
|
||||
Reference in New Issue
Block a user