diff --git a/public/js/app.js b/public/js/app.js
index ded963b44e..fcdcc1a5d3 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -17,7 +17,7 @@ window.env.t = function(string){
window.habitrpg = angular.module('habitrpg',
['ngResource', 'ngSanitize', 'userServices', 'groupServices', 'memberServices', 'challengeServices',
- 'sharedServices', 'authServices', 'notificationServices', 'guideServices',
+ 'authServices', 'notificationServices', 'guideServices',
'ui.bootstrap', 'ui.keypress', 'ui.router', 'chieffancypants.loadingBar', 'At', 'pasvaz.bindonce'])
// @see https://github.com/angular-ui/ui-router/issues/110 and https://github.com/HabitRPG/habitrpg/issues/1705
diff --git a/public/js/controllers/challengesCtrl.js b/public/js/controllers/challengesCtrl.js
index 82854bade3..93ef91e1d3 100644
--- a/public/js/controllers/challengesCtrl.js
+++ b/public/js/controllers/challengesCtrl.js
@@ -132,7 +132,7 @@ habitrpg.controller("ChallengesCtrl", ['$scope', 'User', 'Challenges', 'Notifica
//------------------------------------------------------------
$scope.addTask = function(addTo, listDef) {
- var task = window.habitrpgShared.helpers.taskDefaults({text: listDef.newTask, type: listDef.type});
+ var task = $rootScope.Shared.taskDefaults({text: listDef.newTask, type: listDef.type});
addTo.unshift(task);
//User.log({op: "addTask", data: task}); //TODO persist
delete listDef.newTask;
diff --git a/public/js/controllers/filtersCtrl.js b/public/js/controllers/filtersCtrl.js
index 3839074a6c..9ec425d568 100644
--- a/public/js/controllers/filtersCtrl.js
+++ b/public/js/controllers/filtersCtrl.js
@@ -22,7 +22,7 @@ habitrpg.controller("FiltersCtrl", ['$scope', '$rootScope', 'User', 'API_URL', '
$scope.createTag = function(name) {
user.tags = user.tags || [];
user.tags.push({
- id: window.habitrpgShared.helpers.uuid(),
+ id: $rootScope.Shared.uuid(),
name: name
});
User.log({op:'set',data:{'tags':user.tags}});
diff --git a/public/js/controllers/footerCtrl.js b/public/js/controllers/footerCtrl.js
index 401c40b9fc..4f15ba55b0 100644
--- a/public/js/controllers/footerCtrl.js
+++ b/public/js/controllers/footerCtrl.js
@@ -47,17 +47,16 @@ habitrpg.controller("FooterCtrl", ['$scope', '$rootScope', 'User', '$http', 'Not
$scope.addMissedDay = function(){
if (!confirm("Are you sure you want to reset the day?")) return;
var dayBefore = moment(User.user.lastCron).subtract('days', 1).toDate();
- User.set('lastCron', dayBefore);
+ User.set({'lastCron': dayBefore});
Notification.text('-1 day, remember to refresh');
}
$scope.addTenGems = function(){
- console.log(API_URL);
$http.post(API_URL + '/api/v1/user/addTenGems').success(function(){
User.log({});
})
}
$scope.addLevelsAndGold = function(){
- User.setMultiple({
+ User.set({
'stats.exp': User.user.stats.exp + 10000,
'stats.gp': User.user.stats.gp + 10000
});
diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js
index 09133c3738..793698d465 100644
--- a/public/js/controllers/groupsCtrl.js
+++ b/public/js/controllers/groupsCtrl.js
@@ -66,7 +66,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'A
// We watch Members.selectedMember because it's asynchronously set, so would be a hassle to handle updates here
$scope.$watch( function() { return Members.selectedMember; }, function (member) {
if(member)
- member.petCount = window.habitrpgShared.helpers.countPets(null, member.items.pets);
+ member.petCount = $rootScope.Shared.countPets(null, member.items.pets);
$scope.profile = member;
});
}
diff --git a/public/js/controllers/inventoryCtrl.js b/public/js/controllers/inventoryCtrl.js
index 3e94a7f001..71dd6271df 100644
--- a/public/js/controllers/inventoryCtrl.js
+++ b/public/js/controllers/inventoryCtrl.js
@@ -2,13 +2,13 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
function($rootScope, $scope, User, API_URL, $http, Notification) {
var user = User.user;
- var Items = window.habitrpgShared.items;
+ var Content = $rootScope.Shared.content;
// convenience vars since these are accessed frequently
$scope.selectedEgg = null; // {index: 1, name: "Tiger", value: 5}
$scope.selectedPotion = null; // {index: 5, name: "Red", value: 3}
- $scope.totalPets = _.size($scope.Items.eggs) * _.size($scope.Items.hatchingPotions);
+ $scope.totalPets = _.size(Content.eggs) * _.size(Content.hatchingPotions);
// count egg, food, hatchingPotion stack totals
var countStacks = function(items) { return _.reduce(items,function(m,v){return m+v;},0);}
@@ -20,10 +20,10 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
$scope.$watch('user.items.gear', function(gear){
$scope.gear = {
- base: _.where(Items.items.gear.flat, {klass: 'base'})
+ base: _.where(shared.content.gear.flat, {klass: 'base'})
};
_.each(gear.owned, function(bool,key){
- var item = Items.items.gear.flat[key];
+ var item = shared.content.gear.flat[key];
if (!$scope.gear[item.klass]) $scope.gear[item.klass] = [];
$scope.gear[item.klass].push(item);
})
@@ -33,7 +33,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
if ($scope.selectedEgg && $scope.selectedEgg.name == egg) {
return $scope.selectedEgg = null; // clicked same egg, unselect
}
- var eggData = _.findWhere(Items.items.eggs, {name:egg});
+ var eggData = _.findWhere(shared.content.eggs, {name:egg});
if (!$scope.selectedPotion) {
$scope.selectedEgg = eggData;
} else {
@@ -46,7 +46,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
return $scope.selectedPotion = null; // clicked same egg, unselect
}
// we really didn't think through the way these things are stored and getting passed around...
- var potionData = _.findWhere(Items.items.hatchingPotions, {name:potion});
+ var potionData = _.findWhere(shared.content.hatchingPotions, {name:potion});
if (!$scope.selectedEgg) {
$scope.selectedPotion = potionData;
} else {
@@ -56,42 +56,18 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
$scope.chooseFood = function(food){
if ($scope.selectedFood && $scope.selectedFood.name == food) return $scope.selectedFood = null;
- $scope.selectedFood = $scope.Items.food[food];
+ $scope.selectedFood = Content.food[food];
}
$scope.sellInventory = function() {
- // TODO DRY this
- if ($scope.selectedEgg) {
- user.items.eggs[$scope.selectedEgg.name]--;
- User.setMultiple({
- 'items.eggs': user.items.eggs,
- 'stats.gp': User.user.stats.gp + $scope.selectedEgg.value
- });
- if (user.items.eggs[$scope.selectedEgg.name] < 1) {
- $scope.selectedEgg = null;
- }
-
- } else if ($scope.selectedPotion) {
- user.items.hatchingPotions[$scope.selectedPotion.name]--;
- User.setMultiple({
- 'items.hatchingPotions': user.items.hatchingPotions,
- 'stats.gp': User.user.stats.gp + $scope.selectedPotion.value
- });
- if (user.items.hatchingPotions[$scope.selectedPotion.name] < 1) {
- $scope.selectedPotion = null;
- }
-
- } else if ($scope.selectedFood) {
- user.items.food[$scope.selectedFood.name]--;
- User.setMultiple({
- 'items.food': user.items.food,
- 'stats.gp': User.user.stats.gp + $scope.selectedFood.value
- });
- if (user.items.food[$scope.selectedFood.name] < 1) {
- $scope.selectedFood = null;
+ var selected = $scope.selectedEgg ? 'selectedEgg' : $scope.selectedPotion ? 'selectedPotion' : $scope.selectedFood ? 'selectedFood' : undefined;
+ if (selected) {
+ var type = $scope.selectedEgg ? 'eggs' : $scope.selectedPotion ? 'hatchingPotions' : $scope.selectedFood ? 'food' : undefined;
+ user.ops.sell({query:{type:type, key: $scope[selected].name}});
+ if (user.items[type][$scope[selected].name] < 1) {
+ $scope[selected] = null;
}
}
-
}
$scope.ownedItems = function(inventory){
@@ -99,21 +75,15 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
}
$scope.hatch = function(egg, potion){
- var pet = egg.name+"-"+potion.name;
- if (user.items.pets[pet])
- return alert("You already have that pet. Try hatching a different combination!");
-
- var setObj = {};
- setObj['items.pets.' + pet] = 5;
- setObj['items.eggs.' + egg.name] = user.items.eggs[egg.name] - 1;
- setObj['items.hatchingPotions.' + potion.name] = user.items.hatchingPotions[potion.name] - 1;
-
- User.setMultiple(setObj);
-
- alert("Your egg hatched! Visit your stable to equip your pet.");
-
- $scope.selectedEgg = null;
- $scope.selectedPotion = null;
+ user.ops.hatch({query:{egg:egg.name, hatchingPotion:potion.name}}, function(err, req){
+ // Bypassing the UserServices-injected callback so we can only show alert on success. It's safe, since this means
+ // UserServices callback will be 3rd param and never get called
+ if (err) return Notification.text(err);
+ User.log({op:'hatch', query:req.query});
+ Notification.text("Your egg hatched! Visit your stable to equip your pet.");
+ $scope.selectedEgg = null;
+ $scope.selectedPotion = null;
+ });
}
$scope.buy = function(type, item){
@@ -134,7 +104,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
// Feeding Pet
if ($scope.selectedFood) {
- if (window.habitrpgShared.items.items.specialPets[pet]) return Notification.text("Can't feed this pet.");
+ if (window.habitrpgShared.shared.content.specialPets[pet]) return Notification.text("Can't feed this pet.");
var setObj = {};
var userPets = user.items.pets;
if (user.items.mounts[pet] && (userPets[pet] >= 50 || $scope.selectedFood.name == 'Saddle'))
@@ -163,7 +133,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
}
setObj['items.pets.' + pet] = userPets[pet];
setObj['items.food.' + $scope.selectedFood.name] = user.items.food[$scope.selectedFood.name] - 1;
- User.setMultiple(setObj);
+ User.set(setObj);
$scope.selectedFood = null;
// Selecting Pet
@@ -182,19 +152,5 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
var mount = egg + '-' + potion;
User.set('items.currentMount', (user.items.currentMount == mount) ? '' : mount);
}
-
- $scope.equip = function(user, item, costume) {
- var equipTo = costume ? 'costume' : 'equipped';
- if (item.type == 'shield') {
- var weapon = Items.items.gear.flat[user.items.gear[equipTo].weapon];
- if (weapon && weapon.twoHanded) return Notification.text(weapon.text + ' is two-handed');
- }
- var setVars = {};
- setVars['items.gear.' + equipTo + '.' + item.type] = item.key;
- if (item.twoHanded)
- setVars['items.gear.' + equipTo + '.shield'] = 'warrior_shield_0';
- User.setMultiple(setVars);
- }
-
}
]);
\ No newline at end of file
diff --git a/public/js/controllers/notificationCtrl.js b/public/js/controllers/notificationCtrl.js
index d1ddbda530..4a87b7129b 100644
--- a/public/js/controllers/notificationCtrl.js
+++ b/public/js/controllers/notificationCtrl.js
@@ -53,7 +53,7 @@ habitrpg.controller('NotificationCtrl',
$rootScope.$watch('user.items.pets', function(after, before){
if(_.size(after) === _.size(before) ||
- window.habitrpgShared.helpers.countPets(null, after) < 90) return;
+ $rootScope.Shared.countPets(null, after) < 90) return;
User.user.achievements.beastMaster = true;
$rootScope.modals.achievements.beastMaster = true;
}, true);
diff --git a/public/js/controllers/rootCtrl.js b/public/js/controllers/rootCtrl.js
index 17525266ab..ee95a757f0 100644
--- a/public/js/controllers/rootCtrl.js
+++ b/public/js/controllers/rootCtrl.js
@@ -5,12 +5,15 @@
habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams', 'Notification', 'Groups',
function($scope, $rootScope, $location, User, $http, $state, $stateParams, Notification, Groups) {
+ var user = User.user;
+
$rootScope.modals = {};
$rootScope.modals.achievements = {};
$rootScope.User = User;
- $rootScope.user = User.user;
+ $rootScope.user = user;
$rootScope.settings = User.settings;
- $rootScope.Items = window.habitrpgShared.items.items;
+ $rootScope.Shared = window.habitrpgShared;
+ $rootScope.Content = window.habitrpgShared.content;
// Angular UI Router
$rootScope.$state = $state;
@@ -34,10 +37,10 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
// count pets, mounts collected totals, etc
$rootScope.countExists = function(items) {return _.reduce(items,function(m,v){return m+(v?1:0)},0)}
- $rootScope.petCount = window.habitrpgShared.helpers.countPets(null, User.user.items.pets);
+ $rootScope.petCount = $rootScope.Shared.countPets(null, User.user.items.pets);
$rootScope.$watch('user.items.pets', function(pets){
- $rootScope.petCount = window.habitrpgShared.helpers.countPets($rootScope.countExists(pets), User.user.items.pets);
+ $rootScope.petCount = $rootScope.Shared.countPets($rootScope.countExists(pets), User.user.items.pets);
}, true);
$scope.safeApply = function(fn) {
@@ -51,13 +54,6 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
}
};
- /*
- FIXME this is dangerous, organize helpers.coffee better, so we can group them by which controller needs them,
- and then simply _.defaults($scope, Helpers.user) kinda thing
- */
- _.defaults($rootScope, window.habitrpgShared.algos);
- _.defaults($rootScope, window.habitrpgShared.helpers);
-
$rootScope.set = User.set;
$rootScope.authenticated = User.authenticated;
@@ -150,8 +146,6 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
$rootScope.applyingAction = true;
$scope.spell = spell;
if (spell.target == 'self') {
- var tasks = User.user.habits.concat(User.user.dailys).concat(User.user.todos);
- User.user.tasks = _.object(_.pluck(tasks,'id'), tasks);
$scope.castEnd(null, 'self');
} else if (spell.target == 'party') {
var party = Groups.party();
diff --git a/public/js/controllers/settingsCtrl.js b/public/js/controllers/settingsCtrl.js
index 6d10e0d758..2925e15372 100644
--- a/public/js/controllers/settingsCtrl.js
+++ b/public/js/controllers/settingsCtrl.js
@@ -16,13 +16,13 @@ habitrpg.controller('SettingsCtrl',
// }
$scope.showTour = function(){
- User.set('flags.showTour',true);
+ User.set({'flags.showTour':true});
Guide.initTour();
$location.path('/tasks');
}
$scope.showBailey = function(){
- User.set('flags.newStuff',true);
+ User.set({'flags.newStuff':true});
}
$scope.saveDayStart = function(){
@@ -31,7 +31,7 @@ habitrpg.controller('SettingsCtrl',
dayStart = 0;
return alert('Please enter a number between 0 and 24');
}
- User.set('preferences.dayStart', dayStart);
+ User.set({'preferences.dayStart': dayStart});
}
$scope.language = window.env.language;
@@ -41,7 +41,7 @@ habitrpg.controller('SettingsCtrl',
$rootScope.$on('userSynced', function(){
location.reload();
});
- User.set('preferences.language', $scope.language.code);
+ User.set({'preferences.language': $scope.language.code});
}
$scope.reroll = function(){
@@ -74,24 +74,18 @@ habitrpg.controller('SettingsCtrl',
$rootScope.$watch('modals.restore', function(value){
if(value === true){
$scope.restoreValues.stats = angular.copy(User.user.stats);
-// $scope.restoreValues.items = angular.copy(User.user.items);
$scope.restoreValues.achievements = {streak: User.user.achievements.streak || 0};
}
})
$scope.restore = function(){
var stats = $scope.restoreValues.stats,
-// items = $scope.restoreValues.items,
achievements = $scope.restoreValues.achievements;
- User.setMultiple({
+ User.set({
"stats.hp": stats.hp,
"stats.exp": stats.exp,
"stats.gp": stats.gp,
"stats.lvl": stats.lvl,
-// "items.weapon": items.weapon,
-// "items.armor": items.armor,
-// "items.head": items.head,
-// "items.shield": items.shield,
"achievements.streak": achievements.streak
});
$rootScope.modals.restore = false;
diff --git a/public/js/controllers/tasksCtrl.js b/public/js/controllers/tasksCtrl.js
index 72fb1dcb59..81759ce21f 100644
--- a/public/js/controllers/tasksCtrl.js
+++ b/public/js/controllers/tasksCtrl.js
@@ -1,22 +1,22 @@
"use strict";
-habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', 'Algos', 'Helpers', 'Notification', '$http', 'API_URL',
- function($scope, $rootScope, $location, User, Algos, Helpers, Notification, $http, API_URL) {
+habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'API_URL',
+ function($scope, $rootScope, $location, User, Notification, $http, API_URL) {
$scope.obj = User.user; // used for task-lists
$scope.score = function(task, direction) {
- if (task.type === "reward" && User.user.stats.gp < task.value){
- return Notification.text('Not enough Gold!');
- }
- Algos.score(User.user, task, direction);
- User.log({op: "score",data: task, dir: direction});
-
+ User.user.ops.score({params:{id: task.id, direction:direction}})
};
$scope.addTask = function(addTo, listDef) {
- var task = window.habitrpgShared.helpers.taskDefaults({text: listDef.newTask, type: listDef.type}, User.user.filters);
- addTo.unshift(task);
- User.log({op: "addTask", data: task});
+ var newTask = {
+ text: listDef.newTask,
+ type: listDef.type,
+ tags: _.transform(User.user.filters, function(m,v,k){
+ if (v) m[k]=v;
+ })
+ }
+ User.user.ops.addTask({body:newTask});
delete listDef.newTask;
};
@@ -40,40 +40,12 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', '
$scope.removeTask = function(list, $index) {
if (!confirm("Are you sure you want to delete this task?")) return;
- User.log({ op: "delTask", data: list[$index] });
+ User.user.ops.deleteTask({params:{id:list[$index].id}})
list.splice($index, 1);
};
$scope.saveTask = function(task) {
- var setVal = function(k, v) {
- var op;
- if (typeof v !== "undefined") {
- op = { op: "set", data: {} };
- op.data["tasks." + task.id + "." + k] = v;
- return log.push(op);
- }
- };
- var log = [];
- setVal("text", task.text);
- setVal("notes", task.notes);
- setVal("priority", task.priority);
- setVal("tags", task.tags);
- if (task.type === "habit") {
- setVal("up", task.up);
- setVal("down", task.down);
- } else if (task.type === "daily") {
- setVal("repeat", task.repeat);
- // TODO we'll remove this once rewrite's running for a while. This was a patch for derby issues
- setVal("streak", task.streak);
-
- } else if (task.type === "todo") {
- setVal("date", task.date);
- } else {
- if (task.type === "reward") {
- setVal("value", task.value);
- }
- }
- User.log(log);
+ User.user.ops.updateTask({params:{id:task.id},body:task});
task._editing = false;
};
@@ -104,16 +76,18 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', '
------------------------
*/
- $scope.itemStore = window.habitrpgShared.items.updateStore(User.user);
+ $rootScope.$on('userSynced', function(){
+ $scope.itemStore = User.user.fns.updateStore();
+ })
$scope.buy = function(item) {
- var hasEnough = window.habitrpgShared.items.buyItem(User.user, item);
+ var hasEnough = User.user.ops.buy({query:{key:item.key}});
if (hasEnough) {
- User.log({op: "buy", key: item.key});
Notification.text("Item purchased.");
- $scope.itemStore = window.habitrpgShared.items.updateStore(User.user);
+ $scope.itemStore = User.user.fns.updateStore();
} else {
- Notification.text("Not enough Gold!");
+// Notification.text("Not enough Gold!");
+ // handled by userServices interceptor
}
};
diff --git a/public/js/controllers/userCtrl.js b/public/js/controllers/userCtrl.js
index e0c52fdba2..8fa9ec1bff 100644
--- a/public/js/controllers/userCtrl.js
+++ b/public/js/controllers/userCtrl.js
@@ -12,56 +12,20 @@ habitrpg.controller("UserCtrl", ['$rootScope', '$scope', '$location', 'User', '$
});
$scope.allocate = function(stat){
- var setObj = {}
- setObj['stats.' + stat] = User.user.stats[stat] + 1;
- setObj['stats.points'] = User.user.stats.points - 1;
- User.setMultiple(setObj);
+ User.user.ops.allocate({query:{stat:stat}});
}
- $scope.rerollClass = function(){
- if (!confirm("Are you sure you want to re-roll? This will reset your character's class and allocated points (you'll get them all back to re-allocate)"))
- return;
- User.setMultiple({
- 'flags.classSelected': false,
- //'stats.points': this is handled on the server
- 'stats.str': 0,
- 'stats.def': 0,
- 'stats.per': 0,
- 'stats.int': 0
- })
- }
- $scope.rerollSubmit = function(){
- var klass = $scope.selectedClass;
- var setVars = {
- "stats.class": klass,
- "flags.classSelected": true
- };
+ $scope.changeClass = function(klass){
+ if (!klass) {
+ if (!confirm("Are you sure you want to re-roll? This will reset your character's class and allocated points (you'll get them all back to re-allocate)"))
+ return;
+ return User.user.ops.changeClass({});
+ }
- // Clear their gear and equip their new class's gear (can still equip old gear from inventory)
- // If they've rolled this class before, restore their progress
- _.each(['weapon', 'armor','shield','head'], function(type){
- var foundKey = false;
- _.findLast(User.user.items.gear.owned, function(v,k){
- if (~k.indexOf(type + '_' + klass)) {
- foundKey = k;
- return true;
- }
- });
- setVars['items.gear.equipped.' + type] =
- foundKey ? foundKey : // restore progress from when they last rolled this class
- (type == 'weapon') ? 'weapon_' + klass + '_0' : // weapon_0 is significant, don't reset to base_0
- (type == 'shield' && klass == 'rogue') ? 'shield_rogue_0' : // rogues start with an off-hand weapon
- type + '_base_0'; // naked for the rest!
-
- // Grant them their new class's gear
- if (type == 'weapon' || (type == 'shield' && klass == 'rogue'))
- setVars['items.gear.owned.' + type + '_' + klass + '_0'] = true;
- });
-
- User.setMultiple(setVars);
+ User.user.ops.changeClass({query:{class:klass}});
$scope.selectedClass = undefined;
- //FIXME run updateStore (we need to access a different scope)
+ User.user.fns.updateStore();
}
$scope.save = function(){
@@ -72,11 +36,28 @@ habitrpg.controller("UserCtrl", ['$rootScope', '$scope', '$location', 'User', '$
if(!curVal || $scope.editingProfile[key].toString() !== curVal.toString())
values['profile.' + key] = value;
});
- User.setMultiple(values);
+ User.set(values);
$scope._editing.profile = false;
}
- $scope.unlock = User.unlock;
+ /**
+ * For gem-unlockable preferences, (a) if owned, select preference (b) else, purchase
+ * @param path: User.preferences <-> User.purchased maps like User.preferences.skin=abc <-> User.purchased.skin.abc.
+ * Pass in this paramater as "skin.abc". Alternatively, pass as an array ["skin.abc", "skin.xyz"] to unlock sets
+ */
+ $scope.unlock = function(path){
+ var fullSet = ~path.indexOf(',');
+ var cost = fullSet ? 1.25 : 0.5; // 5G per set, 2G per individual
+
+ if (fullSet) {
+ if (confirm("Purchase for 5 Gems?") !== true) return;
+ if (User.user.balance < cost) return $rootScope.modals.buyGems = true;
+ } else if (!User.user.fns.dotGet('purchased.' + path)) {
+ if (confirm("Purchase for 2 Gems?") !== true) return;
+ if (User.user.balance < cost) return $rootScope.modals.buyGems = true;
+ }
+ User.user.ops.unlock({query:{path:path}})
+ }
}
]);
diff --git a/public/js/services/guideServices.js b/public/js/services/guideServices.js
index cdb3fc034c..ddb43467cb 100644
--- a/public/js/services/guideServices.js
+++ b/public/js/services/guideServices.js
@@ -5,7 +5,7 @@
*/
angular.module('guideServices', []).
- factory('Guide', ['$rootScope', 'User', 'Items', 'Helpers', function($rootScope, User, Items, Helpers) {
+ factory('Guide', ['$rootScope', 'User', function($rootScope, User) {
/**
* Init and show the welcome tour. Note we do it listening to a $rootScope broadcasted 'userLoaded' message,
@@ -79,7 +79,7 @@ angular.module('guideServices', []).
$('.main-herobox').popover('destroy');
var tour = new Tour({
onEnd: function(){
- User.set('flags.showTour', false);
+ User.set({'flags.showTour': false});
}
});
tourSteps.forEach(function(step) {
@@ -134,7 +134,7 @@ angular.module('guideServices', []).
$rootScope.$watch('user.items.pets', function(after, before) {
if (User.user.achievements && User.user.achievements.beastMaster) return;
if (before >= 90) {
- User.set('achievements.beastMaster', true);
+ User.set({'achievements.beastMaster': true});
$('#beastmaster-achievement-modal').modal('show'); // FIXME
}
});
diff --git a/public/js/services/sharedServices.js b/public/js/services/sharedServices.js
deleted file mode 100644
index 50c3fdb72d..0000000000
--- a/public/js/services/sharedServices.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict';
-
-/**
- * Services that persists and retrieves user from localStorage.
- */
-
-angular.module('sharedServices', [] ).
- factory("Items", ['$rootScope', function($rootScope){
- return window.habitrpgShared.items;
- }]).
- factory("Algos", ['$rootScope', function($rootScope){
- return window.habitrpgShared.algos;
- }]).
- factory("Helpers", ['$rootScope', function($rootScope){
- return window.habitrpgShared.helpers;
- }]);
\ No newline at end of file
diff --git a/public/js/services/userServices.js b/public/js/services/userServices.js
index 26308ee955..12cc2f6d30 100644
--- a/public/js/services/userServices.js
+++ b/public/js/services/userServices.js
@@ -21,14 +21,13 @@ angular.module('userServices', []).
user = {}; // this is stored as a reference accessible to all controllers, that way updates propagate
//first we populate user with schema
- _.extend(user, $window.habitrpgShared.helpers.newUser());
user.apiToken = user._id = ''; // we use id / apitoken to determine if registered
- $window.habitrpgShared.algos.defineComputed(user);
//than we try to load localStorage
if (localStorage.getItem(STORAGE_USER_ID)) {
_.extend(user, JSON.parse(localStorage.getItem(STORAGE_USER_ID)));
}
+ user._wrapped = false;
var syncQueue = function (cb) {
if (!authenticated) {
@@ -71,6 +70,16 @@ angular.module('userServices', []).
// Update user
_.extend(user, data);
+ if (!user._wrapped){
+ $rootScope.Shared.wrap(user);
+ _.each(user.ops, function(op,k){
+ user.ops[k] = _.partialRight(op, function(err, req){
+ //if (err) return Notification.text(err); // FIXME Circular dependency found: Notification <- User
+ if (err) return alert(err);
+ userServices.log({op:k, params: req.params, query:req.query, body:req.body});
+ });
+ });
+ }
// Emit event when user is synced
$rootScope.$emit('userSynced');
@@ -108,6 +117,9 @@ angular.module('userServices', []).
};
var userServices = {
user: user,
+ set: function(updates) {
+ user.ops.update({body:updates});
+ },
online: function (status) {
if (status===true) {
settings.online = true;
@@ -130,7 +142,7 @@ angular.module('userServices', []).
// If they don't have timezone, set it
var offset = moment().zone(); // eg, 240 - this will be converted on server as -(offset/60)
if (user.preferences.timezoneOffset !== offset)
- userServices.set('preferences.timezoneOffset', offset);
+ userServices.set({'preferences.timezoneOffset': offset});
cb && cb();
});
} else {
@@ -161,62 +173,6 @@ angular.module('userServices', []).
userServices.log({});
},
- /*
- Very simple path-set. `set('preferences.gender','m')` for example. We'll deprecate this once we have a complete API
- */
- set: function(k, v) {
- var log = { op: 'set', data: {} };
- $window.habitrpgShared.helpers.dotSet(k, v, this.user);
- log.data[k] = v;
- userServices.log(log);
- },
-
- setMultiple: function(obj){
- var log = { op: 'set', data: {} };
- _.each(obj, function(v,k){
- $window.habitrpgShared.helpers.dotSet(k, v, userServices.user);
- log.data[k] = v;
- });
- userServices.log(log);
- },
-
- revive: function(){
- $window.habitrpgShared.algos.revive(user);
- userServices.log({ op: "revive" });
- },
-
- /**
- * For gem-unlockable preferences, (a) if owned, select preference (b) else, purchase
- * @param path: User.preferences <-> User.purchased maps like User.preferences.skin=abc <-> User.purchased.skin.abc.
- * Pass in this paramater as "skin.abc". Alternatively, pass as an array ["skin.abc", "skin.xyz"] to unlock sets
- */
- unlock: function(path){
- var self = userServices; //this; // why isn't this working?
-
- if (_.isArray(path)) {
- if (confirm("Purchase for 5 Gems?") !== true) return;
- if (user.balance < 1.25) return $rootScope.modals.buyGems = true;
- path = path.join(',');
- } else {
- if ($window.habitrpgShared.helpers.dotGet('purchased.' + path, user)) {
- var pref = path.split('.')[0],
- val = path.split('.')[1];
- return self.set('preferences.' + pref, val);
- } else {
- if (confirm("Purchase for 2 Gems?") !== true) return;
- if (user.balance < 0.5) return $rootScope.modals.buyGems = true;
- }
- }
-
- $http.post(API_URL + '/api/v1/user/unlock?path=' + path)
- .success(function(data, status, headers, config){
- self.log({}); // sync new unlocked & preferences
- }).error(function(data, status, headers, config){
- alert(status + ': ' + data);
- //FIXME use method used elsewhere for handling this error, this is temp while developing
- })
- },
-
save: save,
settings: settings
diff --git a/public/manifest.json b/public/manifest.json
index f14e5b3d97..a17b2846a9 100644
--- a/public/manifest.json
+++ b/public/manifest.json
@@ -32,7 +32,6 @@
"js/app.js",
"js/services/authServices.js",
"js/services/notificationServices.js",
- "js/services/sharedServices.js",
"js/services/userServices.js",
"js/services/groupServices.js",
"js/services/memberServices.js",
diff --git a/src/controllers/admin.js b/src/controllers/admin.js
index 3d38243c25..7d8be48150 100644
--- a/src/controllers/admin.js
+++ b/src/controllers/admin.js
@@ -1,9 +1,7 @@
var _ = require('lodash');
var nconf = require('nconf');
var async = require('async');
-var algos = require('habitrpg-shared/script/algos');
-var helpers = require('habitrpg-shared/script/helpers');
-var items = require('habitrpg-shared/script/items');
+var shared = require('habitrpg-shared');
var User = require('./../models/user').model;
var Group = require('./../models/group').model;
var api = module.exports;
diff --git a/src/controllers/auth.js b/src/controllers/auth.js
index 4db8cd2768..0d3a8304d5 100644
--- a/src/controllers/auth.js
+++ b/src/controllers/auth.js
@@ -3,7 +3,7 @@ var validator = require('validator');
var check = validator.check;
var sanitize = validator.sanitize;
var passport = require('passport');
-var helpers = require('habitrpg-shared/script/helpers');
+var shared = require('habitrpg-shared');
var async = require('async');
var utils = require('../utils');
var nconf = require('nconf');
@@ -83,17 +83,18 @@ api.registerUser = function(req, res, next) {
if (found) {
return cb("Username already taken");
}
- newUser = helpers.newUser(true);
salt = utils.makeSalt();
- newUser.auth = {
- local: {
- username: username,
- email: email,
- salt: salt
- },
- timestamps: {created: +new Date(), loggedIn: +new Date()}
+ var newUser = {
+ auth: {
+ local: {
+ username: username,
+ email: email,
+ salt: salt,
+ hashed_password: utils.encryptPassword(password, salt)
+ },
+ timestamps: {created: +new Date(), loggedIn: +new Date()}
+ }
};
- newUser.auth.local.hashed_password = utils.encryptPassword(password, salt);
user = new User(newUser);
user.save(cb);
}
@@ -251,12 +252,12 @@ api.setupPassport = function(router) {
},
function(user, cb){
if (user) return cb(null, user);
- var newUser = helpers.newUser(true);
- newUser.auth = {
- facebook: req.user,
- timestamps: {created: +new Date(), loggedIn: +new Date()}
- };
- user = new User(newUser);
+ user = new User({
+ auth: {
+ facebook: req.user,
+ timestamps: {created: +new Date(), loggedIn: +new Date()}
+ }
+ });
user.save(cb);
diff --git a/src/controllers/challenges.js b/src/controllers/challenges.js
index 9481d5ce49..dc11abe5df 100644
--- a/src/controllers/challenges.js
+++ b/src/controllers/challenges.js
@@ -3,9 +3,7 @@
var _ = require('lodash');
var nconf = require('nconf');
var async = require('async');
-var algos = require('habitrpg-shared/script/algos');
-var helpers = require('habitrpg-shared/script/helpers');
-var items = require('habitrpg-shared/script/items');
+var shared = require('habitrpg-shared');
var User = require('./../models/user').model;
var Group = require('./../models/group').model;
var Challenge = require('./../models/challenge').model;
diff --git a/src/controllers/deprecated.js b/src/controllers/deprecated.js
index d2df8fe934..e38e0a5f7c 100644
--- a/src/controllers/deprecated.js
+++ b/src/controllers/deprecated.js
@@ -31,7 +31,7 @@ var initDeprecated = function(req, res, next) {
return next();
};
-router.post('/v1/users/:uid/tasks/:taskId/:direction', initDeprecated, auth.auth, api.scoreTask);
+router.post('/v1/users/:uid/tasks/:taskId/:direction', initDeprecated, auth.auth, api.score);
router.get('/v1/users/:uid/calendar.ics', function(req, res, next) {
return next() //disable for now
diff --git a/src/controllers/groups.js b/src/controllers/groups.js
index d45adceca3..4efd8c65bd 100644
--- a/src/controllers/groups.js
+++ b/src/controllers/groups.js
@@ -3,9 +3,7 @@
var _ = require('lodash');
var nconf = require('nconf');
var async = require('async');
-var algos = require('habitrpg-shared/script/algos');
-var helpers = require('habitrpg-shared/script/helpers');
-var items = require('habitrpg-shared/script/items');
+var shared = require('habitrpg-shared');
var User = require('./../models/user').model;
var Group = require('./../models/group').model;
var api = module.exports;
@@ -208,7 +206,7 @@ api.postChat = function(req, res, next) {
var user = res.locals.user
var group = res.locals.group;
var message = {
- id: helpers.uuid(),
+ id: shared.uuid(),
uuid: user._id,
contributor: user.contributor && user.contributor.toObject(),
backer: user.backer && user.backer.toObject(),
diff --git a/src/controllers/user.js b/src/controllers/user.js
index a2478e0929..039238e9e0 100644
--- a/src/controllers/user.js
+++ b/src/controllers/user.js
@@ -5,9 +5,7 @@ var ipn = require('paypal-ipn');
var _ = require('lodash');
var nconf = require('nconf');
var async = require('async');
-var algos = require('habitrpg-shared/script/algos');
-var helpers = require('habitrpg-shared/script/helpers');
-var items = require('habitrpg-shared/script/items');
+var shared = require('habitrpg-shared');
var validator = require('validator');
var check = validator.check;
var sanitize = validator.sanitize;
@@ -58,12 +56,6 @@ api.verifyTaskExists = function(req, res, next) {
return next();
};
-function addTask(user, task) {
- task = helpers.taskDefaults(task);
- user[task.type+'s'].unshift(task);
- return task;
-}
-
/*
API Routes
---------------
@@ -73,7 +65,7 @@ function addTask(user, task) {
This is called form deprecated.coffee's score function, and the req.headers are setup properly to handle the login
Export it also so we can call it from deprecated.coffee
*/
-api.scoreTask = function(req, res, next) {
+api.score = function(req, res, next) {
var id = req.params.id,
direction = req.params.direction,
user = res.locals.user,
@@ -106,9 +98,9 @@ api.scoreTask = function(req, res, next) {
if (task.type === 'daily' || task.type === 'todo') {
task.completed = direction === 'up';
}
- task = addTask(user, task);
+ task = user.ops.addTask({body:task});
}
- var delta = algos.score(user, task, direction);
+ var delta = user.ops.score({params:{id:task.id, direction:direction}});
//user.markModified('flags');
user.save(function(err, saved) {
if (err) return res.json(500, {err: err});
@@ -146,46 +138,35 @@ api.getTask = function(req, res, next) {
* Delete Task
*/
api.deleteTask = function(req, res, next) {
- var user = res.locals.user;
- user.deleteTask(res.locals.task.id);
- user.save(function(err) {
- if (err) return res.json(500, {err: err});
- res.send(204);
- });
+ api.verifyTaskExists(req, res, function(){
+ var user = res.locals.user;
+ user.deleteTask(res.locals.task.id);
+ user.save(function(err) {
+ if (err) return res.json(500, {err: err});
+ res.send(204);
+ });
+ })
};
/*
Update Task
*/
-api.updateTask = function(req, res, next) {
- var user = res.locals.user;
- var tid = req.params.id;
- var task = user.tasks[req.params.id];
- _.merge(task, req.body);
- user.save(function(err, saved) {
- if (err) return res.json(500, {err: err})
- return res.json(200, task);
- });
-};
-api.createTask = function(req, res, next) {
- var user = res.locals.user;
- var task = addTask(user, req.body);
- user.save(function(err, saved) {
- if (err) return res.json(500, {err: err});
- return res.json(201, task);
- });
-};
+// api.updateTask // handled in Shared.ops
+
+// api.addTask // handled in Shared.ops
api.sortTask = function(req, res, next) {
- var id = req.params.id;
- var to = req.body.to, from = req.body.from, type = req.body.type;
- var user = res.locals.user;
- user[type+'s'].splice(to, 0, user[type+'s'].splice(from, 1)[0]);
- user.save(function(err, saved) {
- if (err) return res.json(500, {err: err});
- return res.json(200, saved.toJSON()[type+'s']);
- });
+ api.verifyTaskExists(req, res, function(){
+ var id = req.params.id;
+ var to = req.body.to, from = req.body.from, type = req.body.type;
+ var user = res.locals.user;
+ user[type+'s'].splice(to, 0, user[type+'s'].splice(from, 1)[0]);
+ user.save(function(err, saved) {
+ if (err) return res.json(500, {err: err});
+ return res.json(200, saved.toJSON()[type+'s']);
+ });
+ })
};
api.clearCompleted = function(req, res, next) {
@@ -202,22 +183,7 @@ api.clearCompleted = function(req, res, next) {
Items
------------------------------------------------------------------------
*/
-api.buy = function(req, res, next) {
- var user = res.locals.user;
- var key = req.params.key;
- if (key !== 'potion' && !items.items.gear.flat[key]) {
- return res.json(400, {err: ":item must be a supported key, see https://github.com/HabitRPG/habitrpg-shared/blob/master/script/items.coffee"});
- }
- var hasEnough = items.buyItem(user, items.items.gear.flat[key]);
- if (hasEnough) {
- return user.save(function(err, saved) {
- if (err) return res.json(500, {err: err});
- return res.json(200, saved.toJSON().items);
- });
- } else {
- return res.json(200, {err: "Not enough GP"});
- }
-};
+// api.buy // handled in Shard.ops
/*
------------------------------------------------------------------------
@@ -230,7 +196,7 @@ api.buy = function(req, res, next) {
*/
api.getUser = function(req, res, next) {
var user = res.locals.user.toJSON();
- user.stats.toNextLevel = algos.tnl(user.stats.lvl);
+ user.stats.toNextLevel = shared.tnl(user.stats.lvl);
user.stats.maxHealth = 50;
delete user.apiToken;
if (user.auth) {
@@ -249,7 +215,7 @@ api.getUser = function(req, res, next) {
* Note: custom is for 3rd party apps
*/
acceptablePUTPaths = _.reduce(require('./../models/user').schema.paths, function(m,v,leaf){
- var found= _.find('tasks achievements filters flags invitations items lastCron party preferences profile stats tags custom'.split(' '), function(root){
+ var found= _.find('tasks achievements filters flags invitations lastCron party preferences profile stats tags'.split(' '), function(root){
return leaf.indexOf(root) == 0;
});
if (found) m[leaf]=true;
@@ -263,14 +229,14 @@ acceptablePUTPaths['tasks']=true; // and for now, let them fully set tasks.* (fo
* PUT /user {'stats.hp':50, 'tasks.TASK_ID.repeat.m':false}
* See acceptablePUTPaths for which user paths are supported
*/
-api.updateUser = function(req, res, next) {
+api.update = function(req, res, next) {
var user = res.locals.user;
var errors = [];
if (_.isEmpty(req.body)) return res.json(200, user);
_.each(req.body, function(v, k) {
if (acceptablePUTPaths[k])
- helpers.dotSet(k, v, user);
+ user.fns.dotSet(k, v);
else
errors.push("path `" + k + "` was not saved, as it's a protected path. Make sure to send `PUT /api/v1/user` request bodies as `{'set.this.path':value}` instead of `{set:{this:{path:value}}}`");
return true;
@@ -284,7 +250,7 @@ api.updateUser = function(req, res, next) {
api.cron = function(req, res, next) {
var user = res.locals.user;
- algos.cron(user);
+ shared.cron(user);
if (user.isModified()) {
res.locals.wasModified = true;
user.auth.timestamps.loggedin = new Date();
@@ -292,15 +258,6 @@ api.cron = function(req, res, next) {
user.save(next);
};
-api.revive = function(req, res, next) {
- var user = res.locals.user;
- algos.revive(user);
- user.save(function(err, saved) {
- if (err) return res.json(500, {err: err});
- return res.json(200, saved);
- });
-};
-
api.reroll = function(req, res, next) {
var user = res.locals.user;
if (user.balance < 1) return res.json(401, {err: "Not enough tokens."});
@@ -353,36 +310,7 @@ api['delete'] = function(req, res) {
------------------------------------------------------------------------
*/
-api.unlock = function(req, res) {
- var user = res.locals.user;
- var path = req.query.path;
- var fullSet = ~path.indexOf(',');
-
- // 5G per set, 2G per individual
- cost = fullSet ? 1.25 : 0.5;
-
- if (user.balance < cost)
- return res.json(401, {err: 'Not enough gems'});
-
- if (fullSet) {
- var paths = path.split(',');
- _.each(paths, function(p){
- helpers.dotSet('purchased.' + p, true, user);
- });
- } else {
- if (helpers.dotGet('purchased.' + path, user) === true)
- return res.json(401, {err: 'User already purchased that'});
- helpers.dotSet('purchased.' + path, true, user);
- }
-
- user.balance -= cost;
- user._v++;
- user.markModified('purchased');
- user.save(function(err, saved){
- if (err) res.json(500, {err:err});
- res.send(200);
- })
-}
+// api.unlock // see Shared.ops
/*
------------------------------------------------------------------------
@@ -492,7 +420,7 @@ api.deleteTag = function(req, res){
api.cast = function(req, res) {
var user = res.locals.user;
var type = req.body.type, target = req.body.target;
- var spell = items.items.spells[user.stats.class][req.params.spell];
+ var spell = shared.content.spells[user.stats.class][req.params.spell];
var done = function(){
var err = arguments[0];
@@ -548,6 +476,28 @@ api.cast = function(req, res) {
}
}
+/**
+ * All other user.ops which can easily be mapped to habitrpg-shared/index.coffee, not requiring custom API-wrapping
+ */
+_.each(shared.wrap({}).ops, function(op,k){
+ if (!api[k]) {
+ api[k] = function(req, res, next) {
+ var user = res.locals.user;
+ async.series([
+ function(cb){ user.ops[k](req, cb) },
+ function(cb){ user.save(cb) },
+ ], function(err){
+ if (err) {
+ // If we want to send something other than 500, pass err as {code: 200, message: "Not enough GP"}
+ if (err.code) return res.json(err.code, err.message);
+ return res.json(500,{err:err});
+ }
+ return res.send(200);
+ })
+ }
+ }
+})
+
/*
------------------------------------------------------------------------
Batch Update
@@ -558,78 +508,28 @@ api.batchUpdate = function(req, res, next) {
var user = res.locals.user;
var oldSend = res.send;
var oldJson = res.json;
- var performAction = function(action, cb) {
- // TODO come up with a more consistent approach here. like:
- // req.body=action.data; delete action.data; _.defaults(req.params, action)
- // Would require changing action.dir on mobile app
- req.params.id = action.data && action.data.id;
- req.params.direction = action.dir;
- req.params.type = action.type;
- req.params.key = action.key;
- req.body = action.data;
+ var callOp = function(_req, cb) {
res.send = res.json = function(code, data) {
- if (_.isNumber(code) && code >= 400) {
- console.error({
- code: code,
- data: data
- });
- }
+ if (_.isNumber(code) && code >= 400)
+ console.error({code: code, data: data});
//FIXME send error messages down
return cb();
};
- switch (action.op) {
- case "score":
- api.scoreTask(req, res);
- break;
- case "buy":
- api.buy(req, res);
- break;
- case "sortTask":
- api.verifyTaskExists(req, res, function() {
- api.sortTask(req, res);
- });
- break;
- case "addTask":
- api.createTask(req, res);
- break;
- case "delTask":
- api.verifyTaskExists(req, res, function() {
- api.deleteTask(req, res);
- });
- break;
- case "set":
- api.updateUser(req, res);
- break;
- case "delTag":
- api.deleteTag(req, res);
- break;
- case "revive":
- api.revive(req, res);
- break;
- case "clear-completed":
- api.clearCompleted(req, res);
- break;
- case "reroll":
- api.reroll(req, res);
- break;
- default:
- cb();
- break;
- }
+ api[_req.op](_req, res);
};
// Setup the array of functions we're going to call in parallel with async
- var actions = _.transform(req.body || [], function(result, action) {
- if (!_.isEmpty(action)) {
+ var ops = _.transform(req.body || [], function(result, _req) {
+ if (!_.isEmpty(_req)) {
result.push(function(cb) {
- performAction(action, cb);
+ callOp(_req, cb);
});
}
});
// call all the operations, then return the user object to the requester
- async.series(actions, function(err) {
+ async.series(ops, function(err) {
res.json = oldJson;
res.send = oldSend;
if (err) return res.json(500, {err: err});
diff --git a/src/models/challenge.js b/src/models/challenge.js
index 40f2ddd0c9..aab2833bc4 100644
--- a/src/models/challenge.js
+++ b/src/models/challenge.js
@@ -1,12 +1,12 @@
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
-var helpers = require('habitrpg-shared/script/helpers');
+var shared = require('habitrpg-shared');
var _ = require('lodash');
var TaskSchemas = require('./task');
var Group = require('./group').model;
var ChallengeSchema = new Schema({
- _id: {type: String, 'default': helpers.uuid},
+ _id: {type: String, 'default': shared.uuid},
name: String,
shortName: String,
description: String,
diff --git a/src/models/group.js b/src/models/group.js
index 093ca0ae83..b8a7a428b3 100644
--- a/src/models/group.js
+++ b/src/models/group.js
@@ -1,10 +1,10 @@
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
-var helpers = require('habitrpg-shared/script/helpers');
+var shared = require('habitrpg-shared');
var _ = require('lodash');
var GroupSchema = new Schema({
- _id: {type: String, 'default': helpers.uuid},
+ _id: {type: String, 'default': shared.uuid},
name: String,
description: String,
leader: {type: String, ref: 'User'},
diff --git a/src/models/task.js b/src/models/task.js
index 67d32929e9..f56c8fb63b 100644
--- a/src/models/task.js
+++ b/src/models/task.js
@@ -6,7 +6,7 @@
// ------------
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
-var helpers = require('habitrpg-shared/script/helpers');
+var shared = require('habitrpg-shared');
var _ = require('lodash');
// Task Schema
@@ -14,7 +14,7 @@ var _ = require('lodash');
var TaskSchema = {
//_id:{type: String,'default': helpers.uuid},
- id: {type: String,'default': helpers.uuid},
+ id: {type: String,'default': shared.uuid},
text: String,
notes: {type: String, 'default': ''},
tags: {type: Schema.Types.Mixed, 'default': {}}, //{ "4ddf03d9-54bd-41a3-b011-ca1f1d2e9371" : true },
diff --git a/src/models/user.js b/src/models/user.js
index 10e548d11e..152f00d285 100644
--- a/src/models/user.js
+++ b/src/models/user.js
@@ -6,8 +6,7 @@
// ------------
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
-var helpers = require('habitrpg-shared/script/helpers');
-var items = require('habitrpg-shared/script/items');
+var shared = require('habitrpg-shared');
var _ = require('lodash');
var TaskSchemas = require('./task');
var Challenge = require('./challenge').model;
@@ -15,23 +14,23 @@ var Challenge = require('./challenge').model;
// User Schema
// -----------
-var eggPotionMapping = _.transform(items.items.eggs, function(m, egg){
- _.defaults(m, _.transform(items.items.hatchingPotions, function(m2, pot){
+var eggPotionMapping = _.transform(shared.content.eggs, function(m, egg){
+ _.defaults(m, _.transform(shared.content.hatchingPotions, function(m2, pot){
m2[egg.name + '-' + pot.name] = true;
}));
})
-var specialPetsMapping = items.items.specialPets; // may need to revisit if we add additional information about the special pets
+var specialPetsMapping = shared.content.specialPets; // may need to revisit if we add additional information about the special pets
var UserSchema = new Schema({
// ### UUID and API Token
_id: {
type: String,
- 'default': helpers.uuid
+ 'default': shared.uuid
},
apiToken: {
type: String,
- 'default': helpers.uuid
+ 'default': shared.uuid
},
// ### Mongoose Update Object
@@ -109,7 +108,7 @@ var UserSchema = new Schema({
},
items: {
gear: {
- owned: _.transform(items.items.gear.flat, function(m,v,k){
+ owned: _.transform(shared.content.gear.flat, function(m,v,k){
m[v.key] = {type: Boolean};
if (v.key.match(/[weapon|armor|head|shield]_warrior_0/))
m[v.key]['default'] = true;
@@ -149,19 +148,19 @@ var UserSchema = new Schema({
// 'PandaCub': 0, // 0 indicates "doesn't own"
// 'Wolf': 5 // Number indicates "stacking"
// }
- eggs: _.transform(items.items.eggs, function(m,v,k){ m[k] = Number; }),
+ eggs: _.transform(shared.content.eggs, function(m,v,k){ m[k] = Number; }),
// hatchingPotions: {
// 'Desert': 0, // 0 indicates "doesn't own"
// 'CottonCandyBlue': 5 // Number indicates "stacking"
// }
- hatchingPotions: _.transform(items.items.hatchingPotions, function(m,v,k){ m[k] = Number; }),
+ hatchingPotions: _.transform(shared.content.hatchingPotions, function(m,v,k){ m[k] = Number; }),
// Food: {
// 'Watermelon': 0, // 0 indicates "doesn't own"
// 'RottenMeat': 5 // Number indicates "stacking"
// }
- food: _.transform(items.items.food, function(m,v,k){ m[k] = Number; }),
+ food: _.transform(shared.content.food, function(m,v,k){ m[k] = Number; }),
// mounts: {
// 'Wolf-Desert': true,
@@ -281,16 +280,30 @@ UserSchema.methods.toJSON = function() {
return doc;
};
-UserSchema.virtual('tasks').get(function () {
- var tasks = this.habits.concat(this.dailys).concat(this.todos).concat(this.rewards);
- var tasks = _.object(_.pluck(tasks,'id'), tasks);
- return tasks;
-});
+//UserSchema.virtual('tasks').get(function () {
+// var tasks = this.habits.concat(this.dailys).concat(this.todos).concat(this.rewards);
+// var tasks = _.object(_.pluck(tasks,'id'), tasks);
+// return tasks;
+//});
- // FIXME - since we're using special @post('init') above, we need to flag when the original path was modified.
- // Custom setter/getter virtuals?
+UserSchema.post('init', function(doc){
+ shared.wrap(doc);
+})
UserSchema.pre('save', function(next) {
+
+ // Populate new users with default content
+ if (this.isNew){
+ //TODO for some reason this doesn't work here: `_.merge(this, shared.content.userDefaults);`
+ this.habits = shared.content.userDefaults.habits;
+ this.dailys = shared.content.userDefaults.dailys;
+ this.todos = shared.content.userDefaults.todos;
+ this.rewards = shared.content.userDefaults.rewards;
+ this.tags = shared.content.userDefaults.tags;
+ // tasks automatically get id=helpers.uuid() from TaskSchema id.default, but tags are Schema.Types.Mixed - so we need to manually invoke here
+ _.each(this.tags, function(tag){tag.id = shared.uuid();})
+ }
+
//this.markModified('tasks');
if (_.isNaN(this.preferences.dayStart) || this.preferences.dayStart < 0 || this.preferences.dayStart > 24) {
this.preferences.dayStart = 0;
@@ -308,7 +321,7 @@ UserSchema.pre('save', function(next) {
// Actually, can this be used as an attr default? (schema {type: ..., 'default': function(){}})
this.stats.points = this.stats.lvl - (this.stats.con + this.stats.str + this.stats.per + this.stats.int);
- var petCount = helpers.countPets(_.reduce(this.items.pets,function(m,v){
+ var petCount = shared.countPets(_.reduce(this.items.pets,function(m,v){
//HOTFIX - Remove when solution is found, the first argument passed to reduce is a function
if(_.isFunction(v)) return m;
return m+(v?1:0)},0), this.items.pets);
diff --git a/src/routes/api.js b/src/routes/api.js
index f63b8b6fe5..5bee5207fd 100644
--- a/src/routes/api.js
+++ b/src/routes/api.js
@@ -19,7 +19,6 @@ var middleware = require('../middleware');
$ mocha test/user.mocha.coffee
*/
-var verifyTaskExists = user.verifyTaskExists
var cron = user.cron;
router.get('/status', function(req, res) {
@@ -32,16 +31,16 @@ router.get('/status', function(req, res) {
router.get('/export/history',auth.auth,dataexport.history); //[todo] encode data output options in the data controller and use these to build routes
/* Scoring*/
-router.post('/user/task/:id/:direction', auth.auth, cron, user.scoreTask);
-router.post('/user/tasks/:id/:direction', auth.auth, cron, user.scoreTask);
+router.post('/user/task/:id/:direction', auth.auth, cron, user.score);
+router.post('/user/tasks/:id/:direction', auth.auth, cron, user.score);
/* Tasks*/
router.get('/user/tasks', auth.auth, cron, user.getTasks);
router.get('/user/task/:id', auth.auth, cron, user.getTask);
-router.put('/user/task/:id', auth.auth, cron, verifyTaskExists, user.updateTask);
-router["delete"]('/user/task/:id', auth.auth, cron, verifyTaskExists, user.deleteTask);
-router.post('/user/task', auth.auth, cron, user.createTask);
-router.put('/user/task/:id/sort', auth.auth, cron, verifyTaskExists, user.sortTask);
+router.put('/user/task/:id', auth.auth, cron, user.updateTask);
+router["delete"]('/user/task/:id', auth.auth, cron, user.deleteTask);
+router.post('/user/task', auth.auth, cron, user.addTask);
+router.put('/user/task/:id/sort', auth.auth, cron, user.sortTask);
router.post('/user/clear-completed', auth.auth, cron, user.clearCompleted);
router.post('/user/task/:id/unlink', auth.auth, challenges.unlink); // removing cron since they may want to remove task first
if (nconf.get('NODE_ENV') == 'development') {
@@ -53,7 +52,7 @@ router.post('/user/buy/:key', auth.auth, cron, user.buy);
/* User*/
router.get('/user', auth.auth, cron, user.getUser);
-router.put('/user', auth.auth, cron, user.updateUser);
+router.put('/user', auth.auth, cron, user.update);
router.post('/user/revive', auth.auth, cron, user.revive);
router.post('/user/batch-update', middleware.forceRefresh, auth.auth, cron, user.batchUpdate);
router.post('/user/reroll', auth.auth, cron, user.reroll);
diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade
index c1fee38b2c..da2a33522c 100644
--- a/views/options/inventory/inventory.jade
+++ b/views/options/inventory/inventory.jade
@@ -9,7 +9,7 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
li.customize-menu
menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {base:"Base", warrior:"Warrior", wizard:"Wizard", rogue:"Rogue", special:"Special"}', ng-show='gear[klass]')
div(ng-repeat='item in gear[klass]')
- button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='equip(user,item)', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}')
+ button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({query:{key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}')
label.checkbox.inline
input(type="checkbox", ng-model="user.preferences.costume")
| Use Costume
@@ -17,22 +17,22 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
li.customize-menu(ng-if='user.preferences.costume')
menu.pets-menu(label='{{label}}', ng-repeat='(klass,label) in {base:"Base", warrior:"Warrior", wizard:"Wizard", rogue:"Rogue", special:"Special"}', ng-show='gear[klass]')
div(ng-repeat='item in gear[klass]')
- button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='equip(user,item, true)', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}')
+ button.customize-option(popover='{{item.notes}}', popover-title='{{item.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='user.ops.equip({query:{type:"costume", key:item.key}})', class='shop_{{item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}')
li.customize-menu
menu.pets-menu(label='Eggs ({{eggCount}})')
p(ng-show='eggCount < 1') You don't have any eggs.
div(ng-repeat='(egg,points) in ownedItems(user.items.eggs)')
//TODO move positioning this styling to css
- button.customize-option(popover='{{Items.eggs[egg].notes}}', popover-title='{{Items.eggs[egg].text}} Egg', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !user.items.pets[egg+"-"+selectedPotion.name]}')
+ button.customize-option(popover='{{Content.eggs[egg].notes}}', popover-title='{{Content.eggs[egg].text}} Egg', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseEgg(egg)', class='Pet_Egg_{{egg}}', ng-class='{selectableInventory: selectedPotion && !user.items.pets[egg+"-"+selectedPotion.name]}')
.badge.badge-info.stack-count {{points}}
- //-p {{Items.eggs[egg].text}}
+ //-p {{Content.eggs[egg].text}}
li.customize-menu
menu.hatchingPotion-menu(label='Hatching Potions ({{potCount}})')
p(ng-show='potCount < 1') You don't have any hatching potions.
div(ng-repeat='(pot,points) in ownedItems(user.items.hatchingPotions)')
- button.customize-option(popover='{{Items.hatchingPotions[pot].notes}}', popover-title='{{Items.hatchingPotions[pot].text}} Potion', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !user.items.pets[selectedEgg.name+"-"+pot]}')
+ button.customize-option(popover='{{Content.hatchingPotions[pot].notes}}', popover-title='{{Content.hatchingPotions[pot].text}} Potion', popover-trigger='mouseenter', popover-placement='right', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !user.items.pets[selectedEgg.name+"-"+pot]}')
.badge.badge-info.stack-count {{points}}
//-p {{pot}}
@@ -40,7 +40,7 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
menu.pets-menu(label='Food ({{foodCount}})')
p(ng-show='foodCount < 1') You don't have any food.
div(ng-repeat='(food,points) in ownedItems(user.items.food)')
- button.customize-option(popover='{{Items.food[food].notes}}', popover-title='{{Items.food[food].text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
+ button.customize-option(popover='{{Content.food[food].notes}}', popover-title='{{Content.food[food].text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
.badge.badge-info.stack-count {{points}}
//-p {{food}}
@@ -70,7 +70,7 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
menu.inventory-list(type='list')
li.customize-menu
menu.pets-menu(label='Eggs')
- div(ng-repeat='egg in Items.eggs')
+ div(ng-repeat='egg in Content.eggs')
button.customize-option(popover='{{egg.notes}}', popover-title='{{egg.text}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='buy("egg", egg)', class='Pet_Egg_{{egg.name}}')
p
| {{egg.value}}
@@ -78,7 +78,7 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
li.customize-menu
menu.pets-menu(label='Hatching Potions')
- div(ng-repeat='pot in Items.hatchingPotions')
+ div(ng-repeat='pot in Content.hatchingPotions')
button.customize-option(popover='{{pot.notes}}', popover-title='{{pot.text}} Potion', popover-trigger='mouseenter', popover-placement='left', ng-click='buy("hatchingPotion", pot)', class='Pet_HatchingPotion_{{pot.name}}')
p
| {{pot.value}}
@@ -86,7 +86,7 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
li.customize-menu
menu.pets-menu(label='Food')
- div(ng-repeat='food in Items.food')
+ div(ng-repeat='food in Content.food')
button.customize-option(popover='{{food.notes}}', popover-title='{{food.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='buy("food", food)', class='Pet_Food_{{food.name}}')
p
| {{food.value}}
diff --git a/views/options/inventory/stable.jade b/views/options/inventory/stable.jade
index bc90d34ba0..e706713c63 100644
--- a/views/options/inventory/stable.jade
+++ b/views/options/inventory/stable.jade
@@ -26,9 +26,9 @@ script(type='text/ng-template', id='partials/options.inventory.stable.mounts.htm
Shall I bring you your steed, {{user.profile.name}}? Click a mount to saddle up.
h4 {{mountCount}} / {{totalPets}} Mounts Tamed
menu.pets(type='list')
- li.customize-menu(ng-repeat='egg in Items.eggs')
+ li.customize-menu(ng-repeat='egg in Content.eggs')
menu
- div(ng-repeat='potion in Items.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.mountText}}', popover-placement='bottom', ng-init='mount = egg.name+"-"+potion.name')
+ div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.mountText}}', popover-placement='bottom', ng-init='mount = egg.name+"-"+potion.name')
button(class="pet-button Mount_Head_{{mount}}", ng-show='user.items.mounts[mount]', ng-class='{active: user.items.currentMount == mount}', ng-click='chooseMount(egg.name, potion.name)')
//div(class='Mount_Head_{{mount}}')
button(class="pet-button pet-not-owned", ng-hide='user.items.mounts[mount]')
@@ -59,9 +59,9 @@ script(type='text/ng-template', id='partials/options.inventory.stable.pets.html'
h4 {{petCount}} / {{totalPets}} Pets Found
menu.pets(type='list')
- li.customize-menu(ng-repeat='egg in Items.eggs')
+ li.customize-menu(ng-repeat='egg in Content.eggs')
menu
- div(ng-repeat='potion in Items.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.text}}', popover-placement='bottom', ng-init='pet = egg.name+"-"+potion.name')
+ div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.text}}', popover-placement='bottom', ng-init='pet = egg.name+"-"+potion.name')
button(class="pet-button Pet-{{pet}}", ng-if='user.items.pets[pet]>0', ng-class='{active: user.items.currentPet == pet, selectableInventory: selectedFood}', ng-click='choosePet(egg.name, potion.name)')
.progress(ng-class='{"progress-success": user.items.pets[pet]<50}')
.bar(style="width: {{user.items.pets[pet]/.5}}%;")
@@ -85,7 +85,7 @@ script(type='text/ng-template', id='partials/options.inventory.stable.pets.html'
li.customize-menu
menu.pets-menu(label='Food')
div(ng-repeat='(food,points) in ownedItems(user.items.food)')
- button.customize-option(popover-append-to-body='true', popover='{{Items.food[food].notes}}', popover-title='{{Items.food[food].text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
+ button.customize-option(popover-append-to-body='true', popover='{{Content.food[food].notes}}', popover-title='{{Content.food[food].text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
.badge.badge-info.stack-count {{points}}
// Remove this once we have images in
- p {{Items.food[food].text}}
+ p {{Content.food[food].text}}
diff --git a/views/options/profile.jade b/views/options/profile.jade
index b0d32c24a0..c0dba4bceb 100644
--- a/views/options/profile.jade
+++ b/views/options/profile.jade
@@ -6,8 +6,8 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
li.customize-menu
menu(label='Head')
menu
- button.broad_armor_base_0.customize-option(type='button', ng-click='set("preferences.size","broad")')
- button.slim_armor_base_0.customize-option(type='button', ng-click='set("preferences.size","slim")')
+ button.broad_armor_base_0.customize-option(type='button', ng-click='set({"preferences.size":"broad"})')
+ button.slim_armor_base_0.customize-option(type='button', ng-click='set({"preferences.size":"slim"})')
.span4
h3 Hair
@@ -15,60 +15,60 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
// Color
li.customize-menu
menu(label='Color')
- button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#c8c8c8;', ng-click='set("preferences.hair.color", "white")')
- button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#903a00;', ng-click='set("preferences.hair.color", "brown")')
- button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#cfb853;', ng-click='set("preferences.hair.color", "blond")')
- button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#ec720f;', ng-click='set("preferences.hair.color", "red")')
- button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#2e2e2e;', ng-click='set("preferences.hair.color", "black")')
+ button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#c8c8c8;', ng-click='set({"preferences.hair.color": "white"})')
+ button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#903a00;', ng-click='set({"preferences.hair.color": "brown"})')
+ button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#cfb853;', ng-click='set({"preferences.hair.color": "blond"})')
+ button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#ec720f;', ng-click='set({"preferences.hair.color": "red" })')
+ button(type='button', class='customize-option', style='width: 40px; height: 40px; background-color:#2e2e2e;', ng-click='set({"preferences.hair.color": "black"})')
// Bangs
li.customize-menu
menu(label='Bangs')
button(class='head_base_0 customize-option', type='button', ng-click='set("preferences.hair.bangs",0)')
- button(class='hair_bangs_1_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.bangs",1)')
- button(class='hair_bangs_2_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.bangs",2)')
- button(class='hair_bangs_3_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.bangs",3)')
+ button(class='hair_bangs_1_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.bangs":1})')
+ button(class='hair_bangs_2_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.bangs":2})')
+ button(class='hair_bangs_3_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.bangs":3})')
// Beard
li.customize-menu
menu(label='Beard')
- button(class='head_base_0 customize-option', type='button', ng-click='set("preferences.hair.beard",0)')
- button(class='hair_beard_1_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.beard",1)')
- button(class='hair_beard_2_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.beard",2)')
- button(class='hair_beard_3_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.beard",3)')
+ button(class='head_base_0 customize-option', type='button', ng-click='set({"preferences.hair.beard":0})')
+ button(class='hair_beard_1_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.beard":1})')
+ button(class='hair_beard_2_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.beard":2})')
+ button(class='hair_beard_3_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.beard":3})')
// Mustache
li.customize-menu
menu(label='Mustache')
- button(class='head_base_0 customize-option', type='button', ng-click='set("preferences.hair.mustache",0)')
- button(class='hair_mustache_1_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.mustache",1)')
- button(class='hair_mustache_2_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.mustache",2)')
+ button(class='head_base_0 customize-option', type='button', ng-click='set({"preferences.hair.mustache":0})')
+ button(class='hair_mustache_1_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.mustache":1})')
+ button(class='hair_mustache_2_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.mustache":2})')
// Base
li.customize-menu
menu(label='Base')
- button(class='head_base_0 customize-option', type='button', ng-click='set("preferences.hair.base",0)')
- button(class='hair_base_1_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.base",1)')
- button(class='hair_base_2_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.base",2)')
- button(class='hair_base_3_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.base",3)')
- button(class='hair_base_4_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.base",4)')
- button(class='hair_base_5_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.base",5)')
- button(class='hair_base_6_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.base",6)')
- button(class='hair_base_7_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.base",7)')
- button(class='hair_base_8_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set("preferences.hair.base",8)')
+ button(class='head_base_0 customize-option', type='button', ng-click='set({"preferences.hair.base":0})')
+ button(class='hair_base_1_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":1})')
+ button(class='hair_base_2_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":2})')
+ button(class='hair_base_3_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":3})')
+ button(class='hair_base_4_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":4})')
+ button(class='hair_base_5_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":5})')
+ button(class='hair_base_6_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":6})')
+ button(class='hair_base_7_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":7})')
+ button(class='hair_base_8_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":8})')
.span4
// skin
li.customize-menu
menu(label='Basic Skins')
- button.customize-option(type='button', class='skin_asian', ng-click='set("preferences.skin","asian")')
- button.customize-option(type='button', class='skin_white', ng-click='set("preferences.skin","white")')
- button.customize-option(type='button', class='skin_ea8349', ng-click='set("preferences.skin","ea8349")')
- button.customize-option(type='button', class='skin_c06534', ng-click='set("preferences.skin","c06534")')
- button.customize-option(type='button', class='skin_98461a', ng-click='set("preferences.skin","98461a")')
- button.customize-option(type='button', class='skin_black', ng-click='set("preferences.skin","black")')
- button.customize-option(type='button', class='skin_dead', ng-click='set("preferences.skin","dead")')
- button.customize-option(type='button', class='skin_orc', ng-click='set("preferences.skin","orc")')
+ button.customize-option(type='button', class='skin_asian', ng-click='set({"preferences.skin":"asian" })')
+ button.customize-option(type='button', class='skin_white', ng-click='set({"preferences.skin":"white" })')
+ button.customize-option(type='button', class='skin_ea8349', ng-click='set({"preferences.skin":"ea8349"})')
+ button.customize-option(type='button', class='skin_c06534', ng-click='set({"preferences.skin":"c06534"})')
+ button.customize-option(type='button', class='skin_98461a', ng-click='set({"preferences.skin":"98461a"})')
+ button.customize-option(type='button', class='skin_black', ng-click='set({"preferences.skin":"black" })')
+ button.customize-option(type='button', class='skin_dead', ng-click='set({"preferences.skin":"dead" })')
+ button.customize-option(type='button', class='skin_orc', ng-click='set({"preferences.skin":"orc" })')
// Rainbow Skin
h5.
@@ -83,7 +83,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
button.customize-option(type='button', class='skin_d7a9f7', ng-class='{locked: !user.purchased.skin.d7a9f7}', ng-click='unlock("skin.d7a9f7")')
button.customize-option(type='button', class='skin_800ed0', ng-class='{locked: !user.purchased.skin.800ed0}', ng-click='unlock("skin.800ed0")')
button.customize-option(type='button', class='skin_rainbow', ng-class='{locked: !user.purchased.skin.rainbow}', ng-click='unlock("skin.rainbow")')
- button.btn.btn-small.btn-primary(ng-hide='user.purchased.skin.eb052b && user.purchased.skin.f69922 && user.purchased.skin.f5d70f && user.purchased.skin.0ff591 && user.purchased.skin.2b43f6 && user.purchased.skin.d7a9f7 && user.purchased.skin.800ed0 && user.purchased.skin.rainbow', ng-click='unlock(["skin.eb052b", "skin.f69922", "skin.f5d70f", "skin.0ff591", "skin.2b43f6", "skin.d7a9f7", "skin.800ed0", "skin.rainbow"])') Unlock Set - 5
+ button.btn.btn-small.btn-primary(ng-hide='user.purchased.skin.eb052b && user.purchased.skin.f69922 && user.purchased.skin.f5d70f && user.purchased.skin.0ff591 && user.purchased.skin.2b43f6 && user.purchased.skin.d7a9f7 && user.purchased.skin.800ed0 && user.purchased.skin.rainbow', ng-click='unlock("skin.eb052b,skin.f69922,skin.f5d70f,skin.0ff591,skin.2b43f6,skin.d7a9f7,skin.800ed0,skin.rainbow")') Unlock Set - 5
// Special Events
// restore to d4df481 to see purchasing + "limited edition" code
@@ -104,11 +104,11 @@ script(id='partials/options.profile.stats.html', type='text/ng-template')
.span4.border-right(ng-show='user.stats.lvl >= 5')
h4
| {{user.stats.class}}
- a.btn.btn-danger.btn-mini(ng-click='rerollClass()') Re-roll
+ a.btn.btn-danger.btn-mini(ng-click='changeClass(null)') Re-roll
h6 Points: {{user.stats.points}}
fieldset
label.checkbox
- input(type='checkbox', ng-model='user.preferences.automaticAllocation', ng-change='set("preferences.automaticAllocation", user.preferences.automaticAllocation?true: false)')
+ input(type='checkbox', ng-model='user.preferences.automaticAllocation', ng-change='set({"preferences.automaticAllocation": user.preferences.automaticAllocation?true: false})')
| Automatic Allocation
i.icon-question-sign(popover-trigger='mouseenter', popover-placement='bottom', popover="When 'automatic' is checked, your points will be allocated to the stat representing your task focus (see Task > Edit). When unchecked, you'll have one point to allocate each level. The system makes a suggestion, but you can ignore the suggestion.")
table.table.table-striped
diff --git a/views/options/settings.jade b/views/options/settings.jade
index 50f876c201..46cf6f327e 100644
--- a/views/options/settings.jade
+++ b/views/options/settings.jade
@@ -30,8 +30,8 @@ script(type='text/ng-template', id='partials/options.settings.settings.html')
select(ng-model='language.code', ng-options='lang.code as lang.name for lang in avalaibleLanguages', ng-change='changeLanguage()')
hr
h4 Misc
- button.btn(ng-hide='user.preferences.hideHeader', ng-click='set("preferences.hideHeader",true)', popover-trigger='mouseenter', popover-placement='right', popover='Hide your avatar, Health/Experience bars, and party.') Hide Header
- button.btn(ng-show='user.preferences.hideHeader', ng-click='set("preferences.hideHeader",false)', popover-trigger='mouseenter', popover='Display your avatar, Health/Experience bars, and party.') Show Header
+ button.btn(ng-hide='user.preferences.hideHeader', ng-click='set({"preferences.hideHeader":true})', popover-trigger='mouseenter', popover-placement='right', popover='Hide your avatar, Health/Experience bars, and party.') Hide Header
+ button.btn(ng-show='user.preferences.hideHeader', ng-click='set({"preferences.hideHeader":false})', popover-trigger='mouseenter', popover='Display your avatar, Health/Experience bars, and party.') Show Header
button.btn(ng-click='showTour()', popover-trigger='mouseenter', popover='Restart the introductory tour from when you first joined HabitRPG.') Show Tour
button.btn(ng-click='showBailey()', popover-trigger='mouseenter', popover='Bring Bailey the Town Crier out of hiding so you can review past news.') Show Bailey
button.btn(ng-click='modals.restore = true', popover-trigger='mouseenter', popover='Manually change values like Health, Level, and Gold.') Fix Character Values
diff --git a/views/options/social/group.jade b/views/options/social/group.jade
index 17ef4cbde3..62f54a5a7e 100644
--- a/views/options/social/group.jade
+++ b/views/options/social/group.jade
@@ -46,7 +46,7 @@ a.pull-right.gem-wallet(popover-trigger='mouseenter', popover-title='Guild Bank'
ng-model='user.party.order',
ng-controller='ChatCtrl',
ng-options='k as v for (k , v) in partyOrderChoices',
- ng-change='set("party.order", user.party.order)'
+ ng-change='set({"party.order": user.party.order})'
)
table.table.table-striped(bindonce='group')
tr(ng-repeat='member in group.members')
diff --git a/views/shared/header/header.jade b/views/shared/header/header.jade
index ee8fde65d9..7ea8f6315f 100644
--- a/views/shared/header/header.jade
+++ b/views/shared/header/header.jade
@@ -11,15 +11,15 @@
// stat bars
.hero-stats
.meter.health(title='Health')
- .bar(style='width: {{percent(user.stats.hp, 50)}}%;')
+ .bar(style='width: {{Shared.percent(user.stats.hp, 50)}}%;')
span.meter-text
i.icon-heart
| {{user.stats.hp | number:0}} / 50
.meter.experience(title='Experience')
- .bar(style='width: {{percent(user.stats.exp,tnl(user.stats.lvl))}}%;')
+ .bar(style='width: {{Shared.percent(user.stats.exp,Shared.tnl(user.stats.lvl))}}%;')
span.meter-text
i.icon-star
- | {{user.stats.exp | number:0}} / {{tnl(user.stats.lvl) | number:0}}
+ | {{user.stats.exp | number:0}} / {{Shared.tnl(user.stats.lvl) | number:0}}
// FIXME doesn't look great here, but the "Experience" CSS title rollover covers it where it was before
span(ng-show='user.history.exp')
a(ng-click='toggleChart("exp")', tooltip='Progress')
diff --git a/views/shared/modals/achievements.jade b/views/shared/modals/achievements.jade
index c599d910e1..22cdd540c2 100644
--- a/views/shared/modals/achievements.jade
+++ b/views/shared/modals/achievements.jade
@@ -40,7 +40,7 @@ div(modal='user.flags.contributor')
{{user.profile.name}}, you awesome person! You're now a level {{user.contributor.level}} contributor for helping HabitRPG. See what prizes you've earned for your contribution!
.modal-footer
- button.btn.btn-default.cancel(ng-click='set("flags.contributor",false)') Ok
+ button.btn.btn-default.cancel(ng-click='set("{flags.contributor":false})') Ok
diff --git a/views/shared/modals/classes.jade b/views/shared/modals/classes.jade
index ae5c5c06a3..b26bcf8668 100644
--- a/views/shared/modals/classes.jade
+++ b/views/shared/modals/classes.jade
@@ -66,4 +66,4 @@
span(class='weapon_healer_6')
.modal-footer
- button.btn.btn-default.cancel(ng-click='rerollSubmit()') Select
\ No newline at end of file
+ button.btn.btn-default.cancel(ng-click='selectedClass && changeClass(selectedClass)') Select
\ No newline at end of file
diff --git a/views/shared/modals/death.jade b/views/shared/modals/death.jade
index 7069de2135..5b8c7326ed 100644
--- a/views/shared/modals/death.jade
+++ b/views/shared/modals/death.jade
@@ -9,7 +9,7 @@ div(modal='user.stats.hp <= 0', options='{backdrop:true, keyboard:false, backdro
.row-fluid
.span4
p
- a.btn.btn-danger.btn-large.notification-action(ng-click='User.revive()') Continue
+ a.btn.btn-danger.btn-large.notification-action(ng-click='user.ops.revive({})') Continue
.span8
p
| You've lost a Level, all your Gold, and a random piece of Equipment. Arise, Habiteer, and try again! Curb those negative Habits, be vigilant in completion of Dailies, and hold death at arm's length with a Health Potion if you falter!
diff --git a/views/shared/modals/pets.jade b/views/shared/modals/pets.jade
index 0a2f152d08..ccac0bd490 100644
--- a/views/shared/modals/pets.jade
+++ b/views/shared/modals/pets.jade
@@ -10,7 +10,7 @@ div(modal='modals.dropsEnabled')
p
span.item-drop-icon(class='Pet_Egg_Wolf', style='margin-left: 0px')
span.
- You've unlocked the Drop System! Now when you complete tasks, you have a small chance of finding an item. You just found a {{Items.eggs.Wolf.text}} Egg! {{Items.eggs.Wolf.notes}}
+ You've unlocked the Drop System! Now when you complete tasks, you have a small chance of finding an item. You just found a {{Content.eggs.Wolf.text}} Egg! {{Content.eggs.Wolf.notes}}
br
p.
If you've got your eye on a pet, but can't wait any longer for it to drop, use Gems in Options > Inventory to buy one!
diff --git a/views/shared/profiles/stats.jade b/views/shared/profiles/stats.jade
index 1552d4cc02..e0ff5465ae 100644
--- a/views/shared/profiles/stats.jade
+++ b/views/shared/profiles/stats.jade
@@ -23,7 +23,7 @@ p
| : {{profile.stats.lvl}}
p
strong Experience
- | : {{profile.stats.exp | number:0}} / {{tnl(profile.stats.lvl)}}
+ | : {{profile.stats.exp | number:0}} / {{Shared.tnl(profile.stats.lvl)}}
p
strong Strength
| :
diff --git a/views/shared/tasks/lists.jade b/views/shared/tasks/lists.jade
index ec09f0a17b..82ed6e93a7 100644
--- a/views/shared/tasks/lists.jade
+++ b/views/shared/tasks/lists.jade
@@ -18,10 +18,10 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
// Gold & Gems
span.option-box.pull-right.wallet(bo-if='main && list.type=="reward"')
.money
- | {{gold(user.stats.gp)}}
+ | {{Shared.gold(user.stats.gp)}}
span.shop_gold(tooltip='Gold')
.money
- | {{silver(user.stats.gp)}}
+ | {{Shared.silver(user.stats.gp)}}
span.shop_silver(tooltip='Silver')
// Header
@@ -62,7 +62,7 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
// Spells
ul.items(ng-if='main && list.type=="reward" && user.stats.class')
- li.task.reward-item(ng-repeat='(k,spell) in Items.spells[user.stats.class]', ng-show='user.stats.lvl >= spell.lvl')
+ li.task.reward-item(ng-repeat='(k,spell) in Content.spells[user.stats.class]', ng-show='user.stats.lvl >= spell.lvl')
.task-meta-controls
span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{spell.notes}}', popover-title='{{spell.text}}')
i.icon-comment
diff --git a/views/shared/tasks/task.jade b/views/shared/tasks/task.jade
index 55c87fbaaa..770c643a1a 100644
--- a/views/shared/tasks/task.jade
+++ b/views/shared/tasks/task.jade
@@ -1,4 +1,4 @@
-li(bindonce='list', ng-repeat='task in obj[list.type+"s"]', class='task {{taskClasses(task, user.filters, user.preferences.dayStart, user.lastCron, list.showCompleted, main)}}', ng-click='spell && castEnd(task, "task", $event)', ng-class='{"cast-target":spell}')
+li(bindonce='list', ng-repeat='task in obj[list.type+"s"]', class='task {{Shared.taskClasses(task, user.filters, user.preferences.dayStart, user.lastCron, list.showCompleted, main)}}', ng-click='spell && castEnd(task, "task", $event)', ng-class='{"cast-target":spell}')
// right-hand side control buttons
.task-meta-controls
@@ -118,13 +118,13 @@ li(bindonce='list', ng-repeat='task in obj[list.type+"s"]', class='task {{taskCl
legend.option-title Repeat
.task-controls.tile-group.repeat-days(bindonce)
// note, does not use data-toggle="buttons-checkbox" - it would interfere with our own click binding
- button.task-action-btn.tile(ng-class='{active: task.repeat.su}', type='button', ng-click='task.challenge.id || (task.repeat.su = !task.repeat.su)' bo-text='moment.weekdaysMin(0)')
- button.task-action-btn.tile(ng-class='{active: task.repeat.m}', type='button', ng-click='task.challenge.id || (task.repeat.m = !task.repeat.m)' bo-text='moment.weekdaysMin(1)')
- button.task-action-btn.tile(ng-class='{active: task.repeat.t}', type='button', ng-click='task.challenge.id || (task.repeat.t = !task.repeat.t)' bo-text='moment.weekdaysMin(2)')
- button.task-action-btn.tile(ng-class='{active: task.repeat.w}', type='button', ng-click='task.challenge.id || (task.repeat.w = !task.repeat.w)' bo-text='moment.weekdaysMin(3)')
- button.task-action-btn.tile(ng-class='{active: task.repeat.th}', type='button', ng-click='task.challenge.id || (task.repeat.th = !task.repeat.th)' bo-text='moment.weekdaysMin(4)')
- button.task-action-btn.tile(ng-class='{active: task.repeat.f}', type='button', ng-click='task.challenge.id || (task.repeat.f= !task.repeat.f)' bo-text='moment.weekdaysMin(5)')
- button.task-action-btn.tile(ng-class='{active: task.repeat.s}', type='button', ng-click='task.challenge.id || (task.repeat.s = !task.repeat.s)' bo-text='moment.weekdaysMin(6)')
+ button.task-action-btn.tile(ng-class='{active: task.repeat.su}', type='button', ng-click='task.challenge.id || (task.repeat.su = !task.repeat.su)', bo-text='moment.weekdaysMin(0)')
+ button.task-action-btn.tile(ng-class='{active: task.repeat.m}', type='button', ng-click='task.challenge.id || (task.repeat.m = !task.repeat.m)', bo-text='moment.weekdaysMin(1)')
+ button.task-action-btn.tile(ng-class='{active: task.repeat.t}', type='button', ng-click='task.challenge.id || (task.repeat.t = !task.repeat.t)', bo-text='moment.weekdaysMin(2)')
+ button.task-action-btn.tile(ng-class='{active: task.repeat.w}', type='button', ng-click='task.challenge.id || (task.repeat.w = !task.repeat.w)', bo-text='moment.weekdaysMin(3)')
+ button.task-action-btn.tile(ng-class='{active: task.repeat.th}', type='button', ng-click='task.challenge.id || (task.repeat.th = !task.repeat.th)', bo-text='moment.weekdaysMin(4)')
+ button.task-action-btn.tile(ng-class='{active: task.repeat.f}', type='button', ng-click='task.challenge.id || (task.repeat.f= !task.repeat.f)', bo-text='moment.weekdaysMin(5)')
+ button.task-action-btn.tile(ng-class='{active: task.repeat.s}', type='button', ng-click='task.challenge.id || (task.repeat.s = !task.repeat.s)', bo-text='moment.weekdaysMin(6)')
// if Reward, pricing
fieldset.option-group.option-short(ng-if='task.type=="reward" && !task.challenge.id')