diff --git a/common/script/src/content/armoire.js b/common/script/src/content/armoire.js new file mode 100644 index 0000000000..051296272d --- /dev/null +++ b/common/script/src/content/armoire.js @@ -0,0 +1,20 @@ +import {contains} from 'lodash'; +import {translator as t} from './helpers'; + +let armoire = { + type: 'armoire', + text: t('armoireText'), + notes: ((user, count) => { + if (user.flags.armoireEmpty) { + return t('armoireNotesEmpty')(); + } + return t('armoireNotesFull')() + count; + }), + value: 100, + key: 'armoire', + canOwn: ((user) => { + return contains(user.achievements.ultimateGearSets, true); + }) +}; + +export default armoire; diff --git a/common/script/src/content/backgrounds.js b/common/script/src/content/backgrounds.js new file mode 100644 index 0000000000..1f7ca6a1ed --- /dev/null +++ b/common/script/src/content/backgrounds.js @@ -0,0 +1,30 @@ +import {each} from 'lodash'; +import { + translator as t, + generateBackgrounds +} from './helpers'; + +let sets = { + 'backgrounds062014': ['beach', 'fairy_ring', 'forest'], + 'backgrounds072014': ['open_waters', 'coral_reef', 'seafarer_ship'], + 'backgrounds082014': ['volcano', 'clouds', 'dusty_canyons'], + 'backgrounds092014': ['thunderstorm', 'autumn_forest', 'harvest_fields'], + 'backgrounds102014': ['graveyard', 'haunted_house', 'pumpkin_patch'], + 'backgrounds112014': ['harvest_feast', 'sunset_meadow', 'starry_skies'], + 'backgrounds122014': ['iceberg', 'twinkly_lights', 'south_pole'], + 'backgrounds012015': ['ice_cave', 'frigid_peak', 'snowy_pines'], + 'backgrounds022015': ['blacksmithy', 'crystal_cave', 'distant_castle'], + 'backgrounds032015': ['spring_rain', 'stained_glass', 'rolling_hills'], + 'backgrounds042015': ['cherry_trees', 'floral_meadow', 'gumdrop_land'], + 'backgrounds052015': ['marble_temple', 'mountain_lake', 'pagodas'], + 'backgrounds062015': ['drifting_raft', 'shimmery_bubbles', 'island_waterfalls'], + 'backgrounds072015': ['dilatory_ruins', 'giant_wave', 'sunken_ship'], + 'backgrounds082015': ['pyramids', 'sunset_savannah', 'twinkly_party_lights'], + 'backgrounds092015': ['market', 'stable', 'tavern'], + 'backgrounds102015': ['harvest_moon', 'slimy_swamp', 'swarming_darkness'], + 'backgrounds112015': ['floating_islands', 'night_dunes', 'sunset_oasis'] +}; + +generateBackgrounds(sets); + +export default sets; diff --git a/common/script/src/content/card-types.js b/common/script/src/content/card-types.js new file mode 100644 index 0000000000..dc767a70b0 --- /dev/null +++ b/common/script/src/content/card-types.js @@ -0,0 +1,22 @@ +let cardTypes = { + greeting: { + key: 'greeting', + messageOptions: 4, + yearRound: true + }, + nye: { + key: 'nye', + messageOptions: 5 + }, + thankyou: { + key: 'thankyou', + messageOptions: 4, + yearRound: true + }, + valentine: { + key: 'valentine', + messageOptions: 4 + } +}; + +export default cardTypes; diff --git a/common/script/src/content/eggs/drops.js b/common/script/src/content/eggs/drops.js new file mode 100644 index 0000000000..1f91492d87 --- /dev/null +++ b/common/script/src/content/eggs/drops.js @@ -0,0 +1,26 @@ +import {generateEggs} from '../helpers'; + +const DROP_EGGS = [ + 'Wolf', + 'TigerCub', + 'PandaCub', + 'LionCub', + 'Fox', + 'FlyingPig', + 'Dragon', + 'Cactus', + 'BearCub', +]; + +let eggDefaults = { + type: 'drop', + canBuy: () => { + return () => { + return true; + }; + }, +}; + +let eggs = generateEggs(DROP_EGGS, eggDefaults); + +export default eggs; diff --git a/common/script/src/content/eggs/index.js b/common/script/src/content/eggs/index.js new file mode 100644 index 0000000000..ece3a7692f --- /dev/null +++ b/common/script/src/content/eggs/index.js @@ -0,0 +1,32 @@ +import {merge} from '../helpers'; + +//-------------------------------------------------- +// Eggs are generated from an array of pet keys +// +// : { +// text: t(EggText), +// mountText: t(EggMountText), +// notes: t(EggText,{ +// eggText: this.text, +// eggAdjective: t(EggAdjective) +// }), +// canBuy: , +// value: 3, +// key: , +// } +// +// is the name of the pet associated with the egg +// is the type of egg (drop, quest, etc) passed in as part of an options object +// is a boolean passed in as part of an options object +//-------------------------------------------------- + +import dropEggs from './drops'; +import questEggs from './quest'; + +let allEggs = merge([dropEggs, questEggs]); + +export default { + allEggs: allEggs, + dropEggs: dropEggs, + questEggs: questEggs, +} diff --git a/common/script/src/content/eggs/quest.js b/common/script/src/content/eggs/quest.js new file mode 100644 index 0000000000..cd27ecd4d4 --- /dev/null +++ b/common/script/src/content/eggs/quest.js @@ -0,0 +1,65 @@ +import {generateEggs} from '../helpers'; + +const QUEST_EGGS = [ + 'Gryphon', + 'Hedgehog', + 'Deer', + 'Egg', + 'Rat', + 'Octopus', + 'Seahorse', + 'Parrot', + 'Rooster', + 'Spider', + 'Owl', + 'Penguin', + 'TRex', + 'Rock', + 'Bunny', + 'Slime', + 'Sheep', + 'Cuttlefish', + 'Whale', + 'Cheetah', + 'Horse', + 'Frog' +]; + +let eggDefaults = { + type: 'quest', + canBuy: (key) => { + return _generateQuestAchievementRequirement(key); + }, +}; + +let eggs = generateEggs(QUEST_EGGS, eggDefaults); + +// Exceptions to normal defaults +eggs.TRex.canBuy = (user) => { + let achievements = user.achievements.quests; + + if (achievements) { + return achievements.trex > 0 || + achievements.trex_undead > 0; + } +} + +eggs.Deer.canBuy = _generateQuestAchievementRequirement('ghost_stag'); +eggs.Seahorse.canBuy = _generateQuestAchievementRequirement('dilatory_derby'); +eggs.Parrot.canBuy = _generateQuestAchievementRequirement('harpy'); +eggs.Cuttlefish.canBuy = _generateQuestAchievementRequirement('kraken'); + +eggs.Egg.canBuy = () => { return false; } + +function _generateQuestAchievementRequirement(name) { + return (user) => { + let achievements = user.achievements.quests; + let questKey = name.toLowerCase(); + + if (achievements) { + return achievements[questKey] > 0; + } + }; +} + +export default eggs; diff --git a/common/script/src/content/faq.js b/common/script/src/content/faq.js new file mode 100644 index 0000000000..bbe5e97438 --- /dev/null +++ b/common/script/src/content/faq.js @@ -0,0 +1,24 @@ +import {translator as t} from './helpers'; + +const NUMBER_OF_QUESTIONS = 12; + +let faq = {}; + +faq.questions = []; + +for (var i = 0; i <= NUMBER_OF_QUESTIONS; i++) { + let question = { + question: t('faqQuestion' + i), + ios: t('iosFaqAnswer' + i), + web: t('webFaqAnswer' + i) + }; + + faq.questions.push(question); +} + +faq.stillNeedHelp = { + ios: t('iosFaqStillNeedHelp'), + web: t('webFaqStillNeedHelp') +}; + +export default faq; diff --git a/common/script/src/content/food/base.js b/common/script/src/content/food/base.js new file mode 100644 index 0000000000..27a84c22d2 --- /dev/null +++ b/common/script/src/content/food/base.js @@ -0,0 +1,54 @@ +import { + translator as t, + setFoodDefaults +} from '../helpers'; + +const CAN_BUY = true; +const CAN_DROP = true; + +let baseFood = { + Meat: { + target: 'Base', + article: '', + }, + Milk: { + target: 'White', + article: '', + }, + Potatoe: { + target: 'Desert', + article: 'a ', + }, + Strawberry: { + target: 'Red', + article: 'a ', + }, + Chocolate: { + target: 'Shade', + article: '', + }, + Fish: { + target: 'Skeleton', + article: 'a ', + }, + RottenMeat: { + target: 'Zombie', + article: '', + }, + CottonCandyPink: { + target: 'CottonCandyPink', + article: '', + }, + CottonCandyBlue: { + target: 'CottonCandyBlue', + article: '', + }, + Honey: { + target: 'Golden', + article: '', + }, +}; + +setFoodDefaults(baseFood, {canBuy: CAN_BUY, canDrop: CAN_DROP}); + +export default baseFood; diff --git a/common/script/src/content/food/birthday.js b/common/script/src/content/food/birthday.js new file mode 100644 index 0000000000..598373a860 --- /dev/null +++ b/common/script/src/content/food/birthday.js @@ -0,0 +1,54 @@ +import { + translator as t, + setFoodDefaults +} from '../helpers'; + +const CAN_BUY = false; +const CAN_DROP = false; + +let cake = { + Cake_Skeleton: { + target: 'Skeleton', + article: '', + }, + Cake_Base: { + target: 'Base', + article: '', + }, + Cake_CottonCandyBlue: { + target: 'CottonCandyBlue', + article: '', + }, + Cake_CottonCandyPink: { + target: 'CottonCandyPink', + article: '', + }, + Cake_Shade: { + target: 'Shade', + article: '', + }, + Cake_White: { + target: 'White', + article: '', + }, + Cake_Golden: { + target: 'Golden', + article: '', + }, + Cake_Zombie: { + target: 'Zombie', + article: '', + }, + Cake_Desert: { + target: 'Desert', + article: '', + }, + Cake_Red: { + target: 'Red', + article: '', + }, +}; + +setFoodDefaults(cake, {canBuy: CAN_BUY, canDrop: CAN_DROP}); + +export default cake; diff --git a/common/script/src/content/food/fall.js b/common/script/src/content/food/fall.js new file mode 100644 index 0000000000..385b7c2d34 --- /dev/null +++ b/common/script/src/content/food/fall.js @@ -0,0 +1,54 @@ +import { + translator as t, + setFoodDefaults +} from '../helpers'; + +const CAN_BUY = false; +const CAN_DROP = false; + +let candy = { + Candy_Skeleton: { + target: 'Skeleton', + article: '', + }, + Candy_Base: { + target: 'Base', + article: '', + }, + Candy_CottonCandyBlue: { + target: 'CottonCandyBlue', + article: '', + }, + Candy_CottonCandyPink: { + target: 'CottonCandyPink', + article: '', + }, + Candy_Shade: { + target: 'Shade', + article: '', + }, + Candy_White: { + target: 'White', + article: '', + }, + Candy_Golden: { + target: 'Golden', + article: '', + }, + Candy_Zombie: { + target: 'Zombie', + article: '', + }, + Candy_Desert: { + target: 'Desert', + article: '', + }, + Candy_Red: { + target: 'Red', + article: '', + } +}; + +setFoodDefaults(candy, {canBuy: CAN_BUY, canDrop: CAN_DROP}); + +export default candy; diff --git a/common/script/src/content/food/index.js b/common/script/src/content/food/index.js new file mode 100644 index 0000000000..5186831761 --- /dev/null +++ b/common/script/src/content/food/index.js @@ -0,0 +1,37 @@ +import {each, defaults} from 'lodash'; +import { + translator as t, + merge +} from '../helpers'; + +//-------------------------------------------------- +// Food are series objects that have defaults applied if not provided +// +// : { +// key: , +// text: t(food), +// notes: t(foodNotes), +// article:
, +// target: , +// value: , +// canBuy: , +// canDrop: , +// } +// +// is the name of the food +// is a screeaming camelCase version of the key +//
is whether the food requires an indefinite article ('a', 'an', '') +// is the potion key that this food targets +// is the price of the food - defaults to 1 +// is a boolean passed in as part of an options object +// is a boolean passed in as part of an options object +//-------------------------------------------------- + +import baseFood from './base'; +import saddle from './saddle'; +import cake from './birthday'; +import candy from './fall'; + +let allFood = merge([baseFood, saddle, cake, candy]); + +export default allFood; diff --git a/common/script/src/content/food/saddle.js b/common/script/src/content/food/saddle.js new file mode 100644 index 0000000000..9be1da34e2 --- /dev/null +++ b/common/script/src/content/food/saddle.js @@ -0,0 +1,19 @@ +import { + translator as t, + setFoodDefaults +} from '../helpers'; + +const CAN_BUY = true; +const CAN_DROP = false; + +let saddle = { + Saddle: { + value: 5, + text: t('foodSaddleText'), + notes: t('foodSaddleNotes'), + }, +}; + +setFoodDefaults(saddle, {canBuy: CAN_BUY, canDrop: CAN_DROP}); + +export default saddle; diff --git a/common/script/src/content/hatching-potions.js b/common/script/src/content/hatching-potions.js new file mode 100644 index 0000000000..feab00328e --- /dev/null +++ b/common/script/src/content/hatching-potions.js @@ -0,0 +1,59 @@ +import { + merge, + translator as t, + setHatchingPotionDefaults +} from './helpers'; + +let dropPotions = { + Base: { + value: 2, + }, + White: { + value: 2, + }, + Desert: { + value: 2, + }, + Red: { + value: 3, + }, + Shade: { + value: 3, + }, + Skeleton: { + value: 3, + }, + Zombie: { + value: 4, + }, + CottonCandyPink: { + value: 4, + }, + CottonCandyBlue: { + value: 4, + }, + Golden: { + value: 5, + }, +}; + +let premiumPotions = { + Spooky: { + value: 2, + addlNotes: t('premiumPotionAddlNotes'), + premium: true, + limited: true, + canBuy: () => { return false }, + }, +}; + +setHatchingPotionDefaults(dropPotions); +setHatchingPotionDefaults(premiumPotions); + +let allPotions = merge([dropPotions, premiumPotions]); + +export default { + all: allPotions, + drop: dropPotions, + premium: premiumPotions, +}; diff --git a/common/script/src/content/health-potion.js b/common/script/src/content/health-potion.js new file mode 100644 index 0000000000..b248453b2c --- /dev/null +++ b/common/script/src/content/health-potion.js @@ -0,0 +1,11 @@ +import {translator as t} from './helpers'; + +let potion = { + type: 'potion', + text: t('potionText'), + notes: t('potionNotes'), + value: 25, + key: 'potion', +}; + +export default potion; diff --git a/common/script/src/content/helpers.js b/common/script/src/content/helpers.js new file mode 100644 index 0000000000..ca9f0bf074 --- /dev/null +++ b/common/script/src/content/helpers.js @@ -0,0 +1,230 @@ +import { each, defaults, assign, capitalize, camelCase } from 'lodash'; + +import i18n from '../i18n'; + +//---------------------------------------- +// Translator Helpers +//---------------------------------------- +export function translator(string, vars={a: 'a'}) { + let func = (lang) => { + return i18n.t(string, vars, lang); + }; + + func.i18nLangFunc = true; // Trick to recognize this type of function + + return func; +}; + +export function formatForTranslator(name) { + let camelCasedName = camelCase(name); + let capitalCamelCasedName = capitalize(camelCasedName); + + return capitalCamelCasedName; +}; + +//---------------------------------------- +// Object Merger +//---------------------------------------- + +export function merge(array=[]) { + let mergedObject = {}; + + each(array, (item) => { + assign(mergedObject, item); + }); + + return mergedObject; +}; + +//---------------------------------------- +// Set Defaults Helpers +//---------------------------------------- + +export function setSpellDefaults (className, spells) { + let capitalClassName = formatForTranslator(className); + + each(spells, (spell, key) => { + let capitalSpellKey = formatForTranslator(key); + let spellDefaults = { + text: translator(`spell${capitalClassName}${capitalSpellKey}Text`), + notes: translator(`spell${capitalClassName}${capitalSpellKey}Notes`), + }; + + defaults(spell, spellDefaults); + }); +}; + +export function setFoodDefaults(food, options={}) { + each(food, (item, name) => { + let formattedName = formatForTranslator(name); + let canBuy = () => { return options.canBuy; }; + + defaults(item, { + key: name, + text: translator(`food${formattedName}`), + notes: translator('foodNotes'), + value: 1, + canBuy: canBuy, + canDrop: options.canDrop || false, + }); + }); +}; + +export function setHatchingPotionDefaults(hatchingPotions) { + each(hatchingPotions, (potion, key) => { + let text = translator(`hatchingPotion${key}`); + defaults(potion, { + key: key, + value: 2, + text: text, + canBuy: () => { return true }, + notes: translator('hatchingPotionNotes', { + potText: text + }), + }); + }); +}; + +export function setQuestDefaults(quests) { + each(quests, function(quest, key) { + let formattedName = formatForTranslator(key); + + let questDefaults = { + key: key, + text: translator(`quest${formattedName}Text`), + notes: translator(`quest${formattedName}Notes`), + canBuy: () => { return true; }, + value: 4, + }; + + let questBossDefaults = { + name: translator(`quest${formattedName}Boss`), + str: 1, + def: 1, + }; + + let questBossRageDefaults = { + title: translator('bossRageTitle'), + description: translator('bossRageDescription'), + }; + + defaults(quest, questDefaults); + + let boss = quest.boss; + + if (boss) { + defaults(boss, questBossDefaults); + + if (boss.rage) { + defaults(boss.rage, questBossRageDefaults); + } + } + }); +}; + +export function setQuestSetDefaults(quests, mainDefaultsFunction, dropDefaultsFunction) { + each(quests, (quest, name) => { + let formattedName = formatForTranslator(name); + let mainDefaults = mainDefaultsFunction(formattedName); + + defaults(quest, mainDefaults); + + if (quest.drop && dropDefaultsFunction) { + let dropDefaults = dropDefaultsFunction(formattedName); + defaults(quest.drop, dropDefaults); + } + }); +}; + +export function setGearSetDefaults(gearSet, options={}) { + let setName = formatForTranslator(options.setName); + + each(gearSet, (gear, gearType) => { + each(gear, (item, key) => { + let formattedName = formatForTranslator(key); + + let text = `${gearType}${setName}${formattedName}Text`; + let notes = `${gearType}${setName}${formattedName}Notes`; + let attributes = _getGearAttributes(item); + let gearDefaults = { + text: translator(text), + notes: translator(notes, attributes), + canBuy: () => { return false; }, + } + + defaults(item, gearDefaults); + }); + }); +}; + +//---------------------------------------- +// Generators +//---------------------------------------- + +export function generateBackgrounds(sets) { + each(sets, (names, set) => { + sets[set] = {}; + + each(names, (name) => { + let formattedName = formatForTranslator(name); + + sets[set][name] = { + text: translator(`background${formattedName}Text`), + notes: translator(`background${formattedName}Notes`), + }; + }); + }); +}; + +export function generateEggs(set, options={}) { + let eggs = {}; + let type = options.type; + + each(set, (pet) => { + let text = translator(`${type}Egg${pet}Text`); + let adj = translator(`${type}Egg${pet}Adjective`); + let canBuy = options.canBuy(pet); + + eggs[pet] = { + text: text, + mountText: translator(`${type}Egg${pet}MountText`), + adjective: adj, + canBuy: canBuy, + value: 3, + key: pet, + notes: translator('eggNotes', { + eggText: text, + eggAdjective: adj, + }), + } + }); + + return eggs; +}; + +//---------------------------------------- +// Spell Helpers +//---------------------------------------- + +export function diminishingReturns(bonus, max, halfway=max/2) { + return max * (bonus / (bonus + halfway)); +}; + +export function calculateBonus(value, stat, crit=1, stat_scale=0.5) { + return (value < 0 ? 1 : value + 1) + (stat * stat_scale * crit); +}; + +//---------------------------------------- +// Gear Helpers +//---------------------------------------- + +function _getGearAttributes(gear) { + let attr = {}; + + if (gear.str) { attr.str = gear.str }; + if (gear.con) { attr.con = gear.con }; + if (gear.int) { attr.int = gear.int }; + if (gear.per) { attr.per = gear.per }; + + return attr; +} diff --git a/common/script/src/content/index.js b/common/script/src/content/index.js new file mode 100644 index 0000000000..ac233338f2 --- /dev/null +++ b/common/script/src/content/index.js @@ -0,0 +1,110 @@ +import classes from './classes'; +import mysterySets from './mystery-sets'; +import itemList from './item-list'; +import { + tree as gearTree, + flat as gearFlat, + gearTypes, +} from './gear/index'; +import timeTravelerStore from './time-traveler-store'; +import potion from './health-potion'; +import armoire from './armoire'; +import spells from './spells/index'; +import {special} from './spells/index'; +import cardTypes from './card-types'; +import { + dropEggs, + questEggs, + allEggs, +} from './eggs/index'; +import { + dropPets, + premiumPets, + questPets, + dropMounts, + premiumMounts, + questMounts, + specialPets, + specialMounts, +} from './pets-mounts/index'; +import timeTravelStable from './time-traveler-stable'; +import { + all as allHatchingPotions, + drop as dropHatchingPotions, + premium as premiumHatchingPotions, +} from './hatching-potions'; +import food from './food/index'; +import { + all as allQuests, + canOwnCategories as userCanOwnQuestCategories, + byLevel as questsByLevel +} from './quests/index'; +import backgrounds from './backgrounds'; +import subscriptionBlocks from './subscription-blocks'; +import userDefaults from './user-defaults'; +import faq from './faq'; + +export default { + // Constants + classes: classes, + gearTypes: gearTypes, + mystery: mysterySets, + itemList: itemList, + userCanOwnQuestCategories: userCanOwnQuestCategories, + + // Gear + gear: { + tree: gearTree, + flat: gearFlat + }, + + // Time Traveler Store + timeTravelerStore: timeTravelerStore, + timeTravelStable: timeTravelStable, + + // Non-Gear Static Rewards + potion: potion, + armoire: armoire, + + // Spells + spells: spells, + cardTypes: cardTypes, + special: special, + + // Item Drops + dropHatchingPotions: dropHatchingPotions, + premiumHatchingPotions: premiumHatchingPotions, + hatchingPotions: allHatchingPotions, + food: food, + + // Eggs + dropEggs: dropEggs, + questEggs: questEggs, + eggs: allEggs, + + // Pets And Mounts + pets: dropPets, + premiumPets: premiumPets, + questPets: questPets, + mounts: dropMounts, + premiumMounts: premiumMounts, + questMounts: questMounts, + specialPets: specialPets, + specialMounts: specialMounts, + + // Quests + quests: allQuests, + questsByLevel: questsByLevel, + + // Backgrounds + backgrounds: backgrounds, + + // Subscription Blocks + subscriptionBlocks: subscriptionBlocks, + + // Default User Tasks + userDefaults: userDefaults, + + // Frequently Asked Questions + faq: faq, +}; diff --git a/common/script/src/content/pets-mounts/index.js b/common/script/src/content/pets-mounts/index.js new file mode 100644 index 0000000000..c522181ec9 --- /dev/null +++ b/common/script/src/content/pets-mounts/index.js @@ -0,0 +1,53 @@ +import {transform, defaults} from 'lodash'; + +//-------------------------------------------------- +// Pets and Mounts are generated by eggs * potions +// +// { -: true } +// +// - the key of the egg the animal hatched from +// - the potion that hatched the animal +// +//-------------------------------------------------- +// Special Pets and Mounts +// { -: } +// +// - could be existing animal or a totally new animal +// - if a unique animal, potion is Base, if it's a special version of an existing animal, the fake potion is a different from a normal hatching potion +//-------------------------------------------------- + +import { + drop as dropHatchingPotions, + premium as premiumHatchingPotions, +} from '../hatching-potions'; +import dropEggs from '../eggs/drops'; +import questEggs from '../eggs/quest'; + +import specialPets from './special-pets'; +import specialMounts from './special-mounts'; + +let dropPets = generateAnimalSet(dropEggs, dropHatchingPotions); +let premiumPets = generateAnimalSet(dropEggs, premiumHatchingPotions); +let questPets = generateAnimalSet(questEggs, dropHatchingPotions); +let dropMounts = generateAnimalSet(dropEggs, dropHatchingPotions); +let premiumMounts = generateAnimalSet(dropEggs, premiumHatchingPotions); +let questMounts = generateAnimalSet(questEggs, dropHatchingPotions); + +function generateAnimalSet(eggSet, potionSet) { + return transform(eggSet, (m, egg) => { + defaults(m, transform(potionSet, (m2, pot) => { + return m2[egg.key + "-" + pot.key] = true; + })); + }); +} + +export default { + dropPets: dropPets, + dropMounts: dropMounts, + premiumPets: premiumPets, + premiumMounts: premiumMounts, + questPets: questPets, + questMounts: questMounts, + specialPets: specialPets, + specialMounts: specialMounts, +} diff --git a/common/script/src/content/pets-mounts/special-mounts.js b/common/script/src/content/pets-mounts/special-mounts.js new file mode 100644 index 0000000000..6b0d2c9005 --- /dev/null +++ b/common/script/src/content/pets-mounts/special-mounts.js @@ -0,0 +1,13 @@ +let specialMounts = { + 'BearCub-Polar': 'polarBear', + 'LionCub-Ethereal': 'etherealLion', + 'MantisShrimp-Base': 'mantisShrimp', + 'Turkey-Base': 'turkey', + 'Mammoth-Base': 'mammoth', + 'Orca-Base': 'orca', + 'Gryphon-RoyalPurple': 'royalPurpleGryphon', + 'Phoenix-Base': 'phoenix', + 'JackOLantern-Base': 'jackolantern' +} + +export default specialMounts; diff --git a/common/script/src/content/pets-mounts/special-pets.js b/common/script/src/content/pets-mounts/special-pets.js new file mode 100644 index 0000000000..5566830a2d --- /dev/null +++ b/common/script/src/content/pets-mounts/special-pets.js @@ -0,0 +1,14 @@ +let specialPets = { + 'Wolf-Veteran': 'veteranWolf', + 'Wolf-Cerberus': 'cerberusPup', + 'Dragon-Hydra': 'hydra', + 'Turkey-Base': 'turkey', + 'BearCub-Polar': 'polarBearPup', + 'MantisShrimp-Base': 'mantisShrimp', + 'JackOLantern-Base': 'jackolantern', + 'Mammoth-Base': 'mammoth', + 'Tiger-Veteran': 'veteranTiger', + 'Phoenix-Base': 'phoenix' +} + +export default specialPets; diff --git a/common/script/src/content/quests/gold-purchasable.js b/common/script/src/content/quests/gold-purchasable.js new file mode 100644 index 0000000000..9b93e047a1 --- /dev/null +++ b/common/script/src/content/quests/gold-purchasable.js @@ -0,0 +1,116 @@ +import { + translator as t, + merge, + setQuestSetDefaults, +} from '../helpers'; + +let dilatoryDistressSeries = { + dilatoryDistress1: { + goldValue: 200, + collect: { + fireCoral: { + text: t('questDilatoryDistress1CollectFireCoral'), + count: 25 + }, + blueFins: { + text: t('questDilatoryDistress1CollectBlueFins'), + count: 25 + } + }, + drop: { + items: [ + { + type: 'gear', + key: 'armor_special_finnedOceanicArmor', + text: t('questDilatoryDistress1DropArmor') + } + ], + exp: 75 + } + }, + dilatoryDistress2: { + previous: 'dilatoryDistress1', + goldValue: 300, + boss: { + hp: 500, + rage: { + title: t('questDilatoryDistress2RageTitle'), + description: t('questDilatoryDistress2RageDescription'), + value: 50, + healing: .3, + effect: t('questDilatoryDistress2RageEffect') + } + }, + drop: { + items: [ + { + type: 'hatchingPotions', + key: 'Skeleton', + text: t('questDilatoryDistress2DropSkeletonPotion') + }, { + type: 'hatchingPotions', + key: 'CottonCandyBlue', + text: t('questDilatoryDistress2DropCottonCandyBluePotion') + }, { + type: 'gear', + key: 'head_special_fireCoralCirclet', + text: t('questDilatoryDistress2DropHeadgear') + } + ], + exp: 500 + } + }, + dilatoryDistress3: { + previous: 'dilatoryDistress2', + goldValue: 400, + boss: { + hp: 1000, + str: 2 + }, + drop: { + items: [ + { + type: 'food', + key: 'Fish', + text: t('questDilatoryDistress3DropFish') + }, { + type: 'food', + key: 'Fish', + text: t('questDilatoryDistress3DropFish') + }, { + type: 'food', + key: 'Fish', + text: t('questDilatoryDistress3DropFish') + }, { + type: 'gear', + key: 'weapon_special_tridentOfCrashingTides', + text: t('questDilatoryDistress3DropWeapon') + }, { + type: 'gear', + key: 'shield_special_moonpearlShield', + text: t('questDilatoryDistress3DropShield') + } + ], + exp: 650 + }, + }, +}; + +let goldPurchasableQuests = merge([dilatoryDistressSeries]); + +let questDefaults = (name) => { + return { + completion: t(`quest${name}Completion`), + category: 'gold', + } +}; + +let dropDefaults = () => { + return { + gp: 0, + } +}; + +setQuestSetDefaults(goldPurchasableQuests, questDefaults, dropDefaults); + +export default goldPurchasableQuests; diff --git a/common/script/src/content/quests/holiday.js b/common/script/src/content/quests/holiday.js new file mode 100644 index 0000000000..f21d309df9 --- /dev/null +++ b/common/script/src/content/quests/holiday.js @@ -0,0 +1,126 @@ +import {each, defaults} from 'lodash'; +import { + translator as t, + setQuestSetDefaults, +} from '../helpers'; + +let holidayQuests = { + evilsanta: { + text: t('questEvilSantaText'), + notes: t('questEvilSantaNotes'), + completion: t('questEvilSantaCompletion'), + boss: { + name: t('questEvilSantaBoss'), + hp: 300, + str: 1 + }, + drop: { + items: [ + { + type: 'mounts', + key: 'BearCub-Polar', + text: t('questEvilSantaDropBearCubPolarMount') + } + ], + gp: 20, + exp: 100 + } + }, + evilsanta2: { + text: t('questEvilSanta2Text'), + notes: t('questEvilSanta2Notes'), + completion: t('questEvilSanta2Completion'), + collect: { + tracks: { + text: t('questEvilSanta2CollectTracks'), + count: 20 + }, + branches: { + text: t('questEvilSanta2CollectBranches'), + count: 10 + } + }, + drop: { + items: [ + { + type: 'pets', + key: 'BearCub-Polar', + text: t('questEvilSanta2DropBearCubPolarPet') + } + ], + gp: 20, + exp: 100 + } + }, + egg: { + text: t('questEggHuntText'), + notes: t('questEggHuntNotes'), + completion: t('questEggHuntCompletion'), + value: 1, + collect: { + plainEgg: { + text: t('questEggHuntCollectPlainEgg'), + count: 100 + } + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + }, { + type: 'eggs', + key: 'Egg', + text: t('questEggHuntDropPlainEgg') + } + ], + gp: 0, + exp: 0 + } + }, +}; + +let questDefaults = (name) => { + return { + completion: t(`quest${name}Completion`), + canBuy: () => { return false; }, + category: 'pet', + } +}; + +setQuestSetDefaults(holidayQuests, questDefaults); + +export default holidayQuests; diff --git a/common/script/src/content/quests/index.js b/common/script/src/content/quests/index.js new file mode 100644 index 0000000000..1e1a7bf4cf --- /dev/null +++ b/common/script/src/content/quests/index.js @@ -0,0 +1,75 @@ +import {sortBy} from 'lodash'; +import { + merge, + setQuestDefaults, +} from '../helpers'; + +//-------------------------------------------------- +// Quests are series objects that have defaults applied if not provided +// +// : { +// key: , +// text: t(questtext), +// notes: t(questnotes), +// canBuy: , +// value: , +// boss: +// drop: +// } +// +// is the name of the quest +// is a screeaming camelCase version of the key +// is a boolean passed in as part of an options object +// is the price of the quest in gems - defaults to 4 +// only applies to boss quests. An object in this form: { +// name: t(questBoss), +// str: , +// def: , +// rage: , +// } +// only applies to boss quests with rage. An object in this form: { +// title: t('bossRageTitle'), +// description: t('bossRageDescription') +// } +// only applies if quest has drops. An object in this form: { +// items: , +// gp: , +// exp: , +// unlock: t(questUnlockText), +// } +// an array of objects representing the items that will be dropped +// the amount of gp awarded for completing the quest +// the amount of exp awareded for completing the quest +//-------------------------------------------------- + +import worldQuests from './world'; +import holidayQuests from './holiday'; +import petQuests from './pet'; +import unlockableQuests from './unlockable'; +import goldPurchasableQuests from './gold-purchasable'; + +let allQuests = merge([ + worldQuests, + holidayQuests, + petQuests, + unlockableQuests, + goldPurchasableQuests +]); + +setQuestDefaults(allQuests); + +let questsByLevel = sortBy(allQuests, (quest) => { + return quest.lvl || 0; +}); + +let canOwnCategories = [ + 'unlockable', + 'gold', + 'pet', +]; + +export default { + all: allQuests, + byLevel: questsByLevel, + canOwnCategories: canOwnCategories, +}; diff --git a/common/script/src/content/quests/pet.js b/common/script/src/content/quests/pet.js new file mode 100644 index 0000000000..6ae4f7f8a5 --- /dev/null +++ b/common/script/src/content/quests/pet.js @@ -0,0 +1,367 @@ +import { + translator as t, + setQuestSetDefaults, +} from '../helpers'; + +let petQuests = { + gryphon: { + boss: { + hp: 300, + str: 1.5, + }, + drop: { + gp: 25, + exp: 125, + } + }, + hedgehog: { + boss: { + hp: 400, + str: 1.25 + }, + drop: { + gp: 30, + exp: 125, + } + }, + ghost_stag: { + boss: { + hp: 1200, + str: 2.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Deer', + text: t('questGhostStagDropDeerEgg') + }, { + type: 'eggs', + key: 'Deer', + text: t('questGhostStagDropDeerEgg') + }, { + type: 'eggs', + key: 'Deer', + text: t('questGhostStagDropDeerEgg') + } + ], + gp: 80, + exp: 800, + } + }, + rat: { + boss: { + hp: 1200, + str: 2.5 + }, + drop: { + gp: 80, + exp: 800, + } + }, + octopus: { + boss: { + hp: 1200, + str: 2.5 + }, + drop: { + gp: 80, + exp: 800, + } + }, + dilatory_derby: { + text: t('questSeahorseText'), + notes: t('questSeahorseNotes'), + completion: t('questSeahorseCompletion'), + boss: { + name: t('questSeahorseBoss'), + hp: 300, + str: 1.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Seahorse', + text: t('questSeahorseDropSeahorseEgg') + }, { + type: 'eggs', + key: 'Seahorse', + text: t('questSeahorseDropSeahorseEgg') + }, { + type: 'eggs', + key: 'Seahorse', + text: t('questSeahorseDropSeahorseEgg') + } + ], + gp: 25, + exp: 125, + unlock: t('questSeahorseUnlockText') + } + }, + harpy: { + boss: { + hp: 600, + str: 1.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Parrot', + text: t('questHarpyDropParrotEgg') + }, { + type: 'eggs', + key: 'Parrot', + text: t('questHarpyDropParrotEgg') + }, { + type: 'eggs', + key: 'Parrot', + text: t('questHarpyDropParrotEgg') + } + ], + gp: 43, + exp: 350, + } + }, + rooster: { + boss: { + hp: 300, + str: 1.5 + }, + drop: { + gp: 25, + exp: 125, + } + }, + spider: { + boss: { + hp: 400, + str: 1.5 + }, + drop: { + gp: 31, + exp: 200, + } + }, + owl: { + boss: { + hp: 500, + str: 1.5 + }, + drop: { + gp: 37, + exp: 275, + } + }, + penguin: { + boss: { + hp: 400, + str: 1.5 + }, + drop: { + gp: 31, + exp: 200, + } + }, + trex: { + text: t('questTRexText'), + notes: t('questTRexNotes'), + completion: t('questTRexCompletion'), + boss: { + name: t('questTRexBoss'), + hp: 800, + str: 2 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'TRex', + text: t('questTRexDropTRexEgg') + }, { + type: 'eggs', + key: 'TRex', + text: t('questTRexDropTRexEgg') + }, { + type: 'eggs', + key: 'TRex', + text: t('questTRexDropTRexEgg') + } + ], + gp: 55, + exp: 500, + unlock: t('questTRexUnlockText') + } + }, + trex_undead: { + text: t('questTRexUndeadText'), + notes: t('questTRexUndeadNotes'), + completion: t('questTRexUndeadCompletion'), + boss: { + name: t('questTRexUndeadBoss'), + hp: 500, + str: 2, + rage: { + title: t('questTRexUndeadRageTitle'), + description: t('questTRexUndeadRageDescription'), + value: 50, + healing: .3, + effect: t('questTRexUndeadRageEffect') + } + }, + drop: { + items: [ + { + type: 'eggs', + key: 'TRex', + text: t('questTRexDropTRexEgg') + }, { + type: 'eggs', + key: 'TRex', + text: t('questTRexDropTRexEgg') + }, { + type: 'eggs', + key: 'TRex', + text: t('questTRexDropTRexEgg') + } + ], + gp: 55, + exp: 500, + unlock: t('questTRexUnlockText') + } + }, + rock: { + boss: { + hp: 400, + str: 1.5 + }, + drop: { + gp: 31, + exp: 200, + } + }, + bunny: { + boss: { + hp: 300, + str: 1.5 + }, + drop: { + gp: 25, + exp: 125, + } + }, + slime: { + boss: { + hp: 400, + str: 1.5 + }, + drop: { + gp: 31, + exp: 200, + } + }, + sheep: { + boss: { + hp: 300, + str: 1.5 + }, + drop: { + gp: 25, + exp: 125, + } + }, + kraken: { + boss: { + hp: 800, + str: 2 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Cuttlefish', + text: t('questKrakenDropCuttlefishEgg') + }, { + type: 'eggs', + key: 'Cuttlefish', + text: t('questKrakenDropCuttlefishEgg') + }, { + type: 'eggs', + key: 'Cuttlefish', + text: t('questKrakenDropCuttlefishEgg') + } + ], + gp: 55, + exp: 500, + } + }, + whale: { + boss: { + hp: 500, + str: 1.5 + }, + drop: { + gp: 37, + exp: 275, + } + }, + cheetah: { + boss: { + hp: 600, + str: 1.5 + }, + drop: { + gp: 43, + exp: 350, + } + }, + horse: { + boss: { + hp: 500, + str: 1.5 + }, + drop: { + gp: 37, + exp: 275, + } + }, + frog: { + boss: { + hp: 300, + str: 1.5 + }, + drop: { + gp: 25, + exp: 125, + } + } +}; + +let questDefaults = (name) => { + return { + completion: t(`quest${name}Completion`), + category: 'pet', + } +}; + +let dropDefaults = (name) => { + let eggReward = { + type: 'eggs', + key: name, + text: t(`quest${name}Drop${name}Egg`) + }; + + return { + items: [ + eggReward, + eggReward, + eggReward + ], + unlock: t(`quest${name}UnlockText`), + }; +}; + +setQuestSetDefaults(petQuests, questDefaults, dropDefaults); + +export default petQuests; diff --git a/common/script/src/content/quests/unlockable.js b/common/script/src/content/quests/unlockable.js new file mode 100644 index 0000000000..cc4e106f15 --- /dev/null +++ b/common/script/src/content/quests/unlockable.js @@ -0,0 +1,362 @@ +import { + translator as t, + merge, + setQuestSetDefaults, +} from '../helpers'; + +let inviteFriends = { + basilist: { + unlockCondition: { + condition: 'party invite', + text: t('inviteFriends') + }, + boss: { + hp: 100, + str: 0.5 + }, + drop: { + gp: 8, + exp: 42 + } + }, +}; + +let viceSeries = { + vice1: { + lvl: 30, + boss: { + hp: 750, + str: 1.5 + }, + drop: { + items: [ + { + type: 'quests', + key: 'vice2', + text: t('questVice1DropVice2Quest') + } + ], + gp: 20, + exp: 100 + } + }, + vice2: { + lvl: 30, + previous: 'vice1', + collect: { + lightCrystal: { + text: t('questVice2CollectLightCrystal'), + count: 45 + } + }, + drop: { + items: [ + { + type: 'quests', + key: 'vice3', + text: t('questVice2DropVice3Quest') + } + ], + gp: 20, + exp: 75 + } + }, + vice3: { + completion: t('questVice3Completion'), + previous: 'vice2', + lvl: 30, + boss: { + hp: 1500, + str: 3 + }, + drop: { + items: [ + { + type: 'gear', + key: 'weapon_special_2', + text: t('questVice3DropWeaponSpecial2') + }, { + type: 'eggs', + key: 'Dragon', + text: t('questVice3DropDragonEgg') + }, { + type: 'eggs', + key: 'Dragon', + text: t('questVice3DropDragonEgg') + }, { + type: 'hatchingPotions', + key: 'Shade', + text: t('questVice3DropShadeHatchingPotion') + }, { + type: 'hatchingPotions', + key: 'Shade', + text: t('questVice3DropShadeHatchingPotion') + } + ], + gp: 100, + exp: 1000 + } + }, +}; + +let atomSeries = { + atom1: { + lvl: 15, + collect: { + soapBars: { + text: t('questAtom1CollectSoapBars'), + count: 20 + } + }, + drop: { + items: [ + { + type: 'quests', + key: 'atom2', + text: t('questAtom1Drop') + } + ], + gp: 7, + exp: 50 + } + }, + atom2: { + previous: 'atom1', + lvl: 15, + boss: { + hp: 300, + str: 1 + }, + drop: { + items: [ + { + type: 'quests', + key: 'atom3', + text: t('questAtom2Drop') + } + ], + gp: 20, + exp: 100 + } + }, + atom3: { + previous: 'atom2', + completion: t('questAtom3Completion'), + lvl: 15, + boss: { + hp: 800, + str: 1.5 + }, + drop: { + items: [ + { + type: 'gear', + key: 'head_special_2', + text: t('headSpecial2Text') + }, { + type: 'hatchingPotions', + key: 'Base', + text: t('questAtom3DropPotion') + }, { + type: 'hatchingPotions', + key: 'Base', + text: t('questAtom3DropPotion') + } + ], + gp: 25, + exp: 125 + } + }, +}; + +let moonstoneSeries = { + moonstone1: { + lvl: 60, + collect: { + moonstone: { + text: t('questMoonstone1CollectMoonstone'), + count: 500 + } + }, + drop: { + items: [ + { + type: 'quests', + key: 'moonstone2', + text: t('questMoonstone1DropMoonstone2Quest') + } + ], + gp: 50, + exp: 100 + } + }, + moonstone2: { + lvl: 60, + previous: 'moonstone1', + boss: { + hp: 1500, + str: 3 + }, + drop: { + items: [ + { + type: 'quests', + key: 'moonstone3', + text: t('questMoonstone2DropMoonstone3Quest') + } + ], + gp: 500, + exp: 1000 + } + }, + moonstone3: { + completion: t('questMoonstone3Completion'), + previous: 'moonstone2', + lvl: 60, + boss: { + hp: 2000, + str: 3.5 + }, + drop: { + items: [ + { + type: 'gear', + key: 'armor_special_2', + text: t('armorSpecial2Text') + }, { + type: 'food', + key: 'RottenMeat', + text: t('questMoonstone3DropRottenMeat') + }, { + type: 'food', + key: 'RottenMeat', + text: t('questMoonstone3DropRottenMeat') + }, { + type: 'food', + key: 'RottenMeat', + text: t('questMoonstone3DropRottenMeat') + }, { + type: 'food', + key: 'RottenMeat', + text: t('questMoonstone3DropRottenMeat') + }, { + type: 'food', + key: 'RottenMeat', + text: t('questMoonstone3DropRottenMeat') + }, { + type: 'hatchingPotions', + key: 'Zombie', + text: t('questMoonstone3DropZombiePotion') + }, { + type: 'hatchingPotions', + key: 'Zombie', + text: t('questMoonstone3DropZombiePotion') + }, { + type: 'hatchingPotions', + key: 'Zombie', + text: t('questMoonstone3DropZombiePotion') + } + ], + gp: 900, + exp: 1500 + } + }, +}; + +let goldenKnightSeries = { + goldenknight1: { + lvl: 40, + collect: { + testimony: { + text: t('questGoldenknight1CollectTestimony'), + count: 300 + } + }, + drop: { + items: [ + { + type: 'quests', + key: 'goldenknight2', + text: t('questGoldenknight1DropGoldenknight2Quest') + } + ], + gp: 15, + exp: 120 + } + }, + goldenknight2: { + previous: 'goldenknight1', + lvl: 40, + boss: { + hp: 1000, + str: 3 + }, + drop: { + items: [ + { + type: 'quests', + key: 'goldenknight3', + text: t('questGoldenknight2DropGoldenknight3Quest') + } + ], + gp: 75, + exp: 750 + } + }, + goldenknight3: { + completion: t('questGoldenknight3Completion'), + previous: 'goldenknight2', + lvl: 40, + boss: { + hp: 1700, + str: 3.5 + }, + drop: { + items: [ + { + type: 'food', + key: 'Honey', + text: t('questGoldenknight3DropHoney') + }, { + type: 'food', + key: 'Honey', + text: t('questGoldenknight3DropHoney') + }, { + type: 'food', + key: 'Honey', + text: t('questGoldenknight3DropHoney') + }, { + type: 'hatchingPotions', + key: 'Golden', + text: t('questGoldenknight3DropGoldenPotion') + }, { + type: 'hatchingPotions', + key: 'Golden', + text: t('questGoldenknight3DropGoldenPotion') + }, { + type: 'gear', + key: 'shield_special_goldenknight', + text: t('questGoldenknight3DropWeapon') + } + ], + gp: 900, + exp: 1500 + } + }, +}; + +let unlockableQuests = merge([ + inviteFriends, + atomSeries, + viceSeries, + moonstoneSeries, + goldenKnightSeries, +]); + +let questDefaults = () => { + return { category: 'unlockable' } +}; + +setQuestSetDefaults(unlockableQuests, questDefaults); + +export default unlockableQuests; diff --git a/common/script/src/content/quests/world.js b/common/script/src/content/quests/world.js new file mode 100644 index 0000000000..97e7cba466 --- /dev/null +++ b/common/script/src/content/quests/world.js @@ -0,0 +1,242 @@ +import { + translator as t, + setQuestSetDefaults, +} from '../helpers'; + +let worldQuests = { + dilatory: { + boss: { + name: t('questDilatoryBoss'), + hp: 5000000, + str: 1, + def: 1, + rage: { + title: t('questDilatoryBossRageTitle'), + description: t('questDilatoryBossRageDescription'), + value: 4000000, + tavern: t('questDilatoryBossRageTavern'), + stables: t('questDilatoryBossRageStables'), + market: t('questDilatoryBossRageMarket') + } + }, + drop: { + items: [ + { + type: 'pets', + key: 'MantisShrimp-Base', + text: t('questDilatoryDropMantisShrimpPet') + }, { + type: 'mounts', + key: 'MantisShrimp-Base', + text: t('questDilatoryDropMantisShrimpMount') + }, { + type: 'food', + key: 'Meat', + text: t('foodMeat') + }, { + type: 'food', + key: 'Milk', + text: t('foodMilk') + }, { + type: 'food', + key: 'Potatoe', + text: t('foodPotatoe') + }, { + type: 'food', + key: 'Strawberry', + text: t('foodStrawberry') + }, { + type: 'food', + key: 'Chocolate', + text: t('foodChocolate') + }, { + type: 'food', + key: 'Fish', + text: t('foodFish') + }, { + type: 'food', + key: 'RottenMeat', + text: t('foodRottenMeat') + }, { + type: 'food', + key: 'CottonCandyPink', + text: t('foodCottonCandyPink') + }, { + type: 'food', + key: 'CottonCandyBlue', + text: t('foodCottonCandyBlue') + }, { + type: 'food', + key: 'Honey', + text: t('foodHoney') + } + ], + gp: 0, + exp: 0 + } + }, + stressbeast: { + completionChat: t('questStressbeastCompletionChat'), + boss: { + name: t('questStressbeastBoss'), + hp: 2750000, + str: 1, + def: 1, + rage: { + title: t('questStressbeastBossRageTitle'), + description: t('questStressbeastBossRageDescription'), + value: 1450000, + healing: .3, + stables: t('questStressbeastBossRageStables'), + bailey: t('questStressbeastBossRageBailey'), + guide: t('questStressbeastBossRageGuide') + }, + desperation: { + threshold: 500000, + str: 3.5, + def: 2, + text: t('questStressbeastDesperation') + } + }, + drop: { + items: [ + { + type: 'pets', + key: 'Mammoth-Base', + text: t('questStressbeastDropMammothPet') + }, { + type: 'mounts', + key: 'Mammoth-Base', + text: t('questStressbeastDropMammothMount') + }, { + type: 'food', + key: 'Meat', + text: t('foodMeat') + }, { + type: 'food', + key: 'Milk', + text: t('foodMilk') + }, { + type: 'food', + key: 'Potatoe', + text: t('foodPotatoe') + }, { + type: 'food', + key: 'Strawberry', + text: t('foodStrawberry') + }, { + type: 'food', + key: 'Chocolate', + text: t('foodChocolate') + }, { + type: 'food', + key: 'Fish', + text: t('foodFish') + }, { + type: 'food', + key: 'RottenMeat', + text: t('foodRottenMeat') + }, { + type: 'food', + key: 'CottonCandyPink', + text: t('foodCottonCandyPink') + }, { + type: 'food', + key: 'CottonCandyBlue', + text: t('foodCottonCandyBlue') + }, { + type: 'food', + key: 'Honey', + text: t('foodHoney') + } + ], + gp: 0, + exp: 0 + } + }, + burnout: { + completionChat: t('questBurnoutCompletionChat'), + boss: { + name: t('questBurnoutBoss'), + hp: 11000000, + str: 2.5, + def: 1, + rage: { + title: t('questBurnoutBossRageTitle'), + description: t('questBurnoutBossRageDescription'), + value: 1000000, + quests: t('questBurnoutBossRageQuests'), + seasonalShop: t('questBurnoutBossRageSeasonalShop'), + tavern: t('questBurnoutBossRageTavern') + } + }, + drop: { + items: [ + { + type: 'pets', + key: 'Phoenix-Base', + text: t('questBurnoutDropPhoenixPet') + }, { + type: 'mounts', + key: 'Phoenix-Base', + text: t('questBurnoutDropPhoenixMount') + }, { + type: 'food', + key: 'Candy_Base', + text: t('foodCandyBase') + }, { + type: 'food', + key: 'Candy_White', + text: t('foodCandyWhite') + }, { + type: 'food', + key: 'Candy_Desert', + text: t('foodCandyDesert') + }, { + type: 'food', + key: 'Candy_Red', + text: t('foodCandyRed') + }, { + type: 'food', + key: 'Candy_Shade', + text: t('foodCandyShade') + }, { + type: 'food', + key: 'Candy_Skeleton', + text: t('foodCandySkeleton') + }, { + type: 'food', + key: 'Candy_Zombie', + text: t('foodCandyZombie') + }, { + type: 'food', + key: 'Candy_CottonCandyPink', + text: t('foodCandyCottonCandyPink') + }, { + type: 'food', + key: 'Candy_CottonCandyBlue', + text: t('foodCandyCottonCandyBlue') + }, { + type: 'food', + key: 'Candy_Golden', + text: t('foodCandyGolden') + } + ], + gp: 0, + exp: 0 + } + }, +}; + +let questDefaults = (name) => { + return { + completion: t(`quest${name}Completion`), + value: 0, + canBuy: () => { return false; }, + category: 'world', + } +}; + +setQuestSetDefaults(worldQuests, questDefaults); + +export default worldQuests; diff --git a/common/script/src/content/spells/healer.js b/common/script/src/content/spells/healer.js new file mode 100644 index 0000000000..5e603cb2dd --- /dev/null +++ b/common/script/src/content/spells/healer.js @@ -0,0 +1,78 @@ +import { + translator as t, + diminishingReturns, + calculateBonus, + setSpellDefaults +} from '../helpers'; + +import {each} from 'lodash'; + +let heal = { + mana: 15, + lvl: 11, + target: 'self', + cast: (user, target) => { + user.stats.hp += (user._statsComputed.con + user._statsComputed.int + 5) * .075; + if (user.stats.hp > 50) { + return user.stats.hp = 50; + } + } +}; + +let brightness = { + mana: 15, + lvl: 12, + target: 'self', + cast: (user, target) => { + return each(user.tasks, (target) => { + if (target.type === 'reward') { + return; + } + return target.value += 4 * (user._statsComputed.int / (user._statsComputed.int + 40)); + }); + } +}; + +let protectAura = { + mana: 30, + lvl: 13, + target: 'party', + cast: (user, target) => { + return each(target, (member) => { + var base, bonus; + bonus = user._statsComputed.con - user.stats.buffs.con; + if ((base = member.stats.buffs).con == null) { + base.con = 0; + } + return member.stats.buffs.con += Math.ceil(diminishingReturns(bonus, 200, 200)); + }); + } +}; + +let healAll = { + mana: 25, + lvl: 14, + text: t('spellHealerHealAllText'), + notes: t('spellHealerHealAllNotes'), + target: 'party', + cast: (user, target) => { + return each(target, (member) => { + member.stats.hp += (user._statsComputed.con + user._statsComputed.int + 5) * .04; + if (member.stats.hp > 50) { + return member.stats.hp = 50; + } + }); + } +}; + +let healer = { + heal: heal, + brightness: brightness, + protectAura: protectAura, + // @TODO APIv3 - correct to healAll + heallAll: healAll, +}; + +setSpellDefaults('healer', healer); + +export default healer; diff --git a/common/script/src/content/spells/index.js b/common/script/src/content/spells/index.js new file mode 100644 index 0000000000..e99fc03866 --- /dev/null +++ b/common/script/src/content/spells/index.js @@ -0,0 +1,51 @@ +import {each} from 'lodash'; + +import wizard from './wizard'; +import warrior from './warrior'; +import healer from './healer'; +import rogue from './rogue'; +import special from './special'; + +/* + --------------------------------------------------------------- + Spells + --------------------------------------------------------------- + Text, notes, and mana are obvious. The rest: + + * {target}: one of [task, self, party, user]. This is very important, because if the cast() function is expecting one + thing and receives another, it will cause errors. `self` is used for self buffs, multi-task debuffs, AOEs (eg, meteor-shower), + etc. Basically, use self for anything that's not [task, party, user] and is an instant-cast + + * {cast}: the function that's run to perform the ability's action. This is pretty slick - because this is exported to the + web, this function can be performed on the client and on the server. `user` param is self (needed for determining your + own stats for effectiveness of cast), and `target` param is one of [task, party, user]. In the case of `self` spells, + you act on `user` instead of `target`. You can trust these are the correct objects, as long as the `target` attr of the + spell is correct. Take a look at habitrpg/src/models/user.js and habitrpg/src/models/task.js for what attributes are + available on each model. Note `task.value` is its "redness". If party is passed in, it's an array of users, + so you'll want to iterate over them like: `_.each(target,function(member){...})` + + Note, user.stats.mp is docked after automatically (it's appended to functions automatically down below in an _.each) + */ + +var spells = { + wizard: wizard, + warrior: warrior, + rogue: rogue, + healer: healer, + special: special, +}; + +// Intercept all spells to reduce user.stats.mp after casting the spell +each(spells, (spellClass) => { + each(spellClass, (spell, key) => { + spell.key = key; + + let _cast = spell.cast; + spell.cast = (user, target) => { + _cast(user, target); + return user.stats.mp -= spell.mana; + }; + }); +}); + +export default spells; diff --git a/common/script/src/content/spells/rogue.js b/common/script/src/content/spells/rogue.js new file mode 100644 index 0000000000..a4157c43a7 --- /dev/null +++ b/common/script/src/content/spells/rogue.js @@ -0,0 +1,75 @@ +import { + translator as t, + diminishingReturns, + calculateBonus, + setSpellDefaults +} from '../helpers'; +import {each} from 'lodash'; + +let pickPocket = { + mana: 10, + lvl: 11, + target: 'task', + cast: (user, target) => { + var bonus; + bonus = calculateBonus(target.value, user._statsComputed.per); + return user.stats.gp += diminishingReturns(bonus, 25, 75); + } +}; + +let backStab = { + mana: 15, + lvl: 12, + target: 'task', + cast: (user, target) => { + var _crit, bonus, req; + _crit = user.fns.crit('str', .3); + bonus = calculateBonus(target.value, user._statsComputed.str, _crit); + user.stats.exp += diminishingReturns(bonus, 75, 50); + user.stats.gp += diminishingReturns(bonus, 18, 75); + req = { + language: user.preferences.language + }; + return user.fns.updateStats(user.stats, req); + } +}; + +let toolsOfTrade = { + mana: 25, + lvl: 13, + target: 'party', + cast: (user, target) => { + return each(target, (member) => { + var base, bonus; + bonus = user._statsComputed.per - user.stats.buffs.per; + if ((base = member.stats.buffs).per == null) { + base.per = 0; + } + return member.stats.buffs.per += Math.ceil(diminishingReturns(bonus, 100, 50)); + }); + } +}; + +let stealth = { + mana: 45, + lvl: 14, + target: 'self', + cast: (user, target) => { + var base; + if ((base = user.stats.buffs).stealth == null) { + base.stealth = 0; + } + return user.stats.buffs.stealth += Math.ceil(diminishingReturns(user._statsComputed.per, user.dailys.length * 0.64, 55)); + } +}; + +let rogue = { + pickPocket: pickPocket, + backStab: backStab, + toolsOfTrade: toolsOfTrade, + stealth: stealth, +}; + +setSpellDefaults('rogue', rogue); + +export default rogue; diff --git a/common/script/src/content/spells/special.js b/common/script/src/content/spells/special.js new file mode 100644 index 0000000000..023480cd61 --- /dev/null +++ b/common/script/src/content/spells/special.js @@ -0,0 +1,299 @@ +import { translator as t } from '../helpers'; +import {each} from 'lodash'; + +let snowball = { + text: t('spellSpecialSnowballAuraText'), + mana: 0, + value: 15, + target: 'user', + notes: t('spellSpecialSnowballAuraNotes'), + cast: (user, target) => { + var base; + resetVisualBuffs(target); + target.stats.buffs.snowball = true; + + if ((base = target.achievements).snowball == null) { + base.snowball = 0; + } + target.achievements.snowball++; + return user.items.special.snowball--; + } +}; + +let salt = { + text: t('spellSpecialSaltText'), + mana: 0, + value: 5, + immediateUse: true, + target: 'self', + notes: t('spellSpecialSaltNotes'), + cast: (user, target) => { + user.stats.buffs.snowball = false; + return user.stats.gp -= 5; + } +}; + +let spookDust = { + text: t('spellSpecialSpookDustText'), + mana: 0, + value: 15, + target: 'user', + notes: t('spellSpecialSpookDustNotes'), + cast: (user, target) => { + var base; + resetVisualBuffs(target); + target.stats.buffs.spookDust = true; + + if ((base = target.achievements).spookDust == null) { + base.spookDust = 0; + } + target.achievements.spookDust++; + return user.items.special.spookDust--; + } +}; + +let opaquePotion = { + text: t('spellSpecialOpaquePotionText'), + mana: 0, + value: 5, + immediateUse: true, + target: 'self', + notes: t('spellSpecialOpaquePotionNotes'), + cast: (user, target) => { + user.stats.buffs.spookDust = false; + return user.stats.gp -= 5; + } +}; + +let shinySeed = { + text: t('spellSpecialShinySeedText'), + mana: 0, + value: 15, + target: 'user', + notes: t('spellSpecialShinySeedNotes'), + cast: (user, target) => { + var base; + resetVisualBuffs(target); + + target.stats.buffs.shinySeed = true; + + if ((base = target.achievements).shinySeed == null) { + base.shinySeed = 0; + } + target.achievements.shinySeed++; + return user.items.special.shinySeed--; + } +}; + +let petalFreePotion = { + text: t('spellSpecialPetalFreePotionText'), + mana: 0, + value: 5, + immediateUse: true, + target: 'self', + notes: t('spellSpecialPetalFreePotionNotes'), + cast: (user, target) => { + user.stats.buffs.shinySeed = false; + return user.stats.gp -= 5; + } +}; + +let seafoam = { + text: t('spellSpecialSeafoamText'), + mana: 0, + value: 15, + target: 'user', + notes: t('spellSpecialSeafoamNotes'), + cast: (user, target) => { + var base; + resetVisualBuffs(target); + target.stats.buffs.seafoam = true; + + if ((base = target.achievements).seafoam == null) { + base.seafoam = 0; + } + target.achievements.seafoam++; + return user.items.special.seafoam--; + } +}; + +let sand = { + text: t('spellSpecialSandText'), + mana: 0, + value: 5, + immediateUse: true, + target: 'self', + notes: t('spellSpecialSandNotes'), + cast: (user, target) => { + user.stats.buffs.seafoam = false; + return user.stats.gp -= 5; + } +}; + +let nye = { + text: t('nyeCard'), + mana: 0, + value: 10, + immediateUse: true, + silent: true, + target: 'user', + notes: t('nyeCardNotes'), + cast: (user, target) => { + var base; + if (user === target) { + if ((base = user.achievements).nye == null) { + base.nye = 0; + } + user.achievements.nye++; + } else { + each([user, target], (t) => { + var base1; + if ((base1 = t.achievements).nye == null) { + base1.nye = 0; + } + return t.achievements.nye++; + }); + } + if (!target.items.special.nyeReceived) { + target.items.special.nyeReceived = []; + } + target.items.special.nyeReceived.push(user.profile.name); + target.flags.cardReceived = true; + if (typeof target.markModified === "function") { + target.markModified('items.special.nyeReceived'); + } + return user.stats.gp -= 10; + } +}; + +let valentine = { + text: t('valentineCard'), + mana: 0, + value: 10, + immediateUse: true, + silent: true, + target: 'user', + notes: t('valentineCardNotes'), + cast: (user, target) => { + var base; + if (user === target) { + if ((base = user.achievements).valentine == null) { + base.valentine = 0; + } + user.achievements.valentine++; + } else { + each([user, target], (t) => { + var base1; + if ((base1 = t.achievements).valentine == null) { + base1.valentine = 0; + } + return t.achievements.valentine++; + }); + } + if (!target.items.special.valentineReceived) { + target.items.special.valentineReceived = []; + } + target.items.special.valentineReceived.push(user.profile.name); + target.flags.cardReceived = true; + if (typeof target.markModified === "function") { + target.markModified('items.special.valentineReceived'); + } + return user.stats.gp -= 10; + } +}; + +let greeting = { + text: t('greetingCard'), + mana: 0, + value: 10, + immediateUse: true, + silent: true, + target: 'user', + notes: t('greetingCardNotes'), + cast: (user, target) => { + var base; + if (user === target) { + if ((base = user.achievements).greeting == null) { + base.greeting = 0; + } + user.achievements.greeting++; + } else { + each([user, target], (t) => { + var base1; + if ((base1 = t.achievements).greeting == null) { + base1.greeting = 0; + } + return t.achievements.greeting++; + }); + } + if (!target.items.special.greetingReceived) { + target.items.special.greetingReceived = []; + } + target.items.special.greetingReceived.push(user.profile.name); + target.flags.cardReceived = true; + if (typeof target.markModified === "function") { + target.markModified('items.special.greetingReceived'); + } + return user.stats.gp -= 10; + } +}; + +let thankyou = { + text: t('thankyouCard'), + mana: 0, + value: 10, + immediateUse: true, + silent: true, + target: 'user', + notes: t('thankyouCardNotes'), + cast: (user, target) => { + var base; + if (user === target) { + if ((base = user.achievements).thankyou == null) { + base.thankyou = 0; + } + user.achievements.thankyou++; + } else { + each([user, target], (t) => { + var base1; + if ((base1 = t.achievements).thankyou == null) { + base1.thankyou = 0; + } + return t.achievements.thankyou++; + }); + } + if (!target.items.special.thankyouReceived) { + target.items.special.thankyouReceived = []; + } + target.items.special.thankyouReceived.push(user.profile.name); + target.flags.cardReceived = true; + if (typeof target.markModified === "function") { + target.markModified('items.special.thankyouReceived'); + } + return user.stats.gp -= 10; + } +}; + +function resetVisualBuffs(target) { + target.stats.buffs.snowball = false; + target.stats.buffs.spookDust = false; + target.stats.buffs.shinySeed = false; + target.stats.buffs.seafoam = false; +} + +let special = { + snowball: snowball, + salt: salt, + spookDust: spookDust, + opaquePotion: opaquePotion, + shinySeed: shinySeed, + petalFreePotion: petalFreePotion, + seafoam: seafoam, + sand: sand, + nye: nye, + valentine: valentine, + greeting: greeting, + thankyou: thankyou, +}; + +export default special; diff --git a/common/script/src/content/spells/warrior.js b/common/script/src/content/spells/warrior.js new file mode 100644 index 0000000000..6271493089 --- /dev/null +++ b/common/script/src/content/spells/warrior.js @@ -0,0 +1,79 @@ +import { + translator as t, + diminishingReturns, + calculateBonus, + setSpellDefaults +} from '../helpers'; +import {each} from 'lodash'; + +let smash= { + mana: 10, + lvl: 11, + target: 'task', + cast: (user, target) => { + var base, bonus; + bonus = user._statsComputed.str * user.fns.crit('con'); + target.value += diminishingReturns(bonus, 2.5, 35); + if ((base = user.party.quest.progress).up == null) { + base.up = 0; + } + return user.party.quest.progress.up += diminishingReturns(bonus, 55, 70); + } +}; + +let defensiveStance = { + mana: 25, + lvl: 12, + target: 'self', + cast: (user, target) => { + var base, bonus; + bonus = user._statsComputed.con - user.stats.buffs.con; + if ((base = user.stats.buffs).con == null) { + base.con = 0; + } + return user.stats.buffs.con += Math.ceil(diminishingReturns(bonus, 40, 200)); + } +}; + +let valorousPresence = { + mana: 20, + lvl: 13, + target: 'party', + cast: (user, target) => { + return each(target, (member) => { + var base, bonus; + bonus = user._statsComputed.str - user.stats.buffs.str; + if ((base = member.stats.buffs).str == null) { + base.str = 0; + } + return member.stats.buffs.str += Math.ceil(diminishingReturns(bonus, 20, 200)); + }); + } +}; + +let intimidate = { + mana: 15, + lvl: 14, + target: 'party', + cast: (user, target) => { + return each(target, (member) => { + var base, bonus; + bonus = user._statsComputed.con - user.stats.buffs.con; + if ((base = member.stats.buffs).con == null) { + base.con = 0; + } + return member.stats.buffs.con += Math.ceil(diminishingReturns(bonus, 24, 200)); + }); + } +}; + +let warrior = { + smash: smash, + defensiveStance: defensiveStance, + valorousPresence: valorousPresence, + intimidate: intimidate, +}; + +setSpellDefaults('warrior', warrior); + +export default warrior; diff --git a/common/script/src/content/spells/wizard.js b/common/script/src/content/spells/wizard.js new file mode 100644 index 0000000000..7056633c22 --- /dev/null +++ b/common/script/src/content/spells/wizard.js @@ -0,0 +1,82 @@ +import { + translator as t, + diminishingReturns, + calculateBonus, + setSpellDefaults +} from '../helpers'; +import {each} from 'lodash'; + +let fireball = { + mana: 10, + lvl: 11, + target: 'task', + cast: (user, target) => { + let base; + + let bonus = user._statsComputed.int * user.fns.crit('per'); + bonus *= Math.ceil((target.value < 0 ? 1 : target.value + 1) * .075); + + user.stats.exp += diminishingReturns(bonus, 75); + + if ((base = user.party.quest.progress).up == null) { + base.up = 0; + } + user.party.quest.progress.up += Math.ceil(user._statsComputed.int * .1); + let req = { + language: user.preferences.language + }; + return user.fns.updateStats(user.stats, req); + } +}; + +let mpheal = { + text: t('spellWizardMPHealText'), + mana: 30, + lvl: 12, + target: 'party', + notes: t('spellWizardMPHealNotes'), + cast: (user, target) => { + return each(target, (member) => { + let bonus = user._statsComputed.int; + if (user._id !== member._id) { + return member.stats.mp += Math.ceil(diminishingReturns(bonus, 25, 125)); + } + }); + } +}; + +let earth = { + mana: 35, + lvl: 13, + target: 'party', + cast: (user, target) => { + return each(target, (member) => { + var base, bonus; + bonus = user._statsComputed.int - user.stats.buffs.int; + if ((base = member.stats.buffs).int == null) { + base.int = 0; + } + return member.stats.buffs.int += Math.ceil(diminishingReturns(bonus, 30, 200)); + }); + } +}; + +let frost = { + mana: 40, + lvl: 14, + target: 'self', + cast: (user, target) => { + return user.stats.buffs.streaks = true; + } +}; + +let wizard = { + fireball: fireball, + mpheal: mpheal, + earth: earth, + frost: frost, +}; + +setSpellDefaults('wizard', wizard); + +export default wizard; diff --git a/common/script/src/content/subscription-blocks.js b/common/script/src/content/subscription-blocks.js new file mode 100644 index 0000000000..f51ed45cc7 --- /dev/null +++ b/common/script/src/content/subscription-blocks.js @@ -0,0 +1,32 @@ +import {each} from 'lodash'; + +let subscriptionBlocks = { + basic_earned: { + months: 1, + price: 5 + }, + basic_3mo: { + months: 3, + price: 15 + }, + basic_6mo: { + months: 6, + price: 30 + }, + google_6mo: { + months: 6, + price: 24, + discount: true, + original: 30 + }, + basic_12mo: { + months: 12, + price: 48 + } +}; + +each(subscriptionBlocks, function(block, key) { + block.key = key; +}); + +export default subscriptionBlocks; diff --git a/common/script/src/content/time-traveler-stable.js b/common/script/src/content/time-traveler-stable.js new file mode 100644 index 0000000000..7f3178effa --- /dev/null +++ b/common/script/src/content/time-traveler-stable.js @@ -0,0 +1,14 @@ +import {translator as t} from './helpers'; + +let stable = { + pets: { + 'Mammoth-Base': t('mammoth'), + 'MantisShrimp-Base': t('mantisShrimp') + }, + mounts: { + 'Mammoth-Base': t('mammoth'), + 'MantisShrimp-Base': t('mantisShrimp') + } +}; + +export default stable; diff --git a/common/script/src/content/time-traveler-store.js b/common/script/src/content/time-traveler-store.js new file mode 100644 index 0000000000..a34e1d07bf --- /dev/null +++ b/common/script/src/content/time-traveler-store.js @@ -0,0 +1,15 @@ +import {keys, reduce} from 'lodash'; +import mystery from './mystery-sets'; + +function timeTravelerStore(owned) { + var ownedKeys = keys((typeof owned.toObject === "function" ? owned.toObject() : void 0) || owned); + return reduce(mystery, (m, v, k) => { + if (k === 'wondercon' || ~ownedKeys.indexOf(v.items[0].key)) { + return m; + } + m[k] = v; + return m; + }, {}); +}; + +export default timeTravelerStore; diff --git a/common/script/src/content/user-defaults.js b/common/script/src/content/user-defaults.js new file mode 100644 index 0000000000..b09bad06b9 --- /dev/null +++ b/common/script/src/content/user-defaults.js @@ -0,0 +1,62 @@ +import {translator as t} from './helpers'; + +let habits = [ + { + type: 'habit', + text: t('defaultHabit1Text'), + value: 0, + up: true, + down: false, + attribute: 'per', + }, { + type: 'habit', + text: t('defaultHabit2Text'), + value: 0, + up: false, + down: true, + attribute: 'str', + }, { + type: 'habit', + text: t('defaultHabit3Text'), + value: 0, + up: true, + down: true, + attribute: 'str', + } +]; + +let dailys = []; + +let todos = [ + { + type: 'todo', + text: t('defaultTodo1Text'), + notes: t('defaultTodoNotes'), + completed: false, + attribute: 'int', + } +]; + +let rewards = [ + { + type: 'reward', + text: t('defaultReward1Text'), + value: 10, + } +]; + +let tags = [ + { name: t('defaultTag1') }, + { name: t('defaultTag2') }, + { name: t('defaultTag3') }, +] + +let userDefaults = { + habits: habits, + dailys: dailys, + todos: todos, + rewards: rewards, + tags: tags +}; + +export default userDefaults; diff --git a/common/script/src/i18n.js b/common/script/src/i18n.js new file mode 100644 index 0000000000..3b91ede35b --- /dev/null +++ b/common/script/src/i18n.js @@ -0,0 +1,49 @@ +let _ = require('lodash'); + +module.exports = { + strings: null, + translations: {}, + t: function(stringName) { + var clonedVars, e, locale, string, stringNotFound, vars; + vars = arguments[1]; + if (_.isString(arguments[1])) { + vars = null; + locale = arguments[1]; + } else if (arguments[2] != null) { + vars = arguments[1]; + locale = arguments[2]; + } + if ((locale == null) || (!module.exports.strings && !module.exports.translations[locale])) { + locale = 'en'; + } + if (module.exports.strings) { + string = module.exports.strings[stringName]; + } else { + string = module.exports.translations[locale] && module.exports.translations[locale][stringName]; + } + clonedVars = _.clone(vars) || {}; + clonedVars.locale = locale; + if (string) { + try { + return _.template(string)(clonedVars); + } catch (_error) { + e = _error; + return 'Error processing the string. Please see Help > Report a Bug.'; + } + } else { + if (module.exports.strings) { + stringNotFound = module.exports.strings.stringNotFound; + } else if (module.exports.translations[locale]) { + stringNotFound = module.exports.translations[locale] && module.exports.translations[locale].stringNotFound; + } + try { + return _.template(stringNotFound)({ + string: stringName + }); + } catch (_error) { + e = _error; + return 'Error processing the string. Please see Help > Report a Bug.'; + } + } + } +};