Merge branch 'develop' into blade-Finish_weeklies_pr
@@ -37,6 +37,12 @@
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.multi-achievement {
|
||||||
|
margin: auto;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
[class*="Mount_Head_"], [class*="Mount_Body_"]{
|
[class*="Mount_Head_"], [class*="Mount_Body_"]{
|
||||||
margin-top:18px; /* Sprite accommodates 105x123 box */
|
margin-top:18px; /* Sprite accommodates 105x123 box */
|
||||||
}
|
}
|
||||||
|
|||||||
2
common/dist/sprites/habitrpg-shared.css
vendored
1458
common/dist/sprites/spritesmith0.css
vendored
BIN
common/dist/sprites/spritesmith0.png
vendored
|
Before Width: | Height: | Size: 284 KiB After Width: | Height: | Size: 304 KiB |
5420
common/dist/sprites/spritesmith1.css
vendored
BIN
common/dist/sprites/spritesmith1.png
vendored
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
5348
common/dist/sprites/spritesmith2.css
vendored
BIN
common/dist/sprites/spritesmith2.png
vendored
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 153 KiB |
918
common/dist/sprites/spritesmith3.css
vendored
BIN
common/dist/sprites/spritesmith3.png
vendored
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 153 KiB |
862
common/dist/sprites/spritesmith4.css
vendored
BIN
common/dist/sprites/spritesmith4.png
vendored
|
Before Width: | Height: | Size: 673 KiB After Width: | Height: | Size: 681 KiB |
1586
common/dist/sprites/spritesmith5.css
vendored
BIN
common/dist/sprites/spritesmith5.png
vendored
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 357 KiB |
1292
common/dist/sprites/spritesmith6.css
vendored
BIN
common/dist/sprites/spritesmith6.png
vendored
|
Before Width: | Height: | Size: 296 KiB After Width: | Height: | Size: 300 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
BIN
common/img/sprites/spritesmith/misc/shop_armoire.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
common/img/sprites/spritesmith/promo/promo_enchanted_armoire.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 999 B After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 825 B After Width: | Height: | Size: 3.6 KiB |
@@ -95,5 +95,13 @@
|
|||||||
"backgroundMountainLakeText": "Mountain Lake",
|
"backgroundMountainLakeText": "Mountain Lake",
|
||||||
"backgroundMountainLakeNotes": "Dip your toes in a Mountain Lake.",
|
"backgroundMountainLakeNotes": "Dip your toes in a Mountain Lake.",
|
||||||
"backgroundPagodasText": "Pagodas",
|
"backgroundPagodasText": "Pagodas",
|
||||||
"backgroundPagodasNotes": "Climb to the top of Pagodas."
|
"backgroundPagodasNotes": "Climb to the top of Pagodas.",
|
||||||
|
|
||||||
|
"backgrounds062015": "SET 13: Released June 2015",
|
||||||
|
"backgroundDriftingRaftText": "Drifting Raft",
|
||||||
|
"backgroundDriftingRaftNotes": "Paddle a Drifting Raft.",
|
||||||
|
"backgroundShimmeryBubblesText": "Shimmery Bubbles",
|
||||||
|
"backgroundShimmeryBubblesNotes": "Float through a sea of Shimmery Bubbles.",
|
||||||
|
"backgroundIslandWaterfallsText": "Island Waterfalls",
|
||||||
|
"backgroundIslandWaterfallsNotes": "Picnic near Island Waterfalls."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,9 +52,11 @@
|
|||||||
"costume": "Costume",
|
"costume": "Costume",
|
||||||
"costumeText": "If you prefer the look of other gear to what you have equipped, check the \"Use Costume\" box to visually don a costume while wearing your battle gear underneath.",
|
"costumeText": "If you prefer the look of other gear to what you have equipped, check the \"Use Costume\" box to visually don a costume while wearing your battle gear underneath.",
|
||||||
"useCostume": "Use Costume",
|
"useCostume": "Use Costume",
|
||||||
"gearAchievement": "You have earned the \"Ultimate Gear\" Achievement for upgrading to the maximum gear set!",
|
"gearAchievement": "You have earned the \"Ultimate Gear\" Achievement for upgrading to the maximum gear set for a class! You have attained the following complete sets:",
|
||||||
|
"moreGearAchievements": "To attain more Ultimate Gear badges, change classes on <a href='/#/options/profile/stats' target='_blank'>your stats page</a> and buy up your new class's gear!",
|
||||||
|
"armoireUnlocked": "You've also unlocked the <strong>Enchanted Armoire!</strong> Click on the Enchanted Armoire Reward for a random chance at special Equipment! It may also give you random XP or food items.",
|
||||||
"ultimGearName": "Ultimate Gear",
|
"ultimGearName": "Ultimate Gear",
|
||||||
"ultimGearText": "Has upgraded to the maximum weapon and armor set",
|
"ultimGearText": "Has upgraded to the maximum weapon and armor set for the following classes:",
|
||||||
"level": "Level",
|
"level": "Level",
|
||||||
"levelUp": "Level Up!",
|
"levelUp": "Level Up!",
|
||||||
"mana": "Mana",
|
"mana": "Mana",
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
"potionText": "Health Potion",
|
"potionText": "Health Potion",
|
||||||
"potionNotes": "Recover 15 Health (Instant Use)",
|
"potionNotes": "Recover 15 Health (Instant Use)",
|
||||||
|
|
||||||
|
"armoireText": "Enchanted Armoire",
|
||||||
|
"armoireNotesFull": "Open the Armoire to randomly receive special Equipment, Experience, or food! Equipment pieces remaining: ",
|
||||||
|
"armoireLastItem": "You've found the last piece of rare Equipment in the Enchanted Armoire.",
|
||||||
|
"armoireNotesEmpty": "The Armoire will have new Equipment every month. Until then, keep clicking for Experience and Food!",
|
||||||
|
|
||||||
"dropEggWolfText": "Wolf",
|
"dropEggWolfText": "Wolf",
|
||||||
"dropEggWolfAdjective": "loyal",
|
"dropEggWolfAdjective": "loyal",
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,11 @@
|
|||||||
"weaponMystery301404Text": "Steampunk Cane",
|
"weaponMystery301404Text": "Steampunk Cane",
|
||||||
"weaponMystery301404Notes": "Excellent for taking a turn about town. March 3015 Subscriber Item. Confers no benefit.",
|
"weaponMystery301404Notes": "Excellent for taking a turn about town. March 3015 Subscriber Item. Confers no benefit.",
|
||||||
|
|
||||||
|
"weaponArmoireBasicCrossbowText": "Basic Crossbow",
|
||||||
|
"weaponArmoireBasicCrossbowNotes": "This crossbow can pierce a task's armor from very far away! Increases Strength by <%= str %>, Perception by <%= per %>, and Constitution by <%= con %>. Enchanted Armoire: Independent Item.",
|
||||||
|
"weaponArmoireLunarSceptreText": "Soothing Lunar Sceptre",
|
||||||
|
"weaponArmoireLunarSceptreNotes": "The healing power of this wand waxes and wanes. Increases Constitution by <%= con %> and Intelligence by <%= int %>. Enchanted Armoire: Soothing Lunar Set (Item 3 of 3).",
|
||||||
|
|
||||||
"armor": "armor",
|
"armor": "armor",
|
||||||
|
|
||||||
"armorBase0Text": "Plain Clothing",
|
"armorBase0Text": "Plain Clothing",
|
||||||
@@ -282,6 +287,11 @@
|
|||||||
"armorMystery301404Text": "Steampunk Suit",
|
"armorMystery301404Text": "Steampunk Suit",
|
||||||
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
|
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
|
||||||
|
|
||||||
|
"armorArmoireLunarArmorText": "Soothing Lunar Armor",
|
||||||
|
"armorArmoireLunarArmorNotes": "The light of the moon will make you strong and savvy. Increases Strength by <%= str %> and Intelligence by <%= int %>. Enchanted Armoire: Soothing Lunar Set (Item 2 of 3).",
|
||||||
|
"armorArmoireGladiatorArmorText": "Gladiator Armor",
|
||||||
|
"armorArmoireGladiatorArmorNotes": "To be a gladiator you must be not only cunning... but strong. Increases Perception by <%= per %> and Strength by <%= str %>. Enchanted Armoire: Gladiator Set (Item 2 of 3).",
|
||||||
|
|
||||||
"headgear": "headgear",
|
"headgear": "headgear",
|
||||||
|
|
||||||
"headBase0Text": "No Helm",
|
"headBase0Text": "No Helm",
|
||||||
@@ -422,6 +432,17 @@
|
|||||||
"headMystery301405Text": "Basic Top Hat",
|
"headMystery301405Text": "Basic Top Hat",
|
||||||
"headMystery301405Notes": "A basic top hat, just begging to be paired with some fancy head accessories. Confers no benefit. May 3015 Subscriber Item.",
|
"headMystery301405Notes": "A basic top hat, just begging to be paired with some fancy head accessories. Confers no benefit. May 3015 Subscriber Item.",
|
||||||
|
|
||||||
|
"headArmoireLunarCrownText": "Soothing Lunar Crown",
|
||||||
|
"headArmoireLunarCrownNotes": "This crown strengthens health and sharpens senses, especially when the moon is full. Increases Constitution by <%= con %> and Perception by <%= per %>. Enchanted Armoire: Soothing Lunar Set (Item 1 of 3).",
|
||||||
|
"headArmoireRedHairbowText": "Red Hairbow",
|
||||||
|
"headArmoireRedHairbowNotes": "Become strong, tough and smart while wearing this beautiful Red Hairbow! Increases Strength by <%= str %>, Constitution by <%= con %>, and Intelligence by <%= int %>. Enchanted Armoire: Independent Item.",
|
||||||
|
"headArmoireVioletFloppyHatText": "Violet Floppy Hat",
|
||||||
|
"headArmoireVioletFloppyHatNotes": "Many spells have been sewn into this simple hat, giving it a pleasing purple color. Increases Perception by <%= per %>, Intelligence by <%= int %>, and Constitution by <%= con %>. Enchanted Armoire: Independent Item.",
|
||||||
|
"headArmoireGladiatorHelmText": "Gladiator Helm",
|
||||||
|
"headArmoireGladiatorHelmNotes": "To be a gladiator you must be not only strong.... but cunning. Increases Intelligence by <%= int %> and Perception by <%= per %>. Enchanted Armoire: Gladiator Set (Item 1 of 3).",
|
||||||
|
"headArmoireRancherHatText": "Rancher Hat",
|
||||||
|
"headArmoireRancherHatNotes": "Round up your pets and wrangle your mounts while wearing this magical Rancher Hat! Increases Strength by <%= str %>, Perception by <%= per %>, and Intelligence by <%= int %>. Enchanted Armoire: Independent Item.",
|
||||||
|
|
||||||
"offhand": "shield-hand item",
|
"offhand": "shield-hand item",
|
||||||
|
|
||||||
"shieldBase0Text": "No Shield-Hand Equipment",
|
"shieldBase0Text": "No Shield-Hand Equipment",
|
||||||
@@ -500,6 +521,9 @@
|
|||||||
"shieldMystery301405Text": "Clock Shield",
|
"shieldMystery301405Text": "Clock Shield",
|
||||||
"shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.",
|
"shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.",
|
||||||
|
|
||||||
|
"shieldArmoireGladiatorShieldText": "Gladiator Shield",
|
||||||
|
"shieldArmoireGladiatorShieldNotes": "To be a gladiator you must.... eh, whatever, just bash them with your shield. Increases Constitution by <%= con %> and Strength by <%= str %>. Enchanted Armoire: Gladiator Set (Item 3 of 3).",
|
||||||
|
|
||||||
"backBase0Text": "No Back Accessory",
|
"backBase0Text": "No Back Accessory",
|
||||||
"backBase0Notes": "No Back Accessory.",
|
"backBase0Notes": "No Back Accessory.",
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
"close": "Close",
|
"close": "Close",
|
||||||
"saveAndClose": "Save & Close",
|
"saveAndClose": "Save & Close",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"ok": "Ok",
|
"ok": "OK",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
"undo": "Undo",
|
"undo": "Undo",
|
||||||
"continue": "Continue",
|
"continue": "Continue",
|
||||||
|
|||||||
@@ -20,5 +20,8 @@
|
|||||||
"messageDropFood": "You've found <%= dropArticle %><%= dropText %>! <%= dropNotes %>",
|
"messageDropFood": "You've found <%= dropArticle %><%= dropText %>! <%= dropNotes %>",
|
||||||
"messageDropEgg": "You've found a <%= dropText %> Egg! <%= dropNotes %>",
|
"messageDropEgg": "You've found a <%= dropText %> Egg! <%= dropNotes %>",
|
||||||
"messageDropPotion": "You've found a <%= dropText %> Hatching Potion! <%= dropNotes %>",
|
"messageDropPotion": "You've found a <%= dropText %> Hatching Potion! <%= dropNotes %>",
|
||||||
"messageFoundQuest": "You've found the quest \"<%= questText %>\"!"
|
"messageFoundQuest": "You've found the quest \"<%= questText %>\"!",
|
||||||
|
"armoireEquipment": "<%= image %> You found a piece of rare Equipment in the Armoire: <%= dropText %>! Awesome!",
|
||||||
|
"armoireFood": "<%= image %> You rummage in the Armoire and find <%= dropArticle %><%= dropText %>. What's that doing in here?",
|
||||||
|
"armoireExp": "You wrestle with the Armoire and gain Experience. Take that!"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,6 +140,9 @@ gear =
|
|||||||
201502: text: t('weaponMystery201502Text'), notes: t('weaponMystery201502Notes'), mystery:'201502', value: 0
|
201502: text: t('weaponMystery201502Text'), notes: t('weaponMystery201502Notes'), mystery:'201502', value: 0
|
||||||
201505: text: t('weaponMystery201505Text'), notes: t('weaponMystery201505Notes'), mystery:'201505', value: 0
|
201505: text: t('weaponMystery201505Text'), notes: t('weaponMystery201505Notes'), mystery:'201505', value: 0
|
||||||
301404: text: t('weaponMystery301404Text'), notes: t('weaponMystery301404Notes'), mystery:'301404', value: 0
|
301404: text: t('weaponMystery301404Text'), notes: t('weaponMystery301404Notes'), mystery:'301404', value: 0
|
||||||
|
armoire:
|
||||||
|
basicCrossbow: text: t('weaponArmoireBasicCrossbowText'), notes: t('weaponArmoireBasicCrossbowNotes', {str: 5, per: 5, con: 5}), value: 100, str: 5, per: 5, con: 5, canOwn: ((u)-> u.items.gear.owned.weapon_armoire_basicCrossbow?)
|
||||||
|
lunarSceptre: text: t('weaponArmoireLunarSceptreText'), notes: t('weaponArmoireLunarSceptreNotes', {con: 7, int: 7}), value: 100, con: 7, int: 7, set: 'soothing', canOwn: ((u)-> u.items.gear.owned.weapon_armoire_lunarSceptre?)
|
||||||
|
|
||||||
armor:
|
armor:
|
||||||
base:
|
base:
|
||||||
@@ -224,6 +227,9 @@ gear =
|
|||||||
201503: text: t('armorMystery201503Text'), notes: t('armorMystery201503Notes'), mystery:'201503', value: 0
|
201503: text: t('armorMystery201503Text'), notes: t('armorMystery201503Notes'), mystery:'201503', value: 0
|
||||||
201504: text: t('armorMystery201504Text'), notes: t('armorMystery201504Notes'), mystery:'201504', value: 0
|
201504: text: t('armorMystery201504Text'), notes: t('armorMystery201504Notes'), mystery:'201504', value: 0
|
||||||
301404: text: t('armorMystery301404Text'), notes: t('armorMystery301404Notes'), mystery:'301404', value: 0
|
301404: text: t('armorMystery301404Text'), notes: t('armorMystery301404Notes'), mystery:'301404', value: 0
|
||||||
|
armoire:
|
||||||
|
lunarArmor: text: t('armorArmoireLunarArmorText'), notes: t('armorArmoireLunarArmorNotes', {str: 7, int: 7}), value: 100, str: 7, int: 7, set: 'soothing', canOwn: ((u)-> u.items.gear.owned.armor_armoire_lunarArmor?)
|
||||||
|
gladiatorArmor: text: t('armorArmoireGladiatorArmorText'), notes: t('armorArmoireGladiatorArmorNotes', {str: 7, per: 7}), value: 100, str: 7, per: 7, set: 'gladiator', canOwn: ((u)-> u.items.gear.owned.armor_armoire_gladiatorArmor?)
|
||||||
|
|
||||||
head:
|
head:
|
||||||
base:
|
base:
|
||||||
@@ -306,6 +312,12 @@ gear =
|
|||||||
201505: text: t('headMystery201505Text'), notes: t('headMystery201505Notes'), mystery:'201505', value: 0
|
201505: text: t('headMystery201505Text'), notes: t('headMystery201505Notes'), mystery:'201505', value: 0
|
||||||
301404: text: t('headMystery301404Text'), notes: t('headMystery301404Notes'), mystery:'301404', value: 0
|
301404: text: t('headMystery301404Text'), notes: t('headMystery301404Notes'), mystery:'301404', value: 0
|
||||||
301405: text: t('headMystery301405Text'), notes: t('headMystery301405Notes'), mystery:'301405', value: 0
|
301405: text: t('headMystery301405Text'), notes: t('headMystery301405Notes'), mystery:'301405', value: 0
|
||||||
|
armoire:
|
||||||
|
lunarCrown: text: t('headArmoireLunarCrownText'), notes: t('headArmoireLunarCrownNotes', {con: 7, per: 7}), value: 100, con: 7, per: 7, set: 'soothing', canOwn: ((u)-> u.items.gear.owned.head_armoire_lunarCrown?)
|
||||||
|
redHairbow: text: t('headArmoireRedHairbowText'), notes: t('headArmoireRedHairbowNotes', {str: 5, int: 5, con: 5}), value: 100, str: 5, int: 5, con: 5, canOwn: ((u)-> u.items.gear.owned.head_armoire_redHairbow?)
|
||||||
|
violetFloppyHat: text: t('headArmoireVioletFloppyHatText'), notes: t('headArmoireVioletFloppyHatNotes', {per: 5, int: 5, con: 5}), value: 100, per: 5, int: 5, con: 5, canOwn: ((u)-> u.items.gear.owned.head_armoire_violetFloppyHat?)
|
||||||
|
gladiatorHelm: text: t('headArmoireGladiatorHelmText'), notes: t('headArmoireGladiatorHelmNotes', {per: 7, int: 7}), value: 100, per: 7, int: 7, set: 'gladiator', canOwn: ((u)-> u.items.gear.owned.head_armoire_gladiatorHelm?)
|
||||||
|
rancherHat: text: t('headArmoireRancherHatText'), notes: t('headArmoireRancherHatNotes', {str: 5, per: 5, int: 5}), value: 100, str: 5, per: 5, int: 5, canOwn: ((u)-> u.items.gear.owned.head_armoire_rancherHat?)
|
||||||
|
|
||||||
shield:
|
shield:
|
||||||
base:
|
base:
|
||||||
@@ -365,6 +377,8 @@ gear =
|
|||||||
spring2015Healer: event: events.spring2015, specialClass: 'healer', text: t('shieldSpecialSpring2015HealerText'), notes: t('shieldSpecialSpring2015HealerNotes', {con: 9}), value: 70, con: 9
|
spring2015Healer: event: events.spring2015, specialClass: 'healer', text: t('shieldSpecialSpring2015HealerText'), notes: t('shieldSpecialSpring2015HealerNotes', {con: 9}), value: 70, con: 9
|
||||||
mystery:
|
mystery:
|
||||||
301405: text: t('shieldMystery301405Text'), notes: t('shieldMystery301405Notes'), mystery:'301405', value: 0
|
301405: text: t('shieldMystery301405Text'), notes: t('shieldMystery301405Notes'), mystery:'301405', value: 0
|
||||||
|
armoire:
|
||||||
|
gladiatorShield: text: t('shieldArmoireGladiatorShieldText'), notes: t('shieldArmoireGladiatorShieldNotes', {con: 5, str: 5}), value: 100, con: 5, str: 5, set: 'gladiator', canOwn: ((u)-> u.items.gear.owned.shield_armoire_gladiatorShield?)
|
||||||
|
|
||||||
back:
|
back:
|
||||||
base:
|
base:
|
||||||
@@ -442,7 +456,7 @@ api.gear =
|
|||||||
flat: {}
|
flat: {}
|
||||||
|
|
||||||
_.each gearTypes, (type) ->
|
_.each gearTypes, (type) ->
|
||||||
_.each classes.concat(['base', 'special', 'mystery']), (klass) ->
|
_.each classes.concat(['base', 'special', 'mystery', 'armoire']), (klass) ->
|
||||||
# add "type" to each item, so we can reference that as "weapon" or "armor" in the html
|
# add "type" to each item, so we can reference that as "weapon" or "armor" in the html
|
||||||
_.each gear[type][klass], (item, i) ->
|
_.each gear[type][klass], (item, i) ->
|
||||||
key = "#{type}_#{klass}_#{i}"
|
key = "#{type}_#{klass}_#{i}"
|
||||||
@@ -475,11 +489,12 @@ api.timeTravelerStore = (owned) ->
|
|||||||
|
|
||||||
###
|
###
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
Potion
|
Unique Rewards: Potion and Armoire
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
###
|
###
|
||||||
|
|
||||||
api.potion = type: 'potion', text: t('potionText'), notes: t('potionNotes'), value: 25, key: 'potion'
|
api.potion = type: 'potion', text: t('potionText'), notes: t('potionNotes'), value: 25, key: 'potion'
|
||||||
|
api.armoire = type: 'armoire', text: t('armoireText'), notes: t('armoireNotesEmpty'), value: 100, key: 'armoire', canOwn: ((u)-> _.contains(u.achievements.ultimateGearSets, true))
|
||||||
|
|
||||||
###
|
###
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
@@ -1840,6 +1855,16 @@ api.backgrounds =
|
|||||||
pagodas:
|
pagodas:
|
||||||
text: t('backgroundPagodasText')
|
text: t('backgroundPagodasText')
|
||||||
notes: t('backgroundPagodasNotes')
|
notes: t('backgroundPagodasNotes')
|
||||||
|
backgrounds062015:
|
||||||
|
drifting_raft:
|
||||||
|
text: t('backgroundDriftingRaftText')
|
||||||
|
notes: t('backgroundDriftingRaftNotes')
|
||||||
|
shimmery_bubbles:
|
||||||
|
text: t('backgroundShimmeryBubblesText')
|
||||||
|
notes: t('backgroundShimmeryBubblesNotes')
|
||||||
|
island_waterfalls:
|
||||||
|
text: t('backgroundIslandWaterfallsText')
|
||||||
|
notes: t('backgroundIslandWaterfallsNotes')
|
||||||
|
|
||||||
api.subscriptionBlocks =
|
api.subscriptionBlocks =
|
||||||
basic_earned: months:1, price:5
|
basic_earned: months:1, price:5
|
||||||
|
|||||||
@@ -188,8 +188,9 @@ api.updateStore = (user) ->
|
|||||||
true
|
true
|
||||||
# Add special items (contrib gear, backer gear, etc)
|
# Add special items (contrib gear, backer gear, etc)
|
||||||
changes = changes.concat _.filter content.gear.flat, (v) ->
|
changes = changes.concat _.filter content.gear.flat, (v) ->
|
||||||
v.klass in ['special','mystery'] and !user.items.gear.owned[v.key] and v.canOwn?(user)
|
v.klass in ['special','mystery','armoire'] and !user.items.gear.owned[v.key] and v.canOwn?(user)
|
||||||
changes.push content.potion
|
changes.push content.potion
|
||||||
|
if user.flags.armoireEnabled then changes.push content.armoire
|
||||||
# Return sorted store (array)
|
# Return sorted store (array)
|
||||||
_.sortBy changes, (c)->sortOrder[c.type]
|
_.sortBy changes, (c)->sortOrder[c.type]
|
||||||
|
|
||||||
@@ -385,6 +386,10 @@ api.countTriad = (pets) ->
|
|||||||
if pets[egg + "-" + potion] > 0 then count3++
|
if pets[egg + "-" + potion] > 0 then count3++
|
||||||
count3
|
count3
|
||||||
|
|
||||||
|
api.countArmoire = (gear) ->
|
||||||
|
count = _.size(_.filter(content.gear.flat, ((i)->i.klass is 'armoire' and !gear[i.key])))
|
||||||
|
count
|
||||||
|
|
||||||
###
|
###
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
User (prototype wrapper to give it ops, helper funcs, and virtuals
|
User (prototype wrapper to give it ops, helper funcs, and virtuals
|
||||||
@@ -465,7 +470,7 @@ api.wrap = (user, main=true) ->
|
|||||||
if v
|
if v
|
||||||
itm = content.gear.flat[''+k]
|
itm = content.gear.flat[''+k]
|
||||||
if itm
|
if itm
|
||||||
if (itm.value > 0 || k == 'weapon_warrior_0') && ( itm.klass == cl || ( itm.klass == 'special' && (! itm.specialClass || itm.specialClass == cl) ) )
|
if (itm.value > 0 || k == 'weapon_warrior_0') && ( itm.klass == cl || ( itm.klass == 'special' && (! itm.specialClass || itm.specialClass == cl) ) || itm.klass == 'armoire' )
|
||||||
losableItems[''+k]=''+k
|
losableItems[''+k]=''+k
|
||||||
lostItem = user.fns.randomVal losableItems
|
lostItem = user.fns.randomVal losableItems
|
||||||
if item = content.gear.flat[lostItem]
|
if item = content.gear.flat[lostItem]
|
||||||
@@ -859,23 +864,41 @@ api.wrap = (user, main=true) ->
|
|||||||
buy: (req, cb) ->
|
buy: (req, cb) ->
|
||||||
{key} = req.params
|
{key} = req.params
|
||||||
|
|
||||||
item = if key is 'potion' then content.potion else content.gear.flat[key]
|
item = if key is 'potion' then content.potion
|
||||||
|
else if key is 'armoire' then content.armoire
|
||||||
|
else content.gear.flat[key]
|
||||||
return cb?({code:404, message:"Item '#{key} not found (see https://github.com/HabitRPG/habitrpg-shared/blob/develop/script/content.coffee)"}) unless item
|
return cb?({code:404, message:"Item '#{key} not found (see https://github.com/HabitRPG/habitrpg-shared/blob/develop/script/content.coffee)"}) unless item
|
||||||
return cb?({code:401, message: i18n.t('messageNotEnoughGold', req.language)}) if user.stats.gp < item.value
|
return cb?({code:401, message: i18n.t('messageNotEnoughGold', req.language)}) if user.stats.gp < item.value
|
||||||
return cb?({code:401, message: "You can't own this item"}) if item.canOwn? and !item.canOwn(user)
|
return cb?({code:401, message: "You can't buy this item"}) if item.canOwn? and !item.canOwn(user)
|
||||||
if item.key is 'potion'
|
if item.key is 'potion'
|
||||||
user.stats.hp += 15
|
user.stats.hp += 15
|
||||||
user.stats.hp = 50 if user.stats.hp > 50
|
user.stats.hp = 50 if user.stats.hp > 50
|
||||||
|
else if item.key is 'armoire'
|
||||||
|
armoireResult = user.fns.predictableRandom()
|
||||||
|
eligibleEquipment = _.filter(content.gear.flat, ((i)->i.klass is 'armoire' and !user.items.gear.owned[i.key]))
|
||||||
|
if !_.isEmpty(eligibleEquipment) and (armoireResult < .6 or !user.flags.armoireOpened)
|
||||||
|
drop = user.fns.randomVal(eligibleEquipment)
|
||||||
|
user.items.gear.owned[drop.key] = true
|
||||||
|
user.flags.armoireOpened = true
|
||||||
|
message = i18n.t('armoireEquipment', {image: '<span class="shop_'+drop.key+' pull-left"></span>', dropText: drop.text(req.language)}, req.language)
|
||||||
|
if api.countArmoire(user.items.gear.owned) is 0 then user.flags.armoireEmpty = true
|
||||||
|
else if (!_.isEmpty(eligibleEquipment) and armoireResult < .8) or armoireResult < .5
|
||||||
|
drop = user.fns.randomVal _.where(content.food, {canDrop:true})
|
||||||
|
user.items.food[drop.key] ?= 0
|
||||||
|
user.items.food[drop.key] += 1
|
||||||
|
message = i18n.t('armoireFood', {image: '<span class="Pet_Food_'+drop.key+' pull-left"></span>', dropArticle: drop.article, dropText: drop.text(req.language)}, req.language)
|
||||||
|
else
|
||||||
|
user.stats.exp += Math.floor(user.fns.predictableRandom(user.stats.exp) * 40 + 10)
|
||||||
|
message = i18n.t('armoireExp', req.language)
|
||||||
else
|
else
|
||||||
user.items.gear.equipped[item.type] = item.key
|
user.items.gear.equipped[item.type] = item.key
|
||||||
user.items.gear.owned[item.key] = true
|
user.items.gear.owned[item.key] = true
|
||||||
message = user.fns.handleTwoHanded(item, null, req)
|
message = user.fns.handleTwoHanded(item, null, req)
|
||||||
message ?= i18n.t('messageBought', {itemText: item.text(req.language)}, req.language)
|
message ?= i18n.t('messageBought', {itemText: item.text(req.language)}, req.language)
|
||||||
if not user.achievements.ultimateGear and item.last
|
if item.last then user.fns.ultimateGear()
|
||||||
user.fns.ultimateGear()
|
|
||||||
user.stats.gp -= item.value
|
user.stats.gp -= item.value
|
||||||
mixpanel?.track("Acquire Item",{'itemName':key,'acquireMethod':'Gold','goldCost':item.value})
|
mixpanel?.track("Acquire Item",{'itemName':key,'acquireMethod':'Gold','goldCost':item.value})
|
||||||
cb? {code:200, message}, _.pick(user,$w 'items achievements stats')
|
cb? {code:200, message}, _.pick(user,$w 'items achievements stats flags')
|
||||||
|
|
||||||
buyMysterySet: (req, cb)->
|
buyMysterySet: (req, cb)->
|
||||||
return cb?({code:401, message:"You don't have enough Mystic Hourglasses"}) unless user.purchased.plan.consecutive.trinkets>0
|
return cb?({code:401, message:"You don't have enough Mystic Hourglasses"}) unless user.purchased.plan.consecutive.trinkets>0
|
||||||
@@ -1684,32 +1707,19 @@ api.wrap = (user, main=true) ->
|
|||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Achievements
|
# Achievements
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
ultimateGear: () ->
|
ultimateGear: ->
|
||||||
# on the server this is a LoDash transform, on the client its an object
|
# on the server this is a Lodash transform, on the client its an object
|
||||||
gear = if window? then user.items.gear.owned else user.items.gear.owned.toObject()
|
owned = if window? then user.items.gear.owned else user.items.gear.owned.toObject()
|
||||||
ownedLastGear = _.chain(content.gear.flat)
|
user.achievements.ultimateGearSets ?= {healer: false, wizard: false, rogue: false, warrior: false}
|
||||||
.pick(_.keys gear)
|
content.classes.forEach (klass) ->
|
||||||
.values()
|
user.achievements.ultimateGearSets[klass] = _.reduce ['armor', 'shield', 'head', 'weapon'], (soFarGood, type) ->
|
||||||
.filter (gear) -> gear.last
|
found = _.find content.gear.tree[type][klass], {last:true}
|
||||||
|
soFarGood and (!found or owned[found.key]==true) #!found only true when weapon is two-handed (mages)
|
||||||
lastGearClassTypeMatrix = {}
|
, true # start with true, else `and` will fail right away
|
||||||
_.each content.classes, (klass) ->
|
user.markModified? 'achievements.ultimateGearSets'
|
||||||
lastGearClassTypeMatrix[klass] = {}
|
if _.contains(user.achievements.ultimateGearSets, true) and user.flags.armoireEnabled != true
|
||||||
#_.each content.gearTypes, (type) ->
|
user.flags.armoireEnabled = true
|
||||||
_.each ['armor', 'weapon', 'shield', 'head'], (type) ->
|
user.markModified? 'flags'
|
||||||
lastGearClassTypeMatrix[klass][type] = false
|
|
||||||
return true # false exits the each loop early
|
|
||||||
|
|
||||||
ownedLastGear.each (gear) ->
|
|
||||||
lastGearClassTypeMatrix[gear.klass]["shield"] = true if gear.twoHanded
|
|
||||||
lastGearClassTypeMatrix[gear.klass][gear.type] = true
|
|
||||||
|
|
||||||
shouldGrant = _(lastGearClassTypeMatrix)
|
|
||||||
.values()
|
|
||||||
.reduce(((ans, klass) -> ans or _(klass).values().reduce(((ans, gearType) -> ans and gearType), true)), false)
|
|
||||||
.valueOf()
|
|
||||||
|
|
||||||
user.achievements.ultimateGear = shouldGrant
|
|
||||||
|
|
||||||
nullify: ->
|
nullify: ->
|
||||||
user.ops = null
|
user.ops = null
|
||||||
|
|||||||
117
migrations/20150604_ultimateGearSets.js
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* Created by Sabe on 6/3/2015.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var migrationName = '20150604_ultimateGearSets';
|
||||||
|
var authorName = process.env.AUTHOR_NAME || 'Sabe'; // in case script author needs to know when their ...
|
||||||
|
var authorUuid = process.env.AUTHOR_UUID || '7f14ed62-5408-4e1b-be83-ada62d504931'; //... own data is done
|
||||||
|
|
||||||
|
/*
|
||||||
|
* grant the new ultimateGearSets achievement for existing users' collected equipment
|
||||||
|
*/
|
||||||
|
|
||||||
|
var dbserver = process.env.DB_SERVER || 'localhost:27017'; // CHANGE THIS FOR PRODUCTION DATABASE
|
||||||
|
var dbname = process.env.DB_NAME || 'habitrpg';
|
||||||
|
|
||||||
|
var mongo = require('mongoskin');
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
var dbUsers = mongo.db(dbserver + '/' + dbname + '?auto_reconnect').collection('users');
|
||||||
|
|
||||||
|
var fields = {
|
||||||
|
'achievements.ultimateGearSets':1,
|
||||||
|
'items.gear.owned':1
|
||||||
|
};
|
||||||
|
|
||||||
|
var query = {
|
||||||
|
// 'auth.timestamps.loggedin':{$lte:new Date('2015-05-22')},
|
||||||
|
$or: [
|
||||||
|
{'items.gear.owned.weapon_wizard_6': {$exists: true}},
|
||||||
|
{'items.gear.owned.armor_wizard_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.head_wizard_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.weapon_warrior_6': {$exists: true}},
|
||||||
|
{'items.gear.owned.armor_warrior_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.head_warrior_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.shield_warrior_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.weapon_healer_6': {$exists: true}},
|
||||||
|
{'items.gear.owned.armor_healer_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.head_healer_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.shield_healer_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.weapon_rogue_6': {$exists: true}},
|
||||||
|
{'items.gear.owned.armor_rogue_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.head_rogue_5': {$exists: true}},
|
||||||
|
{'items.gear.owned.shield_rogue_6': {$exists: true}}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
console.warn('Updating users...');
|
||||||
|
var progressCount = 1000;
|
||||||
|
var count = 0;
|
||||||
|
dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) {
|
||||||
|
if (err) { return exiting(1, 'ERROR! ' + err); }
|
||||||
|
if (!user) {
|
||||||
|
console.warn('All appropriate users found and modified.');
|
||||||
|
return displayData();
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
|
||||||
|
var achievements = {};
|
||||||
|
var changeUser = false;
|
||||||
|
if ( (typeof user.items.gear.owned.weapon_wizard_6 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.armor_wizard_5 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.head_wizard_5 !== 'undefined')
|
||||||
|
) {
|
||||||
|
achievements['wizard'] = true;
|
||||||
|
changeUser = true;
|
||||||
|
}
|
||||||
|
if ( (typeof user.items.gear.owned.weapon_warrior_6 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.armor_warrior_5 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.head_warrior_5 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.shield_warrior_5 !== 'undefined')
|
||||||
|
) {
|
||||||
|
achievements['warrior'] = true;
|
||||||
|
changeUser = true;
|
||||||
|
}
|
||||||
|
if ( (typeof user.items.gear.owned.weapon_healer_6 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.armor_healer_5 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.head_healer_5 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.shield_healer_5 !== 'undefined')
|
||||||
|
) {
|
||||||
|
achievements['healer'] = true;
|
||||||
|
changeUser = true;
|
||||||
|
}
|
||||||
|
if ( (typeof user.items.gear.owned.weapon_rogue_6 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.armor_rogue_5 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.head_rogue_5 !== 'undefined')
|
||||||
|
&& (typeof user.items.gear.owned.shield_rogue_6 !== 'undefined')
|
||||||
|
) {
|
||||||
|
achievements['rogue'] = true;
|
||||||
|
changeUser = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changeUser) {
|
||||||
|
var set = {'migration':migrationName, 'achievements.ultimateGearSets':achievements, 'flags.armoireEnabled':true};
|
||||||
|
dbUsers.update({_id:user._id}, {$set:set});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count%progressCount == 0) console.warn(count + ' ' + user._id);
|
||||||
|
if (user._id == authorUuid) console.warn(authorName + ' processed');
|
||||||
|
if (user._id == '9' ) console.warn('lefnire' + ' processed');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function displayData() {
|
||||||
|
console.warn('\n' + count + ' users processed\n');
|
||||||
|
return exiting(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function exiting(code, msg) {
|
||||||
|
code = code || 0; // 0 = success
|
||||||
|
if (code && !msg) { msg = 'ERROR!'; }
|
||||||
|
if (msg) {
|
||||||
|
if (code) { console.error(msg); }
|
||||||
|
else { console.log( msg); }
|
||||||
|
}
|
||||||
|
process.exit(code);
|
||||||
|
}
|
||||||
@@ -33,7 +33,8 @@ newUser = (addTasks=true)->
|
|||||||
todos: []
|
todos: []
|
||||||
rewards: []
|
rewards: []
|
||||||
flags: {}
|
flags: {}
|
||||||
achievements: {}
|
achievements:
|
||||||
|
ultimateGearSets: {}
|
||||||
contributor:
|
contributor:
|
||||||
level: 2
|
level: 2
|
||||||
|
|
||||||
@@ -432,7 +433,6 @@ describe 'User', ->
|
|||||||
expect(spell.lvl).to.be.above(0)
|
expect(spell.lvl).to.be.above(0)
|
||||||
expect(spell.cast).to.be.a('function')
|
expect(spell.cast).to.be.a('function')
|
||||||
|
|
||||||
|
|
||||||
describe 'drop system', ->
|
describe 'drop system', ->
|
||||||
user = null
|
user = null
|
||||||
|
|
||||||
@@ -481,6 +481,88 @@ describe 'User', ->
|
|||||||
user.fns.randomVal.restore()
|
user.fns.randomVal.restore()
|
||||||
user.fns.predictableRandom.restore()
|
user.fns.predictableRandom.restore()
|
||||||
|
|
||||||
|
describe 'Enchanted Armoire', ->
|
||||||
|
user = newUser()
|
||||||
|
fullArmoire = {'weapon_warrior_0': true, 'armor_armoire_gladiatorArmor':true,'armor_armoire_lunarArmor':true,'head_armoire_gladiatorHelm':true,'head_armoire_lunarCrown':true,'head_armoire_rancherHat':true,'head_armoire_redHairbow':true,'head_armoire_violetFloppyHat':true,'shield_armoire_gladiatorShield':true,'weapon_armoire_basicCrossbow':true,'weapon_armoire_lunarSceptre':true}
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
# too many predictableRandom calls to stub, let's return the last element
|
||||||
|
sinon.stub(user.fns, 'randomVal', (obj)->
|
||||||
|
result = undefined
|
||||||
|
for key, val of obj
|
||||||
|
result = val
|
||||||
|
result
|
||||||
|
)
|
||||||
|
|
||||||
|
it 'counts all available equipment before any are claimed', ->
|
||||||
|
sinon.stub(user.fns, 'predictableRandom').returns 0
|
||||||
|
expect(shared.countArmoire(user.items.gear.owned)).to.eql (_.size(fullArmoire) - 1)
|
||||||
|
|
||||||
|
it 'does not open without paying', ->
|
||||||
|
sinon.stub(user.fns, 'predictableRandom').returns 0
|
||||||
|
user.ops.buy({params: {key: 'armoire'}})
|
||||||
|
expect(user.items.gear.owned).to.eql {'weapon_warrior_0': true}
|
||||||
|
expect(user.items.food).to.eql {}
|
||||||
|
expect(user.stats.exp).to.eql 0
|
||||||
|
|
||||||
|
it 'does not open without Ultimate Gear achievement', ->
|
||||||
|
sinon.stub(user.fns, 'predictableRandom').returns 0
|
||||||
|
user.stats.gp = 500
|
||||||
|
user.ops.buy({params: {key: 'armoire'}})
|
||||||
|
user.achievements.ultimateGearSets = {'healer':false,'wizard':false,'rogue':false,'warrior':false}
|
||||||
|
user.ops.buy({params: {key: 'armoire'}})
|
||||||
|
expect(user.items.gear.owned).to.eql {'weapon_warrior_0': true}
|
||||||
|
expect(user.items.food).to.eql {}
|
||||||
|
expect(user.stats.exp).to.eql 0
|
||||||
|
|
||||||
|
it 'always drops equipment the first time', ->
|
||||||
|
sinon.stub(user.fns, 'predictableRandom', cycle [.9,.5])
|
||||||
|
user.achievements.ultimateGearSets = {'healer':false,'wizard':false,'rogue':true,'warrior':false}
|
||||||
|
user.ops.buy({params: {key: 'armoire'}})
|
||||||
|
expect(user.items.gear.owned).to.eql {'weapon_warrior_0': true, 'shield_armoire_gladiatorShield':true}
|
||||||
|
expect(shared.countArmoire(user.items.gear.owned)).to.eql (_.size(fullArmoire) - 2)
|
||||||
|
expect(user.items.food).to.eql {}
|
||||||
|
expect(user.stats.exp).to.eql 0
|
||||||
|
expect(user.stats.gp).to.eql 400
|
||||||
|
|
||||||
|
it 'gives Experience', ->
|
||||||
|
sinon.stub(user.fns, 'predictableRandom', cycle [.9,.5])
|
||||||
|
user.ops.buy({params: {key: 'armoire'}})
|
||||||
|
expect(user.items.gear.owned).to.eql {'weapon_warrior_0': true, 'shield_armoire_gladiatorShield':true}
|
||||||
|
expect(user.items.food).to.eql {}
|
||||||
|
expect(user.stats.exp).to.eql 30
|
||||||
|
expect(user.stats.gp).to.eql 300
|
||||||
|
|
||||||
|
it 'gives food', ->
|
||||||
|
sinon.stub(user.fns, 'predictableRandom', cycle [.7,.5])
|
||||||
|
user.ops.buy({params: {key: 'armoire'}})
|
||||||
|
expect(user.items.gear.owned).to.eql {'weapon_warrior_0': true, 'shield_armoire_gladiatorShield':true}
|
||||||
|
expect(user.items.food).to.eql {'Honey': 1}
|
||||||
|
expect(user.stats.exp).to.eql 30
|
||||||
|
expect(user.stats.gp).to.eql 200
|
||||||
|
|
||||||
|
it 'gives more equipment', ->
|
||||||
|
sinon.stub(user.fns, 'predictableRandom', cycle [.5,.5])
|
||||||
|
user.ops.buy({params: {key: 'armoire'}})
|
||||||
|
expect(user.items.gear.owned).to.eql {'weapon_warrior_0': true, 'shield_armoire_gladiatorShield':true,'head_armoire_rancherHat':true}
|
||||||
|
expect(shared.countArmoire(user.items.gear.owned)).to.eql (_.size(fullArmoire) - 3)
|
||||||
|
expect(user.items.food).to.eql {'Honey': 1}
|
||||||
|
expect(user.stats.exp).to.eql 30
|
||||||
|
expect(user.stats.gp).to.eql 100
|
||||||
|
|
||||||
|
it 'does not give equipment if all equipment has been found', ->
|
||||||
|
sinon.stub(user.fns, 'predictableRandom', cycle [.5,.5])
|
||||||
|
user.items.gear.owned = fullArmoire
|
||||||
|
user.ops.buy({params: {key: 'armoire'}})
|
||||||
|
expect(user.items.gear.owned).to.eql fullArmoire
|
||||||
|
expect(shared.countArmoire(user.items.gear.owned)).to.eql 0
|
||||||
|
expect(user.items.food).to.eql {'Honey': 1}
|
||||||
|
expect(user.stats.exp).to.eql 60
|
||||||
|
expect(user.stats.gp).to.eql 0
|
||||||
|
|
||||||
|
afterEach ->
|
||||||
|
user.fns.randomVal.restore()
|
||||||
|
user.fns.predictableRandom.restore()
|
||||||
|
|
||||||
describe 'Quests', ->
|
describe 'Quests', ->
|
||||||
_.each shared.content.quests, (quest)->
|
_.each shared.content.quests, (quest)->
|
||||||
@@ -510,11 +592,11 @@ describe 'User', ->
|
|||||||
_.each [1..5], (i) ->
|
_.each [1..5], (i) ->
|
||||||
user.ops.buy {params:'#{type}_#{klass}_#{i}'}
|
user.ops.buy {params:'#{type}_#{klass}_#{i}'}
|
||||||
it 'does not get ultimateGear ' + klass, ->
|
it 'does not get ultimateGear ' + klass, ->
|
||||||
expect(user.achievements.ultimateGear).to.not.be.ok()
|
expect(user.achievements.ultimateGearSets[klass]).to.not.be.ok()
|
||||||
_.each shared.content.gearTypes, (type) ->
|
_.each shared.content.gearTypes, (type) ->
|
||||||
user.ops.buy {params:'#{type}_#{klass}_6'}
|
user.ops.buy {params:'#{type}_#{klass}_6'}
|
||||||
xit 'gets ultimateGear ' + klass, ->
|
xit 'gets ultimateGear ' + klass, ->
|
||||||
expect(user.achievements.ultimateGear).to.be.ok()
|
expect(user.achievements.ultimateGearSets[klass]).to.be.ok()
|
||||||
|
|
||||||
it 'does not get beastMaster if user has less than 90 drop pets', ->
|
it 'does not get beastMaster if user has less than 90 drop pets', ->
|
||||||
user = newUser()
|
user = newUser()
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
'use strict'
|
||||||
|
TEST_DB = process.env.DB_NAME = 'habitrpg_migration_test'
|
||||||
|
process.env.NODE_DB_URI = 'mongodb://localhost/' + TEST_DB
|
||||||
|
|
||||||
|
app = require('../../website/src/server')
|
||||||
|
sh = require('shelljs')
|
||||||
|
|
||||||
|
runMigration = ->
|
||||||
|
sh.exec 'node ./migrations/20150604_ultimateGearSets.js'
|
||||||
|
|
||||||
|
describe 'Backfill for granting ultimate gear sets achievement', ->
|
||||||
|
before (done) ->
|
||||||
|
sh.exec "mongo \"#{TEST_DB}\" --eval \"db.dropDatabase()\""
|
||||||
|
done()
|
||||||
|
|
||||||
|
context 'User without any purchased equipment', ->
|
||||||
|
before (done) ->
|
||||||
|
registerNewUser done, true
|
||||||
|
|
||||||
|
it 'does not update user', (done)->
|
||||||
|
user_gear = user.items.gear.owned
|
||||||
|
expect(user_gear.weapon_wizard_6).to.not.exist
|
||||||
|
expect(user.achievements.ultimateGearSets).to.not.exist
|
||||||
|
|
||||||
|
runMigration()
|
||||||
|
User.findById user._id, (err, _user) ->
|
||||||
|
user = _user
|
||||||
|
expect(user.achievements.ultimateGearSets).to.not.exist
|
||||||
|
done()
|
||||||
|
|
||||||
|
context 'User with all but one needed piece of equipment', ->
|
||||||
|
before (done) ->
|
||||||
|
registerNewUser ->
|
||||||
|
items = {
|
||||||
|
weapon_wizard_6: true
|
||||||
|
armor_wizard_5: true
|
||||||
|
}
|
||||||
|
|
||||||
|
User.findByIdAndUpdate user._id, {'items.gear.owned': items}, (err, _user) ->
|
||||||
|
user = _user
|
||||||
|
done()
|
||||||
|
, true
|
||||||
|
|
||||||
|
it 'does not update user', (done)->
|
||||||
|
|
||||||
|
runMigration()
|
||||||
|
|
||||||
|
User.findById user._id, (err, _user) ->
|
||||||
|
user = _user
|
||||||
|
expect(user.achievements.ultimateGearSets).to.not.exist
|
||||||
|
done()
|
||||||
|
|
||||||
|
context 'User with all necessary equipment', ->
|
||||||
|
before (done) ->
|
||||||
|
registerNewUser ->
|
||||||
|
items = {
|
||||||
|
weapon_wizard_6: true
|
||||||
|
armor_wizard_5: true
|
||||||
|
head_wizard_5: true
|
||||||
|
}
|
||||||
|
|
||||||
|
User.findByIdAndUpdate user._id, {'items.gear.owned': items}, (err, _user) ->
|
||||||
|
user = _user
|
||||||
|
done()
|
||||||
|
, true
|
||||||
|
|
||||||
|
it 'grants user ultimate gear', (done)->
|
||||||
|
|
||||||
|
runMigration()
|
||||||
|
|
||||||
|
User.findById user._id, (err, _user) ->
|
||||||
|
user = _user
|
||||||
|
expect(user.achievements.ultimateGearSets.wizard).to.exist
|
||||||
|
done()
|
||||||
@@ -10,8 +10,12 @@ describe('Inventory Controller', function() {
|
|||||||
|
|
||||||
inject(function($rootScope, $controller, Shared){
|
inject(function($rootScope, $controller, Shared){
|
||||||
user = specHelper.newUser();
|
user = specHelper.newUser();
|
||||||
user.balance = 4,
|
user.balance = 4;
|
||||||
user.items = {eggs: {Cactus: 1}, hatchingPotions: {Base: 1}, food: {Meat: 1}, pets: {}, mounts: {}};
|
user.items.eggs = {Cactus: 1};
|
||||||
|
user.items.hatchingPotions = {Base: 1};
|
||||||
|
user.items.food = {Meat: 1};
|
||||||
|
user.items.pets = {}
|
||||||
|
user.items.mounts = {};
|
||||||
Shared.wrap(user);
|
Shared.wrap(user);
|
||||||
var mockWindow = {
|
var mockWindow = {
|
||||||
confirm: function(msg){
|
confirm: function(msg){
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ specHelper = {
|
|||||||
food: {},
|
food: {},
|
||||||
pets: {},
|
pets: {},
|
||||||
mounts: {},
|
mounts: {},
|
||||||
gear: {equipped: {}, costume: {}},
|
gear: {equipped: {}, costume: {}, owned: {}},
|
||||||
},
|
},
|
||||||
party: {
|
party: {
|
||||||
quest: {
|
quest: {
|
||||||
|
|||||||
@@ -101,9 +101,14 @@ habitrpg.controller('NotificationCtrl',
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$rootScope.$watch('user.achievements.ultimateGear', function(after, before){
|
$rootScope.$watch('user.achievements.ultimateGearSets', function(after, before){
|
||||||
if (after === before || after !== true) return;
|
if (_.isEqual(after,before) || !_.contains(User.user.achievements.ultimateGearSets, true)) return;
|
||||||
$rootScope.openModal('achievements/ultimateGear');
|
$rootScope.openModal('achievements/ultimateGear');
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
$rootScope.$watch('user.flags.armoireEmpty', function(after,before){
|
||||||
|
if (before == undefined || after == before || after == false) return;
|
||||||
|
$rootScope.openModal('armoireEmpty');
|
||||||
});
|
});
|
||||||
|
|
||||||
$rootScope.$watch('user.achievements.rebirths', function(after, before){
|
$rootScope.$watch('user.achievements.rebirths', function(after, before){
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
|||||||
function($scope, $rootScope, $location, User, Notification, $http, ApiUrl, $timeout, Shared, Guide) {
|
function($scope, $rootScope, $location, User, Notification, $http, ApiUrl, $timeout, Shared, Guide) {
|
||||||
$scope.obj = User.user; // used for task-lists
|
$scope.obj = User.user; // used for task-lists
|
||||||
$scope.user = User.user;
|
$scope.user = User.user;
|
||||||
|
|
||||||
|
$scope.armoireCount = function(gear) {
|
||||||
|
return Shared.countArmoire(gear);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.score = function(task, direction) {
|
$scope.score = function(task, direction) {
|
||||||
switch (task.type) {
|
switch (task.type) {
|
||||||
case 'reward':
|
case 'reward':
|
||||||
@@ -213,7 +218,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
|||||||
------------------------
|
------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$scope.$watch('user.items.gear.equipped', function(){
|
$scope.$watchGroup(['user.items.gear.owned', 'user.flags.armoireEnabled'], function(){
|
||||||
$scope.itemStore = Shared.updateStore(User.user);
|
$scope.itemStore = Shared.updateStore(User.user);
|
||||||
},true);
|
},true);
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ var UserSchema = new Schema({
|
|||||||
originalUser: Boolean,
|
originalUser: Boolean,
|
||||||
helpedHabit: Boolean, //TODO: Deprecate this. Superseded by habitSurveys
|
helpedHabit: Boolean, //TODO: Deprecate this. Superseded by habitSurveys
|
||||||
habitSurveys: Number,
|
habitSurveys: Number,
|
||||||
ultimateGear: Boolean,
|
ultimateGear: Boolean, //TODO: Deprecate this. Superseded by ultimateGearSets
|
||||||
|
ultimateGearSets: Schema.Types.Mixed,
|
||||||
beastMaster: Boolean,
|
beastMaster: Boolean,
|
||||||
beastMasterCount: Number,
|
beastMasterCount: Number,
|
||||||
mountMaster: Boolean,
|
mountMaster: Boolean,
|
||||||
@@ -156,7 +157,10 @@ var UserSchema = new Schema({
|
|||||||
lastWeeklyRecap: {type: Date, 'default': Date.now},
|
lastWeeklyRecap: {type: Date, 'default': Date.now},
|
||||||
communityGuidelinesAccepted: {type: Boolean, 'default': false},
|
communityGuidelinesAccepted: {type: Boolean, 'default': false},
|
||||||
cronCount: {type:Number, 'default':0},
|
cronCount: {type:Number, 'default':0},
|
||||||
welcomed: {type: Boolean, 'default': false}
|
welcomed: {type: Boolean, 'default': false},
|
||||||
|
armoireEnabled: {type: Boolean, 'default': false},
|
||||||
|
armoireOpened: {type: Boolean, 'default': false},
|
||||||
|
armoireEmpty: {type: Boolean, 'default': false}
|
||||||
},
|
},
|
||||||
history: {
|
history: {
|
||||||
exp: Array, // [{date: Date, value: Number}], // big peformance issues if these are defined
|
exp: Array, // [{date: Date, value: Number}], // big peformance issues if these are defined
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ script(type='text/ng-template', id='partials/options.inventory.equipment.html')
|
|||||||
div
|
div
|
||||||
button.btn.btn-default(type="button", ng-click='dequip("battleGear");') {{env.t("unequipBattleGear")}}
|
button.btn.btn-default(type="button", ng-click='dequip("battleGear");') {{env.t("unequipBattleGear")}}
|
||||||
li.customize-menu.inventory-gear
|
li.customize-menu.inventory-gear
|
||||||
menu.pets-menu(label='{{::label}}', ng-repeat='(klass,label) in {warrior:env.t("warrior"), wizard:env.t("mage"), rogue:env.t("rogue"), healer:env.t("healer"), special:env.t("special"), mystery:env.t("mystery")}', ng-show='gear[klass]')
|
menu.pets-menu(label='{{::label}}', ng-repeat='(klass,label) in {warrior:env.t("warrior"), wizard:env.t("mage"), rogue:env.t("rogue"), healer:env.t("healer"), special:env.t("special"), mystery:env.t("mystery"), armoire:env.t("armoireText")}', ng-show='gear[klass]')
|
||||||
div(ng-repeat='item in 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', popover-append-to-body='true', ng-click='user.ops.equip({params:{key:item.key}})', class='shop_{{::item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}')
|
button.customize-option(popover='{{::item.notes()}}', popover-title='{{::item.text()}}', popover-trigger='mouseenter', popover-placement='right', popover-append-to-body='true', ng-click='user.ops.equip({params:{key:item.key}})', class='shop_{{::item.key}}', ng-class='{selectableInventory: user.items.gear.equipped[item.type] == item.key}')
|
||||||
.col-md-6
|
.col-md-6
|
||||||
@@ -20,7 +20,7 @@ script(type='text/ng-template', id='partials/options.inventory.equipment.html')
|
|||||||
button.btn.btn-default(type="button", ng-click='dequip("costume");') {{env.t("unequipCostume")}}
|
button.btn.btn-default(type="button", ng-click='dequip("costume");') {{env.t("unequipCostume")}}
|
||||||
button.btn.btn-default(type="button", ng-click='dequip("petMountBackground");') {{env.t("unequipPetMountBackground")}}
|
button.btn.btn-default(type="button", ng-click='dequip("petMountBackground");') {{env.t("unequipPetMountBackground")}}
|
||||||
li.customize-menu(ng-if='user.preferences.costume')
|
li.customize-menu(ng-if='user.preferences.costume')
|
||||||
menu.pets-menu(label='{{::label}}', ng-repeat='(klass,label) in {warrior:env.t("warrior"), wizard:env.t("mage"), rogue:env.t("rogue"), healer:env.t("healer"), special:env.t("special"), mystery:env.t("mystery")}', ng-show='gear[klass]')
|
menu.pets-menu(label='{{::label}}', ng-repeat='(klass,label) in {warrior:env.t("warrior"), wizard:env.t("mage"), rogue:env.t("rogue"), healer:env.t("healer"), special:env.t("special"), mystery:env.t("mystery"), armoire:env.t("armoireText")}', ng-show='gear[klass]')
|
||||||
div(ng-repeat='item in 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', popover-append-to-body='true', ng-click='user.ops.equip({params:{type:"costume", key:item.key}})', class='shop_{{::item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}')
|
button.customize-option(popover='{{::item.notes()}}', popover-title='{{::item.text()}}', popover-trigger='mouseenter', popover-placement='right', popover-append-to-body='true', ng-click='user.ops.equip({params:{type:"costume", key:item.key}})', class='shop_{{::item.key}}', ng-class='{selectableInventory: user.items.gear.costume[item.type] == item.key}')
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,27 @@ script(id='modals/achievements/ultimateGear.html', type='text/ng-template')
|
|||||||
h4=env.t('modalAchievement')
|
h4=env.t('modalAchievement')
|
||||||
.modal-body
|
.modal-body
|
||||||
.achievement.achievement-armor
|
.achievement.achievement-armor
|
||||||
=env.t('gearAchievement')
|
p=env.t('gearAchievement')
|
||||||
|
br
|
||||||
|
table.multi-achievement
|
||||||
|
tr
|
||||||
|
td(ng-if='::user.achievements.ultimateGearSets.healer').multi-achievement
|
||||||
|
.achievement-ultimate-healer.multi-achievement
|
||||||
|
=env.t('healer')
|
||||||
|
td(ng-if='::user.achievements.ultimateGearSets.wizard').multi-achievement
|
||||||
|
.achievement-ultimate-mage.multi-achievement
|
||||||
|
=env.t('mage')
|
||||||
|
td(ng-if='::user.achievements.ultimateGearSets.rogue').multi-achievement
|
||||||
|
.achievement-ultimate-rogue.multi-achievement
|
||||||
|
=env.t('rogue')
|
||||||
|
td(ng-if='::user.achievements.ultimateGearSets.warrior').multi-achievement
|
||||||
|
.achievement-ultimate-warrior.multi-achievement
|
||||||
|
=env.t('warrior')
|
||||||
|
br
|
||||||
|
p(ng-if='!(user.achievements.ultimateGearSets.healer && user.achievements.ultimateGearSets.wizard && user.achievements.ultimateGearSets.rogue && user.achievements.ultimateGearSets.warrior)')!=env.t('moreGearAchievements')
|
||||||
|
br
|
||||||
|
.shop_armoire.pull-right
|
||||||
|
p!=env.t("armoireUnlocked")
|
||||||
.modal-footer
|
.modal-footer
|
||||||
button.btn.btn-default(ng-click='$close()')=env.t('ok')
|
button.btn.btn-default(ng-click='$close()')=env.t('ok')
|
||||||
|
|
||||||
|
|||||||
@@ -51,3 +51,14 @@ script(type='text/ng-template', id='modals/pet-key.html')
|
|||||||
span(ng-if='!user.achievements.triadBingo')
|
span(ng-if='!user.achievements.triadBingo')
|
||||||
| : 6
|
| : 6
|
||||||
span.Pet_Currency_Gem1x.inline-gems
|
span.Pet_Currency_Gem1x.inline-gems
|
||||||
|
|
||||||
|
script(type='text/ng-template', id='modals/armoireEmpty.html')
|
||||||
|
.modal-header
|
||||||
|
.shop_armoire.pull-right
|
||||||
|
h4=env.t('armoireText')
|
||||||
|
.modal-body
|
||||||
|
p=env.t('armoireLastItem')
|
||||||
|
br
|
||||||
|
p=env.t('armoireNotesEmpty')
|
||||||
|
.modal-footer
|
||||||
|
button.btn.btn-default(ng-click='$close()')=env.t('close')
|
||||||
@@ -1,10 +1,22 @@
|
|||||||
h5 6/1/2015 - JUNE MYSTERY ITEM AND NEW MOUNT POSITIONING!
|
h5 6/1/2015 - NEW EQUIPMENT: THE ENCHANTED ARMOIRE, JUNE BACKGROUNDS, AND NEW MOUNT POSITIONING!
|
||||||
hr
|
hr
|
||||||
tr
|
tr
|
||||||
td
|
td
|
||||||
.inventory_present_06.pull-right
|
.promo_enchanted_armoire.pull-right
|
||||||
h5 June Mystery Item!
|
h5 New Equipment: The Enchanted Armoire!
|
||||||
p Ooh, how mysterious! All Habiticans who are <a href='/#/options/settings/subscription' target='_blank'>subscribed</a> during the month of June will receive the June Mystery Item Set, as well as the ability to buy Gems with Gold! The June Item Set will be revealed on the 25th, so keep your eyes peeled. Thanks for supporting the site <3
|
p Now after you achieve Ultimate Gear, you'll unlock a new Reward: THE ENCHANTED ARMOIRE!
|
||||||
|
br
|
||||||
|
p Click on the Enchanted Armoire, a 100 GP Reward in the Rewards Column, for a random chance at special Equipment! It may also give you random XP or food items. We'll be adding new equipment to it every month, but even when you've exhausted the current supply, you can keep clicking for a chance at food and XP.
|
||||||
|
br
|
||||||
|
p Now go spend all that accumulated Gold! May the Random Number Generator smile upon you...
|
||||||
|
p.small.muted by Lemoness and SabreCat
|
||||||
|
p.small.muted Art by Kiwibot, Starsystemic, UncommonCriminal, Zoebeagle, and Andrews38
|
||||||
|
tr
|
||||||
|
td
|
||||||
|
.background_island_waterfalls.pull-right
|
||||||
|
h5 June Backgrounds Revealed
|
||||||
|
p There are three new avatar backgrounds in the <a href='/#/options/profile/backgrounds' target='_blank'>Background Shop</a>! Now your avatar can paddle a Drifting Raft, float through a sea of Shimmery Bubbles, or picnic near Island Waterfalls!
|
||||||
|
p.small.muted by (in order): Teto is Great, beffymaroo, and UncommonCriminal
|
||||||
tr
|
tr
|
||||||
td
|
td
|
||||||
h5 New Mount Positioning!
|
h5 New Mount Positioning!
|
||||||
@@ -16,6 +28,12 @@ a(href='/static/old-news', target='_blank') Read older news
|
|||||||
|
|
||||||
mixin oldNews
|
mixin oldNews
|
||||||
|
|
||||||
|
h5 6/1/2015 - JUNE MYSTERY ITEM!
|
||||||
|
tr
|
||||||
|
td
|
||||||
|
.inventory_present_06.pull-right
|
||||||
|
h5 June Mystery Item!
|
||||||
|
p Ooh, how mysterious! All Habiticans who are <a href='/#/options/settings/subscription' target='_blank'>subscribed</a> during the month of June will receive the June Mystery Item Set, as well as the ability to buy Gems with Gold! The June Item Set will be revealed on the 25th, so keep your eyes peeled. Thanks for supporting the site <3
|
||||||
h5 5/31/2015 - PUSH NOTIFICATIONS FOR ANDROID, AND LAST CHANCE FOR GREEN KNIGHT SUBSCRIBER ITEMS!
|
h5 5/31/2015 - PUSH NOTIFICATIONS FOR ANDROID, AND LAST CHANCE FOR GREEN KNIGHT SUBSCRIBER ITEMS!
|
||||||
tr
|
tr
|
||||||
td
|
td
|
||||||
|
|||||||
@@ -78,18 +78,25 @@ div(ng-if='::profile.achievements.perfect || user._id == profile._id')
|
|||||||
small(ng-if='::profile.achievements.perfect == 1')=env.t('perfectSingularText')
|
small(ng-if='::profile.achievements.perfect == 1')=env.t('perfectSingularText')
|
||||||
hr
|
hr
|
||||||
|
|
||||||
//-div(ng-if='::profile.achievements.ultimateGear || user._id == profile._id')
|
div(ng-if='::profile.achievements.ultimateGearSets || user._id == profile._id')
|
||||||
.achievement.achievement-armor(ng-if='::profile.achievements.ultimateGear')
|
.achievement.achievement-armor(ng-if='::profile.achievements.ultimateGearSets')
|
||||||
div(ng-class='::{muted: !profile.achievements.ultimateGear}')
|
div(ng-class='::{muted: !profile.achievements.ultimateGearSets}')
|
||||||
h5=env.t('ultimGearName')
|
h5=env.t('ultimGearName')
|
||||||
small=env.t('ultimGearText')
|
small=env.t('ultimGearText')
|
||||||
hr
|
table.multi-achievement
|
||||||
// Remove the following when ultimate gear is fixed (https://github.com/HabitRPG/habitrpg/issues/2232):
|
tr
|
||||||
div(ng-if='::user._id == profile._id')
|
td(ng-if='::profile.achievements.ultimateGearSets.healer').multi-achievement
|
||||||
div.muted
|
.achievement-ultimate-healer.multi-achievement
|
||||||
h5=env.t('ultimGearName')
|
=env.t('healer')
|
||||||
small
|
td(ng-if='::profile.achievements.ultimateGearSets.wizard').multi-achievement
|
||||||
+aLink('https://github.com/HabitRPG/habitrpg/issues/2232', 'Returning soon')
|
.achievement-ultimate-mage.multi-achievement
|
||||||
|
=env.t('mage')
|
||||||
|
td(ng-if='::profile.achievements.ultimateGearSets.rogue').multi-achievement
|
||||||
|
.achievement-ultimate-rogue.multi-achievement
|
||||||
|
=env.t('rogue')
|
||||||
|
td(ng-if='::profile.achievements.ultimateGearSets.warrior').multi-achievement
|
||||||
|
.achievement-ultimate-warrior.multi-achievement
|
||||||
|
=env.t('warrior')
|
||||||
hr
|
hr
|
||||||
|
|
||||||
div(ng-if='::profile.achievements.beastMaster || user._id == profile._id')
|
div(ng-if='::profile.achievements.beastMaster || user._id == profile._id')
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
|
|||||||
|
|
||||||
// Static Rewards
|
// Static Rewards
|
||||||
ul.items.rewards(ng-if='main && list.type=="reward"')
|
ul.items.rewards(ng-if='main && list.type=="reward"')
|
||||||
li.task.reward-item(ng-repeat='item in itemStore',popover-trigger='mouseenter', popover-placement='top', popover='{{item.notes()}}')
|
li.task.reward-item(ng-repeat='item in itemStore',popover-trigger='mouseenter', popover-placement='top', popover='{{item.key == "armoire" && !user.flags.armoireEmpty ? env.t("armoireNotesFull") + armoireCount(user.items.gear.owned) : item.notes()}}')
|
||||||
// right-hand side control buttons
|
// right-hand side control buttons
|
||||||
.task-meta-controls
|
.task-meta-controls
|
||||||
span.task-notes
|
span.task-notes
|
||||||
|
|||||||