mounts: update all html & javascript to support UserSchema overhaul (60421a8). Also add very basic feeding & saddling mounts functionality. use progress bars to indicate pet feeding progress

This commit is contained in:
Tyler Renelle
2013-11-09 20:15:55 -08:00
parent 60421a85cc
commit 085919c000
17 changed files with 248 additions and 199 deletions

View File

@@ -4,7 +4,7 @@
"version": "0.0.0-152", "version": "0.0.0-152",
"main": "./src/server.js", "main": "./src/server.js",
"dependencies": { "dependencies": {
"habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#master", "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#mounts",
"derby-auth": "git://github.com/lefnire/derby-auth#master", "derby-auth": "git://github.com/lefnire/derby-auth#master",
"connect-mongo": "*", "connect-mongo": "*",
"passport-facebook": "~1.0.0", "passport-facebook": "~1.0.0",

View File

@@ -65,10 +65,18 @@ menu.pets div
.Pet_Currency_Gem2x {background-position: -55px -513px; width: 34px; height: 30px} .Pet_Currency_Gem2x {background-position: -55px -513px; width: 34px; height: 30px}
.Pet_Currency_Gem1x {background-position: -63px -542px; width: 19px; height: 17px} .Pet_Currency_Gem1x {background-position: -63px -542px; width: 19px; height: 17px}
.inventory-list p .inventory-list
p
//display: none //display: none
.inventory-list li li
clear:both clear:both
button.customize-option
position:relative
.stack-count
position:absolute
bottom:-6px
right:-9px
.pets-menu > div .pets-menu > div
display:inline-block display:inline-block
vertical-align:top vertical-align:top
@@ -90,6 +98,17 @@ menu.pets div
width:6em width:6em
margin-top:-.5em margin-top:-.5em
// This adds feeding progress bars to pets. If we have any issues with `menu.pets > button`, revisit
menu.pets .customize-menu
button
position: relative
.progress
width: 60%
position: absolute
bottom: -25px
left: 20%
height: 5px
.pet-button .pet-button
border: none border: none
background: none white background: none white

View File

@@ -128,7 +128,8 @@ window.habitrpg = angular.module('habitrpg',
// Options > Inventory // Options > Inventory
.state('options.inventory', { .state('options.inventory', {
url: '/inventory', url: '/inventory',
templateUrl: "partials/options.inventory.html" templateUrl: "partials/options.inventory.html",
controller: 'InventoryCtrl'
}) })
.state('options.inventory.inventory', { .state('options.inventory.inventory', {
url: '/inventory', url: '/inventory',

View File

@@ -1,18 +1,27 @@
habitrpg.controller("InventoryCtrl", ['$scope', 'User', habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL', '$http', 'Notification',
function($scope, User) { function($rootScope, $scope, User, API_URL, $http, Notification) {
var user = User.user;
// convenience vars since these are accessed frequently // convenience vars since these are accessed frequently
$scope.userEggs = User.user.items.eggs;
$scope.userHatchingPotions = User.user.items.hatchingPotions;
$scope.selectedEgg = null; // {index: 1, name: "Tiger", value: 5} $scope.selectedEgg = null; // {index: 1, name: "Tiger", value: 5}
$scope.selectedPotion = null; // {index: 5, name: "Red", value: 3} $scope.selectedPotion = null; // {index: 5, name: "Red", value: 3}
$scope.petCount = _.size(User.user.items.pets);
$scope.totalPets = _.size($scope.Items.eggs) * _.size($scope.Items.hatchingPotions);
$scope.chooseEgg = function(egg, $index){ var countItems = function(items) {
if ($scope.selectedEgg && $scope.selectedEgg.index == $index) { return _.reduce(items,function(m,v){return m+v;},0);
}
$scope.$watch('user.items.pets', function(pets){ $scope.petCount = countItems(pets); });
$scope.$watch('user.items.eggs', function(eggs){ $scope.eggCount = countItems(eggs); });
$scope.$watch('user.items.hatchingPotions', function(pots){ $scope.potCount = countItems(pots); });
$scope.chooseEgg = function(egg){
if ($scope.selectedEgg && $scope.selectedEgg.name == egg) {
return $scope.selectedEgg = null; // clicked same egg, unselect return $scope.selectedEgg = null; // clicked same egg, unselect
} }
var eggData = _.defaults({index:$index}, egg); var eggData = _.findWhere(window.habitrpgShared.items.items.eggs, {name:egg});
if (!$scope.selectedPotion) { if (!$scope.selectedPotion) {
$scope.selectedEgg = eggData; $scope.selectedEgg = eggData;
} else { } else {
@@ -20,13 +29,12 @@ habitrpg.controller("InventoryCtrl", ['$scope', 'User',
} }
} }
$scope.choosePotion = function(potion, $index){ $scope.choosePotion = function(potion){
if ($scope.selectedPotion && $scope.selectedPotion.index == $index) { if ($scope.selectedPotion && $scope.selectedPotion.name == potion) {
return $scope.selectedPotion = null; // clicked same egg, unselect return $scope.selectedPotion = null; // clicked same egg, unselect
} }
// we really didn't think through the way these things are stored and getting passed around... // we really didn't think through the way these things are stored and getting passed around...
var potionData = _.findWhere(window.habitrpgShared.items.items.hatchingPotions, {name:potion}); var potionData = _.findWhere(window.habitrpgShared.items.items.hatchingPotions, {name:potion});
potionData = _.defaults({index:$index}, potionData);
if (!$scope.selectedEgg) { if (!$scope.selectedEgg) {
$scope.selectedPotion = potionData; $scope.selectedPotion = potionData;
} else { } else {
@@ -34,54 +42,52 @@ habitrpg.controller("InventoryCtrl", ['$scope', 'User',
} }
} }
$scope.chooseFood = function(food){
$scope.selectedFood = $scope.Items.food[food];
}
$scope.sellInventory = function() { $scope.sellInventory = function() {
// TODO DRY this
if ($scope.selectedEgg) { if ($scope.selectedEgg) {
$scope.userEggs.splice($scope.selectedEgg.index, 1); user.items.eggs[$scope.selectedEgg.name]--;
User.setMultiple({ User.setMultiple({
'items.eggs': $scope.userEggs, 'items.eggs': user.items.eggs,
'stats.gp': User.user.stats.gp + $scope.selectedEgg.value 'stats.gp': User.user.stats.gp + $scope.selectedEgg.value
}); });
$scope.selectedEgg = null; $scope.selectedEgg = null;
} else if ($scope.selectedPotion) { } else if ($scope.selectedPotion) {
$scope.userHatchingPotions.splice($scope.selectedPotion.index, 1); user.items.hatchingPotions[$scope.selectedPotion.name]--;
User.setMultiple({ User.setMultiple({
'items.hatchingPotions': $scope.userHatchingPotions, 'items.hatchingPotions': user.items.hatchingPotions,
'stats.gp': User.user.stats.gp + $scope.selectedPotion.value 'stats.gp': User.user.stats.gp + $scope.selectedPotion.value
}); });
$scope.selectedPotion = null; $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
});
$scope.selectedFood = null;
} }
$scope.ownsPet = function(egg, potion){
if (!egg || !potion) return;
var pet = egg.name + '-' + potion;
return User.user.items.pets && ~User.user.items.pets.indexOf(pet)
} }
$scope.selectableInventory = function(egg, potion, $index) { $scope.ownedItems = function(inventory){
if (!egg || !potion) return; return _.pick(inventory, function(v,k){return v>0;});
// FIXME this isn't updating the view for some reason
//if ($scope.selectedEgg && $scope.selectedEgg.index == $index) return 'selectableInventory';
//if ($scope.selectedPotion && $scope.selectedPotion.index == $index) return 'selectableInventory';
if (!$scope.ownsPet(egg, potion)) return 'selectableInventory';
} }
$scope.hatch = function(egg, potion){ $scope.hatch = function(egg, potion){
if ($scope.ownsPet(egg, potion.name)){ var pet = egg.name+"-"+potion.name;
return alert("You already have that pet, hatch a different combo.") if (user.items.pets[pet])
} return alert("You already have that pet, hatch a different combo.");
var pet = egg.name + '-' + potion.name;
$scope.userEggs.splice(egg.index, 1);
$scope.userHatchingPotions.splice(potion.index, 1);
if(!User.user.items.pets) User.user.items.pets = []; var setObj = {};
User.user.items.pets.push(pet); 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.log([ User.setMultiple(setObj);
{ op: 'set', data: {'items.pets': User.user.items.pets} },
{ op: 'set', data: {'items.eggs': $scope.userEggs} },
{ op: 'set', data: {'items.hatchingPotions': $scope.userHatchingPotions} }
]);
alert("Your egg hatched! Visit your stable to equip your pet."); alert("Your egg hatched! Visit your stable to equip your pet.");
@@ -89,4 +95,68 @@ habitrpg.controller("InventoryCtrl", ['$scope', 'User',
$scope.selectedPotion = null; $scope.selectedPotion = null;
} }
}]); $scope.buy = function(type, item){
var gems = User.user.balance * 4;
if(gems < item.value) return $rootScope.modals.buyGems = true;
var string = (type == 'hatchingPotion') ? 'hatching potion' : type; // give hatchingPotion a space
var message = "Buy this " + string + " with " + item.value + " of your " + gems + " Gems?"
if(confirm(message)){
$http.post(API_URL + '/api/v1/market/buy?type=' + type, item)
.success(function(data){
User.user.items = data.items;
});
}
}
$scope.choosePet = function(egg, potion){
var pet = egg + '-' + potion;
// Feeding Pet
if ($scope.selectedFood) {
var setObj = {};
var userPets = user.items.pets;
// Saddling a pet
if ($scope.selectedFood.name == 'Saddle') {
if (userPets[pet] < 150)
return Notification.text(egg+" is not strong enough yet to saddle.");
if (!confirm('Saddle ' + pet + '?')) return;
userPets[pet] = 0;
setObj['items.mounts.' + pet] = true;
Notification.text('You have tamed '+egg+", let's go for a ride!");
} else {
if (userPets[pet] >= 150)
return Notification.text(egg+" has become very strong and wild, try using a saddle and something might happen.");
if (!confirm('Feed ' + pet + ' a ' + $scope.selectedFood.name + '?')) return;
if ($scope.selectedFood.target == potion) {
userPets[pet] += 50; // FIXME change this to 5 before we're live
Notification.text(egg+' really likes the '+$scope.selectedFood.name+'!');
} else {
userPets[pet] += 2;
Notification.text(egg+' eats the '+$scope.selectedFood.name+" but doesn't seem to enjoy it.");
}
}
setObj['items.pets.' + pet] = userPets[pet];
setObj['items.food.' + $scope.selectedFood.name] = user.items.food[$scope.selectedFood.name] - 1;
User.setMultiple(setObj);
$scope.selectedFood = null;
// Selecting Pet
} else {
var userCurrentPet = User.user.items.currentPet;
if(userCurrentPet && userCurrentPet == pet){
User.user.items.currentPet = null;
}else{
User.user.items.currentPet = pet;
}
User.set('items.currentPet', User.user.items.currentPet);
}
}
$scope.chooseMount = function(egg, potion) {
var mount = egg + '-' + potion;
User.set('items.currentMount', (user.items.currentMount == mount) ? null : mount);
}
}
]);

View File

@@ -1,37 +0,0 @@
habitrpg.controller("MarketCtrl", ['$rootScope', '$scope', 'User', 'API_URL', '$http',
function($rootScope, $scope, User, API_URL, $http) {
$scope.eggs = window.habitrpgShared.items.items.pets;
$scope.hatchingPotions = window.habitrpgShared.items.items.hatchingPotions;
$scope.userEggs = User.user.items.eggs;
$scope.userHatchingPotions = User.user.items.hatchingPotions;
$scope.buy = function(type, item){
var gems = User.user.balance * 4,
store = type === 'egg' ? $scope.userEggs : $scope.userHatchingPotions,
storePath = type === 'egg' ? 'items.eggs' : 'items.hatchingPotions'
if(gems < item.value){
return $rootScope.modals.buyGems = true;
}
var message = "Buy this " + (type == 'egg' ? 'egg' : 'hatching potion') + " with " + item.value + " of your " + gems + " Gems?"
if(confirm(message)){
$http.post(API_URL + '/api/v1/market/buy?type=' + type, item)
.success(function(data){
// don't know what's going on, but trying to work with the returned data (a) isn't updating the ui, (b) isnt'
// stickign between refreshes until a force-refresh is called (user._v--).
User.user._v--;
User.log({});
//User.user.balance = data.balance;
store.push(type === 'egg' ? item : item.name);
//$scope.items = data.items.eggs; // FIXME this isn't updating the UI
}).error(function(data){
alert(data);
console.error(data);
});
}
}
}]);

View File

@@ -43,8 +43,8 @@ habitrpg.controller('NotificationCtrl',
$rootScope.modals.achievements.ultimateGear = true; $rootScope.modals.achievements.ultimateGear = true;
}); });
$rootScope.$watch('user.items.pets.length', function(after, before){ $rootScope.$watch('user.items.pets', function(after, before){
if(after === before || after < 90) return; if(_.size(after) === _.size(before) || _.size(after) < 90) return;
User.user.achievements.beastMaster = true; User.user.achievements.beastMaster = true;
$rootScope.modals.achievements.beastMaster = true; $rootScope.modals.achievements.beastMaster = true;
}) })

View File

@@ -1,32 +0,0 @@
habitrpg.controller("PetsCtrl", ['$scope', 'User',
function($scope, User) {
$scope.userPets = User.user.items.pets;
$scope.userCurrentPet = User.user.items.currentPet;
$scope.pets = window.habitrpgShared.items.items.pets;
$scope.hatchingPotions = window.habitrpgShared.items.items.hatchingPotions;
$scope.totalPets = $scope.pets.length * $scope.hatchingPotions.length;
$scope.hasPet = function(name, potion){
if (!$scope.userPets) return false;
return _.contains($scope.userPets, name + '-' + potion) ? true : false;
}
$scope.isCurrentPet = function(name, potion){
if (!$scope.userCurrentPet || !$scope.userPets) return false;
return $scope.userCurrentPet.str === (name + '-' + potion);
}
$scope.choosePet = function(name, potion){
if($scope.userCurrentPet && $scope.userCurrentPet.str === (name + '-' + potion)){
$scope.userCurrentPet = null;
}else{
var pet = _.find($scope.pets, {name: name});
pet.modifier = potion;
pet.str = name + '-' + potion;
$scope.userCurrentPet = pet;
}
User.set('items.currentPet', $scope.userCurrentPet);
}
}]);

View File

@@ -10,6 +10,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
$rootScope.User = User; $rootScope.User = User;
$rootScope.user = User.user; $rootScope.user = User.user;
$rootScope.settings = User.settings; $rootScope.settings = User.settings;
$rootScope.Items = window.habitrpgShared.items.items;
// Angular UI Router // Angular UI Router
$rootScope.$state = $state; $rootScope.$state = $state;

View File

@@ -3,8 +3,9 @@ angular.module('habitrpg')
return function (gp) { return function (gp) {
return Math.floor(gp); return Math.floor(gp);
} }
}).filter('silver', function () { })
.filter('silver', function () {
return function (gp) { return function (gp) {
return Math.floor((gp - Math.floor(gp))*100); return Math.floor((gp - Math.floor(gp))*100);
} }
}); })

View File

@@ -96,13 +96,6 @@ angular.module('guideServices', []).
showPopover('div.rewards', 'Item Store Unlocked', html, 'left'); showPopover('div.rewards', 'Item Store Unlocked', html, 'left');
}); });
$rootScope.$watch('user.flags.petsEnabled', function(after, before) {
//TODO is this ever used? I think dropsEnabled is the one that's used
if (alreadyShown(before, after)) return;
var html = "You have unlocked Pets! You can now buy pets with Gems (note, you replenish Gems with real-life money - so chose your pets wisely!)";
showPopover('#rewardsTabs', 'Pets Unlocked', html, 'left');
});
$rootScope.$watch('user.flags.partyEnabled', function(after, before) { $rootScope.$watch('user.flags.partyEnabled', function(after, before) {
if (alreadyShown(before, after)) return; if (alreadyShown(before, after)) return;
var html = "Be social, join a party and play Habit with your friends! You'll be better at your habits with accountability partners. Click User -> Options -> Party, and follow the instructions. LFG anyone?"; var html = "Be social, join a party and play Habit with your friends! You'll be better at your habits with accountability partners. Click User -> Options -> Party, and follow the instructions. LFG anyone?";
@@ -111,10 +104,8 @@ angular.module('guideServices', []).
$rootScope.$watch('user.flags.dropsEnabled', function(after, before) { $rootScope.$watch('user.flags.dropsEnabled', function(after, before) {
if (alreadyShown(before, after)) return; if (alreadyShown(before, after)) return;
var drop = Helpers.randomVal(Items.items.pets); var eggs = User.user.items.eggs || {};
var eggs = User.user.items.eggs || []; eggs['Wolf-Base'] = 5; // This is also set on the server
eggs.push(drop); // FIXME put this on server instead
User.set('items.eggs', eggs);
$rootScope.modals.dropsEnabled = true; $rootScope.modals.dropsEnabled = true;
}); });

View File

@@ -48,9 +48,7 @@
"js/controllers/filtersCtrl.js", "js/controllers/filtersCtrl.js",
"js/controllers/userCtrl.js", "js/controllers/userCtrl.js",
"js/controllers/groupsCtrl.js", "js/controllers/groupsCtrl.js",
"js/controllers/petsCtrl.js",
"js/controllers/inventoryCtrl.js", "js/controllers/inventoryCtrl.js",
"js/controllers/marketCtrl.js",
"js/controllers/footerCtrl.js", "js/controllers/footerCtrl.js",
"js/controllers/challengesCtrl.js", "js/controllers/challengesCtrl.js",
"js/controllers/adminCtrl.js" "js/controllers/adminCtrl.js"

View File

@@ -60,9 +60,7 @@ api.updateMember = function(req, res) {
member.balance += (req.body.contributor.level - (member.contributor.level || 0))*.5 // +2 gems per tier member.balance += (req.body.contributor.level - (member.contributor.level || 0))*.5 // +2 gems per tier
} }
_.merge(member, _.pick(req.body, 'contributor')); _.merge(member, _.pick(req.body, 'contributor'));
if (!member.items.pets) member.items.pets = []; if (member.contributor.level >= 6 && !member.items.pets['Dragon-Hydra']) member.items.pets['Dragon-Hydra'] = 5;
var i = member.items.pets.indexOf('Dragon-Hydra');
if (!~i && member.contributor.level >= 6) member.items.pets.push('Dragon-Hydra');
member.save(cb); member.save(cb);
} }
], function(err, saved){ ], function(err, saved){

View File

@@ -22,17 +22,11 @@ api.marketBuy = function(req, res, next){
type = req.query.type, type = req.query.type,
item = req.body; item = req.body;
if (!_.contains(['hatchingPotion', 'egg'], req.query.type)) if (!_.contains(['hatchingPotion', 'egg', 'food'], type))
return res.json(400, {err: "Type must be in 'hatchingPotion' or 'egg'"}); return res.json(400, {err: "Type must be 'hatchingPotion', 'egg', or 'food'"});
var item; type = (type == 'food' ? type : type + 's'); // I'm stupid, we're passing up 'hatchingPotion' but we need 'hatchingPotions'
if (type == 'egg'){ if (!user.items[type][item.name]) user.items[type][item.name] = 0;
if (!user.items && !user.items.eggs) user.items.eggs = []; user.items[type][item.name]++;
user.items.eggs.push(item);
} else {
if (!user.items && !user.items.hatchingPotions) user.items.hatchingPotions = [];
user.items.hatchingPotions.push(item.name);
}
user.markModified('items'); // I still don't get when this is necessary and when not..
user.balance -= (item.value/4); user.balance -= (item.value/4);
user.save(function(err, saved){ user.save(function(err, saved){
if (err) return res.json(500, {err:err}); if (err) return res.json(500, {err:err});
@@ -270,30 +264,21 @@ api.updateUser = function(req, res, next) {
acceptableAttrs = 'tasks. achievements. filters. flags. invitations. items. lastCron party. preferences. profile. stats. tags custom.'.split(' '); acceptableAttrs = 'tasks. achievements. filters. flags. invitations. items. lastCron party. preferences. profile. stats. tags custom.'.split(' ');
_.each(req.body, function(v, k) { _.each(req.body, function(v, k) {
if ((_.find(acceptableAttrs, function(attr) { var found = _.find(acceptableAttrs, function(attr) { return k.indexOf(attr) == 0; })
return k.indexOf(attr) === 0; if (found) {
})) != null) { // if (_.isObject(v)) {
if (_.isObject(v)) { // errors.push("Value for " + k + " was an object. Be careful here, you could clobber stuff.");
errors.push("Value for " + k + " was an object. Be careful here, you could clobber stuff."); // }
}
helpers.dotSet(k, v, user); helpers.dotSet(k, v, user);
} else { } 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}}}`"); 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; return true;
}); });
return user.save(function(err) { user.save(function(err) {
if (!_.isEmpty(errors)) { if (!_.isEmpty(errors)) return res.json(500, {err: errors});
return res.json(500, { if (err) {return res.json(500, {err: err})}
err: errors res.json(200, user);
});
}
if (err) {
return res.json(500, {
err: err
});
}
return res.json(200, user);
}); });
}; };

View File

@@ -1,25 +1,38 @@
script(type='text/ng-template', id='partials/options.inventory.inventory.html') script(type='text/ng-template', id='partials/options.inventory.inventory.html')
.row-fluid(ng-controller='InventoryCtrl') .row-fluid
.span6.border-right .span6.border-right
h2 Inventory h2 Inventory
p.well Click an egg to see usable potions highlighted in green and then click one of the highlighted potions to hatch your pet. If no potions are highlighted, click that egg again to deselect it, and instead click a potion first to have the usable eggs highlighted. You can also sell unwanted drops to Alexander the Merchant. p.well Click an egg to see usable potions highlighted in green and then click one of the highlighted potions to hatch your pet. If no potions are highlighted, click that egg again to deselect it, and instead click a potion first to have the usable eggs highlighted. You can also sell unwanted drops to Alexander the Merchant.
menu.inventory-list(type='list') menu.inventory-list(type='list')
li.customize-menu li.customize-menu
menu.pets-menu(label='Eggs ({{userEggs.length}})') menu.pets-menu(label='Eggs ({{eggCount}})')
p(ng-show='userEggs.length < 1') You don't have any eggs yet. p(ng-show='user.items.eggs.length < 1') You don't have any eggs yet.
div(ng-repeat='egg in userEggs track by $index') div(ng-repeat='(egg,points) in ownedItems(user.items.eggs)')
button.customize-option(tooltip='{{egg.text}}', ng-click='chooseEgg(egg, $index)', class='Pet_Egg_{{egg.name}}', ng-class='selectableInventory(egg, selectedPotion.name, $index)') //TODO move positioning this styling to css
p {{egg.text}} button.customize-option(tooltip='{{Items.eggs[egg].text}}', 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}}
li.customize-menu li.customize-menu
menu.hatchingPotion-menu(label='Hatching Potions ({{userHatchingPotions.length}})') menu.hatchingPotion-menu(label='Hatching Potions ({{potCount}})')
p(ng-show='userHatchingPotions.length < 1') You don't have any hatching potions yet. p(ng-show='potCount < 1') You don't have any hatching potions yet.
div(ng-repeat='hatchingPotion in userHatchingPotions track by $index') div(ng-repeat='(pot,points) in ownedItems(user.items.hatchingPotions)')
button.customize-option(tooltip='{{hatchingPotion}}', ng-click='choosePotion(hatchingPotion, $index)', class='Pet_HatchingPotion_{{hatchingPotion}}', ng-class='selectableInventory(selectedEgg, hatchingPotion, $index)') button.customize-option(tooltip='{{pot}}', ng-click='choosePotion(pot)', class='Pet_HatchingPotion_{{pot}}', ng-class='{selectableInventory: selectedEgg && !user.items.pets[selectedEgg.name+"-"+pot]}')
p {{hatchingPotion}} .badge.badge-info.stack-count {{points}}
p {{pot}}
li.customize-menu
menu.food-menu(label='Food ({{foodCount}})')
p(ng-show='foodCount < 1') You don't have any food yet.
div(ng-repeat='(food,points) in ownedItems(user.items.food)')
button.customize-option(tooltip='{{food}}', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
.badge.badge-info.stack-count {{points}}
p {{food}}
.span6 .span6
h2 Market h2 Market
.row-fluid(ng-controller='MarketCtrl') .row-fluid
table.NPC-Alex-container table.NPC-Alex-container
tr tr
td td
@@ -37,19 +50,27 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
| Sell {{selectedEgg.name}} for {{selectedEgg.value}} GP | Sell {{selectedEgg.name}} for {{selectedEgg.value}} GP
button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()') button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()')
| Sell {{selectedPotion.name}} for {{selectedPotion.value}} GP | Sell {{selectedPotion.name}} for {{selectedPotion.value}} GP
button.btn.btn-primary(ng-show='selectedFood', ng-click='sellInventory()')
| Sell {{selectedFood.name}} for {{selectedFood.value}} GP
menu.inventory-list(type='list') menu.inventory-list(type='list')
li.customize-menu li.customize-menu
menu.pets-menu(label='Eggs') menu.pets-menu(label='Eggs')
div(ng-repeat='egg in eggs track by $index') div(ng-repeat='egg in Items.eggs')
button.customize-option(tooltip='{{egg.text}} - {{egg.value}} Gem(s)', ng-click='buy("egg", egg)', class='Pet_Egg_{{egg.name}}') button.customize-option(tooltip='{{egg.text}} - {{egg.value}} Gem(s)', ng-click='buy("egg", egg)', class='Pet_Egg_{{egg.name}}')
p {{egg.text}} p {{egg.text}}
li.customize-menu li.customize-menu
menu.pets-menu(label='Hatching Potions') menu.pets-menu(label='Hatching Potions')
div(ng-repeat='hatchingPotion in hatchingPotions track by $index') div(ng-repeat='pot in Items.hatchingPotions')
button.customize-option(tooltip='{{hatchingPotion.text}} - {{hatchingPotion.value}} Gem(s)', ng-click='buy("hatchingPotion", hatchingPotion)', class='Pet_HatchingPotion_{{hatchingPotion.name}}') button.customize-option(tooltip='{{pot.text}} - {{pot.value}} Gem(s)', ng-click='buy("hatchingPotion", pot)', class='Pet_HatchingPotion_{{pot.name}}')
p {{hatchingPotion.text}} p {{pot.text}}
li.customize-menu
menu.pets-menu(label='Food')
div(ng-repeat='food in Items.food')
button.customize-option(tooltip='{{food.text}} - {{food.value}} Gem(s)', ng-click='buy("food", food)', class='Pet_Food_{{food.name}}')
p {{food.text}}

View File

@@ -1,33 +1,51 @@
script(type='text/ng-template', id='partials/options.inventory.stable.html') script(type='text/ng-template', id='partials/options.inventory.stable.html')
.stable(ng-controller='PetsCtrl') .stable
.NPC-Matt .NPC-Matt
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;') .popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
.arrow .arrow
h3.popover-title h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch') Matt Boch a(target='_blank', href='http://www.kickstarter.com/profile/mattboch') Matt Boch
.popover-content .popover-content
p p.
| Welcome to the Stable! I'm Matt, the beast master. Choose a pet here to venture at your side. They aren't much help yet, but I forsee a time when they're able to Welcome to the Stable! I'm Matt, the beast master. Choose a pet here to venture at your side. They aren't much help yet, but I forsee a time when they're able to <a href='https://trello.com/card/mounts/50e5d3684fe3a7266b0036d6/221' target='_blank'>grow into powerful steeds</a>! Until that day, <a target='_blank' href='https://f.cloud.github.com/assets/2374703/164631/3ed5fa6c-78cd-11e2-8743-f65ac477b55e.png'>have a look-see</a> at all the pets you can collect.
a(href='https://trello.com/card/mounts/50e5d3684fe3a7266b0036d6/221') grow into powerful steeds h4 {{petCount}} / {{totalPets}} Pets Found
| ! Until that day,
a(target='_blank', href='https://f.cloud.github.com/assets/2374703/164631/3ed5fa6c-78cd-11e2-8743-f65ac477b55e.png') have a look-see
| at all the pets you can collect.
h4 {{userPets.length}} / {{totalPets}} Pets Found
menu.pets(type='list') menu.pets(type='list')
li.customize-menu(ng-repeat='pet in pets') li.customize-menu(ng-repeat='egg in Items.eggs')
menu menu
div(ng-repeat='potion in hatchingPotions', tooltip='{{potion.name}} {{pet.name}}') div(ng-repeat='potion in Items.hatchingPotions', tooltip='{{potion.name}} {{egg.name}}', ng-init='pet = egg.name+"-"+potion.name')
button(class="pet-button Pet-{{pet.name}}-{{potion.name}}", ng-show='hasPet(pet.name, potion.name)', ng-class="{active: isCurrentPet(pet.name, potion.name)}", ng-click='choosePet(pet.name, potion.name)') button(class="pet-button Pet-{{pet}}", ng-if='user.items.pets[pet]>0', ng-class='{active: user.items.currentPet == pet}', ng-click='choosePet(egg.name, potion.name)')
button(class="pet-button pet-not-owned", ng-hide='hasPet(pet.name, potion.name)') .progress(ng-class='{"progress-success": user.items.pets[pet]<150}')
.bar(style="width: {{user.items.pets[pet]/1.5}}%;")
button(class="pet-button pet-not-owned", ng-if='!user.items.pets[pet]')
img(src='/bower_components/habitrpg-shared/img/PixelPaw.png') img(src='/bower_components/habitrpg-shared/img/PixelPaw.png')
h4 Rare Pets h4 Rare Pets
menu menu
div div
button(ng-if='hasPet("Wolf", "Veteran")', class="pet-button Pet-Wolf-Veteran", ng-class='{active: isCurrentPet("Wolf", "Veteran")}', ng-click='choosePet("Wolf", "Veteran")', tooltip='Veteran Wolf') button(ng-if='user.items.pets["Wolf-Veteran"]', class="pet-button Pet-Wolf-Veteran", ng-class='{active: user.items.currentPet == "Wolf-Veteran")}', ng-click='choosePet("Wolf", "Veteran")', tooltip='Veteran Wolf')
button(ng-if='hasPet("Wolf", "Cerberus")', class="pet-button Pet-Wolf-Cerberus", ng-class='{active: isCurrentPet("Wolf", "Cerberus")}', ng-click='choosePet("Wolf", "Cerberus")', tooltip='Cerberus Pup') button(ng-if='user.items.pets["Wolf-Cerberus"]', class="pet-button Pet-Wolf-Cerberus", ng-class='{active: user.items.currentPet == "Wolf-Cerberus")}', ng-click='choosePet("Wolf", "Cerberus")', tooltip='Cerberus Pup')
button(ng-if='hasPet("Dragon", "Hydra")', class="pet-button Pet-Dragon-Hydra", ng-class='{active: isCurrentPet("Dragon", "Hydra")}', ng-click='choosePet("Dragon", "Hydra")', tooltip='Hydra Pet') button(ng-if='user.items.pets["Dragon-Hydra"]', class="pet-button Pet-Dragon-Hydra", ng-class='{active: user.items.currentPet == "Dragon-Hydra")}', ng-click='choosePet("Dragon", "Hydra")', tooltip='Hydra Pet')
a(target='_blank', href='https://github.com/HabitRPG/habitrpg/wiki/Contributing') a(target='_blank', href='https://github.com/HabitRPG/habitrpg/wiki/Contributing')
button(ng-if='!hasPet("Dragon", "Hydra")', class="pet-button pet-not-owned", popover-trigger='mouseenter', popover-placement='right', popover="Click the gold paw to learn more about how you can obtain this rare pet through contributing to HabitRPG!", popover-title='How to Get this Pet!') button(ng-if='!user.items.pets["Dragon-Hydra"]', class="pet-button pet-not-owned", popover-trigger='mouseenter', popover-placement='right', popover="Click the gold paw to learn more about how you can obtain this rare pet through contributing to HabitRPG!", popover-title='How to Get this Pet!')
img(src='/bower_components/habitrpg-shared/img/PixelPaw-Gold.png') img(src='/bower_components/habitrpg-shared/img/PixelPaw-Gold.png')
hr
h4 Mounts
menu.pets(type='list')
li.customize-menu(ng-repeat='egg in Items.eggs')
menu
div(ng-repeat='potion in Items.hatchingPotions', tooltip='{{potion.name}} {{egg.name}}', ng-init='mount = egg.name+"-"+potion.name')
button(class="pet-button Pet-{{mount}}", ng-show='user.items.mounts[mount]', ng-class='{active: user.items.currentMount == mount}', ng-click='chooseMount(egg.name, potion.name)')
button(class="pet-button pet-not-owned", ng-hide='user.items.mounts[mount]')
img(src='/bower_components/habitrpg-shared/img/PixelPaw.png')
.well(style='position:fixed;right:0px;top:50%;width:200px')
menu.inventory-list(type='list')
li.customize-menu
menu.food-menu(label='Food')
p(ng-show='foodCount < 1') You don't have any food yet.
div(ng-repeat='(food,points) in ownedItems(user.items.food)')
button.customize-option(tooltip='{{food}}', ng-click='chooseFood(food)', class='Pet_Food_{{food}}')
.badge.badge-info.stack-count {{points}}
p {{food}}

View File

@@ -1,6 +1,9 @@
figure.herobox(ng-click='clickMember(profile._id)', data-name='{{profile.profile.name}}', ng-class='{isUser: profile.id==user.id, hasPet: profile.items.pet}', data-level='{{profile.stats.lvl}}', data-uid='{{profile.id}}', rel='popover', data-placement='bottom', data-trigger='hover', data-html='true', data-content="<div ng-hide='profile.id == user.id'> <div class='progress progress-danger' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.hp, 50)}}%;'></div> </div> <div class='progress progress-warning' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.exp, tnl(profile.stats.lvl))}}%;'></div> </div> <div>Level: {{profile.stats.lvl}}</div> <div>GP: {{profile.stats.gp | number:0}}</div> <div>{{count(profile.items.pets)}} / 90 Pets Found</div> </div>") figure.herobox(ng-click='clickMember(profile._id)', data-name='{{profile.profile.name}}', ng-class='{isUser: profile.id==user.id, hasPet: profile.items.currentPet}', data-level='{{profile.stats.lvl}}', data-uid='{{profile.id}}', rel='popover', data-placement='bottom', data-trigger='hover', data-html='true', data-content="<div ng-hide='profile.id == user.id'> <div class='progress progress-danger' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.hp, 50)}}%;'></div> </div> <div class='progress progress-warning' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.exp, tnl(profile.stats.lvl))}}%;'></div> </div> <div>Level: {{profile.stats.lvl}}</div> <div>GP: {{profile.stats.gp | number:0}}</div> <div>{{count(profile.items.pets)}} / 90 Pets Found</div> </div>")
.character-sprites .character-sprites
span(ng-class='{zzz:profile.flags.rest}') // Mount Body
span(class='Mount_Body_{{profile.items.currentMount}}')
// Avatar
span(class='{{profile.preferences.gender}}_skin_{{profile.preferences.skin}}') span(class='{{profile.preferences.gender}}_skin_{{profile.preferences.skin}}')
span(class='{{profile.preferences.gender}}_hair_{{profile.preferences.hair}}') span(class='{{profile.preferences.gender}}_hair_{{profile.preferences.hair}}')
span(class='{{equipped("armor", profile.items.armor, profile.preferences, profile.backer, profile.contributor)}}') span(class='{{equipped("armor", profile.items.armor, profile.preferences, profile.backer, profile.contributor)}}')
@@ -8,6 +11,14 @@ figure.herobox(ng-click='clickMember(profile._id)', data-name='{{profile.profile
span(class='{{equipped("head", profile.items.head, profile.preferences, profile.backer, profile.contributor)}}', ng-show='profile.preferences.showHelm') span(class='{{equipped("head", profile.items.head, profile.preferences, profile.backer, profile.contributor)}}', ng-show='profile.preferences.showHelm')
span(class='{{equipped("shield",profile.items.shield,profile.preferences, profile.backer, profile.contributor)}}') span(class='{{equipped("shield",profile.items.shield,profile.preferences, profile.backer, profile.contributor)}}')
span(class='{{equipped("weapon",profile.items.weapon,profile.preferences, profile.backer, profile.contributor)}}') span(class='{{equipped("weapon",profile.items.weapon,profile.preferences, profile.backer, profile.contributor)}}')
// Mount Head
span(class='Mount_Head_{{profile.items.currentMount}}')
// Resting
span(ng-class='{zzz:profile.flags.rest}')
// Pet
// FIXME handle @minimal, this might have to be a directive // FIXME handle @minimal, this might have to be a directive
span.current-pet(class='Pet-{{profile.items.currentPet.name}}-{{profile.items.currentPet.modifier}}', ng-show='profile.items.currentPet && !minimal') span.current-pet(class='Pet-{{profile.items.currentPet}}', ng-show='profile.items.currentPet && !minimal')
.avatar-level Lvl {{profile.stats.lvl}} .avatar-level Lvl {{profile.stats.lvl}}

View File

@@ -2,11 +2,15 @@ div(modal='modals.dropsEnabled')
.modal-header .modal-header
h3 Drops Enabled! h3 Drops Enabled!
.modal-body .modal-body
p //-p // TODO how to handle random first drop?
span.item-drop-icon(class='Pet_Egg_{{user.items.eggs.0.name}}', style='margin-left: 0px') span.item-drop-icon(class='Pet_Egg_{{user.items.eggs.0.name}}', style='margin-left: 0px')
| You've unlocked the Drop System! Now when you complete tasks, you have a small chance of finding an item. You just found a | 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 {{user.items.eggs.0.text}} Egg strong {{user.items.eggs.0.text}} Egg
| ! {{user.items.eggs.0.notes}}. | ! {{user.items.eggs.0.notes}}.
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}}
br br
p. 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! <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!