diff --git a/bower.json b/bower.json index 7433383b0d..f20cab731c 100644 --- a/bower.json +++ b/bower.json @@ -29,7 +29,7 @@ "bootstrap": "v2.3.2", "bootstrap-datepicker": "~1.2.0", "bootstrap-growl": "~1.1.0", - "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#develop", + "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#bosses", "BrowserQuest": "https://github.com/mozilla/BrowserQuest.git", "github-buttons": "git://github.com/mdo/github-buttons.git", "marked": "~0.2.9", diff --git a/package.json b/package.json index 31ddab7388..81e9b6a1fe 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.0.0-152", "main": "./src/server.js", "dependencies": { - "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#develop", + "habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared#bosses", "derby-auth": "git://github.com/lefnire/derby-auth#master", "connect-mongo": "*", "passport-facebook": "~1.0.0", diff --git a/public/js/controllers/inventoryCtrl.js b/public/js/controllers/inventoryCtrl.js index 8d6921fc90..c415d2a04f 100644 --- a/public/js/controllers/inventoryCtrl.js +++ b/public/js/controllers/inventoryCtrl.js @@ -32,10 +32,10 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', }, true); $scope.chooseEgg = function(egg){ - if ($scope.selectedEgg && $scope.selectedEgg.name == egg) { + if ($scope.selectedEgg && $scope.selectedEgg.key == egg) { return $scope.selectedEgg = null; // clicked same egg, unselect } - var eggData = _.findWhere(Content.eggs, {name:egg}); + var eggData = _.findWhere(Content.eggs, {key:egg}); if (!$scope.selectedPotion) { $scope.selectedEgg = eggData; } else { @@ -44,11 +44,11 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', } $scope.choosePotion = function(potion){ - if ($scope.selectedPotion && $scope.selectedPotion.name == potion) { + if ($scope.selectedPotion && $scope.selectedPotion.key == potion) { 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(Content.hatchingPotions, {name:potion}); + var potionData = _.findWhere(Content.hatchingPotions, {key:potion}); if (!$scope.selectedEgg) { $scope.selectedPotion = potionData; } else { @@ -57,7 +57,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', } $scope.chooseFood = function(food){ - if ($scope.selectedFood && $scope.selectedFood.name == food) return $scope.selectedFood = null; + if ($scope.selectedFood && $scope.selectedFood.key == food) return $scope.selectedFood = null; $scope.selectedFood = Content.food[food]; } @@ -65,8 +65,8 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 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({params:{type:type, key: $scope[selected].name}}); - if (user.items[type][$scope[selected].name] < 1) { + user.ops.sell({params:{type:type, key: $scope[selected].key}}); + if (user.items[type][$scope[selected].key] < 1) { $scope[selected] = null; } } @@ -77,8 +77,8 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', } $scope.hatch = function(egg, potion){ - if (!confirm('Hatch a ' + potion.name + ' ' + egg.name + '?')) return; - user.ops.hatch({params:{egg:egg.name, hatchingPotion:potion.name}}); + if (!confirm('Hatch a ' + potion.key + ' ' + egg.key + '?')) return; + user.ops.hatch({params:{egg:egg.key, hatchingPotion:potion.key}}); $scope.selectedEgg = null; $scope.selectedPotion = null; } @@ -89,7 +89,7 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 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)) - User.user.ops.purchase({params:{type:type,key:item.name}}); + User.user.ops.purchase({params:{type:type,key:item.key}}); } $scope.choosePet = function(egg, potion){ @@ -98,12 +98,12 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', // Feeding Pet if ($scope.selectedFood) { var food = $scope.selectedFood - if (food.name == 'Saddle') { + if (food.key == 'Saddle') { if (!confirm('Saddle ' + pet + '?')) return; - } else if (!confirm('Feed ' + pet + ' a ' + food.name + '?')) { + } else if (!confirm('Feed ' + pet + ' a ' + food.key + '?')) { return; } - User.user.ops.feed({params:{pet: pet, food: food.name}}); + User.user.ops.feed({params:{pet: pet, food: food.key}}); $scope.selectedFood = null; // Selecting Pet @@ -125,7 +125,9 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', $rootScope.modals.showQuest = false; } $scope.questInit = function(){ - $rootScope.party.$questAccept({key:$scope.selectedQuest.name}); + $rootScope.party.$questAccept({key:$scope.selectedQuest.key}, function(){ + $rootScope.party.$get(); + }); $scope.closeQuest(); } } diff --git a/public/js/controllers/notificationCtrl.js b/public/js/controllers/notificationCtrl.js index 03d418ffd0..6c3d7ede2a 100644 --- a/public/js/controllers/notificationCtrl.js +++ b/public/js/controllers/notificationCtrl.js @@ -37,10 +37,10 @@ habitrpg.controller('NotificationCtrl', var type = (after.type == 'Food') ? 'food' : (after.type == 'HatchingPotion') ? 'hatchingPotions' : // can we use camelcase and remove this line? (after.type.toLowerCase() + 's'); - if(!User.user.items[type][after.name]){ - User.user.items[type][after.name] = 0; + if(!User.user.items[type][after.key]){ + User.user.items[type][after.key] = 0; } - User.user.items[type][after.name]++; + User.user.items[type][after.key]++; $rootScope.modals.drop = true; }); diff --git a/public/js/controllers/rootCtrl.js b/public/js/controllers/rootCtrl.js index 6635f828c9..dd652eee74 100644 --- a/public/js/controllers/rootCtrl.js +++ b/public/js/controllers/rootCtrl.js @@ -167,7 +167,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$ if ($scope.spell.target != type) return Notification.text("Invalid target"); $scope.spell.cast(User.user, target); User.save(); - $http.post('/api/v2/user/class/cast/' + $scope.spell.name, {target:target, type:type}).success(function(){ + $http.post('/api/v2/user/class/cast/' + $scope.spell.key, {target:target, type:type}).success(function(){ var msg = "You cast " + $scope.spell.text; switch (type) { case 'task': msg += ' on ' + target.text;break; diff --git a/src/controllers/groups.js b/src/controllers/groups.js index b67ca62634..70ce37279c 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -215,30 +215,18 @@ api.attachGroupPopulated = function(req, res, next) { api.postChat = function(req, res, next) { var user = res.locals.user var group = res.locals.group; - var message = { - id: shared.uuid(), - uuid: user._id, - contributor: user.contributor && user.contributor.toObject(), - backer: user.backer && user.backer.toObject(), - text: req.query.message, // FIXME this should be body, but ngResource is funky - user: user.profile.name, - timestamp: +(new Date) - }; - var lastClientMsg = req.query.previousMsg; var chatUpdated = (lastClientMsg && group.chat && group.chat[0] && group.chat[0].id !== lastClientMsg) ? true : false; - group.chat.unshift(message); - group.chat.splice(200); + group.sendChat(req.query.message, user); // FIXME this should be body, but ngResource is funky if (group.type === 'party') { - user.party.lastMessageSeen = message.id; + user.party.lastMessageSeen = group.chat[0].id; user.save(); } group.save(function(err, saved){ if (err) return res.json(500, {err:err}); - return chatUpdated ? res.json({chat: group.chat}) : res.json({message: saved.chat[0]}); }); } @@ -431,20 +419,22 @@ questStart = function(req, res) { } var parallel = []; + var key = group.quest.key; // TODO will this handle appropriately when people leave/join party between quest invite? _.each(group.members, function(m){ - if (m._id == user._id) m.items.quests[m.party.quest]--; + if (m._id == user._id) m.items.quests[key]--; if (group.quest.members[m._id] == true) { - m.party.quest = group.quest.key; + m.party.quest.key = key; } else { - m.party.quest = undefined; + _.merge(m.party.quest, {key:undefined,collection:{}}); delete group.quest.members[m._id]; } + m._v++; parallel.push(function(cb2){m.save(cb2);}); }) group.quest.active = true; - group.quest.hp = shared.content.quests[group.quest.key].hp; + group.quest.progress.hp = shared.content.quests[group.quest.key].stats.hp; parallel.push(function(cb2){group.save(cb2);}); async.parallel(parallel,function(err, results){ @@ -502,5 +492,4 @@ api.questReject = function(req, res, next) { //TODO -function questEnd(){} function questAbort(){} diff --git a/src/controllers/user.js b/src/controllers/user.js index 705b87bd15..086d37fb63 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -82,11 +82,11 @@ api.score = function(req, res, next) { task = user.ops.addTask({body:task}); } var delta = user.ops.score({params:{id:task.id, direction:direction}}); - //user.markModified('flags'); - user.save(function(err, saved) { + + user.save(function(err,saved){ if (err) return res.json(500, {err: err}); res.json(200, _.extend({ - delta: delta + delta: delta, }, saved.toJSON().stats)); }); @@ -194,10 +194,43 @@ api.update = function(req, res, next) { api.cron = function(req, res, next) { var user = res.locals.user; - user.fns.cron(); - if (user.isModified()) - res.locals.wasModified = true; - user.save(next); + tally = user.fns.cron(); + if (user.isModified()) res.locals.wasModified = true; + + // If user is on a quest, roll for boss & player + if (user.party.quest.key && tally && (tally.up || tally.down)) { + async.waterfall([ + function(cb){ + Group.findOne({type: 'party', members: {'$in': [user._id]}}) + .populate({ + path: 'members', + match: {'party.quest.key':user.party.quest.key} + }) + .exec(cb); + }, + function(group, cb){ + var quest = shared.content.quests[group.quest.key]; + var down = tally.down * quest.stats.str; // multiply by boss strength + var parallel = []; + _.each(group.members, function(m){ + parallel.push(function(cb2){ + m.stats.hp += down; + m._v++; + m.save(cb2); + }) + }) + // Use http://js2coffee.org/ for building this string. Man I wish JS had interpolation... + group.sendChat("`<" + user.profile.name + "> attacks <" + quest.name + "> for " + (tally.up.toFixed(1)) + " damage, <" + quest.name + "> attacks party for " + (tally.down.toFixed(1)) + " damage.`"); + parallel.push(function(cb2){ + group.hurtBoss(tally.up,cb2); + }); + async.parallel(parallel,cb); + } + ], next); + + } else { + user.save(next); + } }; // api.reroll // Shared.ops @@ -347,15 +380,8 @@ api.cast = function(req, res) { if (group) { series.push(function(cb2){ - group.chat.unshift({ - id: shared.uuid(), - uuid: user._id, - contributor: user.contributor && user.contributor.toObject(), - backer: user.backer && user.backer.toObject(), - text: '`casts ' + spell.text + (type == 'user' ? ' on @'+found.profile.name : ' for the party') + '.`', - user: '<'+user.profile.name+'>', - timestamp: +new Date - }); + var message = '`<'+user.profile.name+'> casts '+spell.text + (type=='user' ? ' on @'+found.profile.name : ' for the party')+'.`'; + group.sendChat(message); group.save(cb2); }) } diff --git a/src/models/group.js b/src/models/group.js index e13c5ea961..e06939a3b3 100644 --- a/src/models/group.js +++ b/src/models/group.js @@ -2,6 +2,7 @@ var mongoose = require("mongoose"); var Schema = mongoose.Schema; var shared = require('habitrpg-shared'); var _ = require('lodash'); +var async = require('async'); var GroupSchema = new Schema({ _id: {type: String, 'default': shared.uuid}, @@ -33,14 +34,15 @@ var GroupSchema = new Schema({ challenges: [{type:'String', ref:'Challenge'}], // do we need this? could depend on back-ref instead (Challenge.find({group:GID})) quest: { key: String, - hp: Number, active: {type:Boolean, 'default':false}, + progress:{ + hp: Number, + collected: Schema.Types.Mixed, + }, - /* - Shows boolean for each party-member who has accepted the quest. Eg {UUID: true, UUID: false}. Once all users click - 'Accept', the quest begins. If a false user waits too long, probably a good sign to prod them or boot them. - TODO when booting user, remove from .joined and check again if we can now start the quest - */ + //Shows boolean for each party-member who has accepted the quest. Eg {UUID: true, UUID: false}. Once all users click + //'Accept', the quest begins. If a false user waits too long, probably a good sign to prod them or boot them. + //TODO when booting user, remove from .joined and check again if we can now start the quest members: Schema.Types.Mixed } }, { @@ -83,5 +85,88 @@ GroupSchema.methods.toJSON = function(){ return doc; } +GroupSchema.methods.sendChat = function(message, user){ + var group = this; + var message = { + id: shared.uuid(), + text: message, + timestamp: +(new Date) + }; + if (user) { + _.defaults(message, { + uuid: user._id, + contributor: user.contributor && user.contributor.toObject(), + backer: user.backer && user.backer.toObject(), + user: user.profile.name, + }); + } else { + message.uuid = 'system'; + } + group.chat.unshift(message); + group.chat.splice(200); +} + +GroupSchema.methods.hurtBoss = function(delta, cb) { + var group = this; + group.quest.progress.hp -= delta; + var hp = group.quest.progress.hp; + if (group.quest.progress.hp <= 0) { + var key = group.quest.key, + quest = shared.content.quests[key]; + + var parallel = _.reduce(group.members, function(m,v,k){ + + // Achievement + _.defaults(v.achievements, {quests:{}}) + if (!v.achievements.quests[key]) v.achievements.quests[key] = 0; + v.achievements.quests[key]++; + v.markModified('achievements'); + + // Drops + v.stats.gp += +quest.drop.gp; + v.stats.exp += +quest.drop.exp; + switch (quest.drop.type) { + case 'gear': + // TODO This means they can lose their new gear on death, is that what we want? + v.items.gear.owned[quest.drop.key] = true; + break; + case 'eggs': + case 'food': + case 'hatchingPotions': + if (!v.items.hatchingPotions[quest.drop.key]) v.items.hatchingPotions[quest.drop.key] = 0; + v.items.hatchingPotions[quest.drop.key]++; + break; + case 'pets': + if (!v.items.pets[quest.drop.key]) v.items.pets[quest.drop.key] = 5; + break; + case 'mounts': + v.items.mounts[quest.drop.key] = true; + break; + } + + v.party.quest.key = undefined; + v.party.quest.collection = {}; + v.markModified('party.quest'); + + v._v++; + m.push(function(cb3){ v.save(cb3); }) + return m; + }, []); + + // Finish the quest + group.quest = {};group.markModified('quest'); + group.sendChat('`' + quest.name + ' has been slain! Party has received their rewards`'); + + parallel.push(function(cb3){ + group.save(cb3); + }) + async.parallel(parallel,cb); + } + else { + group.save(cb); + } + return hp; +} + module.exports.schema = GroupSchema; module.exports.model = mongoose.model("Group", GroupSchema); diff --git a/src/models/user.js b/src/models/user.js index 3b0ad8b371..d0249cb433 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -16,7 +16,7 @@ var Challenge = require('./challenge').model; var eggPotionMapping = _.transform(shared.content.eggs, function(m, egg){ _.defaults(m, _.transform(shared.content.hatchingPotions, function(m2, pot){ - m2[egg.name + '-' + pot.name] = true; + m2[egg.key + '-' + pot.key] = true; })); }) @@ -45,7 +45,8 @@ var UserSchema = new Schema({ veteran: Boolean, snowball: Number, streak: Number, - challenges: Array + challenges: Array, + quests: Schema.Types.Mixed }, auth: { facebook: Schema.Types.Mixed, @@ -200,13 +201,17 @@ var UserSchema = new Schema({ }, party: { - //party._id // FIXME make these populate docs? - current: String, // party._id - invitation: String, // party._id + // id // FIXME can we use a populated doc instead of fetching party separate from user? lastMessageSeen: String, - leader: Boolean, order: {type:String, 'default':'level'}, - quest: String + quest: { + key: String, + tally: { + up: {type: Number, 'default': 0}, + down: {type: Number, 'default': 0}, + collection: {type: Schema.Types.Mixed, 'default': {}} // {feather:1, ingot:2} + } + } }, preferences: { armorSet: String, @@ -250,13 +255,13 @@ var UserSchema = new Schema({ int: {type: Number, 'default': 0}, per: {type: Number, 'default': 0}, buffs: { - str: Number, - def: Number, - per: Number, - con: Number, - stealth: Number, - streaks: Boolean, - snowball: Boolean + str: {type: Number, 'default': 0}, + def: {type: Number, 'default': 0}, + per: {type: Number, 'default': 0}, + con: {type: Number, 'default': 0}, + stealth: {type: Number, 'default': 0}, + streaks: {type: Boolean, 'default': false}, + snowball: {type: Boolean, 'default': false} } }, tags: [ diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade index fdb87014a6..14d86bec34 100644 --- a/views/options/inventory/inventory.jade +++ b/views/options/inventory/inventory.jade @@ -31,7 +31,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') 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='{{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]}') + 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.key]}') .badge.badge-info.stack-count {{points}} //-p {{Content.eggs[egg].text}} @@ -39,7 +39,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') 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='{{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]}') + 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.key+"-"+pot]}') .badge.badge-info.stack-count {{points}} li.customize-menu @@ -79,17 +79,17 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') | Welcome to the Market! Buy hard-to-find eggs and potions! Sell your extras! Commission useful services! Come see what we have to offer. p button.btn.btn-primary(ng-show='selectedEgg', ng-click='sellInventory()') - | Sell {{selectedEgg.name}} for {{selectedEgg.value}} Gold + | Sell {{selectedEgg.key}} for {{selectedEgg.value}} Gold button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()') - | Sell {{selectedPotion.name}} for {{selectedPotion.value}} Gold + | Sell {{selectedPotion.key}} for {{selectedPotion.value}} Gold button.btn.btn-primary(ng-show='selectedFood', ng-click='sellInventory()') - | Sell {{selectedFood.name}} for {{selectedFood.value}} Gold + | Sell {{selectedFood.key}} for {{selectedFood.value}} Gold menu.inventory-list(type='list') li.customize-menu menu.pets-menu(label='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='purchase("eggs", egg)', class='Pet_Egg_{{egg.name}}') + button.customize-option(popover='{{egg.notes}}', popover-title='{{egg.text}} Egg', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("eggs", egg)', class='Pet_Egg_{{egg.key}}') p | {{egg.value}} span.Pet_Currency_Gem1x.inline-gems @@ -97,15 +97,15 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label='Hatching Potions') 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='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.name}}') + button.customize-option(popover='{{pot.notes}}', popover-title='{{pot.text}} Potion', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("hatchingPotions", pot)', class='Pet_HatchingPotion_{{pot.key}}') p | {{pot.value}} span.Pet_Currency_Gem1x.inline-gems li.customize-menu menu.pets-menu(label='Food') - div(ng-repeat='food in Content.food', ng-show='food.name !== "Saddle"') - button.customize-option(popover='{{food.notes}}', popover-title='{{food.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", food)', class='Pet_Food_{{food.name}}') + div(ng-repeat='food in Content.food', ng-show='food.key !== "Saddle"') + button.customize-option(popover='{{food.notes}}', popover-title='{{food.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", food)', class='Pet_Food_{{food.key}}') p | {{food.value}} span.Pet_Currency_Gem1x.inline-gems @@ -121,7 +121,7 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html') li.customize-menu menu.pets-menu(label='Special') div - button.customize-option(popover='{{Content.food.Saddle.notes}}', popover-title='{{Content.food.Saddle.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", Content.food.Saddle)', class='Pet_Food_{{Content.food.Saddle.name}}') + button.customize-option(popover='{{Content.food.Saddle.notes}}', popover-title='{{Content.food.Saddle.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("food", Content.food.Saddle)', class='Pet_Food_{{Content.food.Saddle.key}}') p | {{Content.food.Saddle.value}} span.Pet_Currency_Gem1x.inline-gems diff --git a/views/options/inventory/stable.jade b/views/options/inventory/stable.jade index e068bdd0ea..4da7d4830f 100644 --- a/views/options/inventory/stable.jade +++ b/views/options/inventory/stable.jade @@ -16,8 +16,8 @@ script(type='text/ng-template', id='partials/options.inventory.mounts.html') menu.pets(type='list') li.customize-menu(ng-repeat='egg in Content.eggs') menu - 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(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.mountText}}', popover-placement='bottom', ng-init='mount = egg.key+"-"+potion.key') + button(class="pet-button Mount_Head_{{mount}}", ng-show='user.items.mounts[mount]', ng-class='{active: user.items.currentMount == mount}', ng-click='chooseMount(egg.key, potion.key)') //div(class='Mount_Head_{{mount}}') button(class="pet-button pet-not-owned", ng-hide='user.items.mounts[mount]') .PixelPaw @@ -49,8 +49,8 @@ script(type='text/ng-template', id='partials/options.inventory.pets.html') menu.pets(type='list') li.customize-menu(ng-repeat='egg in Content.eggs') menu - 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)') + div(ng-repeat='potion in Content.hatchingPotions', popover-trigger='mouseenter', popover='{{potion.text}} {{egg.text}}', popover-placement='bottom', ng-init='pet = egg.key+"-"+potion.key') + 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.key, potion.key)') .progress(ng-class='{"progress-success": user.items.pets[pet]<50}') .bar(style="width: {{user.items.pets[pet]/.5}}%;") button(class="pet-button pet-not-owned", ng-if='!user.items.pets[pet]') @@ -61,8 +61,9 @@ script(type='text/ng-template', id='partials/options.inventory.pets.html') div 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")', popover='Veteran Wolf', popover-trigger='mouseenter', popover-placement='bottom') 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")', popover='Cerberus Pup', popover-trigger='mouseenter', popover-placement='bottom') - 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")', popover='Hydra', popover-trigger='mouseenter', popover-placement='bottom') button(ng-if='user.items.pets["Turkey-Base"]', class="pet-button Pet-Turkey-Base", ng-class='{active: user.items.currentPet == "Turkey-Base"}', ng-click='choosePet("Turkey", "Base")', popover='Turkey', popover-trigger='mouseenter', popover-placement='bottom') + button(ng-if='user.items.pets["BearCub-Polar"]', class="pet-button Pet-BearCub-Polar", ng-class='{active: user.items.currentPet == "BearCub-Polar"}', ng-click='choosePet("BearCub", "Polar")', popover='Polar Bear Cub', popover-trigger='mouseenter', popover-placement='bottom') + 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")', popover='Hydra', popover-trigger='mouseenter', popover-placement='bottom') a(target='_blank', href='http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG') 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!') .PixelPaw-Gold diff --git a/views/options/social/chat-box.jade b/views/options/social/chat-box.jade index 3d55599b8b..ff4533c6ab 100644 --- a/views/options/social/chat-box.jade +++ b/views/options/social/chat-box.jade @@ -13,6 +13,4 @@ form.chat-form(ng-submit='postChat(group,message.content)') input.btn.chat-btn(type='submit', value='Send Chat', ng-class='{disabled: _sending == true}') td button.btn(type="button", ng-click='sync(group)', tooltip='Fetch Recent Messages') - i(class='pull-right icon-refresh') - - + i(class='pull-right icon-refresh') \ No newline at end of file diff --git a/views/options/social/chat-message.jade b/views/options/social/chat-message.jade index 0baa423a6e..3c83b7abf2 100644 --- a/views/options/social/chat-message.jade +++ b/views/options/social/chat-message.jade @@ -9,5 +9,5 @@ li(bindonce='group.chat', ng-repeat='message in group.chat', bo-class='{highligh a(bo-show='user.contributor.admin || message.uuid == user.id', ng-click='deleteChatMessage(group, message)') | i.icon-remove(tooltip='Delete') - a.label.chat-message(class='float-label', bo-class='{"label-npc": message.backer.npc, "label-contributor-{{message.contributor.level}}":message.contributor.level}', ng-click='clickMember(message.uuid, true)') - span(tooltip='{{contribText(message.contributor, message.backer)}}') {{message.user}}  + a.label.chat-message(bo-show='message.user', class='float-label', bo-class='{"label-npc": message.backer.npc, "label-contributor-{{message.contributor.level}}":message.contributor.level}', ng-click='clickMember(message.uuid, true)') + span(tooltip='{{contribText(message.contributor, message.backer)}}') {{message.user}}  \ No newline at end of file diff --git a/views/options/social/group.jade b/views/options/social/group.jade index 64a924d957..843306a8ba 100644 --- a/views/options/social/group.jade +++ b/views/options/social/group.jade @@ -31,10 +31,10 @@ a.pull-right.gem-wallet(popover-trigger='mouseenter', popover-title='Guild Bank' | {{group.quest.hp | number:0}} / {{Content.quests[group.quest.key].hp}} .hero-stats .meter.health(title='Boss Health') - .bar(style='width: {{Shared.percent(group.quest.hp, Content.quests[group.quest.key].hp)}}%;') + .bar(style='width: {{Shared.percent(group.quest.progress.hp, Content.quests[group.quest.key].stats.hp)}}%;') span.meter-text i.icon-heart - | {{group.quest.hp | number:0}} / {{Content.quests[group.quest.key].hp}} + | {{group.quest.progress.hp | number:0}} / {{Content.quests[group.quest.key].stats.hp}} p {{Content.quests[group.quest.key].notes}} // ------ Information ------- diff --git a/views/shared/modals/drops.jade b/views/shared/modals/drops.jade index ccac0bd490..d9c25b5859 100644 --- a/views/shared/modals/drops.jade +++ b/views/shared/modals/drops.jade @@ -3,7 +3,7 @@ div(modal='modals.dropsEnabled') h3 Drops Enabled! .modal-body //-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.key}}', 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 strong {{user.items.eggs.0.text}} Egg | ! {{user.items.eggs.0.notes}}. @@ -22,7 +22,7 @@ div(modal='modals.drop') h3 An item has dropped! .modal-body p - span.item-drop-icon(class='Pet_{{user._tmp.drop.type}}_{{user._tmp.drop.name}}') + span.item-drop-icon(class='Pet_{{user._tmp.drop.type}}_{{user._tmp.drop.key}}') | {{user._tmp.drop.dialog}} .modal-footer button.btn.btn-default.cancel(ng-click='modals.drop = false') Close \ No newline at end of file diff --git a/views/shared/modals/quests.jade b/views/shared/modals/quests.jade index edd593abfe..4d5fa33956 100644 --- a/views/shared/modals/quests.jade +++ b/views/shared/modals/quests.jade @@ -6,8 +6,18 @@ div(modal='modals.showQuest', ng-controller='InventoryCtrl') tr td p {{selectedQuest.notes}} + br + .well + h5 Rewards + table.table.table-striped + tr + td {{selectedQuest.drop.text}} + tr + td {{selectedQuest.drop.exp}} Experience + tr + td {{selectedQuest.drop.gp}} Gold td - div(class='quest_{{selectedQuest.name}}') + div(class='quest_{{selectedQuest.key}}') hr div(style='clear:left;clear:right') .npc_ian.pull-left @@ -18,10 +28,21 @@ div(modal='modals.showQuest', ng-controller='InventoryCtrl') div(modal='party.quest.key && !questHold && party.quest.members[user._id] == undefined') .modal-header - h3 Quest Invitation + h3 Quest Invitation: {{Content.quests[party.quest.key].text}} .modal-body - p You have been invited to {{Content.quests[party.quest.key].text}}! - p (TODO list rewards) + p You have been invited to "{{Content.quests[party.quest.key].text}}"! + br + p {{Content.quests[party.quest.key].notes}} + br + .well + h5 Rewards + table.table.table-striped + tr + td {{Content.quests[party.quest.key].drop.text}} + tr + td {{Content.quests[party.quest.key].drop.exp}} Experience + tr + td {{Content.quests[party.quest.key].drop.gp}} Gold .modal-footer button.btn.btn-default.btn-small.btn-cancel(ng-click='questHold = true') Ask Later button.btn.btn-default.btn-small.btn-cancel(ng-click='party.$questReject()') Reject