diff --git a/locales/en/app.json b/locales/en/app.json
index c45eaf02b0..0c0fa858bb 100644
--- a/locales/en/app.json
+++ b/locales/en/app.json
@@ -302,7 +302,7 @@
"_commentitemsother" : "OTHER ITEMS",
"healthPotionName" : "Health Potion",
"healthPotionNotes" : "Recover 15 HP Instantly",
- "rerollName" : "Fortify",
+ "rerollName" : "Fortify Potion",
"rerollNotes" : "Resets your task values back to yellow. Useful when everything's red and it's hard to stay alive.",
"rerollModelHeader" : "Reset Your Tasks",
"rerollModelText1" : "Highly discouraged because red tasks provide good incentive to improve",
diff --git a/public/css/inventory.styl b/public/css/inventory.styl
index 50df7c71ab..cf7e917846 100644
--- a/public/css/inventory.styl
+++ b/public/css/inventory.styl
@@ -84,7 +84,7 @@ menu.pets div
margin-top:1em
p
text-align:center
- width:6em
+ //width:6em
margin-top:-.5em
.hatchingPotion-menu > div
display:inline-block
diff --git a/public/js/controllers/rootCtrl.js b/public/js/controllers/rootCtrl.js
index 9c58f11fd7..06f7266bf9 100644
--- a/public/js/controllers/rootCtrl.js
+++ b/public/js/controllers/rootCtrl.js
@@ -166,6 +166,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
$event && ($event.stopPropagation(),$event.preventDefault());
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(){
var msg = "You cast " + $scope.spell.text;
switch (type) {
diff --git a/src/controllers/user.js b/src/controllers/user.js
index b23e601ba2..90ff07fd38 100644
--- a/src/controllers/user.js
+++ b/src/controllers/user.js
@@ -299,7 +299,8 @@ api.buyGemsPaypalIPN = function(req, res) {
api.cast = function(req, res) {
var user = res.locals.user;
var type = req.body.type, target = req.body.target;
- var spell = shared.content.spells[user.stats.class][req.params.spell];
+ var klass = shared.content.spells.special[req.params.spell] ? 'special' : user.stats.class
+ var spell = shared.content.spells[klass][req.params.spell];
var done = function(){
var err = arguments[0];
diff --git a/src/models/user.js b/src/models/user.js
index 8a183b4b56..e757c0c3dd 100644
--- a/src/models/user.js
+++ b/src/models/user.js
@@ -43,6 +43,7 @@ var UserSchema = new Schema({
ultimateGear: Boolean,
beastMaster: Boolean,
veteran: Boolean,
+ snowball: Number,
streak: Number,
challenges: Array
},
@@ -62,9 +63,7 @@ var UserSchema = new Schema({
backer: {
tier: Number,
- //admin: Boolean, // FIXME migrate to contributor.admin
npc: String,
- //contributor: String, // FIXME migrate to contributor.text
tokensApplied: Boolean
},
@@ -82,7 +81,7 @@ var UserSchema = new Schema({
ads: {type: Boolean, 'default': false},
skin: {type: Schema.Types.Mixed, 'default': {}}, // eg, {skeleton: true, pumpkin: true, eb052b: true}
hair: {type: Schema.Types.Mixed, 'default': {}},
- shirt: {type: Schema.Types.Mixed, 'default': {}}
+ shirt: {type: Schema.Types.Mixed, 'default': {}},
},
flags: {
@@ -128,6 +127,10 @@ var UserSchema = new Schema({
},
},
+ special:{
+ snowball: {type: Number, 'default': 0}
+ },
+
// -------------- Animals -------------------
// Complex bit here. The result looks like:
// pets: {
@@ -245,7 +248,8 @@ var UserSchema = new Schema({
per: Number,
con: Number,
stealth: Number,
- streaks: Boolean
+ streaks: Boolean,
+ snowball: Boolean
}
},
tags: [
diff --git a/views/options/inventory/inventory.jade b/views/options/inventory/inventory.jade
index 3bf6c9db29..ef8f4c040e 100644
--- a/views/options/inventory/inventory.jade
+++ b/views/options/inventory/inventory.jade
@@ -47,6 +47,12 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html')
.badge.badge-info.stack-count {{points}}
//-p {{food}}
+ li.customize-menu(ng-if='user.items.special.snowball')
+ menu.pets-menu(label='Special')
+ div
+ button.customize-option(popover='{{Content.special.snowball.notes}}', popover-title='{{Content.special.snowball.text}}', popover-trigger='mouseenter', popover-placement='right', ng-click='castStart(Content.special.snowball)', class='inventory_special_snowball')
+ .badge.badge-info.stack-count {{user.items.special.snowball}}
+
.span6
h2 Market
.row-fluid
@@ -94,17 +100,21 @@ script(type='text/ng-template', id='partials/options.inventory.drops.html')
p
| {{food.value}}
span.Pet_Currency_Gem1x.inline-gems
- menu.pets-menu(label='Saddle')
+
+ 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}}')
p
| {{Content.food.Saddle.value}}
span.Pet_Currency_Gem1x.inline-gems
-
- li.customize-menu
- menu.pets-menu(label='Services')
div
- // Once grunt-spritesmith is merged, let's use https://github.com/browserquest/BrowserQuest/blob/master/client/img/1/item-firepotion.png
- button.btn(popover='Return all tasks to neutral value (yellow color), and restore all lost Health.', popover-title=env.t('rerollName'), popover-trigger='mouseenter', popover-placement='left', ng-click='modals.reroll = true')
- | Fortify 4
+ button.customize-option(popover='Return all tasks to neutral value (yellow color), and restore all lost Health.', popover-title=env.t('rerollName'), popover-trigger='mouseenter', popover-placement='left', ng-click='modals.reroll = true', class='inventory_special_fortify')
+ p
+ | 4
+ span.Pet_Currency_Gem1x.inline-gems
+ div
+ button.customize-option(popover='{{Content.spells.special.snowball.notes}}', popover-title='{{Content.spells.special.snowball.text}}', popover-trigger='mouseenter', popover-placement='left', ng-click='purchase("special", Content.spells.special.snowball)', class='inventory_special_snowball')
+ p
+ | {{Content.spells.special.snowball.value}}
span.Pet_Currency_Gem1x.inline-gems
diff --git a/views/options/profile.jade b/views/options/profile.jade
index 13640cc4de..bbf97f5c93 100644
--- a/views/options/profile.jade
+++ b/views/options/profile.jade
@@ -37,12 +37,21 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
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"})')
+ // Special Events
+ li.customize-menu.well.limited-edition
+ .label.label-info.pull-right(popover='Available for purchase until January 31st (but permanently in your options if purchased).', popover-title='Limited Edition', popover-placement='right', popover-trigger='mouseenter')
+ | Limited Edition
+ i.icon.icon-question-sign
+ menu(label='Winter Colors')
+ each color in ['candycane','frost','winternight','holly']
+ button(type='button', ng-class='{locked: !user.purchased.hair.color.#{color}}', class='customize-option hair_bangs_1_#{color}', style='width: 40px; height: 40px;', ng-click='unlock("hair.color.#{color}")')
+ button.btn.btn-small.btn-primary(ng-hide='user.purchased.hair.color.candycane && user.purchased.hair.color.frost && user.purchased.hair.color.winternight && user.purchased.hair.color.holly', ng-click='unlock("hair.color.candycane,hair.color.frost,hair.color.winternight,hair.color.holly")') Unlock Set - 5
h5 Hair
// 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='head_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})')
@@ -50,7 +59,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
// 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='head_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-class='{locked: !user.purchased.hair.base.2}', ng-click='unlock("hair.base.2")')
button(class='hair_base_3_{{user.preferences.hair.color}} customize-option', type='button', ng-click='set({"preferences.hair.base":3})')
@@ -67,7 +76,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
// 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='head_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-class='{locked: !user.purchased.hair.beard.1}', ng-click='unlock("hair.beard.1")')
button(class='hair_beard_2_{{user.preferences.hair.color}} customize-option', type='button', ng-class='{locked: !user.purchased.hair.beard.2}', ng-click='unlock("hair.beard.2")')
button(class='hair_beard_3_{{user.preferences.hair.color}} customize-option', type='button', ng-class='{locked: !user.purchased.hair.beard.3}', ng-click='unlock("hair.beard.3")')
@@ -75,7 +84,7 @@ script(id='partials/options.profile.avatar.html', type='text/ng-template')
// 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='head_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-class='{locked: !user.purchased.hair.mustache.1}', ng-click='unlock("hair.mustache.1")')
button(class='hair_mustache_2_{{user.preferences.hair.color}} customize-option', type='button', ng-class='{locked: !user.purchased.hair.mustache.2}', ng-click='unlock("hair.mustache.2")')
diff --git a/views/shared/header/avatar.jade b/views/shared/header/avatar.jade
index 572a31cf37..fd9ed71529 100644
--- a/views/shared/header/avatar.jade
+++ b/views/shared/header/avatar.jade
@@ -8,29 +8,32 @@ figure.herobox(ng-click='spell ? castEnd(profile, "user", $event) : clickMember(
// Mount Body
span(ng-if='profile.items.currentMount', class='Mount_Body_{{profile.items.currentMount}}')
- // Avatar
- span(class='skin_{{profile.preferences.skin}}')
+ span(ng-if='profile.stats.buffs.snowball')
+ span.snowman
+ span(ng-if='!profile.stats.buffs.snowball')
+ // Avatar
+ span(class='skin_{{profile.preferences.skin}}')
- span(class='{{profile.preferences.size}}_shirt_{{profile.preferences.shirt}}')
- 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='{{profile.preferences.size}}_shirt_{{profile.preferences.shirt}}')
+ 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='head_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='hair_mustache_{{profile.preferences.hair.mustache}}_{{profile.preferences.hair.color}}')
+ span(class='hair_beard_{{profile.preferences.hair.beard}}_{{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.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.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')
+ 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
diff --git a/views/shared/modals/new-stuff.jade b/views/shared/modals/new-stuff.jade
index 90b2709d7e..15069e69b0 100644
--- a/views/shared/modals/new-stuff.jade
+++ b/views/shared/modals/new-stuff.jade
@@ -12,46 +12,77 @@ div(modal='modals.newStuff')
h3.popover-title
a(target='_blank', href='https://twitter.com/Mihakuu') Bailey
.popover-content
- p Good gracious, where do I start...
- br
+
+ h4 Winter Wonderland Event!
+ p It's time for HabitRPG's biggest event yet - Winter Wonderland! The fun starts today, on the first day of winter, and ends on January 31st - HabitRPG's birthday.
+ p Get prepared to build new habits, earn fun drops, hold your party members accountable for their tasks, and decorate your avatar. Various features will be rolling out over the course of the event, so expect many updates! For starters...
+
table.table.table-striped
tr
td
- h4 Classes
- p You can now be a Warrior, Rogue, Wizard, or Healer. See details here.
+ h4 NPC Decorations
+ p Looks like everyone is really getting into the winter spirit! Check out the new NPC sprites. (And I heard a rumor that the final NPC might show up, just in time for the new year...)
tr
td
- h4 Armory & Costumes
- p Once you select your new class, you're now equipped with your new class's apprentice gear. Fear not, your old gear is still available in your inventory! You can switch gear at any time, and wear a different costume than your equipment. See Armory & Costumes
+ .customize-option.hair_bangs_1_winternight.pull-right
+ h4 Limited-Edition Holiday Hair-Colors
+ p Now your avatar can dye their hair Candy Cane, Frost, Winter Sky, or Holly! You'll only be able to purchase these hair colors until January 31st, when they will be retired.
tr
td
- h4 New Customizations
- p We now have a much wider selection of hair, shirt, facial-hair, body-size, etc. customizations. See Customizations v2
+ .shop_snowball.pull-right
+ h4 The Great HabitRPG Snowball Fight
+ p Yes, you can now buy snowballs and hurl them at all your friends... to, uh, help them improve their habits. How? Weeeeellll, let's just say that after getting walloped, they might find themselves needing some extra gold to escape their predicament...
+ //-span.shop_head_special_candycane.item-img.shop-sprite
tr
td
- h4 300 Tier Gear
- p All you $300 backers who have been waiting patiently, your gear is now in! Currently, only available to $300+ backers, but we'll add them as drops to the Boss system once that's released. See 300-tier
- tr
- td
- h4 API v2
- p The API has been completely overhauled, and v2 comes with many more routes for a *full featured* API. v1 is no longer supported, take heed ye 3rd-party-ists! For the time being, basic routes are supported (such as up/down -scoring). v2 will be documented soon, and I'll ping you when. see APIv2
+ h4 More to Come
+ p A beast is roaring in the distant mountains, mysterious tracks have appeared in the snow, and Lemoness is furiously crocheting something sparkly.
+ p It's going to be a wild winter.
+
hr
- p By @lemoness @sabrecat @danielthebard @fuzzytrees @crystalphoenix @rosemonkeyct @fandekasp, and many more. (Who am I missing? We'll put up a CONTRIBUTORS.md soon)
- small.muted 12/16/2013
+ p By @lemoness
+ small.muted 12/20/2013
hr
+ h5 12/16/2013
+ p Good gracious, where do I start...
+ br
+ table.table.table-striped
+ tr
+ td
+ h4 Classes
+ p You can now be a Warrior, Rogue, Wizard, or Healer. See details here.
+ tr
+ td
+ h4 Armory & Costumes
+ p Once you select your new class, you're now equipped with your new class's apprentice gear. Fear not, your old gear is still available in your inventory! You can switch gear at any time, and wear a different costume than your equipment. See Armory & Costumes
+ tr
+ td
+ h4 New Customizations
+ p We now have a much wider selection of hair, shirt, facial-hair, body-size, etc. customizations. See Customizations v2
+ tr
+ td
+ h4 300 Tier Gear
+ p All you $300 backers who have been waiting patiently, your gear is now in! Currently, only available to $300+ backers, but we'll add them as drops to the Boss system once that's released. See 300-tier
+ tr
+ td
+ h4 API v2
+ p The API has been completely overhauled, and v2 comes with many more routes for a *full featured* API. v1 is no longer supported, take heed ye 3rd-party-ists! For the time being, basic routes are supported (such as up/down -scoring). v2 will be documented soon, and I'll ping you when. see APIv2
+ hr
+ p By @lemoness @sabrecat @danielthebard @fuzzytrees @crystalphoenix @rosemonkeyct @fandekasp, and many more. (Who am I missing? We'll put up a CONTRIBUTORS.md soon)
+
h5 12/7/20132
- table.table.table-striped
- tr
- td
- h4 Mounts!
- p You can now feed your pets and they'll grow into trusty steeds. Obtain food as new random drops, or you can hasten the process buy buying a saddle from Alexander.
- // We may want to use their twitter handles, or something they prefer instead
- hr
- p.
- By @lemoness @Shaners @baconsaur @RandallStanhope @ashjolliffe @fuzzytrees
+ table.table.table-striped
+ tr
+ td
+ h4 Mounts!
+ p You can now feed your pets and they'll grow into trusty steeds. Obtain food as new random drops, or you can hasten the process buy buying a saddle from Alexander.
+ // We may want to use their twitter handles, or something they prefer instead
+ hr
+ p.
+ By @lemoness @Shaners @baconsaur @RandallStanhope @ashjolliffe @fuzzytrees
h5 11/27/2013
table.table.table-striped
diff --git a/views/shared/tasks/lists.jade b/views/shared/tasks/lists.jade
index 99677d4012..1de3dd95a7 100644
--- a/views/shared/tasks/lists.jade
+++ b/views/shared/tasks/lists.jade
@@ -60,6 +60,32 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
span(bo-class='{"shop_{{item.key}} shop-sprite item-img": true}')
p.task-text {{item.text}}
+ // Winter Event
+ ul.items.rewards(ng-if='main && list.type=="reward" && (user.items.special.snowball>0 || user.stats.buffs.snowball)')
+ li.task.reward-item(ng-if='user.items.special.snowball>0')
+ .task-meta-controls
+ span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{Content.spells.special.snowball.notes}}', popover-title='{{Content.spells.special.snowball.text}}')
+ i.icon-comment
+ //left-hand size commands
+ .task-controls
+ a.money.btn-buy.item-btn(ng-click='castStart(Content.spells.special.snowball)')
+ span.reward-cost {{user.items.special.snowball}}
+ span.shop_snowball(style='display:inline-block;vertical-align:top;')
+ // main content
+ p.task-text {{Content.spells.special.snowball.text}}
+ li.task.reward-item(ng-if='user.stats.buffs.snowball')
+ .task-meta-controls
+ span.task-notes(popover-trigger='mouseenter', popover-placement='left', popover='{{Content.spells.special.salt.notes}}', popover-title='{{Content.spells.special.salt.text}}')
+ i.icon-comment
+ //left-hand size commands
+ .task-controls
+ a.money.btn-buy.item-btn(ng-click='castStart(Content.spells.special.salt)')
+ span.reward-cost {{Content.spells.special.salt.value}}
+ span.shop_gold
+ // main content
+ span.shop_salt.shop-sprite.item-img
+ p.task-text {{Content.spells.special.salt.text}}
+
// Spells
ul.items(ng-if='main && list.type=="reward" && user.stats.class && !user.preferences.disableClasses')
li.task.reward-item(ng-repeat='(k,spell) in Content.spells[user.stats.class]', ng-show='user.stats.lvl >= spell.lvl')