Merge branch 'classes' into develop

Conflicts:
	public/js/controllers/tasksCtrl.js
	views/shared/modals/settings.jade
This commit is contained in:
Tyler Renelle 2013-12-08 18:17:53 -07:00
commit 76565384d3
33 changed files with 648 additions and 204 deletions

View file

@ -0,0 +1,26 @@
/**
* Probably the biggest migration of all! This adds the following features:
* - Customization Redo: https://trello.com/c/YKXmHNjY/306-customization-redo
* - Armory: https://trello.com/c/83M5RqQB/299-armory
* - Classes
*/
db.users.find().forEach(function(user){
user.stats.class = 'warrior';
// grant backer/contrib gear, 300, rather than using js logic
// customizations redo: https://trello.com/c/YKXmHNjY/306-customization-redo
// migrate current owned items
// gender => size
user.preferences.size = (user.preferences.gender == 'f') ? 'slim' : 'broad';
delete user.preferences.gender;
// Delete armorSet
delete user.preferences.armorSet;
db.users.update({_id:user._id}, user);
});

View file

@ -150,6 +150,8 @@
background: darken($worse, 38%)
.experience .bar
background: darken($neutral, 30%)
.mana .bar
background: darken($best, 30%)
.meter-text
position: absolute

View file

@ -179,3 +179,12 @@ a
.modal-indented-list
margin-left: 10px;
padding-left: 10px;
// Spells
html.applying-action, html.applying-action *
cursor: copy !important
.cast-target:hover
border: 5px solid green !important
.selected-class
background-color: green

View file

@ -1,36 +1,27 @@
.NPC-Alex, .NPC-Bailey, .NPC-Bailey-Head, .NPC-Daniel, .NPC-Justin, .NPC-Justin-Head, .NPC-Matt {background: url("/bower_components/habitrpg-shared/img/npcs/NPC-SpriteSheet.png") no-repeat}
.npc_alex_container
margin-bottom: 20px
.NPC-Alex {background-position: 0 0; width: 162px; height: 138px;}
.NPC-Alex-container{margin-bottom: 20px;}
.NPC-Daniel {background-position: -222px 0; width: 135px; height: 123px}
.NPC-Justin {background-position: -357px 0; width: 84px; height: 119px}
.NPC-Justin-Head {background-position: -396px 0; width: 36px; height: 96px}
.NPC-Matt {background-position: -441px 0; width: 100%; padding-left: 208px; padding-bottom: 20px;}
.npc_matt
margin-bottom: 20px
// Bailey
.NPC-Bailey
background-position: -162px -42px
width: 60px
height: 72px
float:left
.NPC-Bailey-Head
background-position: -162px -42px
width: 60px
height: 30px
position: absolute
top: 117px // 147 (header-height) - 30 (bailey height)
right: 50px
cursor: pointer
.static-popover
z-index 0
display block
position:relative
.npc_bailey
float:left
.npc_bailey_head
height: 30px !important
position: absolute
top: 117px // 147 (header-height) - 30 (bailey height)
right: 50px
cursor: pointer
// Tour (Justin)
.NPC-Justin.float-left
.npc_justin.float-left
float: left
margin-right: 5px
margin-bottom: 5px
.static-popover
z-index 0
display block
position:relative
.popover-navigation {clear:both;}

View file

@ -402,4 +402,4 @@ form
color: #333
&:hover
border-top: 0
margin-top: 2px
margin-top: 2px

View file

@ -2,6 +2,7 @@ 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;
// convenience vars since these are accessed frequently
@ -17,11 +18,22 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
$scope.$watch('user.items.hatchingPotions', function(pots){ $scope.potCount = countStacks(pots); }, true);
$scope.$watch('user.items.food', function(food){ $scope.foodCount = countStacks(food); }, true);
$scope.$watch('user.items.gear', function(gear){
$scope.gear = {
base: _.where(Items.items.gear.flat, {klass: 'base'})
};
_.each(gear.owned, function(bool,key){
var item = Items.items.gear.flat[key];
if (!$scope.gear[item.klass]) $scope.gear[item.klass] = [];
$scope.gear[item.klass].push(item);
})
}, true)
$scope.chooseEgg = function(egg){
if ($scope.selectedEgg && $scope.selectedEgg.name == egg) {
return $scope.selectedEgg = null; // clicked same egg, unselect
}
var eggData = _.findWhere(window.habitrpgShared.items.items.eggs, {name:egg});
var eggData = _.findWhere(Items.items.eggs, {name:egg});
if (!$scope.selectedPotion) {
$scope.selectedEgg = eggData;
} else {
@ -34,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(window.habitrpgShared.items.items.hatchingPotions, {name:potion});
var potionData = _.findWhere(Items.items.hatchingPotions, {name:potion});
if (!$scope.selectedEgg) {
$scope.selectedPotion = potionData;
} else {
@ -171,5 +183,18 @@ habitrpg.controller("InventoryCtrl", ['$rootScope', '$scope', 'User', 'API_URL',
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);
}
}
]);

View file

@ -3,8 +3,8 @@
/* Make user and settings available for everyone through root scope.
*/
habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams',
function($scope, $rootScope, $location, User, $http, $state, $stateParams) {
habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams', 'Notification', 'Groups',
function($scope, $rootScope, $location, User, $http, $state, $stateParams, Notification, Groups) {
$rootScope.modals = {};
$rootScope.modals.achievements = {};
$rootScope.User = User;
@ -137,5 +137,51 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
chart = new google.visualization.LineChart($("." + id + "-chart")[0]);
chart.draw(data, options);
};
/*
------------------------
Spells
------------------------
*/
$scope.castStart = function(spell) {
if (User.user.stats.mp < spell.mana) return Notification.text("Not enough mana.");
$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();
party = (_.isArray(party) ? party : []).concat(User.user);
$scope.castEnd(party, 'party');
}
}
$scope.castEnd = function(target, type, $event){
if ($scope.spell.target != type) return Notification.text("Invalid target");
$scope.spell.cast(User.user, target);
$http.post('/api/v1/user/cast/' + $scope.spell.name, {target:target, type:type}).success(function(){
var msg = "You cast " + $scope.spell.text;
switch (type) {
case 'task': msg += ' on ' + target.text;break;
case 'user': msg += ' on ' + target.profile.name;break;
case 'party': msg += ' on the Party';break;
}
Notification.text(msg);
$rootScope.applyingAction = false;
$scope.spell = null;
//User.sync(); // FIXME push a lot of the server code to also in client, so we can run updates in browser without requiring sync
})
$event && $event.stopPropagation();
}
// $rootScope.castCancel = function(){
// debugger
// $rootScope.applyingAction = false;
// $scope.spell = null;
// }
}
]);

View file

@ -74,24 +74,24 @@ 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.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,
// items = $scope.restoreValues.items,
achievements = $scope.restoreValues.achievements;
User.setMultiple({
"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,
// "items.weapon": items.weapon,
// "items.armor": items.armor,
// "items.head": items.head,
// "items.shield": items.shield,
"achievements.streak": achievements.streak
});
$rootScope.modals.restore = false;

View file

@ -104,24 +104,14 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', '
------------------------
*/
var updateStore = function(){
var sorted, updated;
updated = window.habitrpgShared.items.updateStore(User.user);
/* Figure out whether we wanna put this in habitrpg-shared
*/
$scope.itemStore = window.habitrpgShared.items.updateStore(User.user);
sorted = [updated.weapon, updated.armor, updated.head, updated.shield, updated.potion];
$scope.itemStore = sorted;
}
updateStore();
$scope.buy = function(type) {
var hasEnough = window.habitrpgShared.items.buyItem(User.user, type);
$scope.buy = function(item) {
var hasEnough = window.habitrpgShared.items.buyItem(User.user, item);
if (hasEnough) {
User.log({op: "buy",type: type});
User.log({op: "buy", key: item.key});
Notification.text("Item purchased.");
updateStore();
$scope.itemStore = window.habitrpgShared.items.updateStore(User.user);
} else {
Notification.text("Not enough Gold!");
}
@ -132,6 +122,13 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', '
User.log({op: 'clear-completed'});
}
/*
------------------------
Ads
------------------------
*/
/**
* See conversation on http://productforums.google.com/forum/#!topic/adsense/WYkC_VzKwbA,
* Adsense is very sensitive. It must be called once-and-only-once for every <ins>, else things break.

View file

@ -11,6 +11,59 @@ habitrpg.controller("UserCtrl", ['$rootScope', '$scope', '$location', 'User', '$
if(value === true) $scope.editingProfile = angular.copy(User.user.profile);
});
$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);
}
$scope.rerollClass = function(){
if (!confirm("Are you sure you want to re-roll? This will reset your character's class and allocated points (you'll get them all back to re-allocate)"))
return;
User.setMultiple({
'flags.classSelected': false,
//'stats.points': this is handled on the server
'stats.str': 0,
'stats.def': 0,
'stats.per': 0,
'stats.int': 0
})
}
$scope.rerollSubmit = function(){
var klass = $scope.selectedClass;
var setVars = {
"stats.class": klass,
"flags.classSelected": true
};
// 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);
$scope.selectedClass = undefined;
//FIXME run updateStore (we need to access a different scope)
}
$scope.save = function(){
var values = {};
_.each($scope.editingProfile, function(value, key){

View file

@ -74,7 +74,7 @@ angular.module('guideServices', []).
}
];
_.each(tourSteps, function(step){
step.content = "<div><div class='NPC-Justin float-left'></div>" + step.content + "</div>"; // add Justin NPC img
step.content = "<div><div class='npc_justin float-left'></div>" + step.content + "</div>"; // add Justin NPC img
});
$('.main-herobox').popover('destroy');
var tour = new Tour({
@ -97,7 +97,7 @@ angular.module('guideServices', []).
if (!placement) placement = 'bottom';
$(selector).popover('destroy');
var button = "<button class='btn btn-sm btn-default' onClick=\"$('" + selector + "').popover('hide');return false;\">Close</button>";
html = "<div><div class='NPC-Justin float-left'></div>" + html + '<br/>' + button + '</div>';
html = "<div><div class='npc_justin float-left'></div>" + html + '<br/>' + button + '</div>';
$(selector).popover({
title: title,
placement: placement,

View file

@ -23,6 +23,7 @@ angular.module('userServices', []).
//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)) {

View file

@ -203,13 +203,12 @@ api.clearCompleted = function(req, res, next) {
------------------------------------------------------------------------
*/
api.buy = function(req, res, next) {
var hasEnough, type, user;
user = res.locals.user;
type = req.params.type;
if (type !== 'weapon' && type !== 'armor' && type !== 'head' && type !== 'shield' && type !== 'potion') {
return res.json(400, {err: ":type must be in one of: 'weapon', 'armor', 'head', 'shield', 'potion'"});
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"});
}
hasEnough = items.buyItem(user, type);
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});
@ -484,6 +483,70 @@ api.deleteTag = function(req, res){
}
}
/*
------------------------------------------------------------------------
Spells
------------------------------------------------------------------------
*/
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 done = function(){
var err = arguments[0];
var saved = _.size(arguments == 3) ? arguments[2] : arguments[1];
if (err) return res.json(500, {err:err});
res.json(saved);
}
switch (type) {
case 'task':
spell.cast(user, user.tasks[target.id]);
user.save(done);
break;
case 'self':
spell.cast(user);
user.save(done);
break;
case 'party':
async.waterfall([
function(cb){
Group.findOne({type: 'party', members: {'$in': [user._id]}}).populate('members').exec(cb);
},
function(group, cb) {
if (!group) group = {members:[user]};
spell.cast(user, group.members);
var series = _.transform(group.members, function(m,v,k){
m[k] = function(cb2){v.save(cb2);}
});
async.series(series, cb);
},
function(whatever, cb){
user.save(cb);
}
], done);
break;
case 'user':
async.waterfall([
function(cb) {
User.findById(target._id, cb);
},
function(member, cb) {
spell.cast(user, member);
member.save(cb); // not parallel because target could be user, which causes race condition when saving
},
function(saved, num, cb) {
user.save(cb);
}
], done);
break;
}
}
/*
------------------------------------------------------------------------
Batch Update
@ -502,6 +565,7 @@ api.batchUpdate = function(req, res, next) {
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;
res.send = res.json = function(code, data) {
if (_.isNumber(code) && code >= 400) {

View file

@ -94,7 +94,8 @@ var UserSchema = new Schema({
rewrite: {type: Boolean, 'default': true},
partyEnabled: Boolean, // FIXME do we need this?
rest: {type: Boolean, 'default': false}, // fixme - change to preferences.resting once we're off derby
contributor: Boolean
contributor: Boolean,
classSelected: {type: Boolean, 'default': false}
},
history: {
exp: Array, // [{date: Date, value: Number}], // big peformance issues if these are defined
@ -107,10 +108,26 @@ var UserSchema = new Schema({
party: Schema.Types.Mixed
},
items: {
armor: Number,
weapon: Number,
head: Number,
shield: Number,
gear: {
owned: _.transform(items.items.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;
}),
equipped: {
weapon: {type: String, 'default': 'weapon_warrior_0'},
armor: {type: String, 'default': 'armor_base_0'},
head: {type: String, 'default': 'head_base_0'},
shield: {type: String, 'default': 'shield_base_0'}
},
costume: {
weapon: {type: String, 'default': 'weapon_base_0'},
armor: {type: String, 'default': 'armor_base_0'},
head: {type: String, 'default': 'head_base_0'},
shield: {type: String, 'default': 'shield_base_0'}
},
},
// -------------- Animals -------------------
// Complex bit here. The result looks like:
@ -185,16 +202,20 @@ var UserSchema = new Schema({
preferences: {
armorSet: String,
dayStart: {type:Number, 'default': 0},
gender: {type:String, 'default': 'm'},
hair: {type:String, 'default':'blond'},
size: {type:String, enum: ['broad','slim'], 'default': 'broad'},
hair: {
color: {type: String, 'default': 'blond'},
base: {type: Number, 'default': 0},
bangs: {type: Number, 'default': 0},
beard: {type: Number, 'default': 0},
mustach: {type: Number, 'default': 0},
},
hideHeader: {type:Boolean, 'default':false},
showHelm: {type:Boolean, 'default':true},
showWeapon: {type:Boolean, 'default':true},
showShield: {type:Boolean, 'default':true},
showArmor: {type:Boolean, 'default':true},
skin: {type:String, 'default':'white'},
timezoneOffset: Number,
language: String
language: String,
automaticAllocation: Boolean,
useCostume: Boolean
},
profile: {
blurb: String,
@ -202,10 +223,25 @@ var UserSchema = new Schema({
name: String,
},
stats: {
hp: Number,
exp: Number,
gp: Number,
lvl: Number
hp: {type: Number, 'default': 50},
mp: {type: Number, 'default': 10},
exp: {type: Number, 'default': 0},
gp: {type: Number, 'default': 0},
lvl: {type: Number, 'default': 1},
// Class System
'class': {type: String, enum: ['warrior','rogue','wizard','healer'], 'default': 'warrior'},
points: {type: Number, 'default': 0},
str: {type: Number, 'default': 0},
con: {type: Number, 'default': 0},
int: {type: Number, 'default': 0},
per: {type: Number, 'default': 0},
buffs: {
str: Number,
def: Number,
per: Number,
stealth: Number
}
},
tags: [
{
@ -268,10 +304,15 @@ UserSchema.pre('save', function(next) {
'Anonymous';
}
// FIXME handle this on level-up instead, and come up with how we're going to handle retroactively
// 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){
//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);
this.achievements.beastMaster = petCount >= 90;
//our own version incrementer

View file

@ -49,7 +49,7 @@ if (nconf.get('NODE_ENV') == 'development') {
}
/* Items*/
router.post('/user/buy/:type', auth.auth, cron, user.buy);
router.post('/user/buy/:key', auth.auth, cron, user.buy);
/* User*/
router.get('/user', auth.auth, cron, user.getUser);
@ -61,6 +61,7 @@ router.post('/user/buy-gems', auth.auth, user.buyGems);
router.post('/user/buy-gems/paypal-ipn', user.buyGemsPaypalIPN);
router.post('/user/unlock', auth.auth, cron, user.unlock);
router.post('/user/reset', auth.auth, user.reset);
router.post('/user/cast/:spell', auth.auth, user.cast);
router['delete']('/user', auth.auth, user['delete']);
/* Tags */

View file

@ -1,10 +1,11 @@
doctype 5
html
//html(ng-app="habitrpg", ng-controller="RootCtrl", ng-class='{"applying-action":applyingAction}', ui-keypress="{27:'castCancel()'}")
html(ng-app="habitrpg", ng-controller="RootCtrl", ng-class='{"applying-action":applyingAction}', ui-keypress="{27:'castCancel()'}")
head
title HabitRPG | Your Life The Role Playing Game
// ?v=1 needed to force refresh
link(rel='shortcut icon' href='#{env.getBuildUrl("favicon.ico")}?v=2')
link(rel='shortcut icon', href='#{env.getBuildUrl("favicon.ico")}?v=2')
script(type='text/javascript').
window.env = !{JSON.stringify(env)};
@ -21,7 +22,7 @@ html
meta(name='viewport', content='width=device-width')
meta(name='apple-mobile-web-app-capable', content='yes')
body(ng-app="habitrpg", ng-controller="RootCtrl", ng-cloak)
body(ng-cloak)
div(ng-controller='GroupsCtrl')
include ./shared/modals/index
include ./shared/header/header

View file

@ -5,6 +5,20 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
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')
h4 Gear
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}')
label.checkbox.inline
input(type="checkbox", ng-model="user.preferences.costume")
| Use Costume&nbsp;
i.icon-question-sign(popover="Show something different on your avatar than the gear you have equipped for battle", popover-trigger='mouseenter', popover-placement='right')
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}')
li.customize-menu
menu.pets-menu(label='Eggs ({{eggCount}})')
p(ng-show='eggCount < 1') You don't have any eggs.
@ -33,10 +47,10 @@ script(type='text/ng-template', id='partials/options.inventory.inventory.html')
.span6
h2 Market
.row-fluid
table.NPC-Alex-container
table.npc_alex_container
tr
td
.NPC-Alex.pull-left
.npc_alex.pull-left
td
.popover.static-popover.fade.right.in
.arrow

View file

@ -12,15 +12,19 @@ script(type='text/ng-template', id='partials/options.inventory.stable.html')
script(type='text/ng-template', id='partials/options.inventory.stable.mounts.html')
.stable
.NPC-Matt
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
.arrow
h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch') Matt Boch
.popover-content
p.
Shall I bring you your steed, {{user.profile.name}}? Click a mount to saddle up.
h4 {{mountCount}} / {{totalPets}} Mounts Tamed
table(style='width:100%')
tr
td(style='width:144px')
.npc_matt
td
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
.arrow
h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch') Matt Boch
.popover-content
p.
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')
menu
@ -28,7 +32,7 @@ script(type='text/ng-template', id='partials/options.inventory.stable.mounts.htm
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]')
img(src='/bower_components/habitrpg-shared/img/PixelPaw.png')
.PixelPaw
h4 Rare Mounts
menu
@ -40,15 +44,19 @@ script(type='text/ng-template', id='partials/options.inventory.stable.mounts.htm
script(type='text/ng-template', id='partials/options.inventory.stable.pets.html')
.stable
.NPC-Matt
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
.arrow
h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch') Matt Boch
.popover-content
p.
Welcome to the Stable! I'm Matt, the beast master. Choose a pet here to venture at your side. Feed them and they'll grow into powerful steeds. <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.
h4 {{petCount}} / {{totalPets}} Pets Found
table(style='width:100%')
tr
td(style='width:144px')
.npc_matt
td
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
.arrow
h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch') Matt Boch
.popover-content
p.
Welcome to the Stable! I'm Matt, the beast master. Choose a pet here to venture at your side. Feed them and they'll grow into powerful steeds. <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.
h4 {{petCount}} / {{totalPets}} Pets Found
menu.pets(type='list')
li.customize-menu(ng-repeat='egg in Items.eggs')
@ -58,7 +66,7 @@ script(type='text/ng-template', id='partials/options.inventory.stable.pets.html'
.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]')
img(src='/bower_components/habitrpg-shared/img/PixelPaw.png')
.PixelPaw
h4 Rare Pets
menu
@ -69,7 +77,7 @@ script(type='text/ng-template', id='partials/options.inventory.stable.pets.html'
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')
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!')
img(src='/bower_components/habitrpg-shared/img/PixelPaw-Gold.png')
.PixelPaw-Gold
.well.food-tray
p(ng-show='foodCount < 1') You don't have any food yet.

View file

@ -6,66 +6,83 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
li.customize-menu
menu(label='Head')
menu
button.m_head_0.customize-option(type='button', ng-click='set("preferences.gender","m")')
button.f_head_0.customize-option(type='button', ng-click='set("preferences.gender","f")')
label.checkbox
input(type='checkbox', ng-model='user.preferences.showHelm', ng-change='set("preferences.showHelm", user.preferences.showHelm?true: false)')
| Show Helm
menu(type='list')
li.customize-menu
menu(label='Clothing')
button.f_armor_0_v1.customize-option(ng-show='user.preferences.gender=="f"', type='button', ng-click='set("preferences.armorSet","v1")')
button.f_armor_0_v2.customize-option(ng-show='user.preferences.gender=="f"', type='button', ng-click='set("preferences.armorSet","v2")')
label.checkbox
input(type='checkbox', ng-model='user.preferences.showArmor', ng-change='set("preferences.showArmor", user.preferences.showArmor?true: false)')
| Show Armor
menu(type='list')
li.customize-menu
menu(label='Other')
label.checkbox
input(type='checkbox', ng-model='user.preferences.showWeapon', ng-change='set("preferences.showWeapon", user.preferences.showWeapon?true: false)')
| Show Weapon
label.checkbox
input(type='checkbox', ng-model='user.preferences.showShield', ng-change='set("preferences.showShield", user.preferences.showShield?true: false)')
| Show Shield
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
// hair
li.customize-menu
menu(label='Hair')
button(class='{{user.preferences.gender}}_hair_blond customize-option', type='button', ng-click='set("preferences.hair","blond")')
button(class='{{user.preferences.gender}}_hair_black customize-option', type='button', ng-click='set("preferences.hair","black")')
button(class='{{user.preferences.gender}}_hair_brown customize-option', type='button', ng-click='set("preferences.hair","brown")')
button(class='{{user.preferences.gender}}_hair_white customize-option', type='button', ng-click='set("preferences.hair","white")')
button(class='{{user.preferences.gender}}_hair_red customize-option', type='button', ng-click='set("preferences.hair","red")')
h3 Hair
menu(type='list')
// 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")')
// 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)')
// 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)')
// 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)')
// 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)')
.span4
// skin
li.customize-menu
menu(label='Basic Skins')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_asian', ng-click='set("preferences.skin","asian")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_white', ng-click='set("preferences.skin","white")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_ea8349', ng-click='set("preferences.skin","ea8349")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_c06534', ng-click='set("preferences.skin","c06534")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_98461a', ng-click='set("preferences.skin","98461a")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_black', ng-click='set("preferences.skin","black")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_dead', ng-click='set("preferences.skin","dead")')
button.customize-option(type='button', class='{{user.preferences.gender}}_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.
Rainbow Skins - 2<span class="Pet_Currency_Gem1x inline-gems"/>/skin
//menu(label='Rainbow Skins (2G / skin)')
menu
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_eb052b', ng-class='{locked: !user.purchased.skin.eb052b}', ng-click='unlock("skin.eb052b")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_f69922', ng-class='{locked: !user.purchased.skin.f69922}', ng-click='unlock("skin.f69922")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_f5d70f', ng-class='{locked: !user.purchased.skin.f5d70f}', ng-click='unlock("skin.f5d70f")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_0ff591', ng-class='{locked: !user.purchased.skin.0ff591}', ng-click='unlock("skin.0ff591")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_2b43f6', ng-class='{locked: !user.purchased.skin.2b43f6}', ng-click='unlock("skin.2b43f6")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_d7a9f7', ng-class='{locked: !user.purchased.skin.d7a9f7}', ng-click='unlock("skin.d7a9f7")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_800ed0', ng-class='{locked: !user.purchased.skin.800ed0}', ng-click='unlock("skin.800ed0")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_rainbow', ng-class='{locked: !user.purchased.skin.rainbow}', ng-click='unlock("skin.rainbow")')
button.customize-option(type='button', class='skin_eb052b', ng-class='{locked: !user.purchased.skin.eb052b}', ng-click='unlock("skin.eb052b")')
button.customize-option(type='button', class='skin_f69922', ng-class='{locked: !user.purchased.skin.f69922}', ng-click='unlock("skin.f69922")')
button.customize-option(type='button', class='skin_f5d70f', ng-class='{locked: !user.purchased.skin.f5d70f}', ng-click='unlock("skin.f5d70f")')
button.customize-option(type='button', class='skin_0ff591', ng-class='{locked: !user.purchased.skin.0ff591}', ng-click='unlock("skin.0ff591")')
button.customize-option(type='button', class='skin_2b43f6', ng-class='{locked: !user.purchased.skin.2b43f6}', ng-click='unlock("skin.2b43f6")')
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"/>
// Special Events
@ -73,18 +90,53 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
div(ng-if='user.purchased.skin.monster || user.purchased.skin.pumpkin || user.purchased.skin.skeleton || user.purchased.skin.zombie || user.purchased.skin.ghost || user.purchased.skin.shadow')
h5 Spooky Skins
menu
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_monster', ng-if='user.purchased.skin.monster', ng-click='unlock("skin.monster")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_pumpkin', ng-if='user.purchased.skin.pumpkin', ng-click='unlock("skin.pumpkin")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_skeleton', ng-if='user.purchased.skin.skeleton', ng-click='unlock("skin.skeleton")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_zombie', ng-if='user.purchased.skin.zombie', ng-click='unlock("skin.zombie")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_ghost', ng-if='user.purchased.skin.ghost', ng-click='unlock("skin.ghost")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_shadow', ng-if='user.purchased.skin.shadow', ng-click='unlock("skin.shadow")')
button.customize-option(type='button', class='skin_monster', ng-if='user.purchased.skin.monster', ng-click='unlock("skin.monster")')
button.customize-option(type='button', class='skin_pumpkin', ng-if='user.purchased.skin.pumpkin', ng-click='unlock("skin.pumpkin")')
button.customize-option(type='button', class='skin_skeleton', ng-if='user.purchased.skin.skeleton', ng-click='unlock("skin.skeleton")')
button.customize-option(type='button', class='skin_zombie', ng-if='user.purchased.skin.zombie', ng-click='unlock("skin.zombie")')
button.customize-option(type='button', class='skin_ghost', ng-if='user.purchased.skin.ghost', ng-click='unlock("skin.ghost")')
button.customize-option(type='button', class='skin_shadow', ng-if='user.purchased.skin.shadow', ng-click='unlock("skin.shadow")')
script(id='partials/options.profile.stats.html', type='text/ng-template')
.row-fluid
.span6.border-right
.border-right(ng-class='user.stats.lvl < 5 ? "span6" : "span4"')
include ../shared/profiles/stats
.span6.border-right
.span4.border-right(ng-show='user.stats.lvl >= 5')
h4
| {{user.stats.class}}&nbsp;
a.btn.btn-danger.btn-mini(ng-click='rerollClass()') 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)')
| 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
tr
td
i.icon-question-sign(popover-title='Strength', popover='Strength increases damage you inflict to tasks, reducing their redness', popover-trigger='mouseenter')
| &nbsp;STR: {{user.stats.str}}
td
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("str")') +
tr
td
i.icon-question-sign(popover-title='Defense', popover='Defense decreases damage inflicted by tasks, and increases the effectiveness of healing and buff spells', popover-trigger='mouseenter')
| &nbsp;DEF: {{user.stats.def}}
td
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("con")') +
tr
td
i.icon-question-sign(popover-title='Perception', popover='Perception increases the likelihood of drops, Gold bonuses, and critical hit chances', popover-trigger='mouseenter')
| &nbsp;PER: {{user.stats.per}}
td
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("per")') +
tr
td
i.icon-question-sign(popover-title='Intelligence', popover='Intelligence increases your overall mana, allowing you to cast more spells', popover-trigger='mouseenter')
| &nbsp;INT: {{user.stats.int}}
td
a.btn.btn-primary(ng-show='user.stats.points', ng-click='allocate("int")') +
.border-right(ng-class='user.stats.lvl < 5 ? "span6" : "span4"')
include ../shared/profiles/achievements
script(id='partials/options.profile.profile.html', type='text/ng-template')

View file

@ -1,7 +1,7 @@
a.pull-right.gem-wallet(popover-trigger='mouseenter', popover-title='Guild Bank', popover='Gems which your guild leader can use for challenge prizes.', popover-placement='left', popover-html='true')
// <span class="task-action-btn tile flush bright add-gems-btn"></span>
span.task-action-btn.tile.flush.neutral
.Gems
.Pet_Currency_Gem2x.Gems
| {{group.balance * 4 | number:0 }} Guild Gems
.row-fluid
.span4

View file

@ -4,7 +4,7 @@
table
tr
td
.NPC-Daniel
.npc_daniel
td
.popover.static-popover.fade.right.in
.arrow
@ -62,23 +62,23 @@
<span class='achievement achievement-firefox'></span> When your <strong>first</strong> submission is deployed, you will receive the HabitRPG Contributor's badge. Your name in Tavern chat will proudly display that you are a contributor. As a bounty for your work, you will also receive <strong>2 Gems</strong>.
hr
p.
<span class='shop_armor_7 shop-sprite item-img'></span> When your <strong>second</strong> submission is deployed, the <strong>Crystal Armor</strong> will be available for purchase in the Rewards shop after the Golden Armor. As a bounty for your continued work, you will also receive <strong>2 Gems</strong>.
<span class='shop_armor_special_1 shop-sprite item-img'></span> When your <strong>second</strong> submission is deployed, the <strong>Crystal Armor</strong> will be available for purchase in the Rewards shop after the Golden Armor. As a bounty for your continued work, you will also receive <strong>2 Gems</strong>.
tr
td
a.label.label-contributor-3(ng-click='toggleUserTier($event)') Elite (3-4)
div(style='display:none;')
p.
<span class='shop_head_7 shop-sprite item-img'></span> When your <strong>third</strong> submission is deployed, the <strong>Crystal Helmet</strong> will be available for purchase in the Rewards shop after the Golden Helmet. As a bounty for your great work, you will also receive <strong>2 Gems</strong>.
<span class='shop_head_special_1 shop-sprite item-img'></span> When your <strong>third</strong> submission is deployed, the <strong>Crystal Helmet</strong> will be available for purchase in the Rewards shop after the Golden Helmet. As a bounty for your great work, you will also receive <strong>2 Gems</strong>.
hr
p.
<span class='shop_weapon_8 shop-sprite item-img'></span> When your <strong>fourth</strong> submission is deployed, the <strong>Crystal Sword</strong> will be available for purchase in the Rewards shop after the Golden Sword. You will once again receive a bounty of <strong>2 Gems</strong>.
<span class='shop_weapon_special_1 shop-sprite item-img'></span> When your <strong>fourth</strong> submission is deployed, the <strong>Crystal Sword</strong> will be available for purchase in the Rewards shop after the Golden Sword. You will once again receive a bounty of <strong>2 Gems</strong>.
tr
td
a.label.label-contributor-5(ng-click='toggleUserTier($event)') Champion (5-6)
div(style='display:none;')
p.
<span class='shop_shield_7 shop-sprite item-img'></span> When your <em>fifth</em> submission is deployed, the <strong>Crystal Shield</strong> will be available for purchase in the Reward shop after the Golden Shield. You will also receive <strong>2 Gems</strong>.
<span class='shop_shield_special_1 shop-sprite item-img'></span> When your <em>fifth</em> submission is deployed, the <strong>Crystal Shield</strong> will be available for purchase in the Reward shop after the Golden Shield. You will also receive <strong>2 Gems</strong>.
hr
p.
<div class='Pet-Dragon-Hydra pull-left'></div> When your <em>sixth</em> submission is deployed, you will receive a <strong>Hydra Pet</strong>. You will also receive <strong>2 Gems</strong>.

View file

@ -1,5 +1,5 @@
a.pull-right.gem-wallet(ng-click='modals.buyGems = true', popover-trigger='mouseenter', popover-title='Gems', popover="Used for buying special items and services (eggs, hatching potions, Fortify, etc.). You'll need to unlock those features before being able to use Gems.", popover-placement='bottom')
span.task-action-btn.tile.flush.bright.add-gems-btn
span.task-action-btn.tile.flush.neutral
.Gems
.Pet_Currency_Gem2x.Gems
| {{user.balance * 4 | number:0}} Gems

View file

@ -3,28 +3,40 @@
Removing it will remove the user's name, but will allow more room for mounts & helms. IMO this is the lesser of two evils, revisit
//-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>")
figure.herobox(ng-click='clickMember(profile._id)', data-name='{{profile.profile.name}}', ng-class='{isUser: user._id==profile._id && !(user.items.currentMount && user.items.currentPet), hasPet: profile.items.currentPet && profile.items.currentMount, isLeader: party.leader==profile._id}')
figure.herobox(ng-click='spell ? castEnd(profile, "user", $event) : clickMember(profile._id)', data-name='{{profile.profile.name}}', ng-class='{isUser: user._id==profile._id && !(user.items.currentMount && user.items.currentPet), hasPet: profile.items.currentPet && profile.items.currentMount, "cast-target": applyingAction, isLeader: party.leader==profile._id}')
.character-sprites
// Mount Body
span(ng-if='profile.items.currentMount', class='Mount_Body_{{profile.items.currentMount}}')
// Avatar
span(class='{{profile.preferences.gender}}_skin_{{profile.preferences.skin}}')
span(class='{{profile.preferences.gender}}_hair_{{profile.preferences.hair}}')
span(class='{{equipped("armor", 0, profile.preferences, profile.backer, profile.contributor)}}')
span(class='{{equipped("armor", profile.items.armor, profile.preferences, profile.backer, profile.contributor)}}', ng-show='profile.preferences.showArmor')
span(class='{{profile.preferences.gender}}_head_0', ng-hide='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)}}', ng-show='profile.preferences.showShield')
span(class='{{equipped("weapon",profile.items.weapon,profile.preferences, profile.backer, profile.contributor)}}', ng-show='profile.preferences.showWeapon')
span(class='skin_{{profile.preferences.skin}}')
span(class='{{profile.preferences.size}}_{{profile.items.gear.equipped.armor}}', ng-if='!profile.preferences.costume')
span(class='{{profile.preferences.size}}_{{profile.items.gear.costume.armor}}', ng-if='profile.preferences.costume')
span(class='head_base_0')
span(class='hair_base_{{profile.preferences.hair.base}}_{{profile.preferences.hair.color}}')
span(class='hair_bangs_{{profile.preferences.hair.bangs}}_{{profile.preferences.hair.color}}')
span(class='hair_beard_{{profile.preferences.hair.beard}}_{{profile.preferences.hair.color}}')
span(class='hair_mustache_{{profile.preferences.hair.mustache}}_{{profile.preferences.hair.color}}')
span(class='{{profile.items.gear.equipped.head}}', ng-if='!profile.preferences.costume')
span(class='{{profile.items.gear.costume.head}}', ng-if='profile.preferences.costume')
span(class='{{profile.items.gear.equipped.shield}}', ng-if='!profile.preferences.costume')
span(class='{{profile.items.gear.costume.shield}}', ng-if='profile.preferences.costume')
span(class='{{profile.items.gear.equipped.weapon}}', ng-if='!profile.preferences.costume')
span(class='{{profile.items.gear.costume.weapon}}', ng-if='profile.preferences.costume')
// Mount Head
span(ng-if='profile.items.currentMount', 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
span.current-pet(class='Pet-{{profile.items.currentPet}}', ng-show='profile.items.currentPet && !minimal')
.avatar-level(ng-class='userLevelStyle(profile,"label")')

View file

@ -1,5 +1,4 @@
//.header-wrap(ng-controller='HeaderCtrl', data-spy="affix", data-offset-top="148")
.header-wrap(ng-controller='HeaderCtrl')
.header-wrap(ng-controller='HeaderCtrl', data-spy="affix", data-offset-top="148")
a.label.undo-button(x-bind='click:undo', ng-show='_undo') Undo
div(ng-if='!user.preferences.hideHeader')
include menu
@ -25,10 +24,16 @@
span(ng-show='user.history.exp')
a(ng-click='toggleChart("exp")', tooltip='Progress')
i.icon-signal
.meter.mana(title='Mana', ng-if='user.flags.classSelected')
.bar(style='width: {{percent(user.stats.mp, user.stats.int+10)}}%;')
span.meter-text
i.icon-fire
| {{user.stats.mp || 0 | number:0}} / {{user.stats.int+10}}
// party
span(ng-controller='PartyCtrl')
.herobox-wrap(ng-repeat='profile in partyMinusSelf')
include avatar
.NPC-Bailey-Head(ng-show='user.flags.newStuff', tooltip='Psst', tooltip-placement='top', ng-click='modals.newStuff=true')
.npc_bailey.npc_bailey_head(ng-show='user.flags.newStuff', tooltip='Psst', tooltip-placement='top', ng-click='modals.newStuff=true')

View file

@ -35,7 +35,7 @@ div(modal='user.flags.contributor')
.modal-header
h3 Contributor Achievement!
.modal-body
.NPC-Justin.float-left
.npc_justin.float-left
p.
{{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>

View file

@ -7,7 +7,7 @@ div(modal='modals.buyGems')
table
tr
td
.NPC-Justin
.npc_justin
td
.popover.static-popover.fade.right.in.wide-popover
.arrow

View file

@ -0,0 +1,69 @@
.modal(ng-if='!user.flags.classSelected && user.stats.lvl >= 5', data-backdrop=true, ng-controller='UserCtrl')
.modal-header
h3 Class System Unlocked!
.modal-body
.well Select your class. Upon level-up, you will now be able to allocate points to various stats. Alternatively, you can choose which stat your tasks represent (physical, mental, social, or "other") and drive your class automatically.
.well(ng-show='selectedClass=="warrior"') Warriors deal moderate damage to tasks and have moderate defense against tasks.
.well(ng-show='selectedClass=="wizard"') Wizards deal high damage to task, and can cast debuff spells on multiple tasks.
.well(ng-show='selectedClass=="rogue"') Rogues finds more drops, Gold, and have a high chance of dealing "critical hits," which grant large GP & Exp bonuses. Rogues can also "go stealth" to avoid and entire day of dailies.
.well(ng-show='selectedClass=="healer"') Healers have high defense against damage, and can heal themselves and other players in the party, as well as buff players.
.row-fluid
.span3(ng-click='selectedClass = "warrior"')
h5 Warrior
figure.herobox(ng-class='{"selected-class": selectedClass=="warrior"}')
.character-sprites
span(class='skin_{{user.preferences.skin}}')
span(class='{{user.preferences.size}}_armor_warrior_5')
span(class='head_base_0')
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
span(class='head_warrior_5')
span(class='shield_warrior_5')
span(class='weapon_warrior_6')
.span3(ng-click='selectedClass = "wizard"')
h5 Wizard
figure.herobox(ng-class='{"selected-class": selectedClass=="wizard"}')
.character-sprites
span(class='skin_{{user.preferences.skin}}')
span(class='{{user.preferences.size}}_armor_wizard_5')
span(class='head_base_0')
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
span(class='head_wizard_5')
span(class='shield_wizard_5')
span(class='weapon_wizard_6')
.span3(ng-click='selectedClass = "rogue"')
h5 Rogue
figure.herobox(ng-class='{"selected-class": selectedClass=="rogue"}')
.character-sprites
span(class='skin_{{user.preferences.skin}}')
span(class='{{user.preferences.size}}_armor_rogue_5')
span(class='head_base_0')
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
span(class='head_rogue_5')
span(class='shield_rogue_5')
span(class='weapon_rogue_6')
.span3(ng-click='selectedClass = "healer"')
h5 Healer
figure.herobox(ng-class='{"selected-class": selectedClass=="healer"}')
.character-sprites
span(class='skin_{{user.preferences.skin}}')
span(class='{{user.preferences.size}}_armor_healer_5')
span(class='head_base_0')
span(class='hair_base_{{user.preferences.hair.base}}_{{user.preferences.hair.color}}')
span(class='hair_bangs_{{user.preferences.hair.bangs}}_{{user.preferences.hair.color}}')
span(class='hair_beard_{{user.preferences.hair.beard}}_{{user.preferences.hair.color}}')
span(class='hair_mustache_{{user.preferences.hair.mustache}}_{{user.preferences.hair.color}}')
span(class='head_healer_5')
span(class='shield_healer_5')
span(class='weapon_healer_6')
.modal-footer
button.btn.btn-default.cancel(ng-click='rerollSubmit()') Select

View file

@ -3,7 +3,7 @@ div(modal='user.stats.hp <= 0', options='{backdrop:true, keyboard:false, backdro
.row-fluid
.span4
figure.notification-character
img(src='/bower_components/habitrpg-shared/img/sprites/dead.png')
.GrimReaper
.span8
h2 You Died!
.row-fluid

View file

@ -6,4 +6,5 @@ include ./new-stuff
include ./buy-gems
include ./members
include ./settings
include ./pets
include ./pets
include ./classes

View file

@ -5,7 +5,7 @@ div(modal='modals.newStuff')
table
tr
td
.NPC-Bailey
.npc_bailey
td
.popover.static-popover.fade.right.in.wide-popover
.arrow

View file

@ -31,19 +31,21 @@ div(ng-controller='SettingsCtrl')
.option-group.option-medium
input.option-content(type='number', data-for='stats.lvl', ng-model='restoreValues.stats.lvl')
span.input-suffix Level
h3 Equipment
.option-group.option-medium
input.option-content(type='number', data-for='items.weapon', ng-model='restoreValues.items.weapon')
span.input-suffix Weapon
.option-group.option-medium
input.option-content(type='number', data-for='items.armor', ng-model='restoreValues.items.armor')
span.input-suffix Armor
.option-group.option-medium
input.option-content(type='number', data-for='items.head', ng-model='restoreValues.items.head')
span.input-suffix Helm
.option-group.option-medium
input.option-content(type='number', data-for='items.shield', ng-model='restoreValues.items.shield')
span.input-suffix Shield
//-
//- Commenting out since it doesn't make sense to restore equipment with Armory anymore. They can just restore GP & buy
h3 Equipment
.option-group.option-medium
input.option-content(type='number', data-for='items.weapon', ng-model='restoreValues.items.weapon')
span.input-suffix Weapon
.option-group.option-medium
input.option-content(type='number', data-for='items.armor', ng-model='restoreValues.items.armor')
span.input-suffix Armor
.option-group.option-medium
input.option-content(type='number', data-for='items.head', ng-model='restoreValues.items.head')
span.input-suffix Helm
.option-group.option-medium
input.option-content(type='number', data-for='items.shield', ng-model='restoreValues.items.shield')
span.input-suffix Shield
h3 Achievements
.option-group.option-medium
input.option-content(type='number', data-for='achievements.streak', ng-model='restoreValues.achievements.streak')

View file

@ -45,8 +45,8 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
include ./task
// Static Rewards
ul.items(bo-if='main && list.type=="reward" && user.flags.itemsEnabled')
li.task.reward-item(ng-hide='item.hide', ng-repeat='item in itemStore')
ul.items.rewards(bo-if='main && list.type=="reward" && user.flags.itemsEnabled')
li.task.reward-item(ng-repeat='item in itemStore')
// right-hand side control buttons
.task-meta-controls
span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{item.notes}}', popover-title='{{item.text}}')
@ -55,13 +55,29 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
.task-controls
a.task-action-btn.btn-reroll(bo-if='item.type=="reroll"', ng-click='modals.reroll = true')
i.icon-repeat
a.money.btn-buy.item-btn(bo-if='item.type!="reroll"', ng-click='buy(item.type)')
a.money.btn-buy.item-btn(bo-if='item.type!="reroll"', ng-click='buy(item)')
span.reward-cost {{item.value}}
span.shop_gold
// main content
span(bo-class='{"shop_{{item.classes}} shop-sprite item-img": true}')
span(bo-class='{"shop_{{item.key}} shop-sprite item-img": true}')
p.task-text {{item.text}}
// 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')
.task-meta-controls
span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{spell.notes}}', popover-title='{{spell.text}}')
i.icon-comment
//left-hand size commands
.task-controls
a.money.btn-buy.item-btn(ng-click='castStart(spell)')
span.reward-cost
strong {{spell.mana}}
| &nbsp;MP
// main content
span(ng-class='{"shop_{{spell.key}} shop-sprite item-img": true}')
p.task-text {{spell.text}}
br
// Ads

View file

@ -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)}}', data-id='{{task.id}}')
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}')
// right-hand side control buttons
.task-meta-controls
@ -161,6 +161,14 @@ li(bindonce='list', ng-repeat='task in obj[list.type+"s"]', class='task {{taskCl
span(ng-if='task.type=="daily"')
legend.option-title Restore Streak
input.option-content(type='number', ng-model='task.streak')
legend.option-title Attributes
.task-controls.tile-group
button.task-action-btn.tile(type='button') Physical
button.task-action-btn.tile(type='button') Mental
button.task-action-btn.tile(type='button') Social
button.task-action-btn.tile(type='button') Other
button.task-action-btn.tile.spacious(type='submit') Save & Close
div(class='{{obj._id}}{{task.id}}-chart', ng-show='charts[obj._id+task.id]')