mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
Login Incentives (#8230)
* feat(incentives): login bennies WIP * feat(content): incentive prize content WIP * fix(content): placeholders pass tests * WIP(content): Bard instrument placeholder * feat(content): Incentives build * chore(sprites): compile and fix some strings * WIP(incentives): quests and backgrounds * fix(quests): correct buy/launch handling * [WIP] Incentives rewarding (#8226) * Added login incentive rewards * Updated incentive rewards * Added incentive modal and updated notification structure * Added analytics to sleeping * Added login incentives to user analytics * Fixed unit tests and ensured that prizes are incremented and not replaced * Updated style of daily login incentive modal * Added rewards modal * Added translations * Added loigin incentive ui elements to profile * Updated login incentives structure and abstracted to common.content * Added dynamic display for login incentives on profile * Added purple potion image * Updated daily login modal * Fixed progress calculation * Added bard gear * Updated login incentive rewards * Fixed styles and text * Added multiple read for notifications * Fixed lint issues * Fixed styles and added 50 limit * Updated quest keys * Added login incentives reward page * Fixed tests * Fixed linting and tests * Read named notifications route. Add image for backgrounds * Fixed style issues and added tranlsations to login incentive notification * Hided abiltiy to purchase incentive backgrounds and added message to detail how to unlock * Updated awarded message * Fixed text and updated progress counter to display better * Fixed purple potion reward text * Fixed check in backgrouns reward text * fix(quest): pass tests * Added display of multiple rewards * Updated modal styles * Fixed neagtive 50 issue * Remvoed total count from daily login incentives modal * Fixed magic paw display * fix(awards): give bunnies again * WIP(incentives): more progress on BG shop * fix(incentives): actually award backgrounds * fix(incentives): more BG fixy * fix(backgrounds): don't gem-buy checkin bgs * Added dust bunny notification * fix(incentives): don't redisplay bunny award * chore(news): Bailey and different promo sprite
This commit is contained in:
@@ -423,6 +423,33 @@ let backgrounds = {
|
||||
notes: t('backgroundWindyAutumnNotes'),
|
||||
},
|
||||
},
|
||||
incentiveBackgrounds: {
|
||||
blue: {
|
||||
text: t('backgroundBlueText'),
|
||||
notes: t('backgroundBlueNotes'),
|
||||
currency: 'loginIncentive',
|
||||
},
|
||||
green: {
|
||||
text: t('backgroundGreenText'),
|
||||
notes: t('backgroundGreenNotes'),
|
||||
currency: 'loginIncentive',
|
||||
},
|
||||
purple: {
|
||||
text: t('backgroundPurpleText'),
|
||||
notes: t('backgroundPurpleNotes'),
|
||||
currency: 'loginIncentive',
|
||||
},
|
||||
red: {
|
||||
text: t('backgroundRedText'),
|
||||
notes: t('backgroundRedNotes'),
|
||||
currency: 'loginIncentive',
|
||||
},
|
||||
yellow: {
|
||||
text: t('backgroundYellowText'),
|
||||
notes: t('backgroundYellowNotes'),
|
||||
currency: 'loginIncentive',
|
||||
},
|
||||
},
|
||||
};
|
||||
/* eslint-enable quote-props */
|
||||
|
||||
|
||||
@@ -27,6 +27,21 @@ let armor = {
|
||||
value: 130,
|
||||
canOwn: ownsItem('armor_special_pyromancersRobes'),
|
||||
},
|
||||
bardRobes: {
|
||||
text: t('armorSpecialBardRobesText'),
|
||||
notes: t('armorSpecialBardRobesNotes', { per: 3 }),
|
||||
per: 3,
|
||||
value: 0,
|
||||
canOwn: ownsItem('armor_special_bardRobes'),
|
||||
},
|
||||
lunarWarriorArmor: {
|
||||
text: t('armorSpecialLunarWarriorArmorText'),
|
||||
notes: t('armorSpecialLunarWarriorArmorNotes', { attrs: 7 }),
|
||||
str: 7,
|
||||
con: 7,
|
||||
value: 130,
|
||||
canOwn: ownsItem('armor_special_lunarWarriorArmor'),
|
||||
},
|
||||
yeti: {
|
||||
event: EVENTS.winter,
|
||||
specialClass: 'warrior',
|
||||
@@ -578,6 +593,21 @@ let head = {
|
||||
value: 130,
|
||||
canOwn: ownsItem('head_special_pyromancersTurban'),
|
||||
},
|
||||
bardHat: {
|
||||
text: t('headSpecialBardHatText'),
|
||||
notes: t('headSpecialBardHatNotes', { int: 3 }),
|
||||
int: 3,
|
||||
value: 0,
|
||||
canOwn: ownsItem('head_special_bardHat'),
|
||||
},
|
||||
lunarWarriorHelm: {
|
||||
text: t('headSpecialLunarWarriorHelmText'),
|
||||
notes: t('headSpecialLunarWarriorHelmNotes', { attrs: 7 }),
|
||||
int: 7,
|
||||
str: 7,
|
||||
value: 130,
|
||||
canOwn: ownsItem('head_special_lunarWarriorHelm'),
|
||||
},
|
||||
nye: {
|
||||
event: EVENTS.winter2016,
|
||||
text: t('headSpecialNyeText'),
|
||||
@@ -1487,6 +1517,24 @@ let weapon = {
|
||||
value: 130,
|
||||
canOwn: ownsItem('weapon_special_taskwoodsLantern'),
|
||||
},
|
||||
bardInstrument: {
|
||||
text: t('weaponSpecialBardInstrumentText'),
|
||||
notes: t('weaponSpecialBardInstrumentNotes', { attrs: 4 }),
|
||||
twoHanded: true,
|
||||
per: 4,
|
||||
int: 4,
|
||||
value: 0,
|
||||
canOwn: ownsItem('weapon_special_bardInstrument'),
|
||||
},
|
||||
lunarScythe: {
|
||||
text: t('weaponSpecialLunarScytheText'),
|
||||
notes: t('weaponSpecialLunarScytheNotes', { attrs: 7 }),
|
||||
twoHanded: true,
|
||||
str: 7,
|
||||
per: 7,
|
||||
value: 130,
|
||||
canOwn: ownsItem('weapon_special_lunarScythe'),
|
||||
},
|
||||
yeti: {
|
||||
event: EVENTS.winter,
|
||||
specialClass: 'warrior',
|
||||
|
||||
@@ -79,6 +79,11 @@ let premium = {
|
||||
limited: true,
|
||||
_season: 'fall',
|
||||
},
|
||||
RoyalPurple: {
|
||||
value: 2,
|
||||
text: t('hatchingPotionRoyalPurple'),
|
||||
limited: true,
|
||||
},
|
||||
};
|
||||
|
||||
each(drops, (pot, key) => {
|
||||
|
||||
@@ -23,6 +23,7 @@ import appearances from './appearance';
|
||||
import backgrounds from './appearance/backgrounds.js'
|
||||
import spells from './spells';
|
||||
import faq from './faq';
|
||||
import loginIncentives from './loginIncentives';
|
||||
|
||||
api.mystery = mysterySets;
|
||||
|
||||
@@ -2653,6 +2654,113 @@ api.quests = {
|
||||
unlock: t('questFerretUnlockText'),
|
||||
},
|
||||
},
|
||||
dustbunnies: {
|
||||
text: t('questDustBunniesText'),
|
||||
notes: t('questDustBunniesNotes'),
|
||||
completion: t('questDustBunniesCompletion'),
|
||||
value: 4,
|
||||
category: 'unlockable',
|
||||
unlockCondition: {
|
||||
condition: 'create account',
|
||||
text: t('createAccountReward')
|
||||
},
|
||||
boss: {
|
||||
name: t('questDustBunniesBoss'),
|
||||
hp: 100,
|
||||
str: 0.5
|
||||
},
|
||||
drop: {
|
||||
gp: 8,
|
||||
exp: 42
|
||||
}
|
||||
},
|
||||
moon1: {
|
||||
text: t('questMoon1Text'),
|
||||
notes: t('questMoon1Notes'),
|
||||
completion: t('questMoon1Completion'),
|
||||
value: 4,
|
||||
category: 'unlockable',
|
||||
unlockCondition: {
|
||||
condition: 'login incentive',
|
||||
incentiveThreshold: 7,
|
||||
text: t('loginReward', {count: 7})
|
||||
},
|
||||
collect: {
|
||||
shard: {
|
||||
text: t('questMoon1CollectShards'),
|
||||
count: 20
|
||||
},
|
||||
},
|
||||
drop: {
|
||||
items: [
|
||||
{
|
||||
type: 'gear',
|
||||
key: "head_special_lunarWarriorHelm",
|
||||
text: t('questMoon1DropHeadgear')
|
||||
},
|
||||
],
|
||||
gp: 7,
|
||||
exp: 50
|
||||
}
|
||||
},
|
||||
moon2: {
|
||||
text: t('questMoon2Text'),
|
||||
notes: t('questMoon2Notes'),
|
||||
completion: t('questMoon2Completion'),
|
||||
previous: 'moon1',
|
||||
value: 4,
|
||||
category: 'unlockable',
|
||||
unlockCondition: {
|
||||
condition: 'login incentive',
|
||||
incentiveThreshold: 22,
|
||||
text: t('loginReward', {count: 22})
|
||||
},
|
||||
boss: {
|
||||
name: t('questMoon2Boss'),
|
||||
hp: 100,
|
||||
str: 1.5
|
||||
},
|
||||
drop: {
|
||||
items: [
|
||||
{
|
||||
type: 'gear',
|
||||
key: "armor_special_lunarWarriorArmor",
|
||||
text: t('questMoon2DropArmor')
|
||||
}
|
||||
],
|
||||
gp: 37,
|
||||
exp: 275
|
||||
}
|
||||
},
|
||||
moon3: {
|
||||
text: t('questMoon3Text'),
|
||||
notes: t('questMoon3Notes'),
|
||||
completion: t('questMoon3Completion'),
|
||||
previous: 'moon2',
|
||||
value: 4,
|
||||
category: 'unlockable',
|
||||
unlockCondition: {
|
||||
condition: 'login incentive',
|
||||
incentiveThreshold: 40,
|
||||
text: t('loginReward', {count: 40})
|
||||
},
|
||||
boss: {
|
||||
name: t('questMoon3Boss'),
|
||||
hp: 1000,
|
||||
str: 2
|
||||
},
|
||||
drop: {
|
||||
items: [
|
||||
{
|
||||
type: 'gear',
|
||||
key: "weapon_special_lunarScythe",
|
||||
text: t('questMoon3DropWeapon')
|
||||
},
|
||||
],
|
||||
gp: 67,
|
||||
exp: 650
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
_.each(api.quests, function(v, key) {
|
||||
@@ -2777,3 +2885,5 @@ api.userDefaults = {
|
||||
};
|
||||
|
||||
api.faq = faq;
|
||||
|
||||
api.loginIncentives = loginIncentives(api);
|
||||
|
||||
174
website/common/script/content/loginIncentives.js
Normal file
174
website/common/script/content/loginIncentives.js
Normal file
@@ -0,0 +1,174 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
module.exports = function getLoginIncentives (api) {
|
||||
let loginIncentives = {
|
||||
1: {
|
||||
rewardKey: ['armor_special_bardRobes'],
|
||||
reward: [api.gear.flat.armor_special_bardRobes],
|
||||
assignReward: function assignReward (user) {
|
||||
user.items.gear.owned.armor_special_bardRobes = true; // eslint-disable-line camelcase
|
||||
},
|
||||
},
|
||||
2: {
|
||||
rewardKey: ['background_blue'],
|
||||
reward: [api.backgrounds.incentiveBackgrounds],
|
||||
assignReward: function assignReward (user) {
|
||||
user.purchased.background.blue = true;
|
||||
user.purchased.background.green = true;
|
||||
user.purchased.background.purple = true;
|
||||
user.purchased.background.red = true;
|
||||
user.purchased.background.yellow = true;
|
||||
user.markModified('purchased.background');
|
||||
},
|
||||
},
|
||||
3: {
|
||||
rewardKey: ['head_special_bardHat'],
|
||||
reward: [api.gear.flat.head_special_bardHat],
|
||||
assignReward: function assignReward (user) {
|
||||
user.items.gear.owned.head_special_bardHat = true; // eslint-disable-line camelcase
|
||||
},
|
||||
},
|
||||
4: {
|
||||
rewardKey: ['Pet_HatchingPotion_RoyalPurple'],
|
||||
reward: [api.hatchingPotions.RoyalPurple],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.hatchingPotions.RoyalPurple) user.items.hatchingPotions.RoyalPurple = 0;
|
||||
user.items.hatchingPotions.RoyalPurple += 1;
|
||||
},
|
||||
},
|
||||
5: {
|
||||
rewardKey: ['Pet_Food_Chocolate', 'Pet_Food_Meat', 'Pet_Food_CottonCandyPink'],
|
||||
reward: [api.food.Chocolate, api.food.Meat, api.food.CottonCandyPink],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.food.Chocolate) user.items.food.Chocolate = 0;
|
||||
user.items.food.Chocolate += 1;
|
||||
if (!user.items.food.Meat) user.items.food.Meat = 0;
|
||||
user.items.food.Meat += 1;
|
||||
if (!user.items.food.CottonCandyPink) user.items.food.CottonCandyPink = 0;
|
||||
user.items.food.CottonCandyPink += 1;
|
||||
},
|
||||
},
|
||||
7: {
|
||||
rewardKey: ['inventory_quest_scroll_moon1'],
|
||||
reward: [api.quests.moon1],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.quests.moon1) user.items.quests.moon1 = 0;
|
||||
user.items.quests.moon1 += 1;
|
||||
},
|
||||
},
|
||||
10: {
|
||||
rewardKey: ['Pet_HatchingPotion_Purple'],
|
||||
reward: [api.hatchingPotions.RoyalPurple],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.hatchingPotions.RoyalPurple) user.items.hatchingPotions.RoyalPurple = 0;
|
||||
user.items.hatchingPotions.RoyalPurple += 1;
|
||||
},
|
||||
},
|
||||
14: {
|
||||
rewardKey: ['Pet_Food_Strawberry', 'Pet_Food_Potatoe', 'Pet_Food_CottonCandyBlue'],
|
||||
reward: [api.food.Strawberry, api.food.Potatoe, api.food.CottonCandyBlue],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.food.Strawberry) user.items.food.Strawberry = 0;
|
||||
user.items.food.Strawberry += 1;
|
||||
if (!user.items.food.Potatoe) user.items.food.Potatoe = 0;
|
||||
user.items.food.Potatoe += 1;
|
||||
if (!user.items.food.CottonCandyBlue) user.items.food.CottonCandyBlue = 0;
|
||||
user.items.food.CottonCandyBlue += 1;
|
||||
},
|
||||
},
|
||||
18: {
|
||||
rewardKey: ['weapon_special_bardInstrument'],
|
||||
reward: [api.gear.flat.weapon_special_bardInstrument],
|
||||
assignReward: function assignReward (user) {
|
||||
user.items.gear.owned.weapon_special_bardInstrument = true; // eslint-disable-line camelcase
|
||||
},
|
||||
},
|
||||
22: {
|
||||
rewardKey: ['inventory_quest_scroll_moon2'],
|
||||
reward: [api.quests.moon2],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.quests.moon2) user.items.quests.moon2 = 0;
|
||||
user.items.quests.moon2 += 1;
|
||||
},
|
||||
},
|
||||
26: {
|
||||
rewardKey: ['Pet_HatchingPotion_Purple'],
|
||||
reward: [api.hatchingPotions.RoyalPurple],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.hatchingPotions.RoyalPurple) user.items.hatchingPotions.RoyalPurple = 0;
|
||||
user.items.hatchingPotions.RoyalPurple += 1;
|
||||
},
|
||||
},
|
||||
30: {
|
||||
rewardKey: ['Pet_Food_Fish', 'Pet_Food_Milk', 'Pet_Food_RottenMeat', 'Pet_Food_Honey'],
|
||||
reward: [api.food.Fish, api.food.Milk, api.food.RottenMeat, api.food.Honey],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.food.Fish) user.items.food.Fish = 0;
|
||||
user.items.food.Fish += 1;
|
||||
if (!user.items.food.Milk) user.items.food.Milk = 0;
|
||||
user.items.food.Milk += 1;
|
||||
if (!user.items.food.RottenMeat) user.items.food.RottenMeat = 0;
|
||||
user.items.food.RottenMeat += 1;
|
||||
if (!user.items.food.Honey) user.items.food.Honey = 0;
|
||||
user.items.food.Honey += 1;
|
||||
},
|
||||
},
|
||||
35: {
|
||||
rewardKey: ['Pet_HatchingPotion_Purple'],
|
||||
reward: [api.hatchingPotions.RoyalPurple],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.hatchingPotions.RoyalPurple) user.items.hatchingPotions.RoyalPurple = 0;
|
||||
user.items.hatchingPotions.RoyalPurple += 1;
|
||||
},
|
||||
},
|
||||
40: {
|
||||
rewardKey: ['inventory_quest_scroll_moon3'],
|
||||
reward: [api.quests.moon3],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.quests.moon3) user.items.quests.moon3 = 0;
|
||||
user.items.quests.moon3 += 1;
|
||||
},
|
||||
},
|
||||
45: {
|
||||
rewardKey: ['Pet_HatchingPotion_Purple'],
|
||||
reward: [api.hatchingPotions.RoyalPurple],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.hatchingPotions.RoyalPurple) user.items.hatchingPotions.RoyalPurple = 0;
|
||||
user.items.hatchingPotions.RoyalPurple += 1;
|
||||
},
|
||||
},
|
||||
50: {
|
||||
rewardKey: ['Pet_Food_Saddle'],
|
||||
reward: [api.food.Saddle],
|
||||
assignReward: function assignReward (user) {
|
||||
if (!user.items.food.Saddle) user.items.food.Saddle = 0;
|
||||
user.items.food.Saddle += 1;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Add refence link to next reward and add filler days so we have a map to refernce the next reward from any day
|
||||
// We could also, use a list, but then we would be cloning each of the rewards.
|
||||
// Create a new array if we want the loginIncentives to be immutable in the future
|
||||
let nextRewardKey;
|
||||
_.range(51).reverse().forEach(function addNextRewardLink (index) {
|
||||
if (loginIncentives[index] && loginIncentives[index].rewardKey) {
|
||||
loginIncentives[index].nextRewardAt = nextRewardKey;
|
||||
nextRewardKey = index;
|
||||
return;
|
||||
}
|
||||
|
||||
loginIncentives[index] = {
|
||||
reward: undefined,
|
||||
nextRewardAt: nextRewardKey,
|
||||
};
|
||||
});
|
||||
|
||||
let prevRewardKey;
|
||||
_.range(51).forEach(function addPrevRewardLink (index) {
|
||||
loginIncentives[index].prevRewardKey = prevRewardKey;
|
||||
if (loginIncentives[index].rewardKey) prevRewardKey = index;
|
||||
});
|
||||
|
||||
return loginIncentives;
|
||||
};
|
||||
Reference in New Issue
Block a user