feat(content): Animal Tails
@@ -193,8 +193,10 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
|||||||
.col-3.text-center.sub-menu-item(@click='changeSubPage("flower")', :class='{active: activeSubPage === "flower"}')
|
.col-3.text-center.sub-menu-item(@click='changeSubPage("flower")', :class='{active: activeSubPage === "flower"}')
|
||||||
strong(v-once) {{$t('accent')}}
|
strong(v-once) {{$t('accent')}}
|
||||||
.row.sub-menu(v-if='editing')
|
.row.sub-menu(v-if='editing')
|
||||||
.col-4.offset-2.text-center.sub-menu-item(@click='changeSubPage("ears")' :class='{active: activeSubPage === "ears"}')
|
.col-4.text-center.sub-menu-item(@click='changeSubPage("ears")' :class='{active: activeSubPage === "ears"}')
|
||||||
strong(v-once) {{$t('animalEars')}}
|
strong(v-once) {{$t('animalEars')}}
|
||||||
|
.col-4.text-center.sub-menu-item(@click='changeSubPage("tails")' :class='{active: activeSubPage === "tails"}')
|
||||||
|
strong(v-once) {{$t('animalTails')}}
|
||||||
.col-4.text-center.sub-menu-item(@click='changeSubPage("headband")' :class='{active: activeSubPage === "headband"}')
|
.col-4.text-center.sub-menu-item(@click='changeSubPage("headband")' :class='{active: activeSubPage === "headband"}')
|
||||||
strong(v-once) {{$t('headband')}}
|
strong(v-once) {{$t('headband')}}
|
||||||
#glasses.row(v-if='activeSubPage === "glasses"')
|
#glasses.row(v-if='activeSubPage === "glasses"')
|
||||||
@@ -203,17 +205,30 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
|||||||
.sprite.customize-option(:class="`eyewear_special_${option.key}`", @click='option.click')
|
.sprite.customize-option(:class="`eyewear_special_${option.key}`", @click='option.click')
|
||||||
#animal-ears.row(v-if='activeSubPage === "ears"')
|
#animal-ears.row(v-if='activeSubPage === "ears"')
|
||||||
.section.col-12.customize-options
|
.section.col-12.customize-options
|
||||||
.option(v-for='option in animalEars',
|
.option(v-for='option in animalItems("headAccessory")',
|
||||||
:class='{active: option.active, locked: option.locked}')
|
:class='{active: option.active, locked: option.locked}')
|
||||||
.sprite.customize-option(:class="`headAccessory_special_${option.key}`", @click='option.click')
|
.sprite.customize-option(:class="`headAccessory_special_${option.key}`", @click='option.click')
|
||||||
.gem-lock(v-if='option.locked')
|
.gem-lock(v-if='option.locked')
|
||||||
.svg-icon.gem(v-html='icons.gem')
|
.svg-icon.gem(v-html='icons.gem')
|
||||||
span 2
|
span 2
|
||||||
.col-12.text-center(v-if='!animalEarsOwned')
|
.col-12.text-center(v-if='!animalItemsOwned("headAccessory")')
|
||||||
.gem-lock
|
.gem-lock
|
||||||
.svg-icon.gem(v-html='icons.gem')
|
.svg-icon.gem(v-html='icons.gem')
|
||||||
span 5
|
span 5
|
||||||
button.btn.btn-secondary.purchase-all(@click='unlock(animalEarsUnlockString)') {{ $t('purchaseAll') }}
|
button.btn.btn-secondary.purchase-all(@click='unlock(animalItemsUnlockString("headAccessory"))') {{ $t('purchaseAll') }}
|
||||||
|
#animal-tails.row(v-if='activeSubPage === "tails"')
|
||||||
|
.section.col-12.customize-options
|
||||||
|
.option(v-for='option in animalItems("back")',
|
||||||
|
:class='{active: option.active, locked: option.locked}')
|
||||||
|
.sprite.customize-option(:class="`icon_back_special_${option.key}`", @click='option.click')
|
||||||
|
.gem-lock(v-if='option.locked')
|
||||||
|
.svg-icon.gem(v-html='icons.gem')
|
||||||
|
span 2
|
||||||
|
.col-12.text-center(v-if='!animalItemsOwned("back")')
|
||||||
|
.gem-lock
|
||||||
|
.svg-icon.gem(v-html='icons.gem')
|
||||||
|
span 5
|
||||||
|
button.btn.btn-secondary.purchase-all(@click='unlock(animalItemsUnlockString("back"))') {{ $t('purchaseAll') }}
|
||||||
#headband.row(v-if='activeSubPage === "headband"')
|
#headband.row(v-if='activeSubPage === "headband"')
|
||||||
.col-12.customize-options
|
.col-12.customize-options
|
||||||
.option(v-for='option in headbands', :class='{active: option.active}')
|
.option(v-for='option in headbands', :class='{active: option.active}')
|
||||||
@@ -1013,7 +1028,10 @@ export default {
|
|||||||
baseHair4Keys: [15, 16, 17, 18, 19, 20],
|
baseHair4Keys: [15, 16, 17, 18, 19, 20],
|
||||||
baseHair5Keys: [1, 2],
|
baseHair5Keys: [1, 2],
|
||||||
baseHair6Keys: [1, 2, 3],
|
baseHair6Keys: [1, 2, 3],
|
||||||
animalEarsKeys: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
|
animalItemKeys: {
|
||||||
|
back: ['bearTail', 'cactusTail', 'foxTail', 'lionTail', 'pandaTail', 'pigTail', 'tigerTail', 'wolfTail'],
|
||||||
|
headAccessory: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
|
||||||
|
},
|
||||||
chairKeys: ['black', 'blue', 'green', 'pink', 'red', 'yellow', 'handleless_black', 'handleless_blue', 'handleless_green', 'handleless_pink', 'handleless_red', 'handleless_yellow'],
|
chairKeys: ['black', 'blue', 'green', 'pink', 'red', 'yellow', 'handleless_black', 'handleless_blue', 'handleless_green', 'handleless_pink', 'handleless_red', 'handleless_yellow'],
|
||||||
icons: Object.freeze({
|
icons: Object.freeze({
|
||||||
logoPurple,
|
logoPurple,
|
||||||
@@ -1075,44 +1093,6 @@ export default {
|
|||||||
});
|
});
|
||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
animalEarsUnlockString () {
|
|
||||||
let animalItemKeys = this.animalEarsKeys.map(key => {
|
|
||||||
return `items.gear.owned.headAccessory_special_${key}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
return animalItemKeys.join(',');
|
|
||||||
},
|
|
||||||
animalEarsOwned () {
|
|
||||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
|
||||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
|
||||||
|
|
||||||
let own = true;
|
|
||||||
this.animalEarsKeys.forEach(key => {
|
|
||||||
if (!this.user.items.gear.owned[`headAccessory_special_${key}`]) own = false;
|
|
||||||
});
|
|
||||||
return own;
|
|
||||||
},
|
|
||||||
animalEars () {
|
|
||||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
|
||||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
|
||||||
let keys = this.animalEarsKeys;
|
|
||||||
let options = keys.map(key => {
|
|
||||||
let newKey = `headAccessory_special_${key}`;
|
|
||||||
let userPurchased = this.user.items.gear.owned[newKey];
|
|
||||||
let locked = !userPurchased;
|
|
||||||
|
|
||||||
let option = {};
|
|
||||||
option.key = key;
|
|
||||||
option.active = this.user.preferences.costume ? this.user.items.gear.costume.headAccessory === newKey : this.user.items.gear.equipped.headAccessory === newKey;
|
|
||||||
option.locked = locked;
|
|
||||||
option.click = () => {
|
|
||||||
let type = this.user.preferences.costume ? 'costume' : 'equipped';
|
|
||||||
return locked ? this.unlock(`items.gear.owned.${newKey}`) : this.equip(newKey, type);
|
|
||||||
};
|
|
||||||
return option;
|
|
||||||
});
|
|
||||||
return options;
|
|
||||||
},
|
|
||||||
specialShirts () {
|
specialShirts () {
|
||||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||||
@@ -1550,6 +1530,44 @@ export default {
|
|||||||
backgroundPurchased () {
|
backgroundPurchased () {
|
||||||
this.backgroundUpdate = new Date();
|
this.backgroundUpdate = new Date();
|
||||||
},
|
},
|
||||||
|
animalItemsUnlockString (category) {
|
||||||
|
const keys = this.animalItemKeys[category].map(key => {
|
||||||
|
return `items.gear.owned.${category}_special_${key}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return keys.join(',');
|
||||||
|
},
|
||||||
|
animalItemsOwned (category) {
|
||||||
|
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||||
|
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||||
|
|
||||||
|
let own = true;
|
||||||
|
this.animalItemKeys[category].forEach(key => {
|
||||||
|
if (!this.user.items.gear.owned[`${category}_special_${key}`]) own = false;
|
||||||
|
});
|
||||||
|
return own;
|
||||||
|
},
|
||||||
|
animalItems (category) {
|
||||||
|
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||||
|
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||||
|
let keys = this.animalItemKeys[category];
|
||||||
|
let options = keys.map(key => {
|
||||||
|
let newKey = `${category}_special_${key}`;
|
||||||
|
let userPurchased = this.user.items.gear.owned[newKey];
|
||||||
|
let locked = !userPurchased;
|
||||||
|
|
||||||
|
let option = {};
|
||||||
|
option.key = key;
|
||||||
|
option.active = this.user.preferences.costume ? this.user.items.gear.costume[category] === newKey : this.user.items.gear.equipped[category] === newKey;
|
||||||
|
option.locked = locked;
|
||||||
|
option.click = () => {
|
||||||
|
let type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||||
|
return locked ? this.unlock(`items.gear.owned.${newKey}`) : this.equip(newKey, type);
|
||||||
|
};
|
||||||
|
return option;
|
||||||
|
});
|
||||||
|
return options;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1512,6 +1512,7 @@
|
|||||||
"backCapitalized": "Back Accessory",
|
"backCapitalized": "Back Accessory",
|
||||||
"backBase0Text": "No Back Accessory",
|
"backBase0Text": "No Back Accessory",
|
||||||
"backBase0Notes": "No Back Accessory.",
|
"backBase0Notes": "No Back Accessory.",
|
||||||
|
"animalTails": "Animal Tails",
|
||||||
|
|
||||||
"backMystery201402Text": "Golden Wings",
|
"backMystery201402Text": "Golden Wings",
|
||||||
"backMystery201402Notes": "These shining wings have feathers that glitter in the sun! Confers no benefit. February 2014 Subscriber Item.",
|
"backMystery201402Notes": "These shining wings have feathers that glitter in the sun! Confers no benefit. February 2014 Subscriber Item.",
|
||||||
@@ -1558,6 +1559,22 @@
|
|||||||
"backSpecialAetherCloakNotes": "This cloak once belonged to the Lost Masterclasser herself. Increases Perception by <%= per %>.",
|
"backSpecialAetherCloakNotes": "This cloak once belonged to the Lost Masterclasser herself. Increases Perception by <%= per %>.",
|
||||||
"backSpecialTurkeyTailBaseText": "Turkey Tail",
|
"backSpecialTurkeyTailBaseText": "Turkey Tail",
|
||||||
"backSpecialTurkeyTailBaseNotes": "Wear your noble Turkey Tail with pride while you celebrate! Confers no benefit.",
|
"backSpecialTurkeyTailBaseNotes": "Wear your noble Turkey Tail with pride while you celebrate! Confers no benefit.",
|
||||||
|
"backBearTailText": "Bear Tail",
|
||||||
|
"backBearTailNotes": "This tail makes you look like a brave bear! Confers no benefit.",
|
||||||
|
"backCactusTailText": "Cactus Tail",
|
||||||
|
"backCactusTailNotes": "This tail makes you look like a prickly cactus! Confers no benefit.",
|
||||||
|
"backFoxTailText": "Fox Tail",
|
||||||
|
"backFoxTailNotes": "This tail makes you look like a wily fox! Confers no benefit.",
|
||||||
|
"backLionTailText": "Lion Tail",
|
||||||
|
"backLionTailNotes": "This tail makes you look like a regal lion! Confers no benefit.",
|
||||||
|
"backPandaTailText": "Panda Tail",
|
||||||
|
"backPandaTailNotes": "This tail makes you look like a gentle panda! Confers no benefit.",
|
||||||
|
"backPigTailText": "Pig Tail",
|
||||||
|
"backPigTailNotes": "This tail makes you look like a whimsical pig! Confers no benefit.",
|
||||||
|
"backTigerTailText": "Tiger Tail",
|
||||||
|
"backTigerTailNotes": "This tail makes you look like a fierce tiger! Confers no benefit.",
|
||||||
|
"backWolfTailText": "Wolf Tail",
|
||||||
|
"backWolfTailNotes": "This tail makes you look like a loyal wolf! Confers no benefit.",
|
||||||
|
|
||||||
"body": "Body Accessory",
|
"body": "Body Accessory",
|
||||||
"bodyCapitalized": "Body Accessory",
|
"bodyCapitalized": "Body Accessory",
|
||||||
|
|||||||
@@ -1029,6 +1029,86 @@ let back = {
|
|||||||
value: 0,
|
value: 0,
|
||||||
canOwn: ownsItem('back_special_turkeyTailBase'),
|
canOwn: ownsItem('back_special_turkeyTailBase'),
|
||||||
},
|
},
|
||||||
|
bearTail: {
|
||||||
|
gearSet: 'animal',
|
||||||
|
text: t('backBearTailText'),
|
||||||
|
notes: t('backBearTailNotes'),
|
||||||
|
value: 20,
|
||||||
|
canOwn: ownsItem('back_special_bearTail'),
|
||||||
|
canBuy: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cactusTail: {
|
||||||
|
gearSet: 'animal',
|
||||||
|
text: t('backCactusTailText'),
|
||||||
|
notes: t('backCactusTailNotes'),
|
||||||
|
value: 20,
|
||||||
|
canOwn: ownsItem('back_special_cactusTail'),
|
||||||
|
canBuy: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
foxTail: {
|
||||||
|
gearSet: 'animal',
|
||||||
|
text: t('backFoxTailText'),
|
||||||
|
notes: t('backFoxTailNotes'),
|
||||||
|
value: 20,
|
||||||
|
canOwn: ownsItem('back_special_foxTail'),
|
||||||
|
canBuy: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lionTail: {
|
||||||
|
gearSet: 'animal',
|
||||||
|
text: t('backLionTailText'),
|
||||||
|
notes: t('backLionTailNotes'),
|
||||||
|
value: 20,
|
||||||
|
canOwn: ownsItem('back_special_lionTail'),
|
||||||
|
canBuy: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pandaTail: {
|
||||||
|
gearSet: 'animal',
|
||||||
|
text: t('backPandaTailText'),
|
||||||
|
notes: t('backPandaTailNotes'),
|
||||||
|
value: 20,
|
||||||
|
canOwn: ownsItem('back_special_pandaTail'),
|
||||||
|
canBuy: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pigTail: {
|
||||||
|
gearSet: 'animal',
|
||||||
|
text: t('backPigTailText'),
|
||||||
|
notes: t('backPigTailNotes'),
|
||||||
|
value: 20,
|
||||||
|
canOwn: ownsItem('back_special_pigTail'),
|
||||||
|
canBuy: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tigerTail: {
|
||||||
|
gearSet: 'animal',
|
||||||
|
text: t('backTigerTailText'),
|
||||||
|
notes: t('backTigerTailNotes'),
|
||||||
|
value: 20,
|
||||||
|
canOwn: ownsItem('back_special_tigerTail'),
|
||||||
|
canBuy: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wolfTail: {
|
||||||
|
gearSet: 'animal',
|
||||||
|
text: t('backWolfTailText'),
|
||||||
|
notes: t('backWolfTailNotes'),
|
||||||
|
value: 20,
|
||||||
|
canOwn: ownsItem('back_special_wolfTail'),
|
||||||
|
canBuy: () => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = {
|
let body = {
|
||||||
|
|||||||
|
After Width: | Height: | Size: 474 B |
|
After Width: | Height: | Size: 471 B |
|
After Width: | Height: | Size: 531 B |
|
After Width: | Height: | Size: 528 B |
|
After Width: | Height: | Size: 474 B |
|
After Width: | Height: | Size: 486 B |
|
After Width: | Height: | Size: 570 B |
|
After Width: | Height: | Size: 525 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 636 B After Width: | Height: | Size: 636 B |
|
After Width: | Height: | Size: 247 B |
|
After Width: | Height: | Size: 258 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 768 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 746 B After Width: | Height: | Size: 746 B |
|
After Width: | Height: | Size: 1.4 KiB |
BIN
website/raw_sprites/spritesmith_large/promo_animal_tails.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -3,7 +3,7 @@ import { authWithHeaders } from '../../middlewares/auth';
|
|||||||
let api = {};
|
let api = {};
|
||||||
|
|
||||||
// @TODO export this const, cannot export it from here because only routes are exported from controllers
|
// @TODO export this const, cannot export it from here because only routes are exported from controllers
|
||||||
const LAST_ANNOUNCEMENT_TITLE = 'AUGUST SUBSCRIBER ITEMS AND WIKI SPOTLIGHT ON CUSTOMIZING THE HABITICA EXPERIENCE';
|
const LAST_ANNOUNCEMENT_TITLE = 'NEW AVATAR CUSTOMIZATIONS: ANIMAL TAILS';
|
||||||
const worldDmg = { // @TODO
|
const worldDmg = { // @TODO
|
||||||
bailey: false,
|
bailey: false,
|
||||||
};
|
};
|
||||||
@@ -26,30 +26,20 @@ api.getNews = {
|
|||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
html: `
|
html: `
|
||||||
<div class="bailey">
|
<div class="bailey">
|
||||||
<div class="media align-items-center">
|
<div class="media">
|
||||||
<div class="mr-3 ${baileyClass}"></div>
|
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<h1 class="align-self-center">${res.t('newStuff')}</h1>
|
<div class="media align-items-center">
|
||||||
<h2>8/23/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
|
<div class="mr-3 ${baileyClass}"></div>
|
||||||
</div>
|
<div class="media-body">
|
||||||
</div>
|
<h1 class="align-self-center">${res.t('newStuff')}</h1>
|
||||||
<hr/>
|
<h2>8/29/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
|
||||||
<div class="media align-items-center">
|
</div>
|
||||||
<div class="media-body">
|
</div>
|
||||||
<h3>August Subscriber Set Revealed!</h3>
|
<hr/>
|
||||||
<p>Subscriber Items for August have been revealed: the Lava Dragon Item Set! You only have until August 31 to receive the item set when you <a href='/user/settings/subscription' target='_blank'>subscribe</a>. If you're already an active subscriber, reload the site and then head to Inventory > Items to claim your gear!</p>
|
<p>There are new customizations available for your avatar! Check out our new sets of tails to match the Animal Skins and Ears--you'll match your pets better than ever. You can find them in User > Avatar > Extra. Enjoy!</p>
|
||||||
</div>
|
<div class="small">by tricksy.fox, Beffymaroo, and SabreCat</div>
|
||||||
<div class="promo_mystery_201808 ml-3"></div>
|
|
||||||
</div>
|
|
||||||
<p>Subscribers also receive the ability to buy Gems for Gold -- the longer you subscribe, the more Gems you can buy per month! There are other perks as well, such as longer access to uncompressed data and a cute Jackalope pet. Best of all, subscriptions let us keep Habitica running. Thank you very much for your support -- it means a lot to us.</p>
|
|
||||||
<div class="small mb-3">by Beffymaroo</div>
|
|
||||||
<div class="media align-items-center">
|
|
||||||
<div class="scene_casting_spells mr-3 mb-3"></div>
|
|
||||||
<div class="media-body">
|
|
||||||
<h3>Blog Post: Creating a Unique Experience</h3>
|
|
||||||
<p>This month's <a href='https://habitica.wordpress.com/2018/08/22/creating-a-unique-experience/' target='_blank'>featured Wiki article</a> is about using Habitica's features to create a unique experience! We hope that it will help you as you customize Habitica to make the app even more motivating and fun. Be sure to check it out, and let us know what you think by reaching out on <a href='https://twitter.com/habitica' target='_blank'>Twitter</a>, <a href='http://blog.habitrpg.com' target='_blank'>Tumblr</a>, and <a href='https://facebook.com/habitica' target='_blank'>Facebook</a>.</p>
|
|
||||||
<div class="small mb-3">by shanaqui and the Wiki Wizards</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="promo_animal_tails ml-3 mb-3"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
|
|||||||