mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
[#1977] APIv2 WIP - start of a framework where operations are shared
between client & server. If the op is called on the client, it updates the user & then POSTs to the server with op of the same name. If called on server, it updates the user and user.save()s
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}});
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
]);
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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(){
|
||||
$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;
|
||||
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
|
||||
})
|
||||
return User.user.ops.changeClass({});
|
||||
}
|
||||
$scope.rerollSubmit = function(){
|
||||
var klass = $scope.selectedClass;
|
||||
var setVars = {
|
||||
"stats.class": klass,
|
||||
"flags.classSelected": true
|
||||
};
|
||||
|
||||
// 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}})
|
||||
}
|
||||
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}]);
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
var newUser = {
|
||||
auth: {
|
||||
local: {
|
||||
username: username,
|
||||
email: email,
|
||||
salt: salt
|
||||
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 = {
|
||||
user = new User({
|
||||
auth: {
|
||||
facebook: req.user,
|
||||
timestamps: {created: +new Date(), loggedIn: +new Date()}
|
||||
};
|
||||
user = new User(newUser);
|
||||
}
|
||||
});
|
||||
user.save(cb);
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,38 +138,26 @@ api.getTask = function(req, res, next) {
|
||||
* Delete Task
|
||||
*/
|
||||
api.deleteTask = function(req, res, next) {
|
||||
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) {
|
||||
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;
|
||||
@@ -186,6 +166,7 @@ api.sortTask = function(req, res, next) {
|
||||
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});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'},
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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<span class="Pet_Currency_Gem1x inline-gems"/>
|
||||
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<span class="Pet_Currency_Gem1x inline-gems"/>
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 <a href='http://habitrpg.wikia.com/wiki/Contributor_Rewards' target='_blank'>what prizes you've earned for your contribution!</a>
|
||||
|
||||
.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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -66,4 +66,4 @@
|
||||
span(class='weapon_healer_6')
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-default.cancel(ng-click='rerollSubmit()') Select
|
||||
button.btn.btn-default.cancel(ng-click='selectedClass && changeClass(selectedClass)') Select
|
||||
@@ -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!
|
||||
|
||||
@@ -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 <strong>{{Items.eggs.Wolf.text}}</strong> 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 <strong>{{Content.eggs.Wolf.text}}</strong> Egg! {{Content.eggs.Wolf.notes}}
|
||||
br
|
||||
p.
|
||||
<span class='Pet_Currency_Gem item-drop-icon'></span> If you've got your eye on a pet, but can't wait any longer for it to drop, use Gems in <strong>Options > Inventory</strong> to buy one!
|
||||
|
||||
@@ -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
|
||||
| :
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user