diff --git a/common/dist/scripts/habitrpg-shared.js b/common/dist/scripts/habitrpg-shared.js index b7926b2ae0..149dc7df01 100644 --- a/common/dist/scripts/habitrpg-shared.js +++ b/common/dist/scripts/habitrpg-shared.js @@ -9,7144 +9,7 @@ if (typeof window !== 'undefined') { window.moment = moment; } -},{"./script/index.coffee":4,"lodash":6,"moment":7}],2:[function(require,module,exports){ -var api, classes, diminishingReturns, events, gear, gearTypes, i18n, moment, repeat, t, _; - -_ = require('lodash'); - -api = module.exports; - -moment = require('moment'); - -i18n = require('./i18n.coffee'); - -t = function(string, vars) { - var func; - func = function(lang) { - if (vars == null) { - vars = { - a: 'a' - }; - } - return i18n.t(string, vars, lang); - }; - func.i18nLangFunc = true; - return func; -}; - - -/* - --------------------------------------------------------------- - Gear (Weapons, Armor, Head, Shield) - Item definitions: {index, text, notes, value, str, def, int, per, classes, type} - --------------------------------------------------------------- - */ - -classes = ['warrior', 'rogue', 'healer', 'wizard']; - -gearTypes = ['weapon', 'armor', 'head', 'shield', 'body', 'back', 'headAccessory', 'eyewear']; - -events = { - winter: { - start: '2013-12-31', - end: '2014-02-01' - }, - birthday: { - start: '2013-01-30', - end: '2014-02-01' - }, - spring: { - start: '2014-03-21', - end: '2014-05-01' - }, - summer: { - start: '2014-06-20', - end: '2014-08-01' - }, - gaymerx: { - start: '2014-07-02', - end: '2014-08-01' - }, - fall: { - start: '2014-09-21', - end: '2014-11-01' - }, - winter2015: { - start: '2014-12-21', - end: '2015-02-02' - } -}; - -api.mystery = { - 201402: { - start: '2014-02-22', - end: '2014-02-28', - text: 'Winged Messenger Set' - }, - 201403: { - start: '2014-03-24', - end: '2014-04-02', - text: 'Forest Walker Set' - }, - 201404: { - start: '2014-04-24', - end: '2014-05-02', - text: 'Twilight Butterfly Set' - }, - 201405: { - start: '2014-05-21', - end: '2014-06-02', - text: 'Flame Wielder Set' - }, - 201406: { - start: '2014-06-23', - end: '2014-07-02', - text: 'Octomage Set' - }, - 201407: { - start: '2014-07-23', - end: '2014-08-02', - text: 'Undersea Explorer Set' - }, - 201408: { - start: '2014-08-23', - end: '2014-09-02', - text: 'Sun Sorcerer Set' - }, - 201409: { - start: '2014-09-24', - end: '2014-10-02', - text: 'Autumn Strider Item Set' - }, - 201410: { - start: '2014-10-24', - end: '2014-11-02', - text: 'Winged Goblin Set' - }, - 201411: { - start: '2014-11-24', - end: '2014-12-02', - text: 'Feast and Fun Set' - }, - 201412: { - start: '2014-12-25', - end: '2015-01-02', - text: 'Penguin Set' - }, - 201501: { - start: '2015-01-26', - end: '2015-02-02', - text: 'Starry Knight Set' - }, - 301404: { - start: '3014-03-24', - end: '3014-04-02', - text: 'Steampunk Standard Set' - }, - 301405: { - start: '3014-04-24', - end: '3014-05-02', - text: 'Steampunk Accessories Set' - }, - wondercon: { - start: '2014-03-24', - end: '2014-04-01' - } -}; - -_.each(api.mystery, function(v, k) { - return v.key = k; -}); - -gear = { - weapon: { - base: { - 0: { - text: t('weaponBase0Text'), - notes: t('weaponBase0Notes'), - value: 0 - } - }, - warrior: { - 0: { - text: t('weaponWarrior0Text'), - notes: t('weaponWarrior0Notes'), - value: 0 - }, - 1: { - text: t('weaponWarrior1Text'), - notes: t('weaponWarrior1Notes', { - str: 3 - }), - str: 3, - value: 20 - }, - 2: { - text: t('weaponWarrior2Text'), - notes: t('weaponWarrior2Notes', { - str: 6 - }), - str: 6, - value: 30 - }, - 3: { - text: t('weaponWarrior3Text'), - notes: t('weaponWarrior3Notes', { - str: 9 - }), - str: 9, - value: 45 - }, - 4: { - text: t('weaponWarrior4Text'), - notes: t('weaponWarrior4Notes', { - str: 12 - }), - str: 12, - value: 65 - }, - 5: { - text: t('weaponWarrior5Text'), - notes: t('weaponWarrior5Notes', { - str: 15 - }), - str: 15, - value: 90 - }, - 6: { - text: t('weaponWarrior6Text'), - notes: t('weaponWarrior6Notes', { - str: 18 - }), - str: 18, - value: 120, - last: true - } - }, - rogue: { - 0: { - text: t('weaponRogue0Text'), - notes: t('weaponRogue0Notes'), - str: 0, - value: 0 - }, - 1: { - text: t('weaponRogue1Text'), - notes: t('weaponRogue1Notes', { - str: 2 - }), - str: 2, - value: 20 - }, - 2: { - text: t('weaponRogue2Text'), - notes: t('weaponRogue2Notes', { - str: 3 - }), - str: 3, - value: 35 - }, - 3: { - text: t('weaponRogue3Text'), - notes: t('weaponRogue3Notes', { - str: 4 - }), - str: 4, - value: 50 - }, - 4: { - text: t('weaponRogue4Text'), - notes: t('weaponRogue4Notes', { - str: 6 - }), - str: 6, - value: 70 - }, - 5: { - text: t('weaponRogue5Text'), - notes: t('weaponRogue5Notes', { - str: 8 - }), - str: 8, - value: 90 - }, - 6: { - text: t('weaponRogue6Text'), - notes: t('weaponRogue6Notes', { - str: 10 - }), - str: 10, - value: 120, - last: true - } - }, - wizard: { - 0: { - twoHanded: true, - text: t('weaponWizard0Text'), - notes: t('weaponWizard0Notes'), - value: 0 - }, - 1: { - twoHanded: true, - text: t('weaponWizard1Text'), - notes: t('weaponWizard1Notes', { - int: 3, - per: 1 - }), - int: 3, - per: 1, - value: 30 - }, - 2: { - twoHanded: true, - text: t('weaponWizard2Text'), - notes: t('weaponWizard2Notes', { - int: 6, - per: 2 - }), - int: 6, - per: 2, - value: 50 - }, - 3: { - twoHanded: true, - text: t('weaponWizard3Text'), - notes: t('weaponWizard3Notes', { - int: 9, - per: 3 - }), - int: 9, - per: 3, - value: 80 - }, - 4: { - twoHanded: true, - text: t('weaponWizard4Text'), - notes: t('weaponWizard4Notes', { - int: 12, - per: 5 - }), - int: 12, - per: 5, - value: 120 - }, - 5: { - twoHanded: true, - text: t('weaponWizard5Text'), - notes: t('weaponWizard5Notes', { - int: 15, - per: 7 - }), - int: 15, - per: 7, - value: 160 - }, - 6: { - twoHanded: true, - text: t('weaponWizard6Text'), - notes: t('weaponWizard6Notes', { - int: 18, - per: 10 - }), - int: 18, - per: 10, - value: 200, - last: true - } - }, - healer: { - 0: { - text: t('weaponHealer0Text'), - notes: t('weaponHealer0Notes'), - value: 0 - }, - 1: { - text: t('weaponHealer1Text'), - notes: t('weaponHealer1Notes', { - int: 2 - }), - int: 2, - value: 20 - }, - 2: { - text: t('weaponHealer2Text'), - notes: t('weaponHealer2Notes', { - int: 3 - }), - int: 3, - value: 30 - }, - 3: { - text: t('weaponHealer3Text'), - notes: t('weaponHealer3Notes', { - int: 5 - }), - int: 5, - value: 45 - }, - 4: { - text: t('weaponHealer4Text'), - notes: t('weaponHealer4Notes', { - int: 7 - }), - int: 7, - value: 65 - }, - 5: { - text: t('weaponHealer5Text'), - notes: t('weaponHealer5Notes', { - int: 9 - }), - int: 9, - value: 90 - }, - 6: { - text: t('weaponHealer6Text'), - notes: t('weaponHealer6Notes', { - int: 11 - }), - int: 11, - value: 120, - last: true - } - }, - special: { - 0: { - text: t('weaponSpecial0Text'), - notes: t('weaponSpecial0Notes', { - str: 20 - }), - str: 20, - value: 150, - canOwn: (function(u) { - var _ref; - return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 70; - }) - }, - 1: { - text: t('weaponSpecial1Text'), - notes: t('weaponSpecial1Notes', { - attrs: 6 - }), - str: 6, - per: 6, - con: 6, - int: 6, - value: 170, - canOwn: (function(u) { - var _ref; - return +((_ref = u.contributor) != null ? _ref.level : void 0) >= 4; - }) - }, - 2: { - text: t('weaponSpecial2Text'), - notes: t('weaponSpecial2Notes', { - attrs: 25 - }), - str: 25, - per: 25, - value: 200, - canOwn: (function(u) { - var _ref; - return (+((_ref = u.backer) != null ? _ref.tier : void 0) >= 300) || (u.items.gear.owned.weapon_special_2 != null); - }) - }, - 3: { - text: t('weaponSpecial3Text'), - notes: t('weaponSpecial3Notes', { - attrs: 17 - }), - str: 17, - int: 17, - con: 17, - value: 200, - canOwn: (function(u) { - var _ref; - return (+((_ref = u.backer) != null ? _ref.tier : void 0) >= 300) || (u.items.gear.owned.weapon_special_3 != null); - }) - }, - critical: { - text: t('weaponSpecialCriticalText'), - notes: t('weaponSpecialCriticalNotes', { - attrs: 40 - }), - str: 40, - per: 40, - value: 200, - canOwn: (function(u) { - var _ref; - return !!((_ref = u.contributor) != null ? _ref.critical : void 0); - }) - }, - yeti: { - event: events.winter, - specialClass: 'warrior', - text: t('weaponSpecialYetiText'), - notes: t('weaponSpecialYetiNotes', { - str: 15 - }), - str: 15, - value: 90 - }, - ski: { - event: events.winter, - specialClass: 'rogue', - text: t('weaponSpecialSkiText'), - notes: t('weaponSpecialSkiNotes', { - str: 8 - }), - str: 8, - value: 90 - }, - candycane: { - event: events.winter, - specialClass: 'wizard', - twoHanded: true, - text: t('weaponSpecialCandycaneText'), - notes: t('weaponSpecialCandycaneNotes', { - int: 15, - per: 7 - }), - int: 15, - per: 7, - value: 160 - }, - snowflake: { - event: events.winter, - specialClass: 'healer', - text: t('weaponSpecialSnowflakeText'), - notes: t('weaponSpecialSnowflakeNotes', { - int: 9 - }), - int: 9, - value: 90 - }, - springRogue: { - event: events.spring, - specialClass: 'rogue', - text: t('weaponSpecialSpringRogueText'), - notes: t('weaponSpecialSpringRogueNotes', { - str: 8 - }), - value: 80, - str: 8 - }, - springWarrior: { - event: events.spring, - specialClass: 'warrior', - text: t('weaponSpecialSpringWarriorText'), - notes: t('weaponSpecialSpringWarriorNotes', { - str: 15 - }), - value: 90, - str: 15 - }, - springMage: { - event: events.spring, - specialClass: 'wizard', - twoHanded: true, - text: t('weaponSpecialSpringMageText'), - notes: t('weaponSpecialSpringMageNotes', { - int: 15, - per: 7 - }), - value: 160, - int: 15, - per: 7 - }, - springHealer: { - event: events.spring, - specialClass: 'healer', - text: t('weaponSpecialSpringHealerText'), - notes: t('weaponSpecialSpringHealerNotes', { - int: 9 - }), - value: 90, - int: 9 - }, - summerRogue: { - event: events.summer, - specialClass: 'rogue', - text: t('weaponSpecialSummerRogueText'), - notes: t('weaponSpecialSummerRogueNotes', { - str: 8 - }), - value: 80, - str: 8 - }, - summerWarrior: { - event: events.summer, - specialClass: 'warrior', - text: t('weaponSpecialSummerWarriorText'), - notes: t('weaponSpecialSummerWarriorNotes', { - str: 15 - }), - value: 90, - str: 15 - }, - summerMage: { - event: events.summer, - specialClass: 'wizard', - twoHanded: true, - text: t('weaponSpecialSummerMageText'), - notes: t('weaponSpecialSummerMageNotes', { - int: 15, - per: 7 - }), - value: 160, - int: 15, - per: 7 - }, - summerHealer: { - event: events.summer, - specialClass: 'healer', - text: t('weaponSpecialSummerHealerText'), - notes: t('weaponSpecialSummerHealerNotes', { - int: 9 - }), - value: 90, - int: 9 - }, - fallRogue: { - event: events.fall, - specialClass: 'rogue', - text: t('weaponSpecialFallRogueText'), - notes: t('weaponSpecialFallRogueNotes', { - str: 8 - }), - value: 80, - str: 8 - }, - fallWarrior: { - event: events.fall, - specialClass: 'warrior', - text: t('weaponSpecialFallWarriorText'), - notes: t('weaponSpecialFallWarriorNotes', { - str: 15 - }), - value: 90, - str: 15 - }, - fallMage: { - event: events.fall, - specialClass: 'wizard', - twoHanded: true, - text: t('weaponSpecialFallMageText'), - notes: t('weaponSpecialFallMageNotes', { - int: 15, - per: 7 - }), - value: 160, - int: 15, - per: 7 - }, - fallHealer: { - event: events.fall, - specialClass: 'healer', - text: t('weaponSpecialFallHealerText'), - notes: t('weaponSpecialFallHealerNotes', { - int: 9 - }), - value: 90, - int: 9 - }, - winter2015Rogue: { - event: events.winter2015, - specialClass: 'rogue', - text: t('weaponSpecialWinter2015RogueText'), - notes: t('weaponSpecialWinter2015RogueNotes', { - str: 8 - }), - value: 80, - str: 8 - }, - winter2015Warrior: { - event: events.winter2015, - specialClass: 'warrior', - text: t('weaponSpecialWinter2015WarriorText'), - notes: t('weaponSpecialWinter2015WarriorNotes', { - str: 15 - }), - value: 90, - str: 15 - }, - winter2015Mage: { - event: events.winter2015, - specialClass: 'wizard', - twoHanded: true, - text: t('weaponSpecialWinter2015MageText'), - notes: t('weaponSpecialWinter2015MageNotes', { - int: 15, - per: 7 - }), - value: 160, - int: 15, - per: 7 - }, - winter2015Healer: { - event: events.winter2015, - specialClass: 'healer', - text: t('weaponSpecialWinter2015HealerText'), - notes: t('weaponSpecialWinter2015HealerNotes', { - int: 9 - }), - value: 90, - int: 9 - } - }, - mystery: { - 201411: { - text: t('weaponMystery201411Text'), - notes: t('weaponMystery201411Notes'), - mystery: '201411', - value: 0 - }, - 301404: { - text: t('weaponMystery301404Text'), - notes: t('weaponMystery301404Notes'), - mystery: '301404', - value: 0 - } - } - }, - armor: { - base: { - 0: { - text: t('armorBase0Text'), - notes: t('armorBase0Notes'), - value: 0 - } - }, - warrior: { - 1: { - text: t('armorWarrior1Text'), - notes: t('armorWarrior1Notes', { - con: 3 - }), - con: 3, - value: 30 - }, - 2: { - text: t('armorWarrior2Text'), - notes: t('armorWarrior2Notes', { - con: 5 - }), - con: 5, - value: 45 - }, - 3: { - text: t('armorWarrior3Text'), - notes: t('armorWarrior3Notes', { - con: 7 - }), - con: 7, - value: 65 - }, - 4: { - text: t('armorWarrior4Text'), - notes: t('armorWarrior4Notes', { - con: 9 - }), - con: 9, - value: 90 - }, - 5: { - text: t('armorWarrior5Text'), - notes: t('armorWarrior5Notes', { - con: 11 - }), - con: 11, - value: 120, - last: true - } - }, - rogue: { - 1: { - text: t('armorRogue1Text'), - notes: t('armorRogue1Notes', { - per: 6 - }), - per: 6, - value: 30 - }, - 2: { - text: t('armorRogue2Text'), - notes: t('armorRogue2Notes', { - per: 9 - }), - per: 9, - value: 45 - }, - 3: { - text: t('armorRogue3Text'), - notes: t('armorRogue3Notes', { - per: 12 - }), - per: 12, - value: 65 - }, - 4: { - text: t('armorRogue4Text'), - notes: t('armorRogue4Notes', { - per: 15 - }), - per: 15, - value: 90 - }, - 5: { - text: t('armorRogue5Text'), - notes: t('armorRogue5Notes', { - per: 18 - }), - per: 18, - value: 120, - last: true - } - }, - wizard: { - 1: { - text: t('armorWizard1Text'), - notes: t('armorWizard1Notes', { - int: 2 - }), - int: 2, - value: 30 - }, - 2: { - text: t('armorWizard2Text'), - notes: t('armorWizard2Notes', { - int: 4 - }), - int: 4, - value: 45 - }, - 3: { - text: t('armorWizard3Text'), - notes: t('armorWizard3Notes', { - int: 6 - }), - int: 6, - value: 65 - }, - 4: { - text: t('armorWizard4Text'), - notes: t('armorWizard4Notes', { - int: 9 - }), - int: 9, - value: 90 - }, - 5: { - text: t('armorWizard5Text'), - notes: t('armorWizard5Notes', { - int: 12 - }), - int: 12, - value: 120, - last: true - } - }, - healer: { - 1: { - text: t('armorHealer1Text'), - notes: t('armorHealer1Notes', { - con: 6 - }), - con: 6, - value: 30 - }, - 2: { - text: t('armorHealer2Text'), - notes: t('armorHealer2Notes', { - con: 9 - }), - con: 9, - value: 45 - }, - 3: { - text: t('armorHealer3Text'), - notes: t('armorHealer3Notes', { - con: 12 - }), - con: 12, - value: 65 - }, - 4: { - text: t('armorHealer4Text'), - notes: t('armorHealer4Notes', { - con: 15 - }), - con: 15, - value: 90 - }, - 5: { - text: t('armorHealer5Text'), - notes: t('armorHealer5Notes', { - con: 18 - }), - con: 18, - value: 120, - last: true - } - }, - special: { - 0: { - text: t('armorSpecial0Text'), - notes: t('armorSpecial0Notes', { - con: 20 - }), - con: 20, - value: 150, - canOwn: (function(u) { - var _ref; - return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 45; - }) - }, - 1: { - text: t('armorSpecial1Text'), - notes: t('armorSpecial1Notes', { - attrs: 6 - }), - con: 6, - str: 6, - per: 6, - int: 6, - value: 170, - canOwn: (function(u) { - var _ref; - return +((_ref = u.contributor) != null ? _ref.level : void 0) >= 2; - }) - }, - 2: { - text: t('armorSpecial2Text'), - notes: t('armorSpecial2Notes', { - attrs: 25 - }), - int: 25, - con: 25, - value: 200, - canOwn: (function(u) { - var _ref; - return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 300 || (u.items.gear.owned.armor_special_2 != null); - }) - }, - yeti: { - event: events.winter, - specialClass: 'warrior', - text: t('armorSpecialYetiText'), - notes: t('armorSpecialYetiNotes', { - con: 9 - }), - con: 9, - value: 90 - }, - ski: { - event: events.winter, - specialClass: 'rogue', - text: t('armorSpecialSkiText'), - notes: t('armorSpecialSkiNotes', { - per: 15 - }), - per: 15, - value: 90 - }, - candycane: { - event: events.winter, - specialClass: 'wizard', - text: t('armorSpecialCandycaneText'), - notes: t('armorSpecialCandycaneNotes', { - int: 9 - }), - int: 9, - value: 90 - }, - snowflake: { - event: events.winter, - specialClass: 'healer', - text: t('armorSpecialSnowflakeText'), - notes: t('armorSpecialSnowflakeNotes', { - con: 15 - }), - con: 15, - value: 90 - }, - birthday: { - event: events.birthday, - text: t('armorSpecialBirthdayText'), - notes: t('armorSpecialBirthdayNotes'), - value: 0 - }, - springRogue: { - event: events.spring, - specialClass: 'rogue', - text: t('armorSpecialSpringRogueText'), - notes: t('armorSpecialSpringRogueNotes', { - per: 15 - }), - value: 90, - per: 15 - }, - springWarrior: { - event: events.spring, - specialClass: 'warrior', - text: t('armorSpecialSpringWarriorText'), - notes: t('armorSpecialSpringWarriorNotes', { - con: 9 - }), - value: 90, - con: 9 - }, - springMage: { - event: events.spring, - specialClass: 'wizard', - text: t('armorSpecialSpringMageText'), - notes: t('armorSpecialSpringMageNotes', { - int: 9 - }), - value: 90, - int: 9 - }, - springHealer: { - event: events.spring, - specialClass: 'healer', - text: t('armorSpecialSpringHealerText'), - notes: t('armorSpecialSpringHealerNotes', { - con: 15 - }), - value: 90, - con: 15 - }, - summerRogue: { - event: events.summer, - specialClass: 'rogue', - text: t('armorSpecialSummerRogueText'), - notes: t('armorSpecialSummerRogueNotes', { - per: 15 - }), - value: 90, - per: 15 - }, - summerWarrior: { - event: events.summer, - specialClass: 'warrior', - text: t('armorSpecialSummerWarriorText'), - notes: t('armorSpecialSummerWarriorNotes', { - con: 9 - }), - value: 90, - con: 9 - }, - summerMage: { - event: events.summer, - specialClass: 'wizard', - text: t('armorSpecialSummerMageText'), - notes: t('armorSpecialSummerMageNotes', { - int: 9 - }), - value: 90, - int: 9 - }, - summerHealer: { - event: events.summer, - specialClass: 'healer', - text: t('armorSpecialSummerHealerText'), - notes: t('armorSpecialSummerHealerNotes', { - con: 15 - }), - value: 90, - con: 15 - }, - fallRogue: { - event: events.fall, - specialClass: 'rogue', - text: t('armorSpecialFallRogueText'), - notes: t('armorSpecialFallRogueNotes', { - per: 15 - }), - value: 90, - per: 15 - }, - fallWarrior: { - event: events.fall, - specialClass: 'warrior', - text: t('armorSpecialFallWarriorText'), - notes: t('armorSpecialFallWarriorNotes', { - con: 9 - }), - value: 90, - con: 9 - }, - fallMage: { - event: events.fall, - specialClass: 'wizard', - text: t('armorSpecialFallMageText'), - notes: t('armorSpecialFallMageNotes', { - int: 9 - }), - value: 90, - int: 9 - }, - fallHealer: { - event: events.fall, - specialClass: 'healer', - text: t('armorSpecialFallHealerText'), - notes: t('armorSpecialFallHealerNotes', { - con: 15 - }), - value: 90, - con: 15 - }, - winter2015Rogue: { - event: events.winter2015, - specialClass: 'rogue', - text: t('armorSpecialWinter2015RogueText'), - notes: t('armorSpecialWinter2015RogueNotes', { - per: 15 - }), - value: 90, - per: 15 - }, - winter2015Warrior: { - event: events.winter2015, - specialClass: 'warrior', - text: t('armorSpecialWinter2015WarriorText'), - notes: t('armorSpecialWinter2015WarriorNotes', { - con: 9 - }), - value: 90, - con: 9 - }, - winter2015Mage: { - event: events.winter2015, - specialClass: 'wizard', - text: t('armorSpecialWinter2015MageText'), - notes: t('armorSpecialWinter2015MageNotes', { - int: 9 - }), - value: 90, - int: 9 - }, - winter2015Healer: { - event: events.winter2015, - specialClass: 'healer', - text: t('armorSpecialWinter2015HealerText'), - notes: t('armorSpecialWinter2015HealerNotes', { - con: 15 - }), - value: 90, - con: 15 - }, - birthday2015: { - text: t('armorSpecialBirthday2015Text'), - notes: t('armorSpecialBirthday2015Notes'), - value: 0, - canOwn: (function(u) { - return u.items.gear.owned.armor_special_birthday2015 != null; - }) - }, - gaymerx: { - event: events.gaymerx, - text: t('armorSpecialGaymerxText'), - notes: t('armorSpecialGaymerxNotes'), - value: 0 - } - }, - mystery: { - 201402: { - text: t('armorMystery201402Text'), - notes: t('armorMystery201402Notes'), - mystery: '201402', - value: 0 - }, - 201403: { - text: t('armorMystery201403Text'), - notes: t('armorMystery201403Notes'), - mystery: '201403', - value: 0 - }, - 201405: { - text: t('armorMystery201405Text'), - notes: t('armorMystery201405Notes'), - mystery: '201405', - value: 0 - }, - 201406: { - text: t('armorMystery201406Text'), - notes: t('armorMystery201406Notes'), - mystery: '201406', - value: 0 - }, - 201407: { - text: t('armorMystery201407Text'), - notes: t('armorMystery201407Notes'), - mystery: '201407', - value: 0 - }, - 201408: { - text: t('armorMystery201408Text'), - notes: t('armorMystery201408Notes'), - mystery: '201408', - value: 0 - }, - 201409: { - text: t('armorMystery201409Text'), - notes: t('armorMystery201409Notes'), - mystery: '201409', - value: 0 - }, - 201410: { - text: t('armorMystery201410Text'), - notes: t('armorMystery201410Notes'), - mystery: '201410', - value: 0 - }, - 201412: { - text: t('armorMystery201412Text'), - notes: t('armorMystery201412Notes'), - mystery: '201412', - value: 0 - }, - 201501: { - text: t('armorMystery201501Text'), - notes: t('armorMystery201501Notes'), - mystery: '201501', - value: 0 - }, - 301404: { - text: t('armorMystery301404Text'), - notes: t('armorMystery301404Notes'), - mystery: '301404', - value: 0 - } - } - }, - head: { - base: { - 0: { - text: t('headBase0Text'), - notes: t('headBase0Notes'), - value: 0 - } - }, - warrior: { - 1: { - text: t('headWarrior1Text'), - notes: t('headWarrior1Notes', { - str: 2 - }), - str: 2, - value: 15 - }, - 2: { - text: t('headWarrior2Text'), - notes: t('headWarrior2Notes', { - str: 4 - }), - str: 4, - value: 25 - }, - 3: { - text: t('headWarrior3Text'), - notes: t('headWarrior3Notes', { - str: 6 - }), - str: 6, - value: 40 - }, - 4: { - text: t('headWarrior4Text'), - notes: t('headWarrior4Notes', { - str: 9 - }), - str: 9, - value: 60 - }, - 5: { - text: t('headWarrior5Text'), - notes: t('headWarrior5Notes', { - str: 12 - }), - str: 12, - value: 80, - last: true - } - }, - rogue: { - 1: { - text: t('headRogue1Text'), - notes: t('headRogue1Notes', { - per: 2 - }), - per: 2, - value: 15 - }, - 2: { - text: t('headRogue2Text'), - notes: t('headRogue2Notes', { - per: 4 - }), - per: 4, - value: 25 - }, - 3: { - text: t('headRogue3Text'), - notes: t('headRogue3Notes', { - per: 6 - }), - per: 6, - value: 40 - }, - 4: { - text: t('headRogue4Text'), - notes: t('headRogue4Notes', { - per: 9 - }), - per: 9, - value: 60 - }, - 5: { - text: t('headRogue5Text'), - notes: t('headRogue5Notes', { - per: 12 - }), - per: 12, - value: 80, - last: true - } - }, - wizard: { - 1: { - text: t('headWizard1Text'), - notes: t('headWizard1Notes', { - per: 2 - }), - per: 2, - value: 15 - }, - 2: { - text: t('headWizard2Text'), - notes: t('headWizard2Notes', { - per: 3 - }), - per: 3, - value: 25 - }, - 3: { - text: t('headWizard3Text'), - notes: t('headWizard3Notes', { - per: 5 - }), - per: 5, - value: 40 - }, - 4: { - text: t('headWizard4Text'), - notes: t('headWizard4Notes', { - per: 7 - }), - per: 7, - value: 60 - }, - 5: { - text: t('headWizard5Text'), - notes: t('headWizard5Notes', { - per: 10 - }), - per: 10, - value: 80, - last: true - } - }, - healer: { - 1: { - text: t('headHealer1Text'), - notes: t('headHealer1Notes', { - int: 2 - }), - int: 2, - value: 15 - }, - 2: { - text: t('headHealer2Text'), - notes: t('headHealer2Notes', { - int: 3 - }), - int: 3, - value: 25 - }, - 3: { - text: t('headHealer3Text'), - notes: t('headHealer3Notes', { - int: 5 - }), - int: 5, - value: 40 - }, - 4: { - text: t('headHealer4Text'), - notes: t('headHealer4Notes', { - int: 7 - }), - int: 7, - value: 60 - }, - 5: { - text: t('headHealer5Text'), - notes: t('headHealer5Notes', { - int: 9 - }), - int: 9, - value: 80, - last: true - } - }, - special: { - 0: { - text: t('headSpecial0Text'), - notes: t('headSpecial0Notes', { - int: 20 - }), - int: 20, - value: 150, - canOwn: (function(u) { - var _ref; - return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 45; - }) - }, - 1: { - text: t('headSpecial1Text'), - notes: t('headSpecial1Notes', { - attrs: 6 - }), - con: 6, - str: 6, - per: 6, - int: 6, - value: 170, - canOwn: (function(u) { - var _ref; - return +((_ref = u.contributor) != null ? _ref.level : void 0) >= 3; - }) - }, - 2: { - text: t('headSpecial2Text'), - notes: t('headSpecial2Notes', { - attrs: 25 - }), - int: 25, - str: 25, - value: 200, - canOwn: (function(u) { - var _ref; - return (+((_ref = u.backer) != null ? _ref.tier : void 0) >= 300) || (u.items.gear.owned.head_special_2 != null); - }) - }, - nye: { - event: events.winter, - text: t('headSpecialNyeText'), - notes: t('headSpecialNyeNotes'), - value: 0 - }, - yeti: { - event: events.winter, - specialClass: 'warrior', - text: t('headSpecialYetiText'), - notes: t('headSpecialYetiNotes', { - str: 9 - }), - str: 9, - value: 60 - }, - ski: { - event: events.winter, - specialClass: 'rogue', - text: t('headSpecialSkiText'), - notes: t('headSpecialSkiNotes', { - per: 9 - }), - per: 9, - value: 60 - }, - candycane: { - event: events.winter, - specialClass: 'wizard', - text: t('headSpecialCandycaneText'), - notes: t('headSpecialCandycaneNotes', { - per: 7 - }), - per: 7, - value: 60 - }, - snowflake: { - event: events.winter, - specialClass: 'healer', - text: t('headSpecialSnowflakeText'), - notes: t('headSpecialSnowflakeNotes', { - int: 7 - }), - int: 7, - value: 60 - }, - springRogue: { - event: events.spring, - specialClass: 'rogue', - text: t('headSpecialSpringRogueText'), - notes: t('headSpecialSpringRogueNotes', { - per: 9 - }), - value: 60, - per: 9 - }, - springWarrior: { - event: events.spring, - specialClass: 'warrior', - text: t('headSpecialSpringWarriorText'), - notes: t('headSpecialSpringWarriorNotes', { - str: 9 - }), - value: 60, - str: 9 - }, - springMage: { - event: events.spring, - specialClass: 'wizard', - text: t('headSpecialSpringMageText'), - notes: t('headSpecialSpringMageNotes', { - per: 7 - }), - value: 60, - per: 7 - }, - springHealer: { - event: events.spring, - specialClass: 'healer', - text: t('headSpecialSpringHealerText'), - notes: t('headSpecialSpringHealerNotes', { - int: 7 - }), - value: 60, - int: 7 - }, - summerRogue: { - event: events.summer, - specialClass: 'rogue', - text: t('headSpecialSummerRogueText'), - notes: t('headSpecialSummerRogueNotes', { - per: 9 - }), - value: 60, - per: 9 - }, - summerWarrior: { - event: events.summer, - specialClass: 'warrior', - text: t('headSpecialSummerWarriorText'), - notes: t('headSpecialSummerWarriorNotes', { - str: 9 - }), - value: 60, - str: 9 - }, - summerMage: { - event: events.summer, - specialClass: 'wizard', - text: t('headSpecialSummerMageText'), - notes: t('headSpecialSummerMageNotes', { - per: 7 - }), - value: 60, - per: 7 - }, - summerHealer: { - event: events.summer, - specialClass: 'healer', - text: t('headSpecialSummerHealerText'), - notes: t('headSpecialSummerHealerNotes', { - int: 7 - }), - value: 60, - int: 7 - }, - fallRogue: { - event: events.fall, - specialClass: 'rogue', - text: t('headSpecialFallRogueText'), - notes: t('headSpecialFallRogueNotes', { - per: 9 - }), - value: 60, - per: 9 - }, - fallWarrior: { - event: events.fall, - specialClass: 'warrior', - text: t('headSpecialFallWarriorText'), - notes: t('headSpecialFallWarriorNotes', { - str: 9 - }), - value: 60, - str: 9 - }, - fallMage: { - event: events.fall, - specialClass: 'wizard', - text: t('headSpecialFallMageText'), - notes: t('headSpecialFallMageNotes', { - per: 7 - }), - value: 60, - per: 7 - }, - fallHealer: { - event: events.fall, - specialClass: 'healer', - text: t('headSpecialFallHealerText'), - notes: t('headSpecialFallHealerNotes', { - int: 7 - }), - value: 60, - int: 7 - }, - winter2015Rogue: { - event: events.winter2015, - specialClass: 'rogue', - text: t('headSpecialWinter2015RogueText'), - notes: t('headSpecialWinter2015RogueNotes', { - per: 9 - }), - value: 60, - per: 9 - }, - winter2015Warrior: { - event: events.winter2015, - specialClass: 'warrior', - text: t('headSpecialWinter2015WarriorText'), - notes: t('headSpecialWinter2015WarriorNotes', { - str: 9 - }), - value: 60, - str: 9 - }, - winter2015Mage: { - event: events.winter2015, - specialClass: 'wizard', - text: t('headSpecialWinter2015MageText'), - notes: t('headSpecialWinter2015MageNotes', { - per: 7 - }), - value: 60, - per: 7 - }, - winter2015Healer: { - event: events.winter2015, - specialClass: 'healer', - text: t('headSpecialWinter2015HealerText'), - notes: t('headSpecialWinter2015HealerNotes', { - int: 7 - }), - value: 60, - int: 7 - }, - nye2014: { - text: t('headSpecialNye2014Text'), - notes: t('headSpecialNye2014Notes'), - value: 0, - canOwn: (function(u) { - return u.items.gear.owned.head_special_nye2014 != null; - }) - }, - gaymerx: { - event: events.gaymerx, - text: t('headSpecialGaymerxText'), - notes: t('headSpecialGaymerxNotes'), - value: 0 - } - }, - mystery: { - 201402: { - text: t('headMystery201402Text'), - notes: t('headMystery201402Notes'), - mystery: '201402', - value: 0 - }, - 201405: { - text: t('headMystery201405Text'), - notes: t('headMystery201405Notes'), - mystery: '201405', - value: 0 - }, - 201406: { - text: t('headMystery201406Text'), - notes: t('headMystery201406Notes'), - mystery: '201406', - value: 0 - }, - 201407: { - text: t('headMystery201407Text'), - notes: t('headMystery201407Notes'), - mystery: '201407', - value: 0 - }, - 201408: { - text: t('headMystery201408Text'), - notes: t('headMystery201408Notes'), - mystery: '201408', - value: 0 - }, - 201411: { - text: t('headMystery201411Text'), - notes: t('headMystery201411Notes'), - mystery: '201411', - value: 0 - }, - 201412: { - text: t('headMystery201412Text'), - notes: t('headMystery201412Notes'), - mystery: '201412', - value: 0 - }, - 201501: { - text: t('headMystery201501Text'), - notes: t('headMystery201501Notes'), - mystery: '201501', - value: 0 - }, - 301404: { - text: t('headMystery301404Text'), - notes: t('headMystery301404Notes'), - mystery: '301404', - value: 0 - }, - 301405: { - text: t('headMystery301405Text'), - notes: t('headMystery301405Notes'), - mystery: '301405', - value: 0 - } - } - }, - shield: { - base: { - 0: { - text: t('shieldBase0Text'), - notes: t('shieldBase0Notes'), - value: 0 - } - }, - warrior: { - 1: { - text: t('shieldWarrior1Text'), - notes: t('shieldWarrior1Notes', { - con: 2 - }), - con: 2, - value: 20 - }, - 2: { - text: t('shieldWarrior2Text'), - notes: t('shieldWarrior2Notes', { - con: 3 - }), - con: 3, - value: 35 - }, - 3: { - text: t('shieldWarrior3Text'), - notes: t('shieldWarrior3Notes', { - con: 5 - }), - con: 5, - value: 50 - }, - 4: { - text: t('shieldWarrior4Text'), - notes: t('shieldWarrior4Notes', { - con: 7 - }), - con: 7, - value: 70 - }, - 5: { - text: t('shieldWarrior5Text'), - notes: t('shieldWarrior5Notes', { - con: 9 - }), - con: 9, - value: 90, - last: true - } - }, - rogue: { - 0: { - text: t('weaponRogue0Text'), - notes: t('weaponRogue0Notes'), - str: 0, - value: 0 - }, - 1: { - text: t('weaponRogue1Text'), - notes: t('weaponRogue1Notes', { - str: 2 - }), - str: 2, - value: 20 - }, - 2: { - text: t('weaponRogue2Text'), - notes: t('weaponRogue2Notes', { - str: 3 - }), - str: 3, - value: 35 - }, - 3: { - text: t('weaponRogue3Text'), - notes: t('weaponRogue3Notes', { - str: 4 - }), - str: 4, - value: 50 - }, - 4: { - text: t('weaponRogue4Text'), - notes: t('weaponRogue4Notes', { - str: 6 - }), - str: 6, - value: 70 - }, - 5: { - text: t('weaponRogue5Text'), - notes: t('weaponRogue5Notes', { - str: 8 - }), - str: 8, - value: 90 - }, - 6: { - text: t('weaponRogue6Text'), - notes: t('weaponRogue6Notes', { - str: 10 - }), - str: 10, - value: 120, - last: true - } - }, - wizard: {}, - healer: { - 1: { - text: t('shieldHealer1Text'), - notes: t('shieldHealer1Notes', { - con: 2 - }), - con: 2, - value: 20 - }, - 2: { - text: t('shieldHealer2Text'), - notes: t('shieldHealer2Notes', { - con: 4 - }), - con: 4, - value: 35 - }, - 3: { - text: t('shieldHealer3Text'), - notes: t('shieldHealer3Notes', { - con: 6 - }), - con: 6, - value: 50 - }, - 4: { - text: t('shieldHealer4Text'), - notes: t('shieldHealer4Notes', { - con: 9 - }), - con: 9, - value: 70 - }, - 5: { - text: t('shieldHealer5Text'), - notes: t('shieldHealer5Notes', { - con: 12 - }), - con: 12, - value: 90, - last: true - } - }, - special: { - 0: { - text: t('shieldSpecial0Text'), - notes: t('shieldSpecial0Notes', { - per: 20 - }), - per: 20, - value: 150, - canOwn: (function(u) { - var _ref; - return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 45; - }) - }, - 1: { - text: t('shieldSpecial1Text'), - notes: t('shieldSpecial1Notes', { - attrs: 6 - }), - con: 6, - str: 6, - per: 6, - int: 6, - value: 170, - canOwn: (function(u) { - var _ref; - return +((_ref = u.contributor) != null ? _ref.level : void 0) >= 5; - }) - }, - goldenknight: { - text: t('shieldSpecialGoldenknightText'), - notes: t('shieldSpecialGoldenknightNotes', { - attrs: 25 - }), - con: 25, - per: 25, - value: 200, - canOwn: (function(u) { - return u.items.gear.owned.shield_special_goldenknight != null; - }) - }, - yeti: { - event: events.winter, - specialClass: 'warrior', - text: t('shieldSpecialYetiText'), - notes: t('shieldSpecialYetiNotes', { - con: 7 - }), - con: 7, - value: 70 - }, - ski: { - event: events.winter, - specialClass: 'rogue', - text: t('weaponSpecialSkiText'), - notes: t('weaponSpecialSkiNotes', { - str: 8 - }), - str: 8, - value: 90 - }, - snowflake: { - event: events.winter, - specialClass: 'healer', - text: t('shieldSpecialSnowflakeText'), - notes: t('shieldSpecialSnowflakeNotes', { - con: 9 - }), - con: 9, - value: 70 - }, - springRogue: { - event: events.spring, - specialClass: 'rogue', - text: t('shieldSpecialSpringRogueText'), - notes: t('shieldSpecialSpringRogueNotes', { - str: 8 - }), - value: 80, - str: 8 - }, - springWarrior: { - event: events.spring, - specialClass: 'warrior', - text: t('shieldSpecialSpringWarriorText'), - notes: t('shieldSpecialSpringWarriorNotes', { - con: 7 - }), - value: 70, - con: 7 - }, - springHealer: { - event: events.spring, - specialClass: 'healer', - text: t('shieldSpecialSpringHealerText'), - notes: t('shieldSpecialSpringHealerNotes', { - con: 9 - }), - value: 70, - con: 9 - }, - summerRogue: { - event: events.summer, - specialClass: 'rogue', - text: t('shieldSpecialSummerRogueText'), - notes: t('shieldSpecialSummerRogueNotes', { - str: 8 - }), - value: 80, - str: 8 - }, - summerWarrior: { - event: events.summer, - specialClass: 'warrior', - text: t('shieldSpecialSummerWarriorText'), - notes: t('shieldSpecialSummerWarriorNotes', { - con: 7 - }), - value: 70, - con: 7 - }, - summerHealer: { - event: events.summer, - specialClass: 'healer', - text: t('shieldSpecialSummerHealerText'), - notes: t('shieldSpecialSummerHealerNotes', { - con: 9 - }), - value: 70, - con: 9 - }, - fallRogue: { - event: events.fall, - specialClass: 'rogue', - text: t('shieldSpecialFallRogueText'), - notes: t('shieldSpecialFallRogueNotes', { - str: 8 - }), - value: 80, - str: 8 - }, - fallWarrior: { - event: events.fall, - specialClass: 'warrior', - text: t('shieldSpecialFallWarriorText'), - notes: t('shieldSpecialFallWarriorNotes', { - con: 7 - }), - value: 70, - con: 7 - }, - fallHealer: { - event: events.fall, - specialClass: 'healer', - text: t('shieldSpecialFallHealerText'), - notes: t('shieldSpecialFallHealerNotes', { - con: 9 - }), - value: 70, - con: 9 - }, - winter2015Rogue: { - event: events.winter2015, - specialClass: 'rogue', - text: t('shieldSpecialWinter2015RogueText'), - notes: t('shieldSpecialWinter2015RogueNotes', { - str: 8 - }), - value: 80, - str: 8 - }, - winter2015Warrior: { - event: events.winter2015, - specialClass: 'warrior', - text: t('shieldSpecialWinter2015WarriorText'), - notes: t('shieldSpecialWinter2015WarriorNotes', { - con: 7 - }), - value: 70, - con: 7 - }, - winter2015Healer: { - event: events.winter2015, - specialClass: 'healer', - text: t('shieldSpecialWinter2015HealerText'), - notes: t('shieldSpecialWinter2015HealerNotes', { - con: 9 - }), - value: 70, - con: 9 - } - }, - mystery: { - 301405: { - text: t('shieldMystery301405Text'), - notes: t('shieldMystery301405Notes'), - mystery: '301405', - value: 0 - } - } - }, - back: { - base: { - 0: { - text: t('backBase0Text'), - notes: t('backBase0Notes'), - value: 0 - } - }, - mystery: { - 201402: { - text: t('backMystery201402Text'), - notes: t('backMystery201402Notes'), - mystery: '201402', - value: 0 - }, - 201404: { - text: t('backMystery201404Text'), - notes: t('backMystery201404Notes'), - mystery: '201404', - value: 0 - }, - 201410: { - text: t('backMystery201410Text'), - notes: t('backMystery201410Notes'), - mystery: '201410', - value: 0 - } - }, - special: { - wondercon_red: { - text: t('backSpecialWonderconRedText'), - notes: t('backSpecialWonderconRedNotes'), - value: 0, - mystery: 'wondercon' - }, - wondercon_black: { - text: t('backSpecialWonderconBlackText'), - notes: t('backSpecialWonderconBlackNotes'), - value: 0, - mystery: 'wondercon' - } - } - }, - body: { - base: { - 0: { - text: t('bodyBase0Text'), - notes: t('bodyBase0Notes'), - value: 0 - } - }, - special: { - wondercon_red: { - text: t('bodySpecialWonderconRedText'), - notes: t('bodySpecialWonderconRedNotes'), - value: 0, - mystery: 'wondercon' - }, - wondercon_gold: { - text: t('bodySpecialWonderconGoldText'), - notes: t('bodySpecialWonderconGoldNotes'), - value: 0, - mystery: 'wondercon' - }, - wondercon_black: { - text: t('bodySpecialWonderconBlackText'), - notes: t('bodySpecialWonderconBlackNotes'), - value: 0, - mystery: 'wondercon' - }, - summerHealer: { - event: events.summer, - specialClass: 'healer', - text: t('bodySpecialSummerHealerText'), - notes: t('bodySpecialSummerHealerNotes'), - value: 20 - }, - summerMage: { - event: events.summer, - specialClass: 'wizard', - text: t('bodySpecialSummerMageText'), - notes: t('bodySpecialSummerMageNotes'), - value: 20 - } - } - }, - headAccessory: { - base: { - 0: { - text: t('headAccessoryBase0Text'), - notes: t('headAccessoryBase0Notes'), - value: 0, - last: true - } - }, - special: { - springRogue: { - event: events.spring, - specialClass: 'rogue', - text: t('headAccessorySpecialSpringRogueText'), - notes: t('headAccessorySpecialSpringRogueNotes'), - value: 20 - }, - springWarrior: { - event: events.spring, - specialClass: 'warrior', - text: t('headAccessorySpecialSpringWarriorText'), - notes: t('headAccessorySpecialSpringWarriorNotes'), - value: 20 - }, - springMage: { - event: events.spring, - specialClass: 'wizard', - text: t('headAccessorySpecialSpringMageText'), - notes: t('headAccessorySpecialSpringMageNotes'), - value: 20 - }, - springHealer: { - event: events.spring, - specialClass: 'healer', - text: t('headAccessorySpecialSpringHealerText'), - notes: t('headAccessorySpecialSpringHealerNotes'), - value: 20 - } - }, - mystery: { - 201403: { - text: t('headAccessoryMystery201403Text'), - notes: t('headAccessoryMystery201403Notes'), - mystery: '201403', - value: 0 - }, - 201404: { - text: t('headAccessoryMystery201404Text'), - notes: t('headAccessoryMystery201404Notes'), - mystery: '201404', - value: 0 - }, - 201409: { - text: t('headAccessoryMystery201409Text'), - notes: t('headAccessoryMystery201409Notes'), - mystery: '201409', - value: 0 - }, - 301405: { - text: t('headAccessoryMystery301405Text'), - notes: t('headAccessoryMystery301405Notes'), - mystery: '301405', - value: 0 - } - } - }, - eyewear: { - base: { - 0: { - text: t('eyewearBase0Text'), - notes: t('eyewearBase0Notes'), - value: 0, - last: true - } - }, - special: { - wondercon_red: { - text: t('eyewearSpecialWonderconRedText'), - notes: t('eyewearSpecialWonderconRedNotes'), - value: 0, - mystery: 'wondercon' - }, - wondercon_black: { - text: t('eyewearSpecialWonderconBlackText'), - notes: t('eyewearSpecialWonderconBlackNotes'), - value: 0, - mystery: 'wondercon' - }, - summerRogue: { - event: events.summer, - specialClass: 'rogue', - text: t('eyewearSpecialSummerRogueText'), - notes: t('eyewearSpecialSummerRogueNotes'), - value: 20 - }, - summerWarrior: { - event: events.summer, - specialClass: 'warrior', - text: t('eyewearSpecialSummerWarriorText'), - notes: t('eyewearSpecialSummerWarriorNotes'), - value: 20 - } - }, - mystery: { - 301404: { - text: t('eyewearMystery301404Text'), - notes: t('eyewearMystery301404Notes'), - mystery: '301404', - value: 0 - }, - 301405: { - text: t('eyewearMystery301405Text'), - notes: t('eyewearMystery301405Notes'), - mystery: '301405', - value: 0 - } - } - } -}; - - -/* - The gear is exported as a tree (defined above), and a flat list (eg, {weapon_healer_1: .., shield_special_0: ...}) since - they are needed in different froms at different points in the app - */ - -api.gear = { - tree: gear, - flat: {} -}; - -_.each(gearTypes, function(type) { - return _.each(classes.concat(['base', 'special', 'mystery']), function(klass) { - return _.each(gear[type][klass], function(item, i) { - var key, _canOwn; - key = "" + type + "_" + klass + "_" + i; - _.defaults(item, { - type: type, - key: key, - klass: klass, - index: i, - str: 0, - int: 0, - per: 0, - con: 0 - }); - if (item.event) { - _canOwn = item.canOwn || (function() { - return true; - }); - item.canOwn = function(u) { - return _canOwn(u) && ((u.items.gear.owned[key] != null) || (moment().isAfter(item.event.start) && moment().isBefore(item.event.end))) && (item.specialClass ? u.stats["class"] === item.specialClass : true); - }; - } - if (item.mystery) { - item.canOwn = function(u) { - return u.items.gear.owned[key] != null; - }; - } - return api.gear.flat[key] = item; - }); - }); -}); - - -/* - Time Traveler Store, mystery sets need their items mapped in - */ - -_.each(api.mystery, function(v, k) { - return v.items = _.where(api.gear.flat, { - mystery: k - }); -}); - -api.timeTravelerStore = function(owned) { - var ownedKeys; - ownedKeys = _.keys((typeof owned.toObject === "function" ? owned.toObject() : void 0) || owned); - return _.reduce(api.mystery, function(m, v, k) { - if (k === 'wondercon' || ~ownedKeys.indexOf(v.items[0].key)) { - return m; - } - m[k] = v; - return m; - }, {}); -}; - - -/* - --------------------------------------------------------------- - Potion - --------------------------------------------------------------- - */ - -api.potion = { - type: 'potion', - text: t('potionText'), - notes: t('potionNotes'), - value: 25, - key: 'potion' -}; - - -/* - --------------------------------------------------------------- - Classes - --------------------------------------------------------------- - */ - -api.classes = classes; - - -/* - --------------------------------------------------------------- - Gear Types - --------------------------------------------------------------- - */ - -api.gearTypes = gearTypes; - - -/* - --------------------------------------------------------------- - 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) - */ - -diminishingReturns = function(bonus, max, halfway) { - if (halfway == null) { - halfway = max / 2; - } - return max * (bonus / (bonus + halfway)); -}; - -api.spells = { - wizard: { - fireball: { - text: t('spellWizardFireballText'), - mana: 10, - lvl: 11, - target: 'task', - notes: t('spellWizardFireballNotes'), - cast: function(user, target) { - var bonus; - bonus = user._statsComputed.int * user.fns.crit('per'); - target.value += diminishingReturns(bonus * .02, 4); - bonus *= Math.ceil((target.value < 0 ? 1 : target.value + 1) * .075); - user.stats.exp += diminishingReturns(bonus, 75); - return user.party.quest.progress.up += diminishingReturns(bonus * .1, 50, 30); - } - }, - mpheal: { - text: t('spellWizardMPHealText'), - mana: 30, - lvl: 12, - target: 'party', - notes: t('spellWizardMPHealNotes'), - cast: function(user, target) { - return _.each(target, function(member) { - var bonus; - bonus = Math.ceil(user._statsComputed.int * .1); - if (bonus > 25) { - bonus = 25; - } - return member.stats.mp += bonus; - }); - } - }, - earth: { - text: t('spellWizardEarthText'), - mana: 35, - lvl: 13, - target: 'party', - notes: t('spellWizardEarthNotes'), - cast: function(user, target) { - return _.each(target, function(member) { - var _base; - if ((_base = member.stats.buffs).int == null) { - _base.int = 0; - } - return member.stats.buffs.int += Math.ceil(user._statsComputed.int * .05); - }); - } - }, - frost: { - text: t('spellWizardFrostText'), - mana: 40, - lvl: 14, - target: 'self', - notes: t('spellWizardFrostNotes'), - cast: function(user, target) { - return user.stats.buffs.streaks = true; - } - } - }, - warrior: { - smash: { - text: t('spellWarriorSmashText'), - mana: 10, - lvl: 11, - target: 'task', - notes: t('spellWarriorSmashNotes'), - cast: function(user, target) { - target.value += 2.5 * (user._statsComputed.str / (user._statsComputed.str + 50)) * user.fns.crit('con'); - return user.party.quest.progress.up += Math.ceil(user._statsComputed.str * .2); - } - }, - defensiveStance: { - text: t('spellWarriorDefensiveStanceText'), - mana: 25, - lvl: 12, - target: 'self', - notes: t('spellWarriorDefensiveStanceNotes'), - cast: function(user, target) { - var _base; - if ((_base = user.stats.buffs).con == null) { - _base.con = 0; - } - return user.stats.buffs.con += Math.ceil(user._statsComputed.con * .05); - } - }, - valorousPresence: { - text: t('spellWarriorValorousPresenceText'), - mana: 20, - lvl: 13, - target: 'party', - notes: t('spellWarriorValorousPresenceNotes'), - cast: function(user, target) { - return _.each(target, function(member) { - var _base; - if ((_base = member.stats.buffs).str == null) { - _base.str = 0; - } - return member.stats.buffs.str += Math.ceil(user._statsComputed.str * .05); - }); - } - }, - intimidate: { - text: t('spellWarriorIntimidateText'), - mana: 15, - lvl: 14, - target: 'party', - notes: t('spellWarriorIntimidateNotes'), - cast: function(user, target) { - return _.each(target, function(member) { - var _base; - if ((_base = member.stats.buffs).con == null) { - _base.con = 0; - } - return member.stats.buffs.con += Math.ceil(user._statsComputed.con * .03); - }); - } - } - }, - rogue: { - pickPocket: { - text: t('spellRoguePickPocketText'), - mana: 10, - lvl: 11, - target: 'task', - notes: t('spellRoguePickPocketNotes'), - cast: function(user, target) { - var bonus; - bonus = (target.value < 0 ? 1 : target.value + 2) + (user._statsComputed.per * 0.5); - return user.stats.gp += 25 * (bonus / (bonus + 75)); - } - }, - backStab: { - text: t('spellRogueBackStabText'), - mana: 15, - lvl: 12, - target: 'task', - notes: t('spellRogueBackStabNotes'), - cast: function(user, target) { - var bonus, _crit; - _crit = user.fns.crit('str', .3); - target.value += _crit * .03; - bonus = (target.value < 0 ? 1 : target.value + 1) * _crit; - user.stats.exp += bonus; - return user.stats.gp += bonus; - } - }, - toolsOfTrade: { - text: t('spellRogueToolsOfTradeText'), - mana: 25, - lvl: 13, - target: 'party', - notes: t('spellRogueToolsOfTradeNotes'), - cast: function(user, target) { - return _.each(target, function(member) { - var _base; - if ((_base = member.stats.buffs).per == null) { - _base.per = 0; - } - return member.stats.buffs.per += Math.ceil(user._statsComputed.per * .03); - }); - } - }, - stealth: { - text: t('spellRogueStealthText'), - mana: 45, - lvl: 14, - target: 'self', - notes: t('spellRogueStealthNotes'), - cast: function(user, target) { - var _base; - if ((_base = user.stats.buffs).stealth == null) { - _base.stealth = 0; - } - return user.stats.buffs.stealth += Math.ceil(user.dailys.length * user._statsComputed.per / 100); - } - } - }, - healer: { - heal: { - text: t('spellHealerHealText'), - mana: 15, - lvl: 11, - target: 'self', - notes: t('spellHealerHealNotes'), - cast: function(user, target) { - user.stats.hp += (user._statsComputed.con + user._statsComputed.int + 5) * .075; - if (user.stats.hp > 50) { - return user.stats.hp = 50; - } - } - }, - brightness: { - text: t('spellHealerBrightnessText'), - mana: 15, - lvl: 12, - target: 'self', - notes: t('spellHealerBrightnessNotes'), - cast: function(user, target) { - return _.each(user.tasks, function(target) { - if (target.type === 'reward') { - return; - } - return target.value += 1.5 * (user._statsComputed.int / (user._statsComputed.int + 40)); - }); - } - }, - protectAura: { - text: t('spellHealerProtectAuraText'), - mana: 30, - lvl: 13, - target: 'party', - notes: t('spellHealerProtectAuraNotes'), - cast: function(user, target) { - return _.each(target, function(member) { - var _base; - if ((_base = member.stats.buffs).con == null) { - _base.con = 0; - } - return member.stats.buffs.con += Math.ceil(user._statsComputed.con * .15); - }); - } - }, - heallAll: { - text: t('spellHealerHealAllText'), - mana: 25, - lvl: 14, - target: 'party', - notes: t('spellHealerHealAllNotes'), - cast: function(user, target) { - return _.each(target, function(member) { - member.stats.hp += (user._statsComputed.con + user._statsComputed.int + 5) * .04; - if (member.stats.hp > 50) { - return member.stats.hp = 50; - } - }); - } - } - }, - special: { - snowball: { - text: t('spellSpecialSnowballAuraText'), - mana: 0, - value: 15, - target: 'user', - notes: t('spellSpecialSnowballAuraNotes'), - cast: function(user, target) { - var _base; - target.stats.buffs.snowball = true; - if ((_base = target.achievements).snowball == null) { - _base.snowball = 0; - } - target.achievements.snowball++; - return user.items.special.snowball--; - } - }, - salt: { - text: t('spellSpecialSaltText'), - mana: 0, - value: 5, - immediateUse: true, - target: 'self', - notes: t('spellSpecialSaltNotes'), - cast: function(user, target) { - user.stats.buffs.snowball = false; - return user.stats.gp -= 5; - } - }, - spookDust: { - text: t('spellSpecialSpookDustText'), - mana: 0, - value: 15, - target: 'user', - notes: t('spellSpecialSpookDustNotes'), - cast: function(user, target) { - var _base; - target.stats.buffs.spookDust = true; - if ((_base = target.achievements).spookDust == null) { - _base.spookDust = 0; - } - target.achievements.spookDust++; - return user.items.special.spookDust--; - } - }, - opaquePotion: { - text: t('spellSpecialOpaquePotionText'), - mana: 0, - value: 5, - immediateUse: true, - target: 'self', - notes: t('spellSpecialOpaquePotionNotes'), - cast: function(user, target) { - user.stats.buffs.spookDust = false; - return user.stats.gp -= 5; - } - }, - nye: { - text: t('nyeCard'), - mana: 0, - value: 10, - immediateUse: true, - target: 'user', - notes: t('nyeCardNotes'), - cast: function(user, target) { - var _base; - if (user === target) { - if ((_base = user.achievements).nye == null) { - _base.nye = 0; - } - user.achievements.nye++; - } else { - _.each([user, target], function(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); - if (typeof target.markModified === "function") { - target.markModified('items.special.nyeReceived'); - } - return user.stats.gp -= 10; - } - } - } -}; - -_.each(api.spells, function(spellClass) { - return _.each(spellClass, function(spell, key) { - var _cast; - spell.key = key; - _cast = spell.cast; - return spell.cast = function(user, target) { - _cast(user, target); - return user.stats.mp -= spell.mana; - }; - }); -}); - -api.special = api.spells.special; - - -/* - --------------------------------------------------------------- - Drops - --------------------------------------------------------------- - */ - -api.dropEggs = { - Wolf: { - text: t('dropEggWolfText'), - adjective: t('dropEggWolfAdjective') - }, - TigerCub: { - text: t('dropEggTigerCubText'), - mountText: t('dropEggTigerCubMountText'), - adjective: t('dropEggTigerCubAdjective') - }, - PandaCub: { - text: t('dropEggPandaCubText'), - mountText: t('dropEggPandaCubMountText'), - adjective: t('dropEggPandaCubAdjective') - }, - LionCub: { - text: t('dropEggLionCubText'), - mountText: t('dropEggLionCubMountText'), - adjective: t('dropEggLionCubAdjective') - }, - Fox: { - text: t('dropEggFoxText'), - adjective: t('dropEggFoxAdjective') - }, - FlyingPig: { - text: t('dropEggFlyingPigText'), - adjective: t('dropEggFlyingPigAdjective') - }, - Dragon: { - text: t('dropEggDragonText'), - adjective: t('dropEggDragonAdjective') - }, - Cactus: { - text: t('dropEggCactusText'), - adjective: t('dropEggCactusAdjective') - }, - BearCub: { - text: t('dropEggBearCubText'), - mountText: t('dropEggBearCubMountText'), - adjective: t('dropEggBearCubAdjective') - } -}; - -_.each(api.dropEggs, function(egg, key) { - return _.defaults(egg, { - canBuy: true, - value: 3, - key: key, - notes: t('eggNotes', { - eggText: egg.text, - eggAdjective: egg.adjective - }), - mountText: egg.text - }); -}); - -api.questEggs = { - Gryphon: { - text: t('questEggGryphonText'), - adjective: t('questEggGryphonAdjective'), - canBuy: false - }, - Hedgehog: { - text: t('questEggHedgehogText'), - adjective: t('questEggHedgehogAdjective'), - canBuy: false - }, - Deer: { - text: t('questEggDeerText'), - adjective: t('questEggDeerAdjective'), - canBuy: false - }, - Egg: { - text: t('questEggEggText'), - adjective: t('questEggEggAdjective'), - canBuy: false, - noMount: true - }, - Rat: { - text: t('questEggRatText'), - adjective: t('questEggRatAdjective'), - canBuy: false - }, - Octopus: { - text: t('questEggOctopusText'), - adjective: t('questEggOctopusAdjective'), - canBuy: false - }, - Seahorse: { - text: t('questEggSeahorseText'), - adjective: t('questEggSeahorseAdjective'), - canBuy: false - }, - Parrot: { - text: t('questEggParrotText'), - adjective: t('questEggParrotAdjective'), - canBuy: false - }, - Rooster: { - text: t('questEggRoosterText'), - adjective: t('questEggRoosterAdjective'), - canBuy: false - }, - Spider: { - text: t('questEggSpiderText'), - adjective: t('questEggSpiderAdjective'), - canBuy: false - }, - Owl: { - text: t('questEggOwlText'), - adjective: t('questEggOwlAdjective'), - canBuy: false - }, - Penguin: { - text: t('questEggPenguinText'), - adjective: t('questEggPenguinAdjective'), - canBuy: false - }, - TRex: { - text: t('questEggTRexText'), - adjective: t('questEggTRexAdjective'), - canBuy: false - } -}; - -_.each(api.questEggs, function(egg, key) { - return _.defaults(egg, { - canBuy: false, - value: 3, - key: key, - notes: t('eggNotes', { - eggText: egg.text, - eggAdjective: egg.adjective - }), - mountText: egg.text - }); -}); - -api.eggs = _.assign(_.cloneDeep(api.dropEggs), api.questEggs); - -api.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' -}; - -api.specialMounts = { - 'BearCub-Polar': 'polarBear', - 'LionCub-Ethereal': 'etherealLion', - 'MantisShrimp-Base': 'mantisShrimp', - 'Turkey-Base': 'turkey', - 'Mammoth-Base': 'mammoth' -}; - -api.hatchingPotions = { - Base: { - value: 2, - text: t('hatchingPotionBase') - }, - White: { - value: 2, - text: t('hatchingPotionWhite') - }, - Desert: { - value: 2, - text: t('hatchingPotionDesert') - }, - Red: { - value: 3, - text: t('hatchingPotionRed') - }, - Shade: { - value: 3, - text: t('hatchingPotionShade') - }, - Skeleton: { - value: 3, - text: t('hatchingPotionSkeleton') - }, - Zombie: { - value: 4, - text: t('hatchingPotionZombie') - }, - CottonCandyPink: { - value: 4, - text: t('hatchingPotionCottonCandyPink') - }, - CottonCandyBlue: { - value: 4, - text: t('hatchingPotionCottonCandyBlue') - }, - Golden: { - value: 5, - text: t('hatchingPotionGolden') - } -}; - -_.each(api.hatchingPotions, function(pot, key) { - return _.defaults(pot, { - key: key, - value: 2, - notes: t('hatchingPotionNotes', { - potText: pot.text - }) - }); -}); - -api.pets = _.transform(api.dropEggs, function(m, egg) { - return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { - return m2[egg.key + "-" + pot.key] = true; - })); -}); - -api.questPets = _.transform(api.questEggs, function(m, egg) { - return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { - return m2[egg.key + "-" + pot.key] = true; - })); -}); - -api.mounts = _.transform(api.dropEggs, function(m, egg) { - return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { - return m2[egg.key + "-" + pot.key] = true; - })); -}); - -api.questMounts = _.transform(api.questEggs, function(m, egg) { - return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { - return m2[egg.key + "-" + pot.key] = true; - })); -}); - -api.food = { - Meat: { - canBuy: true, - canDrop: true, - text: t('foodMeat'), - target: 'Base', - article: '' - }, - Milk: { - canBuy: true, - canDrop: true, - text: t('foodMilk'), - target: 'White', - article: '' - }, - Potatoe: { - canBuy: true, - canDrop: true, - text: t('foodPotatoe'), - target: 'Desert', - article: 'a ' - }, - Strawberry: { - canBuy: true, - canDrop: true, - text: t('foodStrawberry'), - target: 'Red', - article: 'a ' - }, - Chocolate: { - canBuy: true, - canDrop: true, - text: t('foodChocolate'), - target: 'Shade', - article: '' - }, - Fish: { - canBuy: true, - canDrop: true, - text: t('foodFish'), - target: 'Skeleton', - article: 'a ' - }, - RottenMeat: { - canBuy: true, - canDrop: true, - text: t('foodRottenMeat'), - target: 'Zombie', - article: '' - }, - CottonCandyPink: { - canBuy: true, - canDrop: true, - text: t('foodCottonCandyPink'), - target: 'CottonCandyPink', - article: '' - }, - CottonCandyBlue: { - canBuy: true, - canDrop: true, - text: t('foodCottonCandyBlue'), - target: 'CottonCandyBlue', - article: '' - }, - Honey: { - canBuy: true, - canDrop: true, - text: t('foodHoney'), - target: 'Golden', - article: '' - }, - Saddle: { - canBuy: true, - canDrop: false, - text: t('foodSaddleText'), - value: 5, - notes: t('foodSaddleNotes') - }, - Cake_Skeleton: { - canBuy: false, - canDrop: false, - text: t('foodCakeSkeleton'), - target: 'Skeleton', - article: '' - }, - Cake_Base: { - canBuy: false, - canDrop: false, - text: t('foodCakeBase'), - target: 'Base', - article: '' - }, - Cake_CottonCandyBlue: { - canBuy: false, - canDrop: false, - text: t('foodCakeCottonCandyBlue'), - target: 'CottonCandyBlue', - article: '' - }, - Cake_CottonCandyPink: { - canBuy: false, - canDrop: false, - text: t('foodCakeCottonCandyPink'), - target: 'CottonCandyPink', - article: '' - }, - Cake_Shade: { - canBuy: false, - canDrop: false, - text: t('foodCakeShade'), - target: 'Shade', - article: '' - }, - Cake_White: { - canBuy: false, - canDrop: false, - text: t('foodCakeWhite'), - target: 'White', - article: '' - }, - Cake_Golden: { - canBuy: false, - canDrop: false, - text: t('foodCakeGolden'), - target: 'Golden', - article: '' - }, - Cake_Zombie: { - canBuy: false, - canDrop: false, - text: t('foodCakeZombie'), - target: 'Zombie', - article: '' - }, - Cake_Desert: { - canBuy: false, - canDrop: false, - text: t('foodCakeDesert'), - target: 'Desert', - article: '' - }, - Cake_Red: { - canBuy: false, - canDrop: false, - text: t('foodCakeRed'), - target: 'Red', - article: '' - }, - Candy_Skeleton: { - canBuy: false, - canDrop: false, - text: t('foodCandySkeleton'), - target: 'Skeleton', - article: '' - }, - Candy_Base: { - canBuy: false, - canDrop: false, - text: t('foodCandyBase'), - target: 'Base', - article: '' - }, - Candy_CottonCandyBlue: { - canBuy: false, - canDrop: false, - text: t('foodCandyCottonCandyBlue'), - target: 'CottonCandyBlue', - article: '' - }, - Candy_CottonCandyPink: { - canBuy: false, - canDrop: false, - text: t('foodCandyCottonCandyPink'), - target: 'CottonCandyPink', - article: '' - }, - Candy_Shade: { - canBuy: false, - canDrop: false, - text: t('foodCandyShade'), - target: 'Shade', - article: '' - }, - Candy_White: { - canBuy: false, - canDrop: false, - text: t('foodCandyWhite'), - target: 'White', - article: '' - }, - Candy_Golden: { - canBuy: false, - canDrop: false, - text: t('foodCandyGolden'), - target: 'Golden', - article: '' - }, - Candy_Zombie: { - canBuy: false, - canDrop: false, - text: t('foodCandyZombie'), - target: 'Zombie', - article: '' - }, - Candy_Desert: { - canBuy: false, - canDrop: false, - text: t('foodCandyDesert'), - target: 'Desert', - article: '' - }, - Candy_Red: { - canBuy: false, - canDrop: false, - text: t('foodCandyRed'), - target: 'Red', - article: '' - } -}; - -_.each(api.food, function(food, key) { - return _.defaults(food, { - value: 1, - key: key, - notes: t('foodNotes') - }); -}); - -api.quests = { - dilatory: { - text: t("questDilatoryText"), - notes: t("questDilatoryNotes"), - completion: t("questDilatoryCompletion"), - value: 0, - canBuy: false, - 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: { - text: t("questStressbeastText"), - notes: t("questStressbeastNotes"), - completion: t("questStressbeastCompletion"), - completionChat: t("questStressbeastCompletionChat"), - value: 0, - canBuy: false, - 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 - } - }, - evilsanta: { - canBuy: false, - text: t('questEvilSantaText'), - notes: t('questEvilSantaNotes'), - completion: t('questEvilSantaCompletion'), - value: 4, - boss: { - name: t('questEvilSantaBoss'), - hp: 300, - str: 1 - }, - drop: { - items: [ - { - type: 'mounts', - key: 'BearCub-Polar', - text: t('questEvilSantaDropBearCubPolarMount') - } - ], - gp: 20, - exp: 100 - } - }, - evilsanta2: { - canBuy: false, - text: t('questEvilSanta2Text'), - notes: t('questEvilSanta2Notes'), - completion: t('questEvilSanta2Completion'), - value: 4, - previous: 'evilsanta', - 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 - } - }, - gryphon: { - text: t('questGryphonText'), - notes: t('questGryphonNotes'), - completion: t('questGryphonCompletion'), - value: 4, - boss: { - name: t('questGryphonBoss'), - hp: 300, - str: 1.5 - }, - drop: { - items: [ - { - type: 'eggs', - key: 'Gryphon', - text: t('questGryphonDropGryphonEgg') - }, { - type: 'eggs', - key: 'Gryphon', - text: t('questGryphonDropGryphonEgg') - }, { - type: 'eggs', - key: 'Gryphon', - text: t('questGryphonDropGryphonEgg') - } - ], - gp: 25, - exp: 125 - } - }, - hedgehog: { - text: t('questHedgehogText'), - notes: t('questHedgehogNotes'), - completion: t('questHedgehogCompletion'), - value: 4, - boss: { - name: t('questHedgehogBoss'), - hp: 400, - str: 1.25 - }, - drop: { - items: [ - { - type: 'eggs', - key: 'Hedgehog', - text: t('questHedgehogDropHedgehogEgg') - }, { - type: 'eggs', - key: 'Hedgehog', - text: t('questHedgehogDropHedgehogEgg') - }, { - type: 'eggs', - key: 'Hedgehog', - text: t('questHedgehogDropHedgehogEgg') - } - ], - gp: 30, - exp: 125 - } - }, - ghost_stag: { - text: t('questGhostStagText'), - notes: t('questGhostStagNotes'), - completion: t('questGhostStagCompletion'), - value: 4, - boss: { - name: t('questGhostStagBoss'), - 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 - } - }, - vice1: { - text: t('questVice1Text'), - notes: t('questVice1Notes'), - value: 4, - lvl: 30, - boss: { - name: t('questVice1Boss'), - hp: 750, - str: 1.5 - }, - drop: { - items: [ - { - type: 'quests', - key: "vice2", - text: t('questVice1DropVice2Quest') - } - ], - gp: 20, - exp: 100 - } - }, - vice2: { - text: t('questVice2Text'), - notes: t('questVice2Notes'), - value: 4, - lvl: 35, - previous: 'vice1', - collect: { - lightCrystal: { - text: t('questVice2CollectLightCrystal'), - count: 45 - } - }, - drop: { - items: [ - { - type: 'quests', - key: 'vice3', - text: t('questVice2DropVice3Quest') - } - ], - gp: 20, - exp: 75 - } - }, - vice3: { - text: t('questVice3Text'), - notes: t('questVice3Notes'), - completion: t('questVice3Completion'), - previous: 'vice2', - value: 4, - lvl: 40, - boss: { - name: t('questVice3Boss'), - 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 - } - }, - egg: { - text: t('questEggHuntText'), - notes: t('questEggHuntNotes'), - completion: t('questEggHuntCompletion'), - value: 1, - canBuy: false, - 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 - } - }, - rat: { - text: t('questRatText'), - notes: t('questRatNotes'), - completion: t('questRatCompletion'), - value: 4, - boss: { - name: t('questRatBoss'), - hp: 1200, - str: 2.5 - }, - drop: { - items: [ - { - type: 'eggs', - key: 'Rat', - text: t('questRatDropRatEgg') - }, { - type: 'eggs', - key: 'Rat', - text: t('questRatDropRatEgg') - }, { - type: 'eggs', - key: 'Rat', - text: t('questRatDropRatEgg') - } - ], - gp: 80, - exp: 800 - } - }, - octopus: { - text: t('questOctopusText'), - notes: t('questOctopusNotes'), - completion: t('questOctopusCompletion'), - value: 4, - boss: { - name: t('questOctopusBoss'), - hp: 1200, - str: 2.5 - }, - drop: { - items: [ - { - type: 'eggs', - key: 'Octopus', - text: t('questOctopusDropOctopusEgg') - }, { - type: 'eggs', - key: 'Octopus', - text: t('questOctopusDropOctopusEgg') - }, { - type: 'eggs', - key: 'Octopus', - text: t('questOctopusDropOctopusEgg') - } - ], - gp: 80, - exp: 800 - } - }, - dilatory_derby: { - text: t('questSeahorseText'), - notes: t('questSeahorseNotes'), - completion: t('questSeahorseCompletion'), - value: 4, - 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 - } - }, - atom1: { - text: t('questAtom1Text'), - notes: t('questAtom1Notes'), - value: 4, - lvl: 15, - collect: { - soapBars: { - text: t('questAtom1CollectSoapBars'), - count: 20 - } - }, - drop: { - items: [ - { - type: 'quests', - key: "atom2", - text: t('questAtom1Drop') - } - ], - gp: 7, - exp: 50 - } - }, - atom2: { - text: t('questAtom2Text'), - notes: t('questAtom2Notes'), - previous: 'atom1', - value: 4, - lvl: 15, - boss: { - name: t('questAtom2Boss'), - hp: 300, - str: 1 - }, - drop: { - items: [ - { - type: 'quests', - key: "atom3", - text: t('questAtom2Drop') - } - ], - gp: 20, - exp: 100 - } - }, - atom3: { - text: t('questAtom3Text'), - notes: t('questAtom3Notes'), - previous: 'atom2', - completion: t('questAtom3Completion'), - value: 4, - lvl: 15, - boss: { - name: t('questAtom3Boss'), - 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 - } - }, - harpy: { - text: t('questHarpyText'), - notes: t('questHarpyNotes'), - completion: t('questHarpyCompletion'), - value: 4, - boss: { - name: t('questHarpyBoss'), - 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: { - text: t('questRoosterText'), - notes: t('questRoosterNotes'), - completion: t('questRoosterCompletion'), - value: 4, - boss: { - name: t('questRoosterBoss'), - hp: 300, - str: 1.5 - }, - drop: { - items: [ - { - type: 'eggs', - key: 'Rooster', - text: t('questRoosterDropRoosterEgg') - }, { - type: 'eggs', - key: 'Rooster', - text: t('questRoosterDropRoosterEgg') - }, { - type: 'eggs', - key: 'Rooster', - text: t('questRoosterDropRoosterEgg') - } - ], - gp: 25, - exp: 125 - } - }, - spider: { - text: t('questSpiderText'), - notes: t('questSpiderNotes'), - completion: t('questSpiderCompletion'), - value: 4, - boss: { - name: t('questSpiderBoss'), - hp: 400, - str: 1.5 - }, - drop: { - items: [ - { - type: 'eggs', - key: 'Spider', - text: t('questSpiderDropSpiderEgg') - }, { - type: 'eggs', - key: 'Spider', - text: t('questSpiderDropSpiderEgg') - }, { - type: 'eggs', - key: 'Spider', - text: t('questSpiderDropSpiderEgg') - } - ], - gp: 31, - exp: 200 - } - }, - moonstone1: { - text: t('questMoonstone1Text'), - notes: t('questMoonstone1Notes'), - value: 4, - lvl: 60, - collect: { - moonstone: { - text: t('questMoonstone1CollectMoonstone'), - count: 500 - } - }, - drop: { - items: [ - { - type: 'quests', - key: "moonstone2", - text: t('questMoonstone1DropMoonstone2Quest') - } - ], - gp: 50, - exp: 100 - } - }, - moonstone2: { - text: t('questMoonstone2Text'), - notes: t('questMoonstone2Notes'), - value: 4, - lvl: 65, - previous: 'moonstone1', - boss: { - name: t('questMoonstone2Boss'), - hp: 1500, - str: 3 - }, - drop: { - items: [ - { - type: 'quests', - key: 'moonstone3', - text: t('questMoonstone2DropMoonstone3Quest') - } - ], - gp: 500, - exp: 1000 - } - }, - moonstone3: { - text: t('questMoonstone3Text'), - notes: t('questMoonstone3Notes'), - completion: t('questMoonstone3Completion'), - previous: 'moonstone2', - value: 4, - lvl: 70, - boss: { - name: t('questMoonstone3Boss'), - 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 - } - }, - goldenknight1: { - text: t('questGoldenknight1Text'), - notes: t('questGoldenknight1Notes'), - value: 4, - lvl: 40, - collect: { - testimony: { - text: t('questGoldenknight1CollectTestimony'), - count: 300 - } - }, - drop: { - items: [ - { - type: 'quests', - key: "goldenknight2", - text: t('questGoldenknight1DropGoldenknight2Quest') - } - ], - gp: 15, - exp: 120 - } - }, - goldenknight2: { - text: t('questGoldenknight2Text'), - notes: t('questGoldenknight2Notes'), - value: 4, - previous: 'goldenknight1', - lvl: 45, - boss: { - name: t('questGoldenknight2Boss'), - hp: 1000, - str: 3 - }, - drop: { - items: [ - { - type: 'quests', - key: 'goldenknight3', - text: t('questGoldenknight2DropGoldenknight3Quest') - } - ], - gp: 75, - exp: 750 - } - }, - goldenknight3: { - text: t('questGoldenknight3Text'), - notes: t('questGoldenknight3Notes'), - completion: t('questGoldenknight3Completion'), - previous: 'goldenknight2', - value: 4, - lvl: 50, - boss: { - name: t('questGoldenknight3Boss'), - 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 - } - }, - basilist: { - text: t('questBasilistText'), - notes: t('questBasilistNotes'), - completion: t('questBasilistCompletion'), - canBuy: false, - value: 4, - boss: { - name: t('questBasilistBoss'), - hp: 100, - str: 0.5 - }, - drop: { - gp: 8, - exp: 42 - } - }, - owl: { - text: t('questOwlText'), - notes: t('questOwlNotes'), - completion: t('questOwlCompletion'), - value: 4, - boss: { - name: t('questOwlBoss'), - hp: 500, - str: 1.5 - }, - drop: { - items: [ - { - type: 'eggs', - key: 'Owl', - text: t('questOwlDropOwlEgg') - }, { - type: 'eggs', - key: 'Owl', - text: t('questOwlDropOwlEgg') - }, { - type: 'eggs', - key: 'Owl', - text: t('questOwlDropOwlEgg') - } - ], - gp: 37, - exp: 275 - } - }, - penguin: { - text: t('questPenguinText'), - notes: t('questPenguinNotes'), - completion: t('questPenguinCompletion'), - value: 4, - boss: { - name: t('questPenguinBoss'), - hp: 400, - str: 1.5 - }, - drop: { - items: [ - { - type: 'eggs', - key: 'Penguin', - text: t('questPenguinDropPenguinEgg') - }, { - type: 'eggs', - key: 'Penguin', - text: t('questPenguinDropPenguinEgg') - }, { - type: 'eggs', - key: 'Penguin', - text: t('questPenguinDropPenguinEgg') - } - ], - gp: 31, - exp: 200 - } - }, - trex: { - text: t('questTRexText'), - notes: t('questTRexNotes'), - completion: t('questTRexCompletion'), - value: 4, - 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 - } - }, - trex_undead: { - text: t('questTRexUndeadText'), - notes: t('questTRexUndeadNotes'), - completion: t('questTRexUndeadCompletion'), - value: 4, - 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 - } - } -}; - -_.each(api.quests, function(v, key) { - var b; - _.defaults(v, { - key: key, - canBuy: true - }); - b = v.boss; - if (b) { - _.defaults(b, { - str: 1, - def: 1 - }); - if (b.rage) { - return _.defaults(b.rage, { - title: t('bossRageTitle'), - description: t('bossRageDescription') - }); - } - } -}); - -api.backgrounds = { - backgrounds062014: { - beach: { - text: t('backgroundBeachText'), - notes: t('backgroundBeachNotes') - }, - fairy_ring: { - text: t('backgroundFairyRingText'), - notes: t('backgroundFairyRingNotes') - }, - forest: { - text: t('backgroundForestText'), - notes: t('backgroundForestNotes') - } - }, - backgrounds072014: { - open_waters: { - text: t('backgroundOpenWatersText'), - notes: t('backgroundOpenWatersNotes') - }, - coral_reef: { - text: t('backgroundCoralReefText'), - notes: t('backgroundCoralReefNotes') - }, - seafarer_ship: { - text: t('backgroundSeafarerShipText'), - notes: t('backgroundSeafarerShipNotes') - } - }, - backgrounds082014: { - volcano: { - text: t('backgroundVolcanoText'), - notes: t('backgroundVolcanoNotes') - }, - clouds: { - text: t('backgroundCloudsText'), - notes: t('backgroundCloudsNotes') - }, - dusty_canyons: { - text: t('backgroundDustyCanyonsText'), - notes: t('backgroundDustyCanyonsNotes') - } - }, - backgrounds092014: { - thunderstorm: { - text: t('backgroundThunderstormText'), - notes: t('backgroundThunderstormNotes') - }, - autumn_forest: { - text: t('backgroundAutumnForestText'), - notes: t('backgroundAutumnForestNotes') - }, - harvest_fields: { - text: t('backgroundHarvestFieldsText'), - notes: t('backgroundHarvestFieldsNotes') - } - }, - backgrounds102014: { - graveyard: { - text: t('backgroundGraveyardText'), - notes: t('backgroundGraveyardNotes') - }, - haunted_house: { - text: t('backgroundHauntedHouseText'), - notes: t('backgroundHauntedHouseNotes') - }, - pumpkin_patch: { - text: t('backgroundPumpkinPatchText'), - notes: t('backgroundPumpkinPatchNotes') - } - }, - backgrounds112014: { - harvest_feast: { - text: t('backgroundHarvestFeastText'), - notes: t('backgroundHarvestFeastNotes') - }, - sunset_meadow: { - text: t('backgroundSunsetMeadowText'), - notes: t('backgroundSunsetMeadowNotes') - }, - starry_skies: { - text: t('backgroundStarrySkiesText'), - notes: t('backgroundStarrySkiesNotes') - } - }, - backgrounds122014: { - iceberg: { - text: t('backgroundIcebergText'), - notes: t('backgroundIcebergNotes') - }, - twinkly_lights: { - text: t('backgroundTwinklyLightsText'), - notes: t('backgroundTwinklyLightsNotes') - }, - south_pole: { - text: t('backgroundSouthPoleText'), - notes: t('backgroundSouthPoleNotes') - } - }, - backgrounds012015: { - ice_cave: { - text: t('backgroundIceCaveText'), - notes: t('backgroundIceCaveNotes') - }, - frigid_peak: { - text: t('backgroundFrigidPeakText'), - notes: t('backgroundFrigidPeakNotes') - }, - snowy_pines: { - text: t('backgroundSnowyPinesText'), - notes: t('backgroundSnowyPinesNotes') - } - }, - backgrounds022015: { - blacksmithy: { - text: t('backgroundBlacksmithyText'), - notes: t('backgroundBlacksmithyNotes') - }, - crystal_cave: { - text: t('backgroundCrystalCaveText'), - notes: t('backgroundCrystalCaveNotes') - }, - distant_castle: { - text: t('backgroundDistantCastleText'), - notes: t('backgroundDistantCastleNotes') - } - } -}; - -api.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(api.subscriptionBlocks, function(b, k) { - return b.key = k; -}); - -repeat = { - m: true, - t: true, - w: true, - th: true, - f: true, - s: true, - su: true -}; - -api.userDefaults = { - habits: [ - { - type: 'habit', - text: t('defaultHabit1Text'), - notes: t('defaultHabit1Notes'), - value: 0, - up: true, - down: false, - attribute: 'per' - }, { - type: 'habit', - text: t('defaultHabit2Text'), - notes: t('defaultHabit2Notes'), - value: 0, - up: false, - down: true, - attribute: 'con' - }, { - type: 'habit', - text: t('defaultHabit3Text'), - notes: t('defaultHabit3Notes'), - value: 0, - up: true, - down: true, - attribute: 'str' - } - ], - dailys: [ - { - type: 'daily', - text: t('defaultDaily1Text'), - notes: t('defaultDaily1Notes'), - value: 0, - completed: false, - repeat: repeat, - attribute: 'per' - }, { - type: 'daily', - text: t('defaultDaily2Text'), - notes: t('defaultDaily2Notes'), - value: 3, - completed: false, - repeat: repeat, - attribute: 'con' - }, { - type: 'daily', - text: t('defaultDaily3Text'), - notes: t('defaultDaily3Notes'), - value: -10, - completed: false, - repeat: repeat, - attribute: 'int' - }, { - type: 'daily', - text: t('defaultDaily4Text'), - notes: t('defaultDaily4Notes'), - checklist: [ - { - completed: true, - text: t('defaultDaily4Checklist1') - }, { - completed: false, - text: t('defaultDaily4Checklist2') - }, { - completed: false, - text: t('defaultDaily4Checklist3') - } - ], - completed: false, - repeat: repeat, - attribute: 'str' - } - ], - todos: [ - { - type: 'todo', - text: t('defaultTodo1Text'), - notes: t('defaultTodoNotes'), - completed: false, - attribute: 'int' - }, { - type: 'todo', - text: t('defaultTodo2Text'), - notes: t('defaultTodoNotes'), - checklist: [ - { - completed: false, - text: t('defaultTodo2Checklist1') - }, { - completed: false, - text: t('defaultTodo2Checklist2') - }, { - completed: false, - text: t('defaultTodo2Checklist3') - } - ], - completed: false, - attribute: 'per' - }, { - type: 'todo', - text: t('defaultTodo3Text'), - notes: t('defaultTodoNotes'), - checklist: [ - { - completed: false, - text: t('defaultTodo3Checklist1') - }, { - completed: false, - text: t('defaultTodo3Checklist2') - }, { - completed: false, - text: t('defaultTodo3Checklist3') - } - ], - completed: false, - attribute: 'per' - }, { - type: 'todo', - text: t('defaultTodo4Text'), - notes: t('defaultTodoNotes'), - checklist: [ - { - completed: false, - text: t('defaultTodo4Checklist1') - }, { - completed: false, - text: t('defaultTodo4Checklist2') - }, { - completed: false, - text: t('defaultTodo4Checklist3') - } - ], - completed: false, - attribute: 'per' - }, { - type: 'todo', - text: t('defaultTodo5Text'), - notes: t('defaultTodoNotes'), - completed: false, - attribute: 'per' - } - ], - rewards: [ - { - type: 'reward', - text: t('defaultReward1Text'), - notes: t('defaultReward1Notes'), - value: 20 - }, { - type: 'reward', - text: t('defaultReward2Text'), - notes: t('defaultReward2Notes'), - value: 10 - } - ], - tags: [ - { - name: t('defaultTag1') - }, { - name: t('defaultTag2') - }, { - name: t('defaultTag3') - } - ] -}; - - -},{"./i18n.coffee":3,"lodash":6,"moment":7}],3:[function(require,module,exports){ -var _; - -_ = require('lodash'); - -module.exports = { - strings: null, - translations: {}, - t: function(stringName) { - var 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'; - } - string = !module.exports.strings ? module.exports.translations[locale][stringName] : module.exports.strings[stringName]; - if (string) { - try { - return _.template(string, vars || {}); - } catch (_error) { - e = _error; - return 'Error processing string. Please report to http://github.com/HabitRPG/habitrpg.'; - } - } else { - stringNotFound = !module.exports.strings ? module.exports.translations[locale].stringNotFound : module.exports.strings.stringNotFound; - try { - return _.template(stringNotFound, { - string: stringName - }); - } catch (_error) { - e = _error; - return 'Error processing string. Please report to http://github.com/HabitRPG/habitrpg.'; - } - } - } -}; - - -},{"lodash":6}],4:[function(require,module,exports){ -(function (process){ -var $w, api, content, i18n, moment, preenHistory, sanitizeOptions, sortOrder, _, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - -moment = require('moment'); - -_ = require('lodash'); - -content = require('./content.coffee'); - -i18n = require('./i18n.coffee'); - -api = module.exports = {}; - -api.i18n = i18n; - -$w = api.$w = function(s) { - return s.split(' '); -}; - -api.dotSet = function(obj, path, val) { - var arr; - arr = path.split('.'); - return _.reduce(arr, (function(_this) { - return function(curr, next, index) { - if ((arr.length - 1) === index) { - curr[next] = val; - } - return curr[next] != null ? curr[next] : curr[next] = {}; - }; - })(this), obj); -}; - -api.dotGet = function(obj, path) { - return _.reduce(path.split('.'), ((function(_this) { - return function(curr, next) { - return curr != null ? curr[next] : void 0; - }; - })(this)), obj); -}; - - -/* - Reflists are arrays, but stored as objects. Mongoose has a helluvatime working with arrays (the main problem for our - syncing issues) - so the goal is to move away from arrays to objects, since mongoose can reference elements by ID - no problem. To maintain sorting, we use these helper functions: - */ - -api.refPush = function(reflist, item, prune) { - if (prune == null) { - prune = 0; - } - item.sort = _.isEmpty(reflist) ? 0 : _.max(reflist, 'sort').sort + 1; - if (!(item.id && !reflist[item.id])) { - item.id = api.uuid(); - } - return reflist[item.id] = item; -}; - -api.planGemLimits = { - convRate: 20, - convCap: 25 -}; - - -/* - ------------------------------------------------------ - Time / Day - ------------------------------------------------------ - */ - - -/* - Each time we're performing date math (cron, task-due-days, etc), we need to take user preferences into consideration. - Specifically {dayStart} (custom day start) and {timezoneOffset}. This function sanitizes / defaults those values. - {now} is also passed in for various purposes, one example being the test scripts scripts testing different "now" times - */ - -sanitizeOptions = function(o) { - var dayStart, now, timezoneOffset, _ref; - dayStart = !_.isNaN(+o.dayStart) && (0 <= (_ref = +o.dayStart) && _ref <= 24) ? +o.dayStart : 0; - timezoneOffset = o.timezoneOffset ? +o.timezoneOffset : +moment().zone(); - now = o.now ? moment(o.now).zone(timezoneOffset) : moment(+(new Date)).zone(timezoneOffset); - return { - dayStart: dayStart, - timezoneOffset: timezoneOffset, - now: now - }; -}; - -api.startOfWeek = api.startOfWeek = function(options) { - var o; - if (options == null) { - options = {}; - } - o = sanitizeOptions(options); - return moment(o.now).startOf('week'); -}; - -api.startOfDay = function(options) { - var dayStart, o; - if (options == null) { - options = {}; - } - o = sanitizeOptions(options); - dayStart = moment(o.now).startOf('day').add({ - hours: o.dayStart - }); - if (moment(o.now).hour() < o.dayStart) { - dayStart.subtract({ - days: 1 - }); - } - return dayStart; -}; - -api.dayMapping = { - 0: 'su', - 1: 'm', - 2: 't', - 3: 'w', - 4: 'th', - 5: 'f', - 6: 's' -}; - - -/* - Absolute diff from "yesterday" till now - */ - -api.daysSince = function(yesterday, options) { - var o; - if (options == null) { - options = {}; - } - o = sanitizeOptions(options); - return Math.abs(api.startOfDay(_.defaults({ - now: yesterday - }, o)).diff(api.startOfDay(_.defaults({ - now: o.now - }, o)), 'days')); -}; - - -/* - Should the user do this taks on this date, given the task's repeat options and user.preferences.dayStart? - */ - -api.shouldDo = function(day, repeat, options) { - var o, selected; - if (options == null) { - options = {}; - } - if (!repeat) { - return false; - } - o = sanitizeOptions(options); - selected = repeat[api.dayMapping[api.startOfDay(_.defaults({ - now: day - }, o)).day()]]; - return selected; -}; - - -/* - ------------------------------------------------------ - Scoring - ------------------------------------------------------ - */ - -api.tnl = function(lvl) { - return Math.round(((Math.pow(lvl, 2) * 0.25) + (10 * lvl) + 139.75) / 10) * 10; -}; - - -/* - A hyperbola function that creates diminishing returns, so you can't go to infinite (eg, with Exp gain). - {max} The asymptote - {bonus} All the numbers combined for your point bonus (eg, task.value * user.stats.int * critChance, etc) - {halfway} (optional) the point at which the graph starts bending - */ - -api.diminishingReturns = function(bonus, max, halfway) { - if (halfway == null) { - halfway = max / 2; - } - return max * (bonus / (bonus + halfway)); -}; - -api.monod = function(bonus, rateOfIncrease, max) { - return rateOfIncrease * max * bonus / (rateOfIncrease * bonus + max); -}; - - -/* -Preen history for users with > 7 history entries -This takes an infinite array of single day entries [day day day day day...], and turns it into a condensed array -of averages, condensing more the further back in time we go. Eg, 7 entries each for last 7 days; 1 entry each week -of this month; 1 entry for each month of this year; 1 entry per previous year: [day*7 week*4 month*12 year*infinite] - */ - -preenHistory = function(history) { - var newHistory, preen, thisMonth; - history = _.filter(history, function(h) { - return !!h; - }); - newHistory = []; - preen = function(amount, groupBy) { - var groups; - groups = _.chain(history).groupBy(function(h) { - return moment(h.date).format(groupBy); - }).sortBy(function(h, k) { - return k; - }).value(); - groups = groups.slice(-amount); - groups.pop(); - return _.each(groups, function(group) { - newHistory.push({ - date: moment(group[0].date).toDate(), - value: _.reduce(group, (function(m, obj) { - return m + obj.value; - }), 0) / group.length - }); - return true; - }); - }; - preen(50, "YYYY"); - preen(moment().format('MM'), "YYYYMM"); - thisMonth = moment().format('YYYYMM'); - newHistory = newHistory.concat(_.filter(history, function(h) { - return moment(h.date).format('YYYYMM') === thisMonth; - })); - return newHistory; -}; - - -/* - Update the in-browser store with new gear. FIXME this was in user.fns, but it was causing strange issues there - */ - -sortOrder = _.reduce(content.gearTypes, (function(m, v, k) { - m[v] = k; - return m; -}), {}); - -api.updateStore = function(user) { - var changes; - if (!user) { - return; - } - changes = []; - _.each(content.gearTypes, function(type) { - var found; - found = _.find(content.gear.tree[type][user.stats["class"]], function(item) { - return !user.items.gear.owned[item.key]; - }); - if (found) { - changes.push(found); - } - return true; - }); - changes = changes.concat(_.filter(content.gear.flat, function(v) { - var _ref; - return ((_ref = v.klass) === 'special' || _ref === 'mystery') && !user.items.gear.owned[v.key] && (typeof v.canOwn === "function" ? v.canOwn(user) : void 0); - })); - changes.push(content.potion); - return _.sortBy(changes, function(c) { - return sortOrder[c.type]; - }); -}; - - -/* ------------------------------------------------------- -Content ------------------------------------------------------- - */ - -api.content = content; - - -/* ------------------------------------------------------- -Misc Helpers ------------------------------------------------------- - */ - -api.uuid = function() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { - var r, v; - r = Math.random() * 16 | 0; - v = (c === "x" ? r : r & 0x3 | 0x8); - return v.toString(16); - }); -}; - -api.countExists = function(items) { - return _.reduce(items, (function(m, v) { - return m + (v ? 1 : 0); - }), 0); -}; - - -/* -Even though Mongoose handles task defaults, we want to make sure defaults are set on the client-side before -sending up to the server for performance - */ - -api.taskDefaults = function(task) { - var defaults, _ref, _ref1, _ref2; - if (task == null) { - task = {}; - } - if (!(task.type && ((_ref = task.type) === 'habit' || _ref === 'daily' || _ref === 'todo' || _ref === 'reward'))) { - task.type = 'habit'; - } - defaults = { - id: api.uuid(), - text: task.id != null ? task.id : '', - notes: '', - priority: 1, - challenge: {}, - attribute: 'str', - dateCreated: new Date() - }; - _.defaults(task, defaults); - if (task.type === 'habit') { - _.defaults(task, { - up: true, - down: true - }); - } - if ((_ref1 = task.type) === 'habit' || _ref1 === 'daily') { - _.defaults(task, { - history: [] - }); - } - if ((_ref2 = task.type) === 'daily' || _ref2 === 'todo') { - _.defaults(task, { - completed: false - }); - } - if (task.type === 'daily') { - _.defaults(task, { - streak: 0, - repeat: { - su: 1, - m: 1, - t: 1, - w: 1, - th: 1, - f: 1, - s: 1 - } - }); - } - task._id = task.id; - if (task.value == null) { - task.value = task.type === 'reward' ? 10 : 0; - } - if (!_.isNumber(task.priority)) { - task.priority = 1; - } - return task; -}; - -api.percent = function(x, y, dir) { - var roundFn; - switch (dir) { - case "up": - roundFn = Math.ceil; - break; - case "down": - roundFn = Math.floor; - break; - default: - roundFn = Math.round; - } - if (x === 0) { - x = 1; - } - return Math.max(0, roundFn(x / y * 100)); -}; - - -/* -Remove whitespace #FIXME are we using this anywwhere? Should we be? - */ - -api.removeWhitespace = function(str) { - if (!str) { - return ''; - } - return str.replace(/\s/g, ''); -}; - - -/* -Encode the download link for .ics iCal file - */ - -api.encodeiCalLink = function(uid, apiToken) { - var loc, _ref; - loc = (typeof window !== "undefined" && window !== null ? window.location.host : void 0) || (typeof process !== "undefined" && process !== null ? (_ref = process.env) != null ? _ref.BASE_URL : void 0 : void 0) || ''; - return encodeURIComponent("http://" + loc + "/v1/users/" + uid + "/calendar.ics?apiToken=" + apiToken); -}; - - -/* -Gold amount from their money - */ - -api.gold = function(num) { - if (num) { - return Math.floor(num); - } else { - return "0"; - } -}; - - -/* -Silver amount from their money - */ - -api.silver = function(num) { - if (num) { - return ("0" + Math.floor((num - Math.floor(num)) * 100)).slice(-2); - } else { - return "00"; - } -}; - - -/* -Task classes given everything about the class - */ - -api.taskClasses = function(task, filters, dayStart, lastCron, showCompleted, main) { - var classes, completed, enabled, filter, repeat, type, value, _ref; - if (filters == null) { - filters = []; - } - if (dayStart == null) { - dayStart = 0; - } - if (lastCron == null) { - lastCron = +(new Date); - } - if (showCompleted == null) { - showCompleted = false; - } - if (main == null) { - main = false; - } - if (!task) { - return; - } - type = task.type, completed = task.completed, value = task.value, repeat = task.repeat; - if (main) { - if (!task._editing) { - for (filter in filters) { - enabled = filters[filter]; - if (enabled && !((_ref = task.tags) != null ? _ref[filter] : void 0)) { - return 'hidden'; - } - } - } - } - classes = type; - if (task._editing) { - classes += " beingEdited"; - } - if (type === 'todo' || type === 'daily') { - if (completed || (type === 'daily' && !api.shouldDo(+(new Date), task.repeat, { - dayStart: dayStart - }))) { - classes += " completed"; - } else { - classes += " uncompleted"; - } - } else if (type === 'habit') { - if (task.down && task.up) { - classes += ' habit-wide'; - } - if (!task.down && !task.up) { - classes += ' habit-narrow'; - } - } - if (value < -20) { - classes += ' color-worst'; - } else if (value < -10) { - classes += ' color-worse'; - } else if (value < -1) { - classes += ' color-bad'; - } else if (value < 1) { - classes += ' color-neutral'; - } else if (value < 5) { - classes += ' color-good'; - } else if (value < 10) { - classes += ' color-better'; - } else { - classes += ' color-best'; - } - return classes; -}; - - -/* -Friendly timestamp - */ - -api.friendlyTimestamp = function(timestamp) { - return moment(timestamp).format('MM/DD h:mm:ss a'); -}; - - -/* -Does user have new chat messages? - */ - -api.newChatMessages = function(messages, lastMessageSeen) { - if (!((messages != null ? messages.length : void 0) > 0)) { - return false; - } - return (messages != null ? messages[0] : void 0) && (messages[0].id !== lastMessageSeen); -}; - - -/* -are any tags active? - */ - -api.noTags = function(tags) { - return _.isEmpty(tags) || _.isEmpty(_.filter(tags, function(t) { - return t; - })); -}; - - -/* -Are there tags applied? - */ - -api.appliedTags = function(userTags, taskTags) { - var arr; - arr = []; - _.each(userTags, function(t) { - if (t == null) { - return; - } - if (taskTags != null ? taskTags[t.id] : void 0) { - return arr.push(t.name); - } - }); - return arr.join(', '); -}; - -api.countPets = function(originalCount, pets) { - var count, pet; - count = originalCount != null ? originalCount : _.size(pets); - for (pet in content.questPets) { - if (pets[pet]) { - count--; - } - } - for (pet in content.specialPets) { - if (pets[pet]) { - count--; - } - } - return count; -}; - -api.countMounts = function(originalCount, mounts) { - var count2, mount; - count2 = originalCount != null ? originalCount : _.size(mounts); - for (mount in content.questPets) { - if (mounts[mount]) { - count2--; - } - } - for (mount in content.specialMounts) { - if (mounts[mount]) { - count2--; - } - } - return count2; -}; - -api.countTriad = function(pets) { - var count3, egg, potion; - count3 = 0; - for (egg in content.dropEggs) { - for (potion in content.hatchingPotions) { - if (pets[egg + "-" + potion] > 0) { - count3++; - } - } - } - return count3; -}; - - -/* ------------------------------------------------------- -User (prototype wrapper to give it ops, helper funcs, and virtuals ------------------------------------------------------- - */ - - -/* -User is now wrapped (both on client and server), adding a few new properties: - * getters (_statsComputed, tasks, etc) - * user.fns, which is a bunch of helper functions - These were originally up above, but they make more sense belonging to the user object so we don't have to pass - the user object all over the place. In fact, we should pull in more functions such as cron(), updateStats(), etc. - * user.ops, which is super important: - -If a function is inside user.ops, it has magical properties. If you call it on the client it updates the user object in -the browser and when it's done it automatically POSTs to the server, calling src/controllers/user.js#OP_NAME (the exact same name -of the op function). The first argument req is {query, body, params}, it's what the express controller function -expects. This means we call our functions as if we were calling an Express route. Eg, instead of score(task, direction), -we call score({params:{id:task.id,direction:direction}}). This also forces us to think about our routes (whether to use -params, query, or body for variables). see http://stackoverflow.com/questions/4024271/rest-api-best-practices-where-to-put-parameters - -If `src/controllers/user.js#OP_NAME` doesn't exist on the server, it's automatically added. It runs the code in user.ops.OP_NAME -to update the user model server-side, then performs `user.save()`. You can see this in action for `user.ops.buy`. That -function doesn't exist on the server - so the client calls it, it updates user in the browser, auto-POSTs to server, server -handles it by calling `user.ops.buy` again (to update user on the server), and then saves. We can do this for -everything that doesn't need any code difference from what's in user.ops.OP_NAME for special-handling server-side. If we -*do* need special handling, just add `src/controllers/user.js#OP_NAME` to override the user.ops.OP_NAME, and be -sure to call user.ops.OP_NAME at some point within the overridden function. - -TODO - * Is this the best way to wrap the user object? I thought of using user.prototype, but user is an object not a Function. - user on the server is a Mongoose model, so we can use prototype - but to do it on the client, we'd probably have to - move to $resource for user - * Move to $resource! - */ - -api.wrap = function(user, main) { - if (main == null) { - main = true; - } - if (user._wrapped) { - return; - } - user._wrapped = true; - if (main) { - user.ops = { - update: function(req, cb) { - _.each(req.body, function(v, k) { - user.fns.dotSet(k, v); - return true; - }); - return typeof cb === "function" ? cb(null, user) : void 0; - }, - sleep: function(req, cb) { - user.preferences.sleep = !user.preferences.sleep; - return typeof cb === "function" ? cb(null, {}) : void 0; - }, - revive: function(req, cb) { - var cl, gearOwned, item, losableItems, lostItem, lostStat, _base; - if (!(user.stats.hp <= 0)) { - return typeof cb === "function" ? cb({ - code: 400, - message: "Cannot revive if not dead" - }) : void 0; - } - _.merge(user.stats, { - hp: 50, - exp: 0, - gp: 0 - }); - if (user.stats.lvl > 1) { - user.stats.lvl--; - } - lostStat = user.fns.randomVal(_.reduce(['str', 'con', 'per', 'int'], (function(m, k) { - if (user.stats[k]) { - m[k] = k; - } - return m; - }), {})); - if (lostStat) { - user.stats[lostStat]--; - } - cl = user.stats["class"]; - gearOwned = (typeof (_base = user.items.gear.owned).toObject === "function" ? _base.toObject() : void 0) || user.items.gear.owned; - losableItems = {}; - _.each(gearOwned, function(v, k) { - var itm; - if (v) { - itm = content.gear.flat['' + k]; - if (itm) { - if ((itm.value > 0 || k === 'weapon_warrior_0') && (itm.klass === cl || (itm.klass === 'special' && (!itm.specialClass || itm.specialClass === cl)))) { - return losableItems['' + k] = '' + k; - } - } - } - }); - lostItem = user.fns.randomVal(losableItems); - if (item = content.gear.flat[lostItem]) { - user.items.gear.owned[lostItem] = false; - if (user.items.gear.equipped[item.type] === lostItem) { - user.items.gear.equipped[item.type] = "" + item.type + "_base_0"; - } - if (user.items.gear.costume[item.type] === lostItem) { - user.items.gear.costume[item.type] = "" + item.type + "_base_0"; - } - } - if (typeof user.markModified === "function") { - user.markModified('items.gear'); - } - return typeof cb === "function" ? cb((item ? { - code: 200, - message: i18n.t('messageLostItem', { - itemText: item.text(req.language) - }, req.language) - } : null), user) : void 0; - }, - reset: function(req, cb) { - var gear; - user.habits = []; - user.dailys = []; - user.todos = []; - user.rewards = []; - user.stats.hp = 50; - user.stats.lvl = 1; - user.stats.gp = 0; - user.stats.exp = 0; - gear = user.items.gear; - _.each(['equipped', 'costume'], function(type) { - gear[type].armor = 'armor_base_0'; - gear[type].weapon = 'weapon_base_0'; - gear[type].head = 'head_base_0'; - return gear[type].shield = 'shield_base_0'; - }); - if (typeof gear.owned === 'undefined') { - gear.owned = {}; - } - _.each(gear.owned, function(v, k) { - if (gear.owned[k]) { - gear.owned[k] = false; - } - return true; - }); - gear.owned.weapon_warrior_0 = true; - if (typeof user.markModified === "function") { - user.markModified('items.gear.owned'); - } - user.preferences.costume = false; - return typeof cb === "function" ? cb(null, user) : void 0; - }, - reroll: function(req, cb, ga) { - if (user.balance < 1) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } - user.balance--; - _.each(user.tasks, function(task) { - if (task.type !== 'reward') { - return task.value = 0; - } - }); - user.stats.hp = 50; - if (typeof cb === "function") { - cb(null, user); - } - return ga != null ? ga.event('purchase', 'reroll').send() : void 0; - }, - rebirth: function(req, cb, ga) { - var flags, gear, lvl, stats; - if (user.balance < 2 && user.stats.lvl < 100) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } - if (user.stats.lvl < 100) { - user.balance -= 2; - } - if (user.stats.lvl < 100) { - lvl = user.stats.lvl; - } else { - lvl = 100; - } - _.each(user.tasks, function(task) { - if (task.type !== 'reward') { - task.value = 0; - } - if (task.type === 'daily') { - return task.streak = 0; - } - }); - stats = user.stats; - stats.buffs = {}; - stats.hp = 50; - stats.lvl = 1; - stats["class"] = 'warrior'; - _.each(['per', 'int', 'con', 'str', 'points', 'gp', 'exp', 'mp'], function(value) { - return stats[value] = 0; - }); - gear = user.items.gear; - _.each(['equipped', 'costume'], function(type) { - gear[type] = {}; - gear[type].armor = 'armor_base_0'; - gear[type].weapon = 'weapon_warrior_0'; - gear[type].head = 'head_base_0'; - return gear[type].shield = 'shield_base_0'; - }); - if (user.items.currentPet) { - user.ops.equip({ - params: { - type: 'pet', - key: user.items.currentPet - } - }); - } - if (user.items.currentMount) { - user.ops.equip({ - params: { - type: 'mount', - key: user.items.currentMount - } - }); - } - _.each(gear.owned, function(v, k) { - if (gear.owned[k]) { - gear.owned[k] = false; - return true; - } - }); - gear.owned.weapon_warrior_0 = true; - if (typeof user.markModified === "function") { - user.markModified('items.gear.owned'); - } - user.preferences.costume = false; - flags = user.flags; - if (!(user.achievements.ultimateGear || user.achievements.beastMaster)) { - flags.rebirthEnabled = false; - } - flags.itemsEnabled = false; - flags.dropsEnabled = false; - flags.classSelected = false; - flags.levelDrops = {}; - if (!user.achievements.rebirths) { - user.achievements.rebirths = 1; - user.achievements.rebirthLevel = lvl; - } else if (lvl > user.achievements.rebirthLevel || lvl === 100) { - user.achievements.rebirths++; - user.achievements.rebirthLevel = lvl; - } - user.stats.buffs = {}; - if (typeof cb === "function") { - cb(null, user); - } - return ga != null ? ga.event('purchase', 'Rebirth').send() : void 0; - }, - allocateNow: function(req, cb) { - _.times(user.stats.points, user.fns.autoAllocate); - user.stats.points = 0; - if (typeof user.markModified === "function") { - user.markModified('stats'); - } - return typeof cb === "function" ? cb(null, user.stats) : void 0; - }, - clearCompleted: function(req, cb) { - _.remove(user.todos, function(t) { - var _ref; - return t.completed && !((_ref = t.challenge) != null ? _ref.id : void 0); - }); - if (typeof user.markModified === "function") { - user.markModified('todos'); - } - return typeof cb === "function" ? cb(null, user.todos) : void 0; - }, - sortTask: function(req, cb) { - var from, id, movedTask, task, tasks, to, _ref; - id = req.params.id; - _ref = req.query, to = _ref.to, from = _ref.from; - task = user.tasks[id]; - if (!task) { - return typeof cb === "function" ? cb({ - code: 404, - message: i18n.t('messageTaskNotFound', req.language) - }) : void 0; - } - if (!((to != null) && (from != null))) { - return typeof cb === "function" ? cb('?to=__&from=__ are required') : void 0; - } - tasks = user["" + task.type + "s"]; - movedTask = tasks.splice(from, 1)[0]; - if (to === -1) { - tasks.push(movedTask); - } else { - tasks.splice(to, 0, movedTask); - } - return typeof cb === "function" ? cb(null, tasks) : void 0; - }, - updateTask: function(req, cb) { - var task, _ref; - if (!(task = user.tasks[(_ref = req.params) != null ? _ref.id : void 0])) { - return typeof cb === "function" ? cb({ - code: 404, - message: i18n.t('messageTaskNotFound', req.language) - }) : void 0; - } - _.merge(task, _.omit(req.body, ['checklist', 'id', 'type'])); - if (req.body.checklist) { - task.checklist = req.body.checklist; - } - if (typeof task.markModified === "function") { - task.markModified('tags'); - } - return typeof cb === "function" ? cb(null, task) : void 0; - }, - deleteTask: function(req, cb) { - var i, task, _ref; - task = user.tasks[(_ref = req.params) != null ? _ref.id : void 0]; - if (!task) { - return typeof cb === "function" ? cb({ - code: 404, - message: i18n.t('messageTaskNotFound', req.language) - }) : void 0; - } - i = user[task.type + "s"].indexOf(task); - if (~i) { - user[task.type + "s"].splice(i, 1); - } - return typeof cb === "function" ? cb(null, {}) : void 0; - }, - addTask: function(req, cb) { - var task; - task = api.taskDefaults(req.body); - user["" + task.type + "s"].unshift(task); - if (user.preferences.newTaskEdit) { - task._editing = true; - } - if (user.preferences.tagsCollapsed) { - task._tags = true; - } - if (user.preferences.advancedCollapsed) { - task._advanced = true; - } - if (typeof cb === "function") { - cb(null, task); - } - return task; - }, - addTag: function(req, cb) { - if (user.tags == null) { - user.tags = []; - } - user.tags.push({ - name: req.body.name, - id: req.body.id || api.uuid() - }); - return typeof cb === "function" ? cb(null, user.tags) : void 0; - }, - sortTag: function(req, cb) { - var from, to, _ref; - _ref = req.query, to = _ref.to, from = _ref.from; - if (!((to != null) && (from != null))) { - return typeof cb === "function" ? cb('?to=__&from=__ are required') : void 0; - } - user.tags.splice(to, 0, user.tags.splice(from, 1)[0]); - return typeof cb === "function" ? cb(null, user.tags) : void 0; - }, - updateTag: function(req, cb) { - var i, tid; - tid = req.params.id; - i = _.findIndex(user.tags, { - id: tid - }); - if (!~i) { - return typeof cb === "function" ? cb({ - code: 404, - message: i18n.t('messageTagNotFound', req.language) - }) : void 0; - } - user.tags[i].name = req.body.name; - return typeof cb === "function" ? cb(null, user.tags[i]) : void 0; - }, - deleteTag: function(req, cb) { - var i, tag, tid; - tid = req.params.id; - i = _.findIndex(user.tags, { - id: tid - }); - if (!~i) { - return typeof cb === "function" ? cb({ - code: 404, - message: i18n.t('messageTagNotFound', req.language) - }) : void 0; - } - tag = user.tags[i]; - delete user.filters[tag.id]; - user.tags.splice(i, 1); - _.each(user.tasks, function(task) { - return delete task.tags[tag.id]; - }); - _.each(['habits', 'dailys', 'todos', 'rewards'], function(type) { - return typeof user.markModified === "function" ? user.markModified(type) : void 0; - }); - return typeof cb === "function" ? cb(null, user.tags) : void 0; - }, - addWebhook: function(req, cb) { - var wh; - wh = user.preferences.webhooks; - api.refPush(wh, { - url: req.body.url, - enabled: req.body.enabled || true, - id: req.body.id - }); - if (typeof user.markModified === "function") { - user.markModified('preferences.webhooks'); - } - return typeof cb === "function" ? cb(null, user.preferences.webhooks) : void 0; - }, - updateWebhook: function(req, cb) { - _.merge(user.preferences.webhooks[req.params.id], req.body); - if (typeof user.markModified === "function") { - user.markModified('preferences.webhooks'); - } - return typeof cb === "function" ? cb(null, user.preferences.webhooks) : void 0; - }, - deleteWebhook: function(req, cb) { - delete user.preferences.webhooks[req.params.id]; - if (typeof user.markModified === "function") { - user.markModified('preferences.webhooks'); - } - return typeof cb === "function" ? cb(null, user.preferences.webhooks) : void 0; - }, - clearPMs: function(req, cb) { - user.inbox.messages = {}; - if (typeof user.markModified === "function") { - user.markModified('inbox.messages'); - } - return typeof cb === "function" ? cb(null, user.inbox.messages) : void 0; - }, - deletePM: function(req, cb) { - delete user.inbox.messages[req.params.id]; - if (typeof user.markModified === "function") { - user.markModified('inbox.messages.' + req.params.id); - } - return typeof cb === "function" ? cb(null, user.inbox.messages) : void 0; - }, - blockUser: function(req, cb) { - var i; - i = user.inbox.blocks.indexOf(req.params.uuid); - if (~i) { - user.inbox.blocks.splice(i, 1); - } else { - user.inbox.blocks.push(req.params.uuid); - } - if (typeof user.markModified === "function") { - user.markModified('inbox.blocks'); - } - return typeof cb === "function" ? cb(null, user.inbox.blocks) : void 0; - }, - feed: function(req, cb) { - var egg, evolve, food, message, pet, potion, userPets, _ref, _ref1, _ref2; - _ref = req.params, pet = _ref.pet, food = _ref.food; - food = content.food[food]; - _ref1 = pet.split('-'), egg = _ref1[0], potion = _ref1[1]; - userPets = user.items.pets; - if (!userPets[pet]) { - return typeof cb === "function" ? cb({ - code: 404, - message: i18n.t('messagePetNotFound', req.language) - }) : void 0; - } - if (!((_ref2 = user.items.food) != null ? _ref2[food.key] : void 0)) { - return typeof cb === "function" ? cb({ - code: 404, - message: i18n.t('messageFoodNotFound', req.language) - }) : void 0; - } - if (content.specialPets[pet] || (egg === "Egg")) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('messageCannotFeedPet', req.language) - }) : void 0; - } - if (user.items.mounts[pet]) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('messageAlreadyMount', req.language) - }) : void 0; - } - message = ''; - evolve = function() { - userPets[pet] = -1; - user.items.mounts[pet] = true; - if (pet === user.items.currentPet) { - user.items.currentPet = ""; - } - return message = i18n.t('messageEvolve', { - egg: egg - }, req.language); - }; - if (food.key === 'Saddle') { - evolve(); - } else { - if (food.target === potion) { - userPets[pet] += 5; - message = i18n.t('messageLikesFood', { - egg: egg, - foodText: food.text(req.language) - }, req.language); - } else { - userPets[pet] += 2; - message = i18n.t('messageDontEnjoyFood', { - egg: egg, - foodText: food.text(req.language) - }, req.language); - } - if (userPets[pet] >= 50 && !user.items.mounts[pet]) { - evolve(); - } - } - user.items.food[food.key]--; - return typeof cb === "function" ? cb({ - code: 200, - message: message - }, userPets[pet]) : void 0; - }, - buySpecialSpell: function(req, cb) { - var item, key, message, _base; - key = req.params.key; - item = content.special[key]; - if (user.stats.gp < item.value) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('messageNotEnoughGold', req.language) - }) : void 0; - } - user.stats.gp -= item.value; - if ((_base = user.items.special)[key] == null) { - _base[key] = 0; - } - user.items.special[key]++; - if (typeof user.markModified === "function") { - user.markModified('items.special'); - } - message = i18n.t('messageBought', { - itemText: item.text(req.language) - }, req.language); - return typeof cb === "function" ? cb({ - code: 200, - message: message - }, _.pick(user, $w('items stats'))) : void 0; - }, - purchase: function(req, cb, ga) { - var convCap, convRate, item, key, price, type, _ref, _ref1, _ref2, _ref3; - _ref = req.params, type = _ref.type, key = _ref.key; - if (type === 'gems' && key === 'gem') { - _ref1 = api.planGemLimits, convRate = _ref1.convRate, convCap = _ref1.convCap; - convCap += user.purchased.plan.consecutive.gemCapExtra; - if (!((_ref2 = user.purchased) != null ? (_ref3 = _ref2.plan) != null ? _ref3.customerId : void 0 : void 0)) { - return typeof cb === "function" ? cb({ - code: 401, - message: "Must subscribe to purchase gems with GP" - }, req) : void 0; - } - if (!(user.stats.gp >= convRate)) { - return typeof cb === "function" ? cb({ - code: 401, - message: "Not enough Gold" - }) : void 0; - } - if (user.purchased.plan.gemsBought >= convCap) { - return typeof cb === "function" ? cb({ - code: 401, - message: "You've reached the Gold=>Gem conversion cap (" + convCap + ") for this month. We have this to prevent abuse / farming. The cap will reset within the first three days of next month." - }) : void 0; - } - user.balance += .25; - user.purchased.plan.gemsBought++; - user.stats.gp -= convRate; - return typeof cb === "function" ? cb({ - code: 200, - message: "+1 Gems" - }, _.pick(user, $w('stats balance'))) : void 0; - } - if (type !== 'eggs' && type !== 'hatchingPotions' && type !== 'food' && type !== 'quests' && type !== 'gear') { - return typeof cb === "function" ? cb({ - code: 404, - message: ":type must be in [eggs,hatchingPotions,food,quests,gear]" - }, req) : void 0; - } - if (type === 'gear') { - item = content.gear.flat[key]; - if (user.items.gear.owned[key]) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('alreadyHave', req.language) - }) : void 0; - } - price = (item.twoHanded ? 2 : 1) / 4; - } else { - item = content[type][key]; - price = item.value / 4; - } - if (!item) { - return typeof cb === "function" ? cb({ - code: 404, - message: ":key not found for Content." + type - }, req) : void 0; - } - if (user.balance < price) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } - user.balance -= price; - if (type === 'gear') { - user.items.gear.owned[key] = true; - } else { - if (!(user.items[type][key] > 0)) { - user.items[type][key] = 0; - } - user.items[type][key]++; - } - if (typeof cb === "function") { - cb(null, _.pick(user, $w('items balance'))); - } - return ga != null ? ga.event('purchase', key).send() : void 0; - }, - releasePets: function(req, cb) { - var pet; - if (user.balance < 1) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } else { - user.balance--; - for (pet in content.pets) { - user.items.pets[pet] = 0; - } - if (!user.achievements.beastMasterCount) { - user.achievements.beastMasterCount = 0; - } - user.achievements.beastMasterCount++; - user.items.currentPet = ""; - } - return typeof cb === "function" ? cb(null, user) : void 0; - }, - releaseMounts: function(req, cb) { - var mount; - if (user.balance < 1) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } else { - user.balance -= 1; - user.items.currentMount = ""; - for (mount in content.pets) { - user.items.mounts[mount] = null; - } - if (!user.achievements.mountMasterCount) { - user.achievements.mountMasterCount = 0; - } - user.achievements.mountMasterCount++; - } - return typeof cb === "function" ? cb(null, user) : void 0; - }, - releaseBoth: function(req, cb) { - var animal, giveTriadBingo; - if (user.balance < 1.5) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } else { - giveTriadBingo = true; - user.balance -= 1.5; - user.items.currentMount = ""; - user.items.currentPet = ""; - for (animal in content.pets) { - if (user.items.pets[animal] === -1) { - giveTriadBingo = false; - } - user.items.pets[animal] = 0; - user.items.mounts[animal] = null; - } - if (!user.achievements.beastMasterCount) { - user.achievements.beastMasterCount = 0; - } - user.achievements.beastMasterCount++; - if (!user.achievements.mountMasterCount) { - user.achievements.mountMasterCount = 0; - } - user.achievements.mountMasterCount++; - if (giveTriadBingo) { - if (!user.achievements.triadBingoCount) { - user.achievements.triadBingoCount = 0; - } - user.achievements.triadBingoCount++; - } - } - return typeof cb === "function" ? cb(null, user) : void 0; - }, - buy: function(req, cb) { - var item, key, message; - key = req.params.key; - item = key === 'potion' ? content.potion : content.gear.flat[key]; - if (!item) { - return typeof cb === "function" ? cb({ - code: 404, - message: "Item '" + key + " not found (see https://github.com/HabitRPG/habitrpg-shared/blob/develop/script/content.coffee)" - }) : void 0; - } - if (user.stats.gp < item.value) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('messageNotEnoughGold', req.language) - }) : void 0; - } - if ((item.canOwn != null) && !item.canOwn(user)) { - return typeof cb === "function" ? cb({ - code: 401, - message: "You can't own this item" - }) : void 0; - } - if (item.key === 'potion') { - user.stats.hp += 15; - if (user.stats.hp > 50) { - user.stats.hp = 50; - } - } else { - user.items.gear.equipped[item.type] = item.key; - user.items.gear.owned[item.key] = true; - message = user.fns.handleTwoHanded(item, null, req); - if (message == null) { - message = i18n.t('messageBought', { - itemText: item.text(req.language) - }, req.language); - } - if (!user.achievements.ultimateGear && item.last) { - user.fns.ultimateGear(); - } - } - user.stats.gp -= item.value; - return typeof cb === "function" ? cb({ - code: 200, - message: message - }, _.pick(user, $w('items achievements stats'))) : void 0; - }, - buyMysterySet: function(req, cb) { - var mysterySet, _ref; - if (!(user.purchased.plan.consecutive.trinkets > 0)) { - return typeof cb === "function" ? cb({ - code: 401, - message: "You don't have enough Mystic Hourglasses" - }) : void 0; - } - mysterySet = (_ref = content.timeTravelerStore(user.items.gear.owned)) != null ? _ref[req.params.key] : void 0; - if ((typeof window !== "undefined" && window !== null ? window.confirm : void 0) != null) { - if (!window.confirm("Buy this full set of items for 1 Mystic Hourglass?")) { - return; - } - } - if (!mysterySet) { - return typeof cb === "function" ? cb({ - code: 404, - message: "Mystery set not found, or set already owned" - }) : void 0; - } - _.each(mysterySet.items, function(i) { - return user.items.gear.owned[i.key] = true; - }); - user.purchased.plan.consecutive.trinkets--; - return typeof cb === "function" ? cb(null, _.pick(user, $w('items purchased.plan.consecutive'))) : void 0; - }, - sell: function(req, cb) { - var key, type, _ref; - _ref = req.params, key = _ref.key, type = _ref.type; - if (type !== 'eggs' && type !== 'hatchingPotions' && type !== 'food') { - return typeof cb === "function" ? cb({ - code: 404, - message: ":type not found. Must bes in [eggs, hatchingPotions, food]" - }) : void 0; - } - if (!user.items[type][key]) { - return typeof cb === "function" ? cb({ - code: 404, - message: ":key not found for user.items." + type - }) : void 0; - } - user.items[type][key]--; - user.stats.gp += content[type][key].value; - return typeof cb === "function" ? cb(null, _.pick(user, $w('stats items'))) : void 0; - }, - equip: function(req, cb) { - var item, key, message, type, _ref; - _ref = [req.params.type || 'equipped', req.params.key], type = _ref[0], key = _ref[1]; - switch (type) { - case 'mount': - if (!user.items.mounts[key]) { - return typeof cb === "function" ? cb({ - code: 404, - message: ":You do not own this mount." - }) : void 0; - } - user.items.currentMount = user.items.currentMount === key ? '' : key; - break; - case 'pet': - if (!user.items.pets[key]) { - return typeof cb === "function" ? cb({ - code: 404, - message: ":You do not own this pet." - }) : void 0; - } - user.items.currentPet = user.items.currentPet === key ? '' : key; - break; - case 'costume': - case 'equipped': - item = content.gear.flat[key]; - if (!user.items.gear.owned[key]) { - return typeof cb === "function" ? cb({ - code: 404, - message: ":You do not own this gear." - }) : void 0; - } - if (user.items.gear[type][item.type] === key) { - user.items.gear[type][item.type] = "" + item.type + "_base_0"; - message = i18n.t('messageUnEquipped', { - itemText: item.text(req.language) - }, req.language); - } else { - user.items.gear[type][item.type] = item.key; - message = user.fns.handleTwoHanded(item, type, req); - } - if (typeof user.markModified === "function") { - user.markModified("items.gear." + type); - } - } - return typeof cb === "function" ? cb((message ? { - code: 200, - message: message - } : null), user.items) : void 0; - }, - hatch: function(req, cb) { - var egg, hatchingPotion, pet, _ref; - _ref = req.params, egg = _ref.egg, hatchingPotion = _ref.hatchingPotion; - if (!(egg && hatchingPotion)) { - return typeof cb === "function" ? cb({ - code: 404, - message: "Please specify query.egg & query.hatchingPotion" - }) : void 0; - } - if (!(user.items.eggs[egg] > 0 && user.items.hatchingPotions[hatchingPotion] > 0)) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('messageMissingEggPotion', req.language) - }) : void 0; - } - pet = "" + egg + "-" + hatchingPotion; - if (user.items.pets[pet] && user.items.pets[pet] > 0) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('messageAlreadyPet', req.language) - }) : void 0; - } - user.items.pets[pet] = 5; - user.items.eggs[egg]--; - user.items.hatchingPotions[hatchingPotion]--; - return typeof cb === "function" ? cb({ - code: 200, - message: i18n.t('messageHatched', req.language) - }, user.items) : void 0; - }, - unlock: function(req, cb, ga) { - var alreadyOwns, cost, fullSet, k, path, split, v; - path = req.query.path; - fullSet = ~path.indexOf(","); - cost = ~path.indexOf('background.') ? fullSet ? 3.75 : 1.75 : fullSet ? 1.25 : 0.5; - alreadyOwns = !fullSet && user.fns.dotGet("purchased." + path) === true; - if (user.balance < cost && !alreadyOwns) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } - if (fullSet) { - _.each(path.split(","), function(p) { - user.fns.dotSet("purchased." + p, true); - return true; - }); - } else { - if (alreadyOwns) { - split = path.split('.'); - v = split.pop(); - k = split.join('.'); - if (k === 'background' && v === user.preferences.background) { - v = ''; - } - user.fns.dotSet("preferences." + k, v); - return typeof cb === "function" ? cb(null, req) : void 0; - } - user.fns.dotSet("purchased." + path, true); - } - user.balance -= cost; - if (typeof user.markModified === "function") { - user.markModified('purchased'); - } - if (typeof cb === "function") { - cb(null, _.pick(user, $w('purchased preferences'))); - } - return ga != null ? ga.event('purchase', path).send() : void 0; - }, - changeClass: function(req, cb, ga) { - var klass, _ref; - klass = (_ref = req.query) != null ? _ref["class"] : void 0; - if (klass === 'warrior' || klass === 'rogue' || klass === 'wizard' || klass === 'healer') { - user.stats["class"] = klass; - user.flags.classSelected = true; - _.each(["weapon", "armor", "shield", "head"], function(type) { - var foundKey; - foundKey = false; - _.findLast(user.items.gear.owned, function(v, k) { - if (~k.indexOf(type + "_" + klass) && v === true) { - return foundKey = k; - } - }); - user.items.gear.equipped[type] = foundKey ? foundKey : type === "weapon" ? "weapon_" + klass + "_0" : type === "shield" && klass === "rogue" ? "shield_rogue_0" : "" + type + "_base_0"; - if (type === "weapon" || (type === "shield" && klass === "rogue")) { - user.items.gear.owned["" + type + "_" + klass + "_0"] = true; - } - return true; - }); - } else { - if (user.preferences.disableClasses) { - user.preferences.disableClasses = false; - user.preferences.autoAllocate = false; - } else { - if (!(user.balance >= .75)) { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('notEnoughGems', req.language) - }) : void 0; - } - user.balance -= .75; - } - _.merge(user.stats, { - str: 0, - con: 0, - per: 0, - int: 0, - points: user.stats.lvl - }); - user.flags.classSelected = false; - if (ga != null) { - ga.event('purchase', 'changeClass').send(); - } - } - return typeof cb === "function" ? cb(null, _.pick(user, $w('stats flags items preferences'))) : void 0; - }, - disableClasses: function(req, cb) { - user.stats["class"] = 'warrior'; - user.flags.classSelected = true; - user.preferences.disableClasses = true; - user.preferences.autoAllocate = true; - user.stats.str = user.stats.lvl; - user.stats.points = 0; - return typeof cb === "function" ? cb(null, _.pick(user, $w('stats flags preferences'))) : void 0; - }, - allocate: function(req, cb) { - var stat; - stat = req.query.stat || 'str'; - if (user.stats.points > 0) { - user.stats[stat]++; - user.stats.points--; - if (stat === 'int') { - user.stats.mp++; - } - } - return typeof cb === "function" ? cb(null, _.pick(user, $w('stats'))) : void 0; - }, - readValentine: function(req, cb) { - user.items.special.valentineReceived.shift(); - if (typeof user.markModified === "function") { - user.markModified('items.special.valentineReceived'); - } - return typeof cb === "function" ? cb(null, 'items.special') : void 0; - }, - openMysteryItem: function(req, cb, ga) { - var item, _ref, _ref1; - item = (_ref = user.purchased.plan) != null ? (_ref1 = _ref.mysteryItems) != null ? _ref1.shift() : void 0 : void 0; - if (!item) { - return typeof cb === "function" ? cb({ - code: 400, - message: "Empty" - }) : void 0; - } - item = content.gear.flat[item]; - user.items.gear.owned[item.key] = true; - if (typeof user.markModified === "function") { - user.markModified('purchased.plan.mysteryItems'); - } - if (typeof window !== 'undefined') { - (user._tmp != null ? user._tmp : user._tmp = {}).drop = { - type: 'gear', - dialog: "" + (item.text(req.language)) + " inside!" - }; - } - return typeof cb === "function" ? cb(null, user.items.gear.owned) : void 0; - }, - readNYE: function(req, cb) { - user.items.special.nyeReceived.shift(); - if (typeof user.markModified === "function") { - user.markModified('items.special.nyeReceived'); - } - return typeof cb === "function" ? cb(null, 'items.special') : void 0; - }, - score: function(req, cb) { - var addPoints, calculateDelta, calculateReverseDelta, changeTaskValue, delta, direction, id, mpDelta, multiplier, num, options, stats, subtractPoints, task, th, _ref; - _ref = req.params, id = _ref.id, direction = _ref.direction; - task = user.tasks[id]; - options = req.query || {}; - _.defaults(options, { - times: 1, - cron: false - }); - user._tmp = {}; - stats = { - gp: +user.stats.gp, - hp: +user.stats.hp, - exp: +user.stats.exp - }; - task.value = +task.value; - task.streak = ~~task.streak; - if (task.priority == null) { - task.priority = 1; - } - if (task.value > stats.gp && task.type === 'reward') { - return typeof cb === "function" ? cb({ - code: 401, - message: i18n.t('messageNotEnoughGold', req.language) - }) : void 0; - } - delta = 0; - calculateDelta = function() { - var currVal, nextDelta, _ref1; - currVal = task.value < -47.27 ? -47.27 : task.value > 21.27 ? 21.27 : task.value; - nextDelta = Math.pow(0.9747, currVal) * (direction === 'down' ? -1 : 1); - if (((_ref1 = task.checklist) != null ? _ref1.length : void 0) > 0) { - if (direction === 'down' && task.type === 'daily' && options.cron) { - nextDelta *= 1 - _.reduce(task.checklist, (function(m, i) { - return m + (i.completed ? 1 : 0); - }), 0) / task.checklist.length; - } - if (task.type === 'todo') { - nextDelta *= 1 + _.reduce(task.checklist, (function(m, i) { - return m + (i.completed ? 1 : 0); - }), 0); - } - } - return nextDelta; - }; - calculateReverseDelta = function() { - var calc, closeEnough, currVal, diff, nextDelta, testVal, _ref1; - currVal = task.value < -47.27 ? -47.27 : task.value > 21.27 ? 21.27 : task.value; - testVal = currVal + Math.pow(0.9747, currVal) * (direction === 'down' ? -1 : 1); - closeEnough = 0.00001; - while (true) { - calc = testVal + Math.pow(0.9747, testVal); - diff = currVal - calc; - if (Math.abs(diff) < closeEnough) { - break; - } - if (diff > 0) { - testVal -= diff; - } else { - testVal += diff; - } - } - nextDelta = testVal - currVal; - if (((_ref1 = task.checklist) != null ? _ref1.length : void 0) > 0) { - if (task.type === 'todo') { - nextDelta *= 1 + _.reduce(task.checklist, (function(m, i) { - return m + (i.completed ? 1 : 0); - }), 0); - } - } - return nextDelta; - }; - changeTaskValue = function() { - return _.times(options.times, function() { - var nextDelta, _ref1; - nextDelta = !options.cron && direction === 'down' ? calculateReverseDelta() : calculateDelta(); - if (task.type !== 'reward') { - if (user.preferences.automaticAllocation === true && user.preferences.allocationMode === 'taskbased' && !(task.type === 'todo' && direction === 'down')) { - user.stats.training[task.attribute] += nextDelta; - } - if (direction === 'up' && !(task.type === 'habit' && !task.down)) { - user.party.quest.progress.up = user.party.quest.progress.up || 0; - if ((_ref1 = task.type) === 'daily' || _ref1 === 'todo') { - user.party.quest.progress.up += nextDelta * (1 + (user._statsComputed.str / 200)); - } - } - task.value += nextDelta; - } - return delta += nextDelta; - }); - }; - addPoints = function() { - var afterStreak, currStreak, gpMod, intBonus, perBonus, streakBonus, _crit; - _crit = (delta > 0 ? user.fns.crit() : 1); - if (_crit > 1) { - user._tmp.crit = _crit; - } - intBonus = 1 + (user._statsComputed.int * .025); - stats.exp += Math.round(delta * intBonus * task.priority * _crit * 6); - perBonus = 1 + user._statsComputed.per * .02; - gpMod = delta * task.priority * _crit * perBonus; - return stats.gp += task.streak ? (currStreak = direction === 'down' ? task.streak - 1 : task.streak, streakBonus = currStreak / 100 + 1, afterStreak = gpMod * streakBonus, currStreak > 0 ? gpMod > 0 ? user._tmp.streakBonus = afterStreak - gpMod : void 0 : void 0, afterStreak) : gpMod; - }; - subtractPoints = function() { - var conBonus, hpMod; - conBonus = 1 - (user._statsComputed.con / 250); - if (conBonus < .1) { - conBonus = 0.1; - } - hpMod = delta * conBonus * task.priority * 2; - return stats.hp += Math.round(hpMod * 10) / 10; - }; - switch (task.type) { - case 'habit': - changeTaskValue(); - if (delta > 0) { - addPoints(); - } else { - subtractPoints(); - } - th = (task.history != null ? task.history : task.history = []); - if (th[th.length - 1] && moment(th[th.length - 1].date).isSame(new Date, 'day')) { - th[th.length - 1].value = task.value; - } else { - th.push({ - date: +(new Date), - value: task.value - }); - } - if (typeof user.markModified === "function") { - user.markModified("habits." + (_.findIndex(user.habits, { - id: task.id - })) + ".history"); - } - break; - case 'daily': - if (options.cron) { - changeTaskValue(); - subtractPoints(); - if (!user.stats.buffs.streaks) { - task.streak = 0; - } - } else { - changeTaskValue(); - if (direction === 'down') { - delta = calculateDelta(); - } - addPoints(); - if (direction === 'up') { - task.streak = task.streak ? task.streak + 1 : 1; - if ((task.streak % 21) === 0) { - user.achievements.streak = user.achievements.streak ? user.achievements.streak + 1 : 1; - } - } else { - if ((task.streak % 21) === 0) { - user.achievements.streak = user.achievements.streak ? user.achievements.streak - 1 : 0; - } - task.streak = task.streak ? task.streak - 1 : 0; - } - } - break; - case 'todo': - if (options.cron) { - changeTaskValue(); - } else { - task.dateCompleted = direction === 'up' ? new Date : void 0; - changeTaskValue(); - if (direction === 'down') { - delta = calculateDelta(); - } - addPoints(); - multiplier = _.max([ - _.reduce(task.checklist, (function(m, i) { - return m + (i.completed ? 1 : 0); - }), 1), 1 - ]); - mpDelta = _.max([multiplier, .01 * user._statsComputed.maxMP * multiplier]); - mpDelta *= user._tmp.crit || 1; - if (direction === 'down') { - mpDelta *= -1; - } - user.stats.mp += mpDelta; - if (user.stats.mp >= user._statsComputed.maxMP) { - user.stats.mp = user._statsComputed.maxMP; - } - if (user.stats.mp < 0) { - user.stats.mp = 0; - } - } - break; - case 'reward': - changeTaskValue(); - stats.gp -= Math.abs(task.value); - num = parseFloat(task.value).toFixed(2); - if (stats.gp < 0) { - stats.hp += stats.gp; - stats.gp = 0; - } - } - user.fns.updateStats(stats, req); - if (typeof window === 'undefined') { - if (direction === 'up') { - user.fns.randomDrop({ - task: task, - delta: delta - }, req); - } - } - if (typeof cb === "function") { - cb(null, user); - } - return delta; - } - }; - } - user.fns = { - getItem: function(type) { - var item; - item = content.gear.flat[user.items.gear.equipped[type]]; - if (!item) { - return content.gear.flat["" + type + "_base_0"]; - } - return item; - }, - handleTwoHanded: function(item, type, req) { - var message, weapon, _ref; - if (type == null) { - type = 'equipped'; - } - if (item.type === "shield" && ((_ref = (weapon = content.gear.flat[user.items.gear[type].weapon])) != null ? _ref.twoHanded : void 0)) { - user.items.gear[type].weapon = 'weapon_base_0'; - message = i18n.t('messageTwoHandled', { - gearText: weapon.text(req.language) - }, req.language); - } - if (item.twoHanded) { - user.items.gear[type].shield = "shield_base_0"; - message = i18n.t('messageTwoHandled', { - gearText: item.text(req.language) - }, req.language); - } - return message; - }, - - /* - Because the same op needs to be performed on the client and the server (critical hits, item drops, etc), - we need things to be "random", but technically predictable so that they don't go out-of-sync - */ - predictableRandom: function(seed) { - var x; - if (!seed || seed === Math.PI) { - seed = _.reduce(user.stats, (function(m, v) { - if (_.isNumber(v)) { - return m + v; - } else { - return m; - } - }), 0); - } - x = Math.sin(seed++) * 10000; - return x - Math.floor(x); - }, - crit: function(stat, chance) { - if (stat == null) { - stat = 'str'; - } - if (chance == null) { - chance = .03; - } - if (user.fns.predictableRandom() <= chance * (1 + user._statsComputed[stat] / 100)) { - return 1.5 + (.02 * user._statsComputed[stat]); - } else { - return 1; - } - }, - - /* - Get a random property from an object - returns random property (the value) - */ - randomVal: function(obj, options) { - var array, rand; - array = (options != null ? options.key : void 0) ? _.keys(obj) : _.values(obj); - rand = user.fns.predictableRandom(options != null ? options.seed : void 0); - array.sort(); - return array[Math.floor(rand * array.length)]; - }, - - /* - This allows you to set object properties by dot-path. Eg, you can run pathSet('stats.hp',50,user) which is the same as - user.stats.hp = 50. This is useful because in our habitrpg-shared functions we're returning changesets as {path:value}, - so that different consumers can implement setters their own way. Derby needs model.set(path, value) for example, where - Angular sets object properties directly - in which case, this function will be used. - */ - dotSet: function(path, val) { - return api.dotSet(user, path, val); - }, - dotGet: function(path) { - return api.dotGet(user, path); - }, - randomDrop: function(modifiers, req) { - var acceptableDrops, chance, drop, dropK, dropMultiplier, quest, rarity, task, _base, _base1, _base2, _name, _name1, _name2, _ref, _ref1, _ref2, _ref3; - task = modifiers.task; - chance = _.min([Math.abs(task.value - 21.27), 37.5]) / 150 + .02; - chance *= task.priority * (1 + (task.streak / 100 || 0)) * (1 + (user._statsComputed.per / 100)) * (1 + (user.contributor.level / 40 || 0)) * (1 + (user.achievements.rebirths / 20 || 0)) * (1 + (user.achievements.streak / 200 || 0)) * (user._tmp.crit || 1) * (1 + .5 * (_.reduce(task.checklist, (function(m, i) { - return m + (i.completed ? 1 : 0); - }), 0) || 0)); - chance = api.diminishingReturns(chance, 0.75); - quest = content.quests[(_ref = user.party.quest) != null ? _ref.key : void 0]; - if ((quest != null ? quest.collect : void 0) && user.fns.predictableRandom(user.stats.gp) < chance) { - dropK = user.fns.randomVal(quest.collect, { - key: true - }); - user.party.quest.progress.collect[dropK]++; - if (typeof user.markModified === "function") { - user.markModified('party.quest.progress'); - } - } - dropMultiplier = ((_ref1 = user.purchased) != null ? (_ref2 = _ref1.plan) != null ? _ref2.customerId : void 0 : void 0) ? 2 : 1; - if ((api.daysSince(user.items.lastDrop.date, user.preferences) === 0) && (user.items.lastDrop.count >= dropMultiplier * (5 + Math.floor(user._statsComputed.per / 25) + (user.contributor.level || 0)))) { - return; - } - if (((_ref3 = user.flags) != null ? _ref3.dropsEnabled : void 0) && user.fns.predictableRandom(user.stats.exp) < chance) { - rarity = user.fns.predictableRandom(user.stats.gp); - if (rarity > .6) { - drop = user.fns.randomVal(_.where(content.food, { - canDrop: true - })); - if ((_base = user.items.food)[_name = drop.key] == null) { - _base[_name] = 0; - } - user.items.food[drop.key] += 1; - drop.type = 'Food'; - drop.dialog = i18n.t('messageDropFood', { - dropArticle: drop.article, - dropText: drop.text(req.language), - dropNotes: drop.notes(req.language) - }, req.language); - } else if (rarity > .3) { - drop = user.fns.randomVal(_.where(content.eggs, { - canBuy: true - })); - if ((_base1 = user.items.eggs)[_name1 = drop.key] == null) { - _base1[_name1] = 0; - } - user.items.eggs[drop.key]++; - drop.type = 'Egg'; - drop.dialog = i18n.t('messageDropEgg', { - dropText: drop.text(req.language), - dropNotes: drop.notes(req.language) - }, req.language); - } else { - acceptableDrops = rarity < .02 ? ['Golden'] : rarity < .09 ? ['Zombie', 'CottonCandyPink', 'CottonCandyBlue'] : rarity < .18 ? ['Red', 'Shade', 'Skeleton'] : ['Base', 'White', 'Desert']; - drop = user.fns.randomVal(_.pick(content.hatchingPotions, (function(v, k) { - return __indexOf.call(acceptableDrops, k) >= 0; - }))); - if ((_base2 = user.items.hatchingPotions)[_name2 = drop.key] == null) { - _base2[_name2] = 0; - } - user.items.hatchingPotions[drop.key]++; - drop.type = 'HatchingPotion'; - drop.dialog = i18n.t('messageDropPotion', { - dropText: drop.text(req.language), - dropNotes: drop.notes(req.language) - }, req.language); - } - user._tmp.drop = drop; - user.items.lastDrop.date = +(new Date); - return user.items.lastDrop.count++; - } - }, - - /* - Updates user stats with new stats. Handles death, leveling up, etc - {stats} new stats - {update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately - */ - autoAllocate: function() { - return user.stats[(function() { - var diff, ideal, preference, stats, suggested; - switch (user.preferences.allocationMode) { - case "flat": - stats = _.pick(user.stats, $w('con str per int')); - return _.invert(stats)[_.min(stats)]; - case "classbased": - ideal = [user.stats.lvl / 7 * 3, user.stats.lvl / 7 * 2, user.stats.lvl / 7, user.stats.lvl / 7]; - preference = (function() { - switch (user.stats["class"]) { - case "wizard": - return ["int", "per", "con", "str"]; - case "rogue": - return ["per", "str", "int", "con"]; - case "healer": - return ["con", "int", "str", "per"]; - default: - return ["str", "con", "per", "int"]; - } - })(); - diff = [user.stats[preference[0]] - ideal[0], user.stats[preference[1]] - ideal[1], user.stats[preference[2]] - ideal[2], user.stats[preference[3]] - ideal[3]]; - suggested = _.findIndex(diff, (function(val) { - if (val === _.min(diff)) { - return true; - } - })); - if (~suggested) { - return preference[suggested]; - } else { - return "str"; - } - case "taskbased": - suggested = _.invert(user.stats.training)[_.max(user.stats.training)]; - _.merge(user.stats.training, { - str: 0, - int: 0, - con: 0, - per: 0 - }); - return suggested || "str"; - default: - return "str"; - } - })()]++; - }, - updateStats: function(stats, req) { - var tnl; - if (stats.hp <= 0) { - return user.stats.hp = 0; - } - user.stats.hp = stats.hp; - user.stats.gp = stats.gp >= 0 ? stats.gp : 0; - tnl = api.tnl(user.stats.lvl); - if (stats.exp >= tnl) { - user.stats.exp = stats.exp; - while (stats.exp >= tnl) { - stats.exp -= tnl; - user.stats.lvl++; - tnl = api.tnl(user.stats.lvl); - if (user.preferences.automaticAllocation) { - user.fns.autoAllocate(); - } else { - user.stats.points = user.stats.lvl - (user.stats.con + user.stats.str + user.stats.per + user.stats.int); - } - user.stats.hp = 50; - } - } - user.stats.exp = stats.exp; - if (user.flags == null) { - user.flags = {}; - } - if (!user.flags.customizationsNotification && (user.stats.exp > 5 || user.stats.lvl > 1)) { - user.flags.customizationsNotification = true; - } - if (!user.flags.itemsEnabled && (user.stats.exp > 10 || user.stats.lvl > 1)) { - user.flags.itemsEnabled = true; - } - if (!user.flags.partyEnabled && user.stats.lvl >= 3) { - user.flags.partyEnabled = true; - } - if (!user.flags.dropsEnabled && user.stats.lvl >= 4) { - user.flags.dropsEnabled = true; - if (user.items.eggs["Wolf"] > 0) { - user.items.eggs["Wolf"]++; - } else { - user.items.eggs["Wolf"] = 1; - } - } - if (!user.flags.classSelected && user.stats.lvl >= 10) { - user.flags.classSelected; - } - _.each({ - vice1: 30, - atom1: 15, - moonstone1: 60, - goldenknight1: 40 - }, function(lvl, k) { - var _base, _base1, _ref; - if (!((_ref = user.flags.levelDrops) != null ? _ref[k] : void 0) && user.stats.lvl >= lvl) { - if ((_base = user.items.quests)[k] == null) { - _base[k] = 0; - } - user.items.quests[k]++; - ((_base1 = user.flags).levelDrops != null ? _base1.levelDrops : _base1.levelDrops = {})[k] = true; - if (typeof user.markModified === "function") { - user.markModified('flags.levelDrops'); - } - return user._tmp.drop = _.defaults(content.quests[k], { - type: 'Quest', - dialog: i18n.t('messageFoundQuest', { - questText: content.quests[k].text(req.language) - }, req.language) - }); - } - }); - if (!user.flags.rebirthEnabled && (user.stats.lvl >= 50 || user.achievements.ultimateGear || user.achievements.beastMaster)) { - user.flags.rebirthEnabled = true; - } - if (user.stats.lvl >= 100 && !user.flags.freeRebirth) { - return user.flags.freeRebirth = true; - } - }, - - /* - ------------------------------------------------------ - Cron - ------------------------------------------------------ - */ - - /* - At end of day, add value to all incomplete Daily & Todo tasks (further incentive) - For incomplete Dailys, deduct experience - Make sure to run this function once in a while as server will not take care of overnight calculations. - And you have to run it every time client connects. - {user} - */ - cron: function(options) { - var clearBuffs, daysMissed, expTally, lvl, lvlDiv2, now, perfect, plan, progress, todoTally, _base, _base1, _base2, _base3, _progress, _ref, _ref1, _ref2; - if (options == null) { - options = {}; - } - now = +options.now || +(new Date); - daysMissed = api.daysSince(user.lastCron, _.defaults({ - now: now - }, user.preferences)); - if (!(daysMissed > 0)) { - return; - } - user.auth.timestamps.loggedin = new Date(); - user.lastCron = now; - if (user.items.lastDrop.count > 0) { - user.items.lastDrop.count = 0; - } - perfect = true; - clearBuffs = { - str: 0, - int: 0, - per: 0, - con: 0, - stealth: 0, - streaks: false - }; - plan = (_ref = user.purchased) != null ? _ref.plan : void 0; - if (plan != null ? plan.customerId : void 0) { - if (moment(plan.dateUpdated).format('MMYYYY') !== moment().format('MMYYYY')) { - plan.gemsBought = 0; - plan.dateUpdated = new Date(); - _.defaults(plan.consecutive, { - count: 0, - offset: 0, - trinkets: 0, - gemCapExtra: 0 - }); - plan.consecutive.count++; - if (plan.consecutive.offset > 0) { - plan.consecutive.offset--; - } else if (plan.consecutive.count % 3 === 0) { - plan.consecutive.trinkets++; - plan.consecutive.gemCapExtra += 5; - if (plan.consecutive.gemCapExtra > 25) { - plan.consecutive.gemCapExtra = 25; - } - } - } - if (plan.dateTerminated && moment(plan.dateTerminated).isBefore(+(new Date))) { - _.merge(plan, { - planId: null, - customerId: null, - paymentMethod: null - }); - _.merge(plan.consecutive, { - count: 0, - offset: 0, - gemCapExtra: 0 - }); - if (typeof user.markModified === "function") { - user.markModified('purchased.plan'); - } - } - } - if (user.preferences.sleep === true) { - user.stats.buffs = clearBuffs; - return; - } - todoTally = 0; - if ((_base = user.party.quest.progress).down == null) { - _base.down = 0; - } - user.todos.concat(user.dailys).forEach(function(task) { - var absVal, completed, delta, id, repeat, scheduleMisses, type; - if (!task) { - return; - } - id = task.id, type = task.type, completed = task.completed, repeat = task.repeat; - if ((type === 'daily') && !completed && user.stats.buffs.stealth && user.stats.buffs.stealth--) { - return; - } - if (!completed) { - scheduleMisses = daysMissed; - if ((type === 'daily') && repeat) { - scheduleMisses = 0; - _.times(daysMissed, function(n) { - var thatDay; - thatDay = moment(now).subtract({ - days: n + 1 - }); - if (api.shouldDo(thatDay, repeat, user.preferences)) { - return scheduleMisses++; - } - }); - } - if (scheduleMisses > 0) { - if (type === 'daily') { - perfect = false; - } - delta = user.ops.score({ - params: { - id: task.id, - direction: 'down' - }, - query: { - times: scheduleMisses, - cron: true - } - }); - if (type === 'daily') { - user.party.quest.progress.down += delta; - } - } - } - switch (type) { - case 'daily': - (task.history != null ? task.history : task.history = []).push({ - date: +(new Date), - value: task.value - }); - task.completed = false; - return _.each(task.checklist, (function(i) { - i.completed = false; - return true; - })); - case 'todo': - absVal = completed ? Math.abs(task.value) : task.value; - return todoTally += absVal; - } - }); - user.habits.forEach(function(task) { - if (task.up === false || task.down === false) { - if (Math.abs(task.value) < 0.1) { - return task.value = 0; - } else { - return task.value = task.value / 2; - } - } - }); - ((_base1 = (user.history != null ? user.history : user.history = {})).todos != null ? _base1.todos : _base1.todos = []).push({ - date: now, - value: todoTally - }); - expTally = user.stats.exp; - lvl = 0; - while (lvl < (user.stats.lvl - 1)) { - lvl++; - expTally += api.tnl(lvl); - } - ((_base2 = user.history).exp != null ? _base2.exp : _base2.exp = []).push({ - date: now, - value: expTally - }); - if (!((_ref1 = user.purchased) != null ? (_ref2 = _ref1.plan) != null ? _ref2.customerId : void 0 : void 0)) { - user.fns.preenUserHistory(); - if (typeof user.markModified === "function") { - user.markModified('history'); - } - if (typeof user.markModified === "function") { - user.markModified('dailys'); - } - } - user.stats.buffs = perfect ? ((_base3 = user.achievements).perfect != null ? _base3.perfect : _base3.perfect = 0, user.achievements.perfect++, user.stats.lvl < 100 ? lvlDiv2 = Math.ceil(user.stats.lvl / 2) : lvlDiv2 = 50, { - str: lvlDiv2, - int: lvlDiv2, - per: lvlDiv2, - con: lvlDiv2, - stealth: 0, - streaks: false - }) : clearBuffs; - user.stats.mp += _.max([10, .1 * user._statsComputed.maxMP]); - if (user.stats.mp > user._statsComputed.maxMP) { - user.stats.mp = user._statsComputed.maxMP; - } - progress = user.party.quest.progress; - _progress = _.cloneDeep(progress); - _.merge(progress, { - down: 0, - up: 0 - }); - progress.collect = _.transform(progress.collect, (function(m, v, k) { - return m[k] = 0; - })); - return _progress; - }, - preenUserHistory: function(minHistLen) { - if (minHistLen == null) { - minHistLen = 7; - } - _.each(user.habits.concat(user.dailys), function(task) { - var _ref; - if (((_ref = task.history) != null ? _ref.length : void 0) > minHistLen) { - task.history = preenHistory(task.history); - } - return true; - }); - _.defaults(user.history, { - todos: [], - exp: [] - }); - if (user.history.exp.length > minHistLen) { - user.history.exp = preenHistory(user.history.exp); - } - if (user.history.todos.length > minHistLen) { - return user.history.todos = preenHistory(user.history.todos); - } - }, - ultimateGear: function() { - var gear, lastGearClassTypeMatrix, ownedLastGear, shouldGrant; - gear = typeof window !== "undefined" && window !== null ? user.items.gear.owned : user.items.gear.owned.toObject(); - ownedLastGear = _.chain(content.gear.flat).pick(_.keys(gear)).values().filter(function(gear) { - return gear.last; - }); - lastGearClassTypeMatrix = {}; - _.each(content.classes, function(klass) { - lastGearClassTypeMatrix[klass] = {}; - return _.each(['armor', 'weapon', 'shield', 'head'], function(type) { - lastGearClassTypeMatrix[klass][type] = false; - return true; - }); - }); - ownedLastGear.each(function(gear) { - if (gear.twoHanded) { - lastGearClassTypeMatrix[gear.klass]["shield"] = true; - } - return lastGearClassTypeMatrix[gear.klass][gear.type] = true; - }); - shouldGrant = _(lastGearClassTypeMatrix).values().reduce((function(ans, klass) { - return ans || _(klass).values().reduce((function(ans, gearType) { - return ans && gearType; - }), true); - }), false).valueOf(); - return user.achievements.ultimateGear = shouldGrant; - }, - nullify: function() { - user.ops = null; - user.fns = null; - return user = null; - } - }; - Object.defineProperty(user, '_statsComputed', { - get: function() { - var computed; - computed = _.reduce(['per', 'con', 'str', 'int'], (function(_this) { - return function(m, stat) { - m[stat] = _.reduce($w('stats stats.buffs items.gear.equipped.weapon items.gear.equipped.armor items.gear.equipped.head items.gear.equipped.shield'), function(m2, path) { - var item, val; - val = user.fns.dotGet(path); - return m2 + (~path.indexOf('items.gear') ? (item = content.gear.flat[val], (+(item != null ? item[stat] : void 0) || 0) * ((item != null ? item.klass : void 0) === user.stats["class"] || (item != null ? item.specialClass : void 0) === user.stats["class"] ? 1.5 : 1)) : +val[stat] || 0); - }, 0); - if (user.stats.lvl < 100) { - m[stat] += (user.stats.lvl - 1) / 2; - } else { - m[stat] += 50; - } - return m; - }; - })(this), {}); - computed.maxMP = computed.int * 2 + 30; - return computed; - } - }); - return Object.defineProperty(user, 'tasks', { - get: function() { - var tasks; - tasks = user.habits.concat(user.dailys).concat(user.todos).concat(user.rewards); - return _.object(_.pluck(tasks, "id"), tasks); - } - }); -}; - - -}).call(this,require('_process')) -},{"./content.coffee":2,"./i18n.coffee":3,"_process":5,"lodash":6,"moment":7}],5:[function(require,module,exports){ -// shim for using process in browser - -var process = module.exports = {}; -var queue = []; -var draining = false; - -function drainQueue() { - if (draining) { - return; - } - draining = true; - var currentQueue; - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - var i = -1; - while (++i < len) { - currentQueue[i](); - } - len = queue.length; - } - draining = false; -} -process.nextTick = function (fun) { - queue.push(fun); - if (!draining) { - setTimeout(drainQueue, 0); - } -}; - -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - -},{}],6:[function(require,module,exports){ +},{"./script/index.coffee":6,"lodash":2,"moment":3}],2:[function(require,module,exports){ (function (global){ /** * @license @@ -13935,7 +6798,7 @@ process.umask = function() { return 0; }; }.call(this)); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],7:[function(require,module,exports){ +},{}],3:[function(require,module,exports){ (function (global){ //! moment.js //! version : 2.8.4 @@ -16875,4 +9738,7143 @@ process.umask = function() { return 0; }; }).call(this); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],4:[function(require,module,exports){ +var api, classes, diminishingReturns, events, gear, gearTypes, i18n, moment, repeat, t, _; + +_ = require('lodash'); + +api = module.exports; + +moment = require('moment'); + +i18n = require('./i18n.coffee'); + +t = function(string, vars) { + var func; + func = function(lang) { + if (vars == null) { + vars = { + a: 'a' + }; + } + return i18n.t(string, vars, lang); + }; + func.i18nLangFunc = true; + return func; +}; + + +/* + --------------------------------------------------------------- + Gear (Weapons, Armor, Head, Shield) + Item definitions: {index, text, notes, value, str, def, int, per, classes, type} + --------------------------------------------------------------- + */ + +classes = ['warrior', 'rogue', 'healer', 'wizard']; + +gearTypes = ['weapon', 'armor', 'head', 'shield', 'body', 'back', 'headAccessory', 'eyewear']; + +events = { + winter: { + start: '2013-12-31', + end: '2014-02-01' + }, + birthday: { + start: '2013-01-30', + end: '2014-02-01' + }, + spring: { + start: '2014-03-21', + end: '2014-05-01' + }, + summer: { + start: '2014-06-20', + end: '2014-08-01' + }, + gaymerx: { + start: '2014-07-02', + end: '2014-08-01' + }, + fall: { + start: '2014-09-21', + end: '2014-11-01' + }, + winter2015: { + start: '2014-12-21', + end: '2015-02-02' + } +}; + +api.mystery = { + 201402: { + start: '2014-02-22', + end: '2014-02-28', + text: 'Winged Messenger Set' + }, + 201403: { + start: '2014-03-24', + end: '2014-04-02', + text: 'Forest Walker Set' + }, + 201404: { + start: '2014-04-24', + end: '2014-05-02', + text: 'Twilight Butterfly Set' + }, + 201405: { + start: '2014-05-21', + end: '2014-06-02', + text: 'Flame Wielder Set' + }, + 201406: { + start: '2014-06-23', + end: '2014-07-02', + text: 'Octomage Set' + }, + 201407: { + start: '2014-07-23', + end: '2014-08-02', + text: 'Undersea Explorer Set' + }, + 201408: { + start: '2014-08-23', + end: '2014-09-02', + text: 'Sun Sorcerer Set' + }, + 201409: { + start: '2014-09-24', + end: '2014-10-02', + text: 'Autumn Strider Item Set' + }, + 201410: { + start: '2014-10-24', + end: '2014-11-02', + text: 'Winged Goblin Set' + }, + 201411: { + start: '2014-11-24', + end: '2014-12-02', + text: 'Feast and Fun Set' + }, + 201412: { + start: '2014-12-25', + end: '2015-01-02', + text: 'Penguin Set' + }, + 201501: { + start: '2015-01-26', + end: '2015-02-02', + text: 'Starry Knight Set' + }, + 301404: { + start: '3014-03-24', + end: '3014-04-02', + text: 'Steampunk Standard Set' + }, + 301405: { + start: '3014-04-24', + end: '3014-05-02', + text: 'Steampunk Accessories Set' + }, + wondercon: { + start: '2014-03-24', + end: '2014-04-01' + } +}; + +_.each(api.mystery, function(v, k) { + return v.key = k; +}); + +gear = { + weapon: { + base: { + 0: { + text: t('weaponBase0Text'), + notes: t('weaponBase0Notes'), + value: 0 + } + }, + warrior: { + 0: { + text: t('weaponWarrior0Text'), + notes: t('weaponWarrior0Notes'), + value: 0 + }, + 1: { + text: t('weaponWarrior1Text'), + notes: t('weaponWarrior1Notes', { + str: 3 + }), + str: 3, + value: 20 + }, + 2: { + text: t('weaponWarrior2Text'), + notes: t('weaponWarrior2Notes', { + str: 6 + }), + str: 6, + value: 30 + }, + 3: { + text: t('weaponWarrior3Text'), + notes: t('weaponWarrior3Notes', { + str: 9 + }), + str: 9, + value: 45 + }, + 4: { + text: t('weaponWarrior4Text'), + notes: t('weaponWarrior4Notes', { + str: 12 + }), + str: 12, + value: 65 + }, + 5: { + text: t('weaponWarrior5Text'), + notes: t('weaponWarrior5Notes', { + str: 15 + }), + str: 15, + value: 90 + }, + 6: { + text: t('weaponWarrior6Text'), + notes: t('weaponWarrior6Notes', { + str: 18 + }), + str: 18, + value: 120, + last: true + } + }, + rogue: { + 0: { + text: t('weaponRogue0Text'), + notes: t('weaponRogue0Notes'), + str: 0, + value: 0 + }, + 1: { + text: t('weaponRogue1Text'), + notes: t('weaponRogue1Notes', { + str: 2 + }), + str: 2, + value: 20 + }, + 2: { + text: t('weaponRogue2Text'), + notes: t('weaponRogue2Notes', { + str: 3 + }), + str: 3, + value: 35 + }, + 3: { + text: t('weaponRogue3Text'), + notes: t('weaponRogue3Notes', { + str: 4 + }), + str: 4, + value: 50 + }, + 4: { + text: t('weaponRogue4Text'), + notes: t('weaponRogue4Notes', { + str: 6 + }), + str: 6, + value: 70 + }, + 5: { + text: t('weaponRogue5Text'), + notes: t('weaponRogue5Notes', { + str: 8 + }), + str: 8, + value: 90 + }, + 6: { + text: t('weaponRogue6Text'), + notes: t('weaponRogue6Notes', { + str: 10 + }), + str: 10, + value: 120, + last: true + } + }, + wizard: { + 0: { + twoHanded: true, + text: t('weaponWizard0Text'), + notes: t('weaponWizard0Notes'), + value: 0 + }, + 1: { + twoHanded: true, + text: t('weaponWizard1Text'), + notes: t('weaponWizard1Notes', { + int: 3, + per: 1 + }), + int: 3, + per: 1, + value: 30 + }, + 2: { + twoHanded: true, + text: t('weaponWizard2Text'), + notes: t('weaponWizard2Notes', { + int: 6, + per: 2 + }), + int: 6, + per: 2, + value: 50 + }, + 3: { + twoHanded: true, + text: t('weaponWizard3Text'), + notes: t('weaponWizard3Notes', { + int: 9, + per: 3 + }), + int: 9, + per: 3, + value: 80 + }, + 4: { + twoHanded: true, + text: t('weaponWizard4Text'), + notes: t('weaponWizard4Notes', { + int: 12, + per: 5 + }), + int: 12, + per: 5, + value: 120 + }, + 5: { + twoHanded: true, + text: t('weaponWizard5Text'), + notes: t('weaponWizard5Notes', { + int: 15, + per: 7 + }), + int: 15, + per: 7, + value: 160 + }, + 6: { + twoHanded: true, + text: t('weaponWizard6Text'), + notes: t('weaponWizard6Notes', { + int: 18, + per: 10 + }), + int: 18, + per: 10, + value: 200, + last: true + } + }, + healer: { + 0: { + text: t('weaponHealer0Text'), + notes: t('weaponHealer0Notes'), + value: 0 + }, + 1: { + text: t('weaponHealer1Text'), + notes: t('weaponHealer1Notes', { + int: 2 + }), + int: 2, + value: 20 + }, + 2: { + text: t('weaponHealer2Text'), + notes: t('weaponHealer2Notes', { + int: 3 + }), + int: 3, + value: 30 + }, + 3: { + text: t('weaponHealer3Text'), + notes: t('weaponHealer3Notes', { + int: 5 + }), + int: 5, + value: 45 + }, + 4: { + text: t('weaponHealer4Text'), + notes: t('weaponHealer4Notes', { + int: 7 + }), + int: 7, + value: 65 + }, + 5: { + text: t('weaponHealer5Text'), + notes: t('weaponHealer5Notes', { + int: 9 + }), + int: 9, + value: 90 + }, + 6: { + text: t('weaponHealer6Text'), + notes: t('weaponHealer6Notes', { + int: 11 + }), + int: 11, + value: 120, + last: true + } + }, + special: { + 0: { + text: t('weaponSpecial0Text'), + notes: t('weaponSpecial0Notes', { + str: 20 + }), + str: 20, + value: 150, + canOwn: (function(u) { + var _ref; + return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 70; + }) + }, + 1: { + text: t('weaponSpecial1Text'), + notes: t('weaponSpecial1Notes', { + attrs: 6 + }), + str: 6, + per: 6, + con: 6, + int: 6, + value: 170, + canOwn: (function(u) { + var _ref; + return +((_ref = u.contributor) != null ? _ref.level : void 0) >= 4; + }) + }, + 2: { + text: t('weaponSpecial2Text'), + notes: t('weaponSpecial2Notes', { + attrs: 25 + }), + str: 25, + per: 25, + value: 200, + canOwn: (function(u) { + var _ref; + return (+((_ref = u.backer) != null ? _ref.tier : void 0) >= 300) || (u.items.gear.owned.weapon_special_2 != null); + }) + }, + 3: { + text: t('weaponSpecial3Text'), + notes: t('weaponSpecial3Notes', { + attrs: 17 + }), + str: 17, + int: 17, + con: 17, + value: 200, + canOwn: (function(u) { + var _ref; + return (+((_ref = u.backer) != null ? _ref.tier : void 0) >= 300) || (u.items.gear.owned.weapon_special_3 != null); + }) + }, + critical: { + text: t('weaponSpecialCriticalText'), + notes: t('weaponSpecialCriticalNotes', { + attrs: 40 + }), + str: 40, + per: 40, + value: 200, + canOwn: (function(u) { + var _ref; + return !!((_ref = u.contributor) != null ? _ref.critical : void 0); + }) + }, + yeti: { + event: events.winter, + specialClass: 'warrior', + text: t('weaponSpecialYetiText'), + notes: t('weaponSpecialYetiNotes', { + str: 15 + }), + str: 15, + value: 90 + }, + ski: { + event: events.winter, + specialClass: 'rogue', + text: t('weaponSpecialSkiText'), + notes: t('weaponSpecialSkiNotes', { + str: 8 + }), + str: 8, + value: 90 + }, + candycane: { + event: events.winter, + specialClass: 'wizard', + twoHanded: true, + text: t('weaponSpecialCandycaneText'), + notes: t('weaponSpecialCandycaneNotes', { + int: 15, + per: 7 + }), + int: 15, + per: 7, + value: 160 + }, + snowflake: { + event: events.winter, + specialClass: 'healer', + text: t('weaponSpecialSnowflakeText'), + notes: t('weaponSpecialSnowflakeNotes', { + int: 9 + }), + int: 9, + value: 90 + }, + springRogue: { + event: events.spring, + specialClass: 'rogue', + text: t('weaponSpecialSpringRogueText'), + notes: t('weaponSpecialSpringRogueNotes', { + str: 8 + }), + value: 80, + str: 8 + }, + springWarrior: { + event: events.spring, + specialClass: 'warrior', + text: t('weaponSpecialSpringWarriorText'), + notes: t('weaponSpecialSpringWarriorNotes', { + str: 15 + }), + value: 90, + str: 15 + }, + springMage: { + event: events.spring, + specialClass: 'wizard', + twoHanded: true, + text: t('weaponSpecialSpringMageText'), + notes: t('weaponSpecialSpringMageNotes', { + int: 15, + per: 7 + }), + value: 160, + int: 15, + per: 7 + }, + springHealer: { + event: events.spring, + specialClass: 'healer', + text: t('weaponSpecialSpringHealerText'), + notes: t('weaponSpecialSpringHealerNotes', { + int: 9 + }), + value: 90, + int: 9 + }, + summerRogue: { + event: events.summer, + specialClass: 'rogue', + text: t('weaponSpecialSummerRogueText'), + notes: t('weaponSpecialSummerRogueNotes', { + str: 8 + }), + value: 80, + str: 8 + }, + summerWarrior: { + event: events.summer, + specialClass: 'warrior', + text: t('weaponSpecialSummerWarriorText'), + notes: t('weaponSpecialSummerWarriorNotes', { + str: 15 + }), + value: 90, + str: 15 + }, + summerMage: { + event: events.summer, + specialClass: 'wizard', + twoHanded: true, + text: t('weaponSpecialSummerMageText'), + notes: t('weaponSpecialSummerMageNotes', { + int: 15, + per: 7 + }), + value: 160, + int: 15, + per: 7 + }, + summerHealer: { + event: events.summer, + specialClass: 'healer', + text: t('weaponSpecialSummerHealerText'), + notes: t('weaponSpecialSummerHealerNotes', { + int: 9 + }), + value: 90, + int: 9 + }, + fallRogue: { + event: events.fall, + specialClass: 'rogue', + text: t('weaponSpecialFallRogueText'), + notes: t('weaponSpecialFallRogueNotes', { + str: 8 + }), + value: 80, + str: 8 + }, + fallWarrior: { + event: events.fall, + specialClass: 'warrior', + text: t('weaponSpecialFallWarriorText'), + notes: t('weaponSpecialFallWarriorNotes', { + str: 15 + }), + value: 90, + str: 15 + }, + fallMage: { + event: events.fall, + specialClass: 'wizard', + twoHanded: true, + text: t('weaponSpecialFallMageText'), + notes: t('weaponSpecialFallMageNotes', { + int: 15, + per: 7 + }), + value: 160, + int: 15, + per: 7 + }, + fallHealer: { + event: events.fall, + specialClass: 'healer', + text: t('weaponSpecialFallHealerText'), + notes: t('weaponSpecialFallHealerNotes', { + int: 9 + }), + value: 90, + int: 9 + }, + winter2015Rogue: { + event: events.winter2015, + specialClass: 'rogue', + text: t('weaponSpecialWinter2015RogueText'), + notes: t('weaponSpecialWinter2015RogueNotes', { + str: 8 + }), + value: 80, + str: 8 + }, + winter2015Warrior: { + event: events.winter2015, + specialClass: 'warrior', + text: t('weaponSpecialWinter2015WarriorText'), + notes: t('weaponSpecialWinter2015WarriorNotes', { + str: 15 + }), + value: 90, + str: 15 + }, + winter2015Mage: { + event: events.winter2015, + specialClass: 'wizard', + twoHanded: true, + text: t('weaponSpecialWinter2015MageText'), + notes: t('weaponSpecialWinter2015MageNotes', { + int: 15, + per: 7 + }), + value: 160, + int: 15, + per: 7 + }, + winter2015Healer: { + event: events.winter2015, + specialClass: 'healer', + text: t('weaponSpecialWinter2015HealerText'), + notes: t('weaponSpecialWinter2015HealerNotes', { + int: 9 + }), + value: 90, + int: 9 + } + }, + mystery: { + 201411: { + text: t('weaponMystery201411Text'), + notes: t('weaponMystery201411Notes'), + mystery: '201411', + value: 0 + }, + 301404: { + text: t('weaponMystery301404Text'), + notes: t('weaponMystery301404Notes'), + mystery: '301404', + value: 0 + } + } + }, + armor: { + base: { + 0: { + text: t('armorBase0Text'), + notes: t('armorBase0Notes'), + value: 0 + } + }, + warrior: { + 1: { + text: t('armorWarrior1Text'), + notes: t('armorWarrior1Notes', { + con: 3 + }), + con: 3, + value: 30 + }, + 2: { + text: t('armorWarrior2Text'), + notes: t('armorWarrior2Notes', { + con: 5 + }), + con: 5, + value: 45 + }, + 3: { + text: t('armorWarrior3Text'), + notes: t('armorWarrior3Notes', { + con: 7 + }), + con: 7, + value: 65 + }, + 4: { + text: t('armorWarrior4Text'), + notes: t('armorWarrior4Notes', { + con: 9 + }), + con: 9, + value: 90 + }, + 5: { + text: t('armorWarrior5Text'), + notes: t('armorWarrior5Notes', { + con: 11 + }), + con: 11, + value: 120, + last: true + } + }, + rogue: { + 1: { + text: t('armorRogue1Text'), + notes: t('armorRogue1Notes', { + per: 6 + }), + per: 6, + value: 30 + }, + 2: { + text: t('armorRogue2Text'), + notes: t('armorRogue2Notes', { + per: 9 + }), + per: 9, + value: 45 + }, + 3: { + text: t('armorRogue3Text'), + notes: t('armorRogue3Notes', { + per: 12 + }), + per: 12, + value: 65 + }, + 4: { + text: t('armorRogue4Text'), + notes: t('armorRogue4Notes', { + per: 15 + }), + per: 15, + value: 90 + }, + 5: { + text: t('armorRogue5Text'), + notes: t('armorRogue5Notes', { + per: 18 + }), + per: 18, + value: 120, + last: true + } + }, + wizard: { + 1: { + text: t('armorWizard1Text'), + notes: t('armorWizard1Notes', { + int: 2 + }), + int: 2, + value: 30 + }, + 2: { + text: t('armorWizard2Text'), + notes: t('armorWizard2Notes', { + int: 4 + }), + int: 4, + value: 45 + }, + 3: { + text: t('armorWizard3Text'), + notes: t('armorWizard3Notes', { + int: 6 + }), + int: 6, + value: 65 + }, + 4: { + text: t('armorWizard4Text'), + notes: t('armorWizard4Notes', { + int: 9 + }), + int: 9, + value: 90 + }, + 5: { + text: t('armorWizard5Text'), + notes: t('armorWizard5Notes', { + int: 12 + }), + int: 12, + value: 120, + last: true + } + }, + healer: { + 1: { + text: t('armorHealer1Text'), + notes: t('armorHealer1Notes', { + con: 6 + }), + con: 6, + value: 30 + }, + 2: { + text: t('armorHealer2Text'), + notes: t('armorHealer2Notes', { + con: 9 + }), + con: 9, + value: 45 + }, + 3: { + text: t('armorHealer3Text'), + notes: t('armorHealer3Notes', { + con: 12 + }), + con: 12, + value: 65 + }, + 4: { + text: t('armorHealer4Text'), + notes: t('armorHealer4Notes', { + con: 15 + }), + con: 15, + value: 90 + }, + 5: { + text: t('armorHealer5Text'), + notes: t('armorHealer5Notes', { + con: 18 + }), + con: 18, + value: 120, + last: true + } + }, + special: { + 0: { + text: t('armorSpecial0Text'), + notes: t('armorSpecial0Notes', { + con: 20 + }), + con: 20, + value: 150, + canOwn: (function(u) { + var _ref; + return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 45; + }) + }, + 1: { + text: t('armorSpecial1Text'), + notes: t('armorSpecial1Notes', { + attrs: 6 + }), + con: 6, + str: 6, + per: 6, + int: 6, + value: 170, + canOwn: (function(u) { + var _ref; + return +((_ref = u.contributor) != null ? _ref.level : void 0) >= 2; + }) + }, + 2: { + text: t('armorSpecial2Text'), + notes: t('armorSpecial2Notes', { + attrs: 25 + }), + int: 25, + con: 25, + value: 200, + canOwn: (function(u) { + var _ref; + return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 300 || (u.items.gear.owned.armor_special_2 != null); + }) + }, + yeti: { + event: events.winter, + specialClass: 'warrior', + text: t('armorSpecialYetiText'), + notes: t('armorSpecialYetiNotes', { + con: 9 + }), + con: 9, + value: 90 + }, + ski: { + event: events.winter, + specialClass: 'rogue', + text: t('armorSpecialSkiText'), + notes: t('armorSpecialSkiNotes', { + per: 15 + }), + per: 15, + value: 90 + }, + candycane: { + event: events.winter, + specialClass: 'wizard', + text: t('armorSpecialCandycaneText'), + notes: t('armorSpecialCandycaneNotes', { + int: 9 + }), + int: 9, + value: 90 + }, + snowflake: { + event: events.winter, + specialClass: 'healer', + text: t('armorSpecialSnowflakeText'), + notes: t('armorSpecialSnowflakeNotes', { + con: 15 + }), + con: 15, + value: 90 + }, + birthday: { + event: events.birthday, + text: t('armorSpecialBirthdayText'), + notes: t('armorSpecialBirthdayNotes'), + value: 0 + }, + springRogue: { + event: events.spring, + specialClass: 'rogue', + text: t('armorSpecialSpringRogueText'), + notes: t('armorSpecialSpringRogueNotes', { + per: 15 + }), + value: 90, + per: 15 + }, + springWarrior: { + event: events.spring, + specialClass: 'warrior', + text: t('armorSpecialSpringWarriorText'), + notes: t('armorSpecialSpringWarriorNotes', { + con: 9 + }), + value: 90, + con: 9 + }, + springMage: { + event: events.spring, + specialClass: 'wizard', + text: t('armorSpecialSpringMageText'), + notes: t('armorSpecialSpringMageNotes', { + int: 9 + }), + value: 90, + int: 9 + }, + springHealer: { + event: events.spring, + specialClass: 'healer', + text: t('armorSpecialSpringHealerText'), + notes: t('armorSpecialSpringHealerNotes', { + con: 15 + }), + value: 90, + con: 15 + }, + summerRogue: { + event: events.summer, + specialClass: 'rogue', + text: t('armorSpecialSummerRogueText'), + notes: t('armorSpecialSummerRogueNotes', { + per: 15 + }), + value: 90, + per: 15 + }, + summerWarrior: { + event: events.summer, + specialClass: 'warrior', + text: t('armorSpecialSummerWarriorText'), + notes: t('armorSpecialSummerWarriorNotes', { + con: 9 + }), + value: 90, + con: 9 + }, + summerMage: { + event: events.summer, + specialClass: 'wizard', + text: t('armorSpecialSummerMageText'), + notes: t('armorSpecialSummerMageNotes', { + int: 9 + }), + value: 90, + int: 9 + }, + summerHealer: { + event: events.summer, + specialClass: 'healer', + text: t('armorSpecialSummerHealerText'), + notes: t('armorSpecialSummerHealerNotes', { + con: 15 + }), + value: 90, + con: 15 + }, + fallRogue: { + event: events.fall, + specialClass: 'rogue', + text: t('armorSpecialFallRogueText'), + notes: t('armorSpecialFallRogueNotes', { + per: 15 + }), + value: 90, + per: 15 + }, + fallWarrior: { + event: events.fall, + specialClass: 'warrior', + text: t('armorSpecialFallWarriorText'), + notes: t('armorSpecialFallWarriorNotes', { + con: 9 + }), + value: 90, + con: 9 + }, + fallMage: { + event: events.fall, + specialClass: 'wizard', + text: t('armorSpecialFallMageText'), + notes: t('armorSpecialFallMageNotes', { + int: 9 + }), + value: 90, + int: 9 + }, + fallHealer: { + event: events.fall, + specialClass: 'healer', + text: t('armorSpecialFallHealerText'), + notes: t('armorSpecialFallHealerNotes', { + con: 15 + }), + value: 90, + con: 15 + }, + winter2015Rogue: { + event: events.winter2015, + specialClass: 'rogue', + text: t('armorSpecialWinter2015RogueText'), + notes: t('armorSpecialWinter2015RogueNotes', { + per: 15 + }), + value: 90, + per: 15 + }, + winter2015Warrior: { + event: events.winter2015, + specialClass: 'warrior', + text: t('armorSpecialWinter2015WarriorText'), + notes: t('armorSpecialWinter2015WarriorNotes', { + con: 9 + }), + value: 90, + con: 9 + }, + winter2015Mage: { + event: events.winter2015, + specialClass: 'wizard', + text: t('armorSpecialWinter2015MageText'), + notes: t('armorSpecialWinter2015MageNotes', { + int: 9 + }), + value: 90, + int: 9 + }, + winter2015Healer: { + event: events.winter2015, + specialClass: 'healer', + text: t('armorSpecialWinter2015HealerText'), + notes: t('armorSpecialWinter2015HealerNotes', { + con: 15 + }), + value: 90, + con: 15 + }, + birthday2015: { + text: t('armorSpecialBirthday2015Text'), + notes: t('armorSpecialBirthday2015Notes'), + value: 0, + canOwn: (function(u) { + return u.items.gear.owned.armor_special_birthday2015 != null; + }) + }, + gaymerx: { + event: events.gaymerx, + text: t('armorSpecialGaymerxText'), + notes: t('armorSpecialGaymerxNotes'), + value: 0 + } + }, + mystery: { + 201402: { + text: t('armorMystery201402Text'), + notes: t('armorMystery201402Notes'), + mystery: '201402', + value: 0 + }, + 201403: { + text: t('armorMystery201403Text'), + notes: t('armorMystery201403Notes'), + mystery: '201403', + value: 0 + }, + 201405: { + text: t('armorMystery201405Text'), + notes: t('armorMystery201405Notes'), + mystery: '201405', + value: 0 + }, + 201406: { + text: t('armorMystery201406Text'), + notes: t('armorMystery201406Notes'), + mystery: '201406', + value: 0 + }, + 201407: { + text: t('armorMystery201407Text'), + notes: t('armorMystery201407Notes'), + mystery: '201407', + value: 0 + }, + 201408: { + text: t('armorMystery201408Text'), + notes: t('armorMystery201408Notes'), + mystery: '201408', + value: 0 + }, + 201409: { + text: t('armorMystery201409Text'), + notes: t('armorMystery201409Notes'), + mystery: '201409', + value: 0 + }, + 201410: { + text: t('armorMystery201410Text'), + notes: t('armorMystery201410Notes'), + mystery: '201410', + value: 0 + }, + 201412: { + text: t('armorMystery201412Text'), + notes: t('armorMystery201412Notes'), + mystery: '201412', + value: 0 + }, + 201501: { + text: t('armorMystery201501Text'), + notes: t('armorMystery201501Notes'), + mystery: '201501', + value: 0 + }, + 301404: { + text: t('armorMystery301404Text'), + notes: t('armorMystery301404Notes'), + mystery: '301404', + value: 0 + } + } + }, + head: { + base: { + 0: { + text: t('headBase0Text'), + notes: t('headBase0Notes'), + value: 0 + } + }, + warrior: { + 1: { + text: t('headWarrior1Text'), + notes: t('headWarrior1Notes', { + str: 2 + }), + str: 2, + value: 15 + }, + 2: { + text: t('headWarrior2Text'), + notes: t('headWarrior2Notes', { + str: 4 + }), + str: 4, + value: 25 + }, + 3: { + text: t('headWarrior3Text'), + notes: t('headWarrior3Notes', { + str: 6 + }), + str: 6, + value: 40 + }, + 4: { + text: t('headWarrior4Text'), + notes: t('headWarrior4Notes', { + str: 9 + }), + str: 9, + value: 60 + }, + 5: { + text: t('headWarrior5Text'), + notes: t('headWarrior5Notes', { + str: 12 + }), + str: 12, + value: 80, + last: true + } + }, + rogue: { + 1: { + text: t('headRogue1Text'), + notes: t('headRogue1Notes', { + per: 2 + }), + per: 2, + value: 15 + }, + 2: { + text: t('headRogue2Text'), + notes: t('headRogue2Notes', { + per: 4 + }), + per: 4, + value: 25 + }, + 3: { + text: t('headRogue3Text'), + notes: t('headRogue3Notes', { + per: 6 + }), + per: 6, + value: 40 + }, + 4: { + text: t('headRogue4Text'), + notes: t('headRogue4Notes', { + per: 9 + }), + per: 9, + value: 60 + }, + 5: { + text: t('headRogue5Text'), + notes: t('headRogue5Notes', { + per: 12 + }), + per: 12, + value: 80, + last: true + } + }, + wizard: { + 1: { + text: t('headWizard1Text'), + notes: t('headWizard1Notes', { + per: 2 + }), + per: 2, + value: 15 + }, + 2: { + text: t('headWizard2Text'), + notes: t('headWizard2Notes', { + per: 3 + }), + per: 3, + value: 25 + }, + 3: { + text: t('headWizard3Text'), + notes: t('headWizard3Notes', { + per: 5 + }), + per: 5, + value: 40 + }, + 4: { + text: t('headWizard4Text'), + notes: t('headWizard4Notes', { + per: 7 + }), + per: 7, + value: 60 + }, + 5: { + text: t('headWizard5Text'), + notes: t('headWizard5Notes', { + per: 10 + }), + per: 10, + value: 80, + last: true + } + }, + healer: { + 1: { + text: t('headHealer1Text'), + notes: t('headHealer1Notes', { + int: 2 + }), + int: 2, + value: 15 + }, + 2: { + text: t('headHealer2Text'), + notes: t('headHealer2Notes', { + int: 3 + }), + int: 3, + value: 25 + }, + 3: { + text: t('headHealer3Text'), + notes: t('headHealer3Notes', { + int: 5 + }), + int: 5, + value: 40 + }, + 4: { + text: t('headHealer4Text'), + notes: t('headHealer4Notes', { + int: 7 + }), + int: 7, + value: 60 + }, + 5: { + text: t('headHealer5Text'), + notes: t('headHealer5Notes', { + int: 9 + }), + int: 9, + value: 80, + last: true + } + }, + special: { + 0: { + text: t('headSpecial0Text'), + notes: t('headSpecial0Notes', { + int: 20 + }), + int: 20, + value: 150, + canOwn: (function(u) { + var _ref; + return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 45; + }) + }, + 1: { + text: t('headSpecial1Text'), + notes: t('headSpecial1Notes', { + attrs: 6 + }), + con: 6, + str: 6, + per: 6, + int: 6, + value: 170, + canOwn: (function(u) { + var _ref; + return +((_ref = u.contributor) != null ? _ref.level : void 0) >= 3; + }) + }, + 2: { + text: t('headSpecial2Text'), + notes: t('headSpecial2Notes', { + attrs: 25 + }), + int: 25, + str: 25, + value: 200, + canOwn: (function(u) { + var _ref; + return (+((_ref = u.backer) != null ? _ref.tier : void 0) >= 300) || (u.items.gear.owned.head_special_2 != null); + }) + }, + nye: { + event: events.winter, + text: t('headSpecialNyeText'), + notes: t('headSpecialNyeNotes'), + value: 0 + }, + yeti: { + event: events.winter, + specialClass: 'warrior', + text: t('headSpecialYetiText'), + notes: t('headSpecialYetiNotes', { + str: 9 + }), + str: 9, + value: 60 + }, + ski: { + event: events.winter, + specialClass: 'rogue', + text: t('headSpecialSkiText'), + notes: t('headSpecialSkiNotes', { + per: 9 + }), + per: 9, + value: 60 + }, + candycane: { + event: events.winter, + specialClass: 'wizard', + text: t('headSpecialCandycaneText'), + notes: t('headSpecialCandycaneNotes', { + per: 7 + }), + per: 7, + value: 60 + }, + snowflake: { + event: events.winter, + specialClass: 'healer', + text: t('headSpecialSnowflakeText'), + notes: t('headSpecialSnowflakeNotes', { + int: 7 + }), + int: 7, + value: 60 + }, + springRogue: { + event: events.spring, + specialClass: 'rogue', + text: t('headSpecialSpringRogueText'), + notes: t('headSpecialSpringRogueNotes', { + per: 9 + }), + value: 60, + per: 9 + }, + springWarrior: { + event: events.spring, + specialClass: 'warrior', + text: t('headSpecialSpringWarriorText'), + notes: t('headSpecialSpringWarriorNotes', { + str: 9 + }), + value: 60, + str: 9 + }, + springMage: { + event: events.spring, + specialClass: 'wizard', + text: t('headSpecialSpringMageText'), + notes: t('headSpecialSpringMageNotes', { + per: 7 + }), + value: 60, + per: 7 + }, + springHealer: { + event: events.spring, + specialClass: 'healer', + text: t('headSpecialSpringHealerText'), + notes: t('headSpecialSpringHealerNotes', { + int: 7 + }), + value: 60, + int: 7 + }, + summerRogue: { + event: events.summer, + specialClass: 'rogue', + text: t('headSpecialSummerRogueText'), + notes: t('headSpecialSummerRogueNotes', { + per: 9 + }), + value: 60, + per: 9 + }, + summerWarrior: { + event: events.summer, + specialClass: 'warrior', + text: t('headSpecialSummerWarriorText'), + notes: t('headSpecialSummerWarriorNotes', { + str: 9 + }), + value: 60, + str: 9 + }, + summerMage: { + event: events.summer, + specialClass: 'wizard', + text: t('headSpecialSummerMageText'), + notes: t('headSpecialSummerMageNotes', { + per: 7 + }), + value: 60, + per: 7 + }, + summerHealer: { + event: events.summer, + specialClass: 'healer', + text: t('headSpecialSummerHealerText'), + notes: t('headSpecialSummerHealerNotes', { + int: 7 + }), + value: 60, + int: 7 + }, + fallRogue: { + event: events.fall, + specialClass: 'rogue', + text: t('headSpecialFallRogueText'), + notes: t('headSpecialFallRogueNotes', { + per: 9 + }), + value: 60, + per: 9 + }, + fallWarrior: { + event: events.fall, + specialClass: 'warrior', + text: t('headSpecialFallWarriorText'), + notes: t('headSpecialFallWarriorNotes', { + str: 9 + }), + value: 60, + str: 9 + }, + fallMage: { + event: events.fall, + specialClass: 'wizard', + text: t('headSpecialFallMageText'), + notes: t('headSpecialFallMageNotes', { + per: 7 + }), + value: 60, + per: 7 + }, + fallHealer: { + event: events.fall, + specialClass: 'healer', + text: t('headSpecialFallHealerText'), + notes: t('headSpecialFallHealerNotes', { + int: 7 + }), + value: 60, + int: 7 + }, + winter2015Rogue: { + event: events.winter2015, + specialClass: 'rogue', + text: t('headSpecialWinter2015RogueText'), + notes: t('headSpecialWinter2015RogueNotes', { + per: 9 + }), + value: 60, + per: 9 + }, + winter2015Warrior: { + event: events.winter2015, + specialClass: 'warrior', + text: t('headSpecialWinter2015WarriorText'), + notes: t('headSpecialWinter2015WarriorNotes', { + str: 9 + }), + value: 60, + str: 9 + }, + winter2015Mage: { + event: events.winter2015, + specialClass: 'wizard', + text: t('headSpecialWinter2015MageText'), + notes: t('headSpecialWinter2015MageNotes', { + per: 7 + }), + value: 60, + per: 7 + }, + winter2015Healer: { + event: events.winter2015, + specialClass: 'healer', + text: t('headSpecialWinter2015HealerText'), + notes: t('headSpecialWinter2015HealerNotes', { + int: 7 + }), + value: 60, + int: 7 + }, + nye2014: { + text: t('headSpecialNye2014Text'), + notes: t('headSpecialNye2014Notes'), + value: 0, + canOwn: (function(u) { + return u.items.gear.owned.head_special_nye2014 != null; + }) + }, + gaymerx: { + event: events.gaymerx, + text: t('headSpecialGaymerxText'), + notes: t('headSpecialGaymerxNotes'), + value: 0 + } + }, + mystery: { + 201402: { + text: t('headMystery201402Text'), + notes: t('headMystery201402Notes'), + mystery: '201402', + value: 0 + }, + 201405: { + text: t('headMystery201405Text'), + notes: t('headMystery201405Notes'), + mystery: '201405', + value: 0 + }, + 201406: { + text: t('headMystery201406Text'), + notes: t('headMystery201406Notes'), + mystery: '201406', + value: 0 + }, + 201407: { + text: t('headMystery201407Text'), + notes: t('headMystery201407Notes'), + mystery: '201407', + value: 0 + }, + 201408: { + text: t('headMystery201408Text'), + notes: t('headMystery201408Notes'), + mystery: '201408', + value: 0 + }, + 201411: { + text: t('headMystery201411Text'), + notes: t('headMystery201411Notes'), + mystery: '201411', + value: 0 + }, + 201412: { + text: t('headMystery201412Text'), + notes: t('headMystery201412Notes'), + mystery: '201412', + value: 0 + }, + 201501: { + text: t('headMystery201501Text'), + notes: t('headMystery201501Notes'), + mystery: '201501', + value: 0 + }, + 301404: { + text: t('headMystery301404Text'), + notes: t('headMystery301404Notes'), + mystery: '301404', + value: 0 + }, + 301405: { + text: t('headMystery301405Text'), + notes: t('headMystery301405Notes'), + mystery: '301405', + value: 0 + } + } + }, + shield: { + base: { + 0: { + text: t('shieldBase0Text'), + notes: t('shieldBase0Notes'), + value: 0 + } + }, + warrior: { + 1: { + text: t('shieldWarrior1Text'), + notes: t('shieldWarrior1Notes', { + con: 2 + }), + con: 2, + value: 20 + }, + 2: { + text: t('shieldWarrior2Text'), + notes: t('shieldWarrior2Notes', { + con: 3 + }), + con: 3, + value: 35 + }, + 3: { + text: t('shieldWarrior3Text'), + notes: t('shieldWarrior3Notes', { + con: 5 + }), + con: 5, + value: 50 + }, + 4: { + text: t('shieldWarrior4Text'), + notes: t('shieldWarrior4Notes', { + con: 7 + }), + con: 7, + value: 70 + }, + 5: { + text: t('shieldWarrior5Text'), + notes: t('shieldWarrior5Notes', { + con: 9 + }), + con: 9, + value: 90, + last: true + } + }, + rogue: { + 0: { + text: t('weaponRogue0Text'), + notes: t('weaponRogue0Notes'), + str: 0, + value: 0 + }, + 1: { + text: t('weaponRogue1Text'), + notes: t('weaponRogue1Notes', { + str: 2 + }), + str: 2, + value: 20 + }, + 2: { + text: t('weaponRogue2Text'), + notes: t('weaponRogue2Notes', { + str: 3 + }), + str: 3, + value: 35 + }, + 3: { + text: t('weaponRogue3Text'), + notes: t('weaponRogue3Notes', { + str: 4 + }), + str: 4, + value: 50 + }, + 4: { + text: t('weaponRogue4Text'), + notes: t('weaponRogue4Notes', { + str: 6 + }), + str: 6, + value: 70 + }, + 5: { + text: t('weaponRogue5Text'), + notes: t('weaponRogue5Notes', { + str: 8 + }), + str: 8, + value: 90 + }, + 6: { + text: t('weaponRogue6Text'), + notes: t('weaponRogue6Notes', { + str: 10 + }), + str: 10, + value: 120, + last: true + } + }, + wizard: {}, + healer: { + 1: { + text: t('shieldHealer1Text'), + notes: t('shieldHealer1Notes', { + con: 2 + }), + con: 2, + value: 20 + }, + 2: { + text: t('shieldHealer2Text'), + notes: t('shieldHealer2Notes', { + con: 4 + }), + con: 4, + value: 35 + }, + 3: { + text: t('shieldHealer3Text'), + notes: t('shieldHealer3Notes', { + con: 6 + }), + con: 6, + value: 50 + }, + 4: { + text: t('shieldHealer4Text'), + notes: t('shieldHealer4Notes', { + con: 9 + }), + con: 9, + value: 70 + }, + 5: { + text: t('shieldHealer5Text'), + notes: t('shieldHealer5Notes', { + con: 12 + }), + con: 12, + value: 90, + last: true + } + }, + special: { + 0: { + text: t('shieldSpecial0Text'), + notes: t('shieldSpecial0Notes', { + per: 20 + }), + per: 20, + value: 150, + canOwn: (function(u) { + var _ref; + return +((_ref = u.backer) != null ? _ref.tier : void 0) >= 45; + }) + }, + 1: { + text: t('shieldSpecial1Text'), + notes: t('shieldSpecial1Notes', { + attrs: 6 + }), + con: 6, + str: 6, + per: 6, + int: 6, + value: 170, + canOwn: (function(u) { + var _ref; + return +((_ref = u.contributor) != null ? _ref.level : void 0) >= 5; + }) + }, + goldenknight: { + text: t('shieldSpecialGoldenknightText'), + notes: t('shieldSpecialGoldenknightNotes', { + attrs: 25 + }), + con: 25, + per: 25, + value: 200, + canOwn: (function(u) { + return u.items.gear.owned.shield_special_goldenknight != null; + }) + }, + yeti: { + event: events.winter, + specialClass: 'warrior', + text: t('shieldSpecialYetiText'), + notes: t('shieldSpecialYetiNotes', { + con: 7 + }), + con: 7, + value: 70 + }, + ski: { + event: events.winter, + specialClass: 'rogue', + text: t('weaponSpecialSkiText'), + notes: t('weaponSpecialSkiNotes', { + str: 8 + }), + str: 8, + value: 90 + }, + snowflake: { + event: events.winter, + specialClass: 'healer', + text: t('shieldSpecialSnowflakeText'), + notes: t('shieldSpecialSnowflakeNotes', { + con: 9 + }), + con: 9, + value: 70 + }, + springRogue: { + event: events.spring, + specialClass: 'rogue', + text: t('shieldSpecialSpringRogueText'), + notes: t('shieldSpecialSpringRogueNotes', { + str: 8 + }), + value: 80, + str: 8 + }, + springWarrior: { + event: events.spring, + specialClass: 'warrior', + text: t('shieldSpecialSpringWarriorText'), + notes: t('shieldSpecialSpringWarriorNotes', { + con: 7 + }), + value: 70, + con: 7 + }, + springHealer: { + event: events.spring, + specialClass: 'healer', + text: t('shieldSpecialSpringHealerText'), + notes: t('shieldSpecialSpringHealerNotes', { + con: 9 + }), + value: 70, + con: 9 + }, + summerRogue: { + event: events.summer, + specialClass: 'rogue', + text: t('shieldSpecialSummerRogueText'), + notes: t('shieldSpecialSummerRogueNotes', { + str: 8 + }), + value: 80, + str: 8 + }, + summerWarrior: { + event: events.summer, + specialClass: 'warrior', + text: t('shieldSpecialSummerWarriorText'), + notes: t('shieldSpecialSummerWarriorNotes', { + con: 7 + }), + value: 70, + con: 7 + }, + summerHealer: { + event: events.summer, + specialClass: 'healer', + text: t('shieldSpecialSummerHealerText'), + notes: t('shieldSpecialSummerHealerNotes', { + con: 9 + }), + value: 70, + con: 9 + }, + fallRogue: { + event: events.fall, + specialClass: 'rogue', + text: t('shieldSpecialFallRogueText'), + notes: t('shieldSpecialFallRogueNotes', { + str: 8 + }), + value: 80, + str: 8 + }, + fallWarrior: { + event: events.fall, + specialClass: 'warrior', + text: t('shieldSpecialFallWarriorText'), + notes: t('shieldSpecialFallWarriorNotes', { + con: 7 + }), + value: 70, + con: 7 + }, + fallHealer: { + event: events.fall, + specialClass: 'healer', + text: t('shieldSpecialFallHealerText'), + notes: t('shieldSpecialFallHealerNotes', { + con: 9 + }), + value: 70, + con: 9 + }, + winter2015Rogue: { + event: events.winter2015, + specialClass: 'rogue', + text: t('shieldSpecialWinter2015RogueText'), + notes: t('shieldSpecialWinter2015RogueNotes', { + str: 8 + }), + value: 80, + str: 8 + }, + winter2015Warrior: { + event: events.winter2015, + specialClass: 'warrior', + text: t('shieldSpecialWinter2015WarriorText'), + notes: t('shieldSpecialWinter2015WarriorNotes', { + con: 7 + }), + value: 70, + con: 7 + }, + winter2015Healer: { + event: events.winter2015, + specialClass: 'healer', + text: t('shieldSpecialWinter2015HealerText'), + notes: t('shieldSpecialWinter2015HealerNotes', { + con: 9 + }), + value: 70, + con: 9 + } + }, + mystery: { + 301405: { + text: t('shieldMystery301405Text'), + notes: t('shieldMystery301405Notes'), + mystery: '301405', + value: 0 + } + } + }, + back: { + base: { + 0: { + text: t('backBase0Text'), + notes: t('backBase0Notes'), + value: 0 + } + }, + mystery: { + 201402: { + text: t('backMystery201402Text'), + notes: t('backMystery201402Notes'), + mystery: '201402', + value: 0 + }, + 201404: { + text: t('backMystery201404Text'), + notes: t('backMystery201404Notes'), + mystery: '201404', + value: 0 + }, + 201410: { + text: t('backMystery201410Text'), + notes: t('backMystery201410Notes'), + mystery: '201410', + value: 0 + } + }, + special: { + wondercon_red: { + text: t('backSpecialWonderconRedText'), + notes: t('backSpecialWonderconRedNotes'), + value: 0, + mystery: 'wondercon' + }, + wondercon_black: { + text: t('backSpecialWonderconBlackText'), + notes: t('backSpecialWonderconBlackNotes'), + value: 0, + mystery: 'wondercon' + } + } + }, + body: { + base: { + 0: { + text: t('bodyBase0Text'), + notes: t('bodyBase0Notes'), + value: 0 + } + }, + special: { + wondercon_red: { + text: t('bodySpecialWonderconRedText'), + notes: t('bodySpecialWonderconRedNotes'), + value: 0, + mystery: 'wondercon' + }, + wondercon_gold: { + text: t('bodySpecialWonderconGoldText'), + notes: t('bodySpecialWonderconGoldNotes'), + value: 0, + mystery: 'wondercon' + }, + wondercon_black: { + text: t('bodySpecialWonderconBlackText'), + notes: t('bodySpecialWonderconBlackNotes'), + value: 0, + mystery: 'wondercon' + }, + summerHealer: { + event: events.summer, + specialClass: 'healer', + text: t('bodySpecialSummerHealerText'), + notes: t('bodySpecialSummerHealerNotes'), + value: 20 + }, + summerMage: { + event: events.summer, + specialClass: 'wizard', + text: t('bodySpecialSummerMageText'), + notes: t('bodySpecialSummerMageNotes'), + value: 20 + } + } + }, + headAccessory: { + base: { + 0: { + text: t('headAccessoryBase0Text'), + notes: t('headAccessoryBase0Notes'), + value: 0, + last: true + } + }, + special: { + springRogue: { + event: events.spring, + specialClass: 'rogue', + text: t('headAccessorySpecialSpringRogueText'), + notes: t('headAccessorySpecialSpringRogueNotes'), + value: 20 + }, + springWarrior: { + event: events.spring, + specialClass: 'warrior', + text: t('headAccessorySpecialSpringWarriorText'), + notes: t('headAccessorySpecialSpringWarriorNotes'), + value: 20 + }, + springMage: { + event: events.spring, + specialClass: 'wizard', + text: t('headAccessorySpecialSpringMageText'), + notes: t('headAccessorySpecialSpringMageNotes'), + value: 20 + }, + springHealer: { + event: events.spring, + specialClass: 'healer', + text: t('headAccessorySpecialSpringHealerText'), + notes: t('headAccessorySpecialSpringHealerNotes'), + value: 20 + } + }, + mystery: { + 201403: { + text: t('headAccessoryMystery201403Text'), + notes: t('headAccessoryMystery201403Notes'), + mystery: '201403', + value: 0 + }, + 201404: { + text: t('headAccessoryMystery201404Text'), + notes: t('headAccessoryMystery201404Notes'), + mystery: '201404', + value: 0 + }, + 201409: { + text: t('headAccessoryMystery201409Text'), + notes: t('headAccessoryMystery201409Notes'), + mystery: '201409', + value: 0 + }, + 301405: { + text: t('headAccessoryMystery301405Text'), + notes: t('headAccessoryMystery301405Notes'), + mystery: '301405', + value: 0 + } + } + }, + eyewear: { + base: { + 0: { + text: t('eyewearBase0Text'), + notes: t('eyewearBase0Notes'), + value: 0, + last: true + } + }, + special: { + wondercon_red: { + text: t('eyewearSpecialWonderconRedText'), + notes: t('eyewearSpecialWonderconRedNotes'), + value: 0, + mystery: 'wondercon' + }, + wondercon_black: { + text: t('eyewearSpecialWonderconBlackText'), + notes: t('eyewearSpecialWonderconBlackNotes'), + value: 0, + mystery: 'wondercon' + }, + summerRogue: { + event: events.summer, + specialClass: 'rogue', + text: t('eyewearSpecialSummerRogueText'), + notes: t('eyewearSpecialSummerRogueNotes'), + value: 20 + }, + summerWarrior: { + event: events.summer, + specialClass: 'warrior', + text: t('eyewearSpecialSummerWarriorText'), + notes: t('eyewearSpecialSummerWarriorNotes'), + value: 20 + } + }, + mystery: { + 301404: { + text: t('eyewearMystery301404Text'), + notes: t('eyewearMystery301404Notes'), + mystery: '301404', + value: 0 + }, + 301405: { + text: t('eyewearMystery301405Text'), + notes: t('eyewearMystery301405Notes'), + mystery: '301405', + value: 0 + } + } + } +}; + + +/* + The gear is exported as a tree (defined above), and a flat list (eg, {weapon_healer_1: .., shield_special_0: ...}) since + they are needed in different froms at different points in the app + */ + +api.gear = { + tree: gear, + flat: {} +}; + +_.each(gearTypes, function(type) { + return _.each(classes.concat(['base', 'special', 'mystery']), function(klass) { + return _.each(gear[type][klass], function(item, i) { + var key, _canOwn; + key = "" + type + "_" + klass + "_" + i; + _.defaults(item, { + type: type, + key: key, + klass: klass, + index: i, + str: 0, + int: 0, + per: 0, + con: 0 + }); + if (item.event) { + _canOwn = item.canOwn || (function() { + return true; + }); + item.canOwn = function(u) { + return _canOwn(u) && ((u.items.gear.owned[key] != null) || (moment().isAfter(item.event.start) && moment().isBefore(item.event.end))) && (item.specialClass ? u.stats["class"] === item.specialClass : true); + }; + } + if (item.mystery) { + item.canOwn = function(u) { + return u.items.gear.owned[key] != null; + }; + } + return api.gear.flat[key] = item; + }); + }); +}); + + +/* + Time Traveler Store, mystery sets need their items mapped in + */ + +_.each(api.mystery, function(v, k) { + return v.items = _.where(api.gear.flat, { + mystery: k + }); +}); + +api.timeTravelerStore = function(owned) { + var ownedKeys; + ownedKeys = _.keys((typeof owned.toObject === "function" ? owned.toObject() : void 0) || owned); + return _.reduce(api.mystery, function(m, v, k) { + if (k === 'wondercon' || ~ownedKeys.indexOf(v.items[0].key)) { + return m; + } + m[k] = v; + return m; + }, {}); +}; + + +/* + --------------------------------------------------------------- + Potion + --------------------------------------------------------------- + */ + +api.potion = { + type: 'potion', + text: t('potionText'), + notes: t('potionNotes'), + value: 25, + key: 'potion' +}; + + +/* + --------------------------------------------------------------- + Classes + --------------------------------------------------------------- + */ + +api.classes = classes; + + +/* + --------------------------------------------------------------- + Gear Types + --------------------------------------------------------------- + */ + +api.gearTypes = gearTypes; + + +/* + --------------------------------------------------------------- + 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) + */ + +diminishingReturns = function(bonus, max, halfway) { + if (halfway == null) { + halfway = max / 2; + } + return max * (bonus / (bonus + halfway)); +}; + +api.spells = { + wizard: { + fireball: { + text: t('spellWizardFireballText'), + mana: 10, + lvl: 11, + target: 'task', + notes: t('spellWizardFireballNotes'), + cast: function(user, target) { + var bonus; + bonus = user._statsComputed.int * user.fns.crit('per'); + target.value += diminishingReturns(bonus * .02, 4); + bonus *= Math.ceil((target.value < 0 ? 1 : target.value + 1) * .075); + user.stats.exp += diminishingReturns(bonus, 75); + return user.party.quest.progress.up += diminishingReturns(bonus * .1, 50, 30); + } + }, + mpheal: { + text: t('spellWizardMPHealText'), + mana: 30, + lvl: 12, + target: 'party', + notes: t('spellWizardMPHealNotes'), + cast: function(user, target) { + return _.each(target, function(member) { + var bonus; + bonus = Math.ceil(user._statsComputed.int * .1); + if (bonus > 25) { + bonus = 25; + } + return member.stats.mp += bonus; + }); + } + }, + earth: { + text: t('spellWizardEarthText'), + mana: 35, + lvl: 13, + target: 'party', + notes: t('spellWizardEarthNotes'), + cast: function(user, target) { + return _.each(target, function(member) { + var _base; + if ((_base = member.stats.buffs).int == null) { + _base.int = 0; + } + return member.stats.buffs.int += Math.ceil(user._statsComputed.int * .05); + }); + } + }, + frost: { + text: t('spellWizardFrostText'), + mana: 40, + lvl: 14, + target: 'self', + notes: t('spellWizardFrostNotes'), + cast: function(user, target) { + return user.stats.buffs.streaks = true; + } + } + }, + warrior: { + smash: { + text: t('spellWarriorSmashText'), + mana: 10, + lvl: 11, + target: 'task', + notes: t('spellWarriorSmashNotes'), + cast: function(user, target) { + target.value += 2.5 * (user._statsComputed.str / (user._statsComputed.str + 50)) * user.fns.crit('con'); + return user.party.quest.progress.up += Math.ceil(user._statsComputed.str * .2); + } + }, + defensiveStance: { + text: t('spellWarriorDefensiveStanceText'), + mana: 25, + lvl: 12, + target: 'self', + notes: t('spellWarriorDefensiveStanceNotes'), + cast: function(user, target) { + var _base; + if ((_base = user.stats.buffs).con == null) { + _base.con = 0; + } + return user.stats.buffs.con += Math.ceil(user._statsComputed.con * .05); + } + }, + valorousPresence: { + text: t('spellWarriorValorousPresenceText'), + mana: 20, + lvl: 13, + target: 'party', + notes: t('spellWarriorValorousPresenceNotes'), + cast: function(user, target) { + return _.each(target, function(member) { + var _base; + if ((_base = member.stats.buffs).str == null) { + _base.str = 0; + } + return member.stats.buffs.str += Math.ceil(user._statsComputed.str * .05); + }); + } + }, + intimidate: { + text: t('spellWarriorIntimidateText'), + mana: 15, + lvl: 14, + target: 'party', + notes: t('spellWarriorIntimidateNotes'), + cast: function(user, target) { + return _.each(target, function(member) { + var _base; + if ((_base = member.stats.buffs).con == null) { + _base.con = 0; + } + return member.stats.buffs.con += Math.ceil(user._statsComputed.con * .03); + }); + } + } + }, + rogue: { + pickPocket: { + text: t('spellRoguePickPocketText'), + mana: 10, + lvl: 11, + target: 'task', + notes: t('spellRoguePickPocketNotes'), + cast: function(user, target) { + var bonus; + bonus = (target.value < 0 ? 1 : target.value + 2) + (user._statsComputed.per * 0.5); + return user.stats.gp += 25 * (bonus / (bonus + 75)); + } + }, + backStab: { + text: t('spellRogueBackStabText'), + mana: 15, + lvl: 12, + target: 'task', + notes: t('spellRogueBackStabNotes'), + cast: function(user, target) { + var bonus, _crit; + _crit = user.fns.crit('str', .3); + target.value += _crit * .03; + bonus = (target.value < 0 ? 1 : target.value + 1) * _crit; + user.stats.exp += bonus; + return user.stats.gp += bonus; + } + }, + toolsOfTrade: { + text: t('spellRogueToolsOfTradeText'), + mana: 25, + lvl: 13, + target: 'party', + notes: t('spellRogueToolsOfTradeNotes'), + cast: function(user, target) { + return _.each(target, function(member) { + var _base; + if ((_base = member.stats.buffs).per == null) { + _base.per = 0; + } + return member.stats.buffs.per += Math.ceil(user._statsComputed.per * .03); + }); + } + }, + stealth: { + text: t('spellRogueStealthText'), + mana: 45, + lvl: 14, + target: 'self', + notes: t('spellRogueStealthNotes'), + cast: function(user, target) { + var _base; + if ((_base = user.stats.buffs).stealth == null) { + _base.stealth = 0; + } + return user.stats.buffs.stealth += Math.ceil(user.dailys.length * user._statsComputed.per / 100); + } + } + }, + healer: { + heal: { + text: t('spellHealerHealText'), + mana: 15, + lvl: 11, + target: 'self', + notes: t('spellHealerHealNotes'), + cast: function(user, target) { + user.stats.hp += (user._statsComputed.con + user._statsComputed.int + 5) * .075; + if (user.stats.hp > 50) { + return user.stats.hp = 50; + } + } + }, + brightness: { + text: t('spellHealerBrightnessText'), + mana: 15, + lvl: 12, + target: 'self', + notes: t('spellHealerBrightnessNotes'), + cast: function(user, target) { + return _.each(user.tasks, function(target) { + if (target.type === 'reward') { + return; + } + return target.value += 1.5 * (user._statsComputed.int / (user._statsComputed.int + 40)); + }); + } + }, + protectAura: { + text: t('spellHealerProtectAuraText'), + mana: 30, + lvl: 13, + target: 'party', + notes: t('spellHealerProtectAuraNotes'), + cast: function(user, target) { + return _.each(target, function(member) { + var _base; + if ((_base = member.stats.buffs).con == null) { + _base.con = 0; + } + return member.stats.buffs.con += Math.ceil(user._statsComputed.con * .15); + }); + } + }, + heallAll: { + text: t('spellHealerHealAllText'), + mana: 25, + lvl: 14, + target: 'party', + notes: t('spellHealerHealAllNotes'), + cast: function(user, target) { + return _.each(target, function(member) { + member.stats.hp += (user._statsComputed.con + user._statsComputed.int + 5) * .04; + if (member.stats.hp > 50) { + return member.stats.hp = 50; + } + }); + } + } + }, + special: { + snowball: { + text: t('spellSpecialSnowballAuraText'), + mana: 0, + value: 15, + target: 'user', + notes: t('spellSpecialSnowballAuraNotes'), + cast: function(user, target) { + var _base; + target.stats.buffs.snowball = true; + if ((_base = target.achievements).snowball == null) { + _base.snowball = 0; + } + target.achievements.snowball++; + return user.items.special.snowball--; + } + }, + salt: { + text: t('spellSpecialSaltText'), + mana: 0, + value: 5, + immediateUse: true, + target: 'self', + notes: t('spellSpecialSaltNotes'), + cast: function(user, target) { + user.stats.buffs.snowball = false; + return user.stats.gp -= 5; + } + }, + spookDust: { + text: t('spellSpecialSpookDustText'), + mana: 0, + value: 15, + target: 'user', + notes: t('spellSpecialSpookDustNotes'), + cast: function(user, target) { + var _base; + target.stats.buffs.spookDust = true; + if ((_base = target.achievements).spookDust == null) { + _base.spookDust = 0; + } + target.achievements.spookDust++; + return user.items.special.spookDust--; + } + }, + opaquePotion: { + text: t('spellSpecialOpaquePotionText'), + mana: 0, + value: 5, + immediateUse: true, + target: 'self', + notes: t('spellSpecialOpaquePotionNotes'), + cast: function(user, target) { + user.stats.buffs.spookDust = false; + return user.stats.gp -= 5; + } + }, + nye: { + text: t('nyeCard'), + mana: 0, + value: 10, + immediateUse: true, + target: 'user', + notes: t('nyeCardNotes'), + cast: function(user, target) { + var _base; + if (user === target) { + if ((_base = user.achievements).nye == null) { + _base.nye = 0; + } + user.achievements.nye++; + } else { + _.each([user, target], function(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); + if (typeof target.markModified === "function") { + target.markModified('items.special.nyeReceived'); + } + return user.stats.gp -= 10; + } + } + } +}; + +_.each(api.spells, function(spellClass) { + return _.each(spellClass, function(spell, key) { + var _cast; + spell.key = key; + _cast = spell.cast; + return spell.cast = function(user, target) { + _cast(user, target); + return user.stats.mp -= spell.mana; + }; + }); +}); + +api.special = api.spells.special; + + +/* + --------------------------------------------------------------- + Drops + --------------------------------------------------------------- + */ + +api.dropEggs = { + Wolf: { + text: t('dropEggWolfText'), + adjective: t('dropEggWolfAdjective') + }, + TigerCub: { + text: t('dropEggTigerCubText'), + mountText: t('dropEggTigerCubMountText'), + adjective: t('dropEggTigerCubAdjective') + }, + PandaCub: { + text: t('dropEggPandaCubText'), + mountText: t('dropEggPandaCubMountText'), + adjective: t('dropEggPandaCubAdjective') + }, + LionCub: { + text: t('dropEggLionCubText'), + mountText: t('dropEggLionCubMountText'), + adjective: t('dropEggLionCubAdjective') + }, + Fox: { + text: t('dropEggFoxText'), + adjective: t('dropEggFoxAdjective') + }, + FlyingPig: { + text: t('dropEggFlyingPigText'), + adjective: t('dropEggFlyingPigAdjective') + }, + Dragon: { + text: t('dropEggDragonText'), + adjective: t('dropEggDragonAdjective') + }, + Cactus: { + text: t('dropEggCactusText'), + adjective: t('dropEggCactusAdjective') + }, + BearCub: { + text: t('dropEggBearCubText'), + mountText: t('dropEggBearCubMountText'), + adjective: t('dropEggBearCubAdjective') + } +}; + +_.each(api.dropEggs, function(egg, key) { + return _.defaults(egg, { + canBuy: true, + value: 3, + key: key, + notes: t('eggNotes', { + eggText: egg.text, + eggAdjective: egg.adjective + }), + mountText: egg.text + }); +}); + +api.questEggs = { + Gryphon: { + text: t('questEggGryphonText'), + adjective: t('questEggGryphonAdjective'), + canBuy: false + }, + Hedgehog: { + text: t('questEggHedgehogText'), + adjective: t('questEggHedgehogAdjective'), + canBuy: false + }, + Deer: { + text: t('questEggDeerText'), + adjective: t('questEggDeerAdjective'), + canBuy: false + }, + Egg: { + text: t('questEggEggText'), + adjective: t('questEggEggAdjective'), + canBuy: false, + noMount: true + }, + Rat: { + text: t('questEggRatText'), + adjective: t('questEggRatAdjective'), + canBuy: false + }, + Octopus: { + text: t('questEggOctopusText'), + adjective: t('questEggOctopusAdjective'), + canBuy: false + }, + Seahorse: { + text: t('questEggSeahorseText'), + adjective: t('questEggSeahorseAdjective'), + canBuy: false + }, + Parrot: { + text: t('questEggParrotText'), + adjective: t('questEggParrotAdjective'), + canBuy: false + }, + Rooster: { + text: t('questEggRoosterText'), + adjective: t('questEggRoosterAdjective'), + canBuy: false + }, + Spider: { + text: t('questEggSpiderText'), + adjective: t('questEggSpiderAdjective'), + canBuy: false + }, + Owl: { + text: t('questEggOwlText'), + adjective: t('questEggOwlAdjective'), + canBuy: false + }, + Penguin: { + text: t('questEggPenguinText'), + adjective: t('questEggPenguinAdjective'), + canBuy: false + }, + TRex: { + text: t('questEggTRexText'), + adjective: t('questEggTRexAdjective'), + canBuy: false + } +}; + +_.each(api.questEggs, function(egg, key) { + return _.defaults(egg, { + canBuy: false, + value: 3, + key: key, + notes: t('eggNotes', { + eggText: egg.text, + eggAdjective: egg.adjective + }), + mountText: egg.text + }); +}); + +api.eggs = _.assign(_.cloneDeep(api.dropEggs), api.questEggs); + +api.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' +}; + +api.specialMounts = { + 'BearCub-Polar': 'polarBear', + 'LionCub-Ethereal': 'etherealLion', + 'MantisShrimp-Base': 'mantisShrimp', + 'Turkey-Base': 'turkey', + 'Mammoth-Base': 'mammoth' +}; + +api.hatchingPotions = { + Base: { + value: 2, + text: t('hatchingPotionBase') + }, + White: { + value: 2, + text: t('hatchingPotionWhite') + }, + Desert: { + value: 2, + text: t('hatchingPotionDesert') + }, + Red: { + value: 3, + text: t('hatchingPotionRed') + }, + Shade: { + value: 3, + text: t('hatchingPotionShade') + }, + Skeleton: { + value: 3, + text: t('hatchingPotionSkeleton') + }, + Zombie: { + value: 4, + text: t('hatchingPotionZombie') + }, + CottonCandyPink: { + value: 4, + text: t('hatchingPotionCottonCandyPink') + }, + CottonCandyBlue: { + value: 4, + text: t('hatchingPotionCottonCandyBlue') + }, + Golden: { + value: 5, + text: t('hatchingPotionGolden') + } +}; + +_.each(api.hatchingPotions, function(pot, key) { + return _.defaults(pot, { + key: key, + value: 2, + notes: t('hatchingPotionNotes', { + potText: pot.text + }) + }); +}); + +api.pets = _.transform(api.dropEggs, function(m, egg) { + return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { + return m2[egg.key + "-" + pot.key] = true; + })); +}); + +api.questPets = _.transform(api.questEggs, function(m, egg) { + return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { + return m2[egg.key + "-" + pot.key] = true; + })); +}); + +api.mounts = _.transform(api.dropEggs, function(m, egg) { + return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { + return m2[egg.key + "-" + pot.key] = true; + })); +}); + +api.questMounts = _.transform(api.questEggs, function(m, egg) { + return _.defaults(m, _.transform(api.hatchingPotions, function(m2, pot) { + return m2[egg.key + "-" + pot.key] = true; + })); +}); + +api.food = { + Meat: { + canBuy: true, + canDrop: true, + text: t('foodMeat'), + target: 'Base', + article: '' + }, + Milk: { + canBuy: true, + canDrop: true, + text: t('foodMilk'), + target: 'White', + article: '' + }, + Potatoe: { + canBuy: true, + canDrop: true, + text: t('foodPotatoe'), + target: 'Desert', + article: 'a ' + }, + Strawberry: { + canBuy: true, + canDrop: true, + text: t('foodStrawberry'), + target: 'Red', + article: 'a ' + }, + Chocolate: { + canBuy: true, + canDrop: true, + text: t('foodChocolate'), + target: 'Shade', + article: '' + }, + Fish: { + canBuy: true, + canDrop: true, + text: t('foodFish'), + target: 'Skeleton', + article: 'a ' + }, + RottenMeat: { + canBuy: true, + canDrop: true, + text: t('foodRottenMeat'), + target: 'Zombie', + article: '' + }, + CottonCandyPink: { + canBuy: true, + canDrop: true, + text: t('foodCottonCandyPink'), + target: 'CottonCandyPink', + article: '' + }, + CottonCandyBlue: { + canBuy: true, + canDrop: true, + text: t('foodCottonCandyBlue'), + target: 'CottonCandyBlue', + article: '' + }, + Honey: { + canBuy: true, + canDrop: true, + text: t('foodHoney'), + target: 'Golden', + article: '' + }, + Saddle: { + canBuy: true, + canDrop: false, + text: t('foodSaddleText'), + value: 5, + notes: t('foodSaddleNotes') + }, + Cake_Skeleton: { + canBuy: false, + canDrop: false, + text: t('foodCakeSkeleton'), + target: 'Skeleton', + article: '' + }, + Cake_Base: { + canBuy: false, + canDrop: false, + text: t('foodCakeBase'), + target: 'Base', + article: '' + }, + Cake_CottonCandyBlue: { + canBuy: false, + canDrop: false, + text: t('foodCakeCottonCandyBlue'), + target: 'CottonCandyBlue', + article: '' + }, + Cake_CottonCandyPink: { + canBuy: false, + canDrop: false, + text: t('foodCakeCottonCandyPink'), + target: 'CottonCandyPink', + article: '' + }, + Cake_Shade: { + canBuy: false, + canDrop: false, + text: t('foodCakeShade'), + target: 'Shade', + article: '' + }, + Cake_White: { + canBuy: false, + canDrop: false, + text: t('foodCakeWhite'), + target: 'White', + article: '' + }, + Cake_Golden: { + canBuy: false, + canDrop: false, + text: t('foodCakeGolden'), + target: 'Golden', + article: '' + }, + Cake_Zombie: { + canBuy: false, + canDrop: false, + text: t('foodCakeZombie'), + target: 'Zombie', + article: '' + }, + Cake_Desert: { + canBuy: false, + canDrop: false, + text: t('foodCakeDesert'), + target: 'Desert', + article: '' + }, + Cake_Red: { + canBuy: false, + canDrop: false, + text: t('foodCakeRed'), + target: 'Red', + article: '' + }, + Candy_Skeleton: { + canBuy: false, + canDrop: false, + text: t('foodCandySkeleton'), + target: 'Skeleton', + article: '' + }, + Candy_Base: { + canBuy: false, + canDrop: false, + text: t('foodCandyBase'), + target: 'Base', + article: '' + }, + Candy_CottonCandyBlue: { + canBuy: false, + canDrop: false, + text: t('foodCandyCottonCandyBlue'), + target: 'CottonCandyBlue', + article: '' + }, + Candy_CottonCandyPink: { + canBuy: false, + canDrop: false, + text: t('foodCandyCottonCandyPink'), + target: 'CottonCandyPink', + article: '' + }, + Candy_Shade: { + canBuy: false, + canDrop: false, + text: t('foodCandyShade'), + target: 'Shade', + article: '' + }, + Candy_White: { + canBuy: false, + canDrop: false, + text: t('foodCandyWhite'), + target: 'White', + article: '' + }, + Candy_Golden: { + canBuy: false, + canDrop: false, + text: t('foodCandyGolden'), + target: 'Golden', + article: '' + }, + Candy_Zombie: { + canBuy: false, + canDrop: false, + text: t('foodCandyZombie'), + target: 'Zombie', + article: '' + }, + Candy_Desert: { + canBuy: false, + canDrop: false, + text: t('foodCandyDesert'), + target: 'Desert', + article: '' + }, + Candy_Red: { + canBuy: false, + canDrop: false, + text: t('foodCandyRed'), + target: 'Red', + article: '' + } +}; + +_.each(api.food, function(food, key) { + return _.defaults(food, { + value: 1, + key: key, + notes: t('foodNotes') + }); +}); + +api.quests = { + dilatory: { + text: t("questDilatoryText"), + notes: t("questDilatoryNotes"), + completion: t("questDilatoryCompletion"), + value: 0, + canBuy: false, + 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: { + text: t("questStressbeastText"), + notes: t("questStressbeastNotes"), + completion: t("questStressbeastCompletion"), + completionChat: t("questStressbeastCompletionChat"), + value: 0, + canBuy: false, + 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 + } + }, + evilsanta: { + canBuy: false, + text: t('questEvilSantaText'), + notes: t('questEvilSantaNotes'), + completion: t('questEvilSantaCompletion'), + value: 4, + boss: { + name: t('questEvilSantaBoss'), + hp: 300, + str: 1 + }, + drop: { + items: [ + { + type: 'mounts', + key: 'BearCub-Polar', + text: t('questEvilSantaDropBearCubPolarMount') + } + ], + gp: 20, + exp: 100 + } + }, + evilsanta2: { + canBuy: false, + text: t('questEvilSanta2Text'), + notes: t('questEvilSanta2Notes'), + completion: t('questEvilSanta2Completion'), + value: 4, + previous: 'evilsanta', + 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 + } + }, + gryphon: { + text: t('questGryphonText'), + notes: t('questGryphonNotes'), + completion: t('questGryphonCompletion'), + value: 4, + boss: { + name: t('questGryphonBoss'), + hp: 300, + str: 1.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Gryphon', + text: t('questGryphonDropGryphonEgg') + }, { + type: 'eggs', + key: 'Gryphon', + text: t('questGryphonDropGryphonEgg') + }, { + type: 'eggs', + key: 'Gryphon', + text: t('questGryphonDropGryphonEgg') + } + ], + gp: 25, + exp: 125 + } + }, + hedgehog: { + text: t('questHedgehogText'), + notes: t('questHedgehogNotes'), + completion: t('questHedgehogCompletion'), + value: 4, + boss: { + name: t('questHedgehogBoss'), + hp: 400, + str: 1.25 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Hedgehog', + text: t('questHedgehogDropHedgehogEgg') + }, { + type: 'eggs', + key: 'Hedgehog', + text: t('questHedgehogDropHedgehogEgg') + }, { + type: 'eggs', + key: 'Hedgehog', + text: t('questHedgehogDropHedgehogEgg') + } + ], + gp: 30, + exp: 125 + } + }, + ghost_stag: { + text: t('questGhostStagText'), + notes: t('questGhostStagNotes'), + completion: t('questGhostStagCompletion'), + value: 4, + boss: { + name: t('questGhostStagBoss'), + 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 + } + }, + vice1: { + text: t('questVice1Text'), + notes: t('questVice1Notes'), + value: 4, + lvl: 30, + boss: { + name: t('questVice1Boss'), + hp: 750, + str: 1.5 + }, + drop: { + items: [ + { + type: 'quests', + key: "vice2", + text: t('questVice1DropVice2Quest') + } + ], + gp: 20, + exp: 100 + } + }, + vice2: { + text: t('questVice2Text'), + notes: t('questVice2Notes'), + value: 4, + lvl: 35, + previous: 'vice1', + collect: { + lightCrystal: { + text: t('questVice2CollectLightCrystal'), + count: 45 + } + }, + drop: { + items: [ + { + type: 'quests', + key: 'vice3', + text: t('questVice2DropVice3Quest') + } + ], + gp: 20, + exp: 75 + } + }, + vice3: { + text: t('questVice3Text'), + notes: t('questVice3Notes'), + completion: t('questVice3Completion'), + previous: 'vice2', + value: 4, + lvl: 40, + boss: { + name: t('questVice3Boss'), + 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 + } + }, + egg: { + text: t('questEggHuntText'), + notes: t('questEggHuntNotes'), + completion: t('questEggHuntCompletion'), + value: 1, + canBuy: false, + 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 + } + }, + rat: { + text: t('questRatText'), + notes: t('questRatNotes'), + completion: t('questRatCompletion'), + value: 4, + boss: { + name: t('questRatBoss'), + hp: 1200, + str: 2.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Rat', + text: t('questRatDropRatEgg') + }, { + type: 'eggs', + key: 'Rat', + text: t('questRatDropRatEgg') + }, { + type: 'eggs', + key: 'Rat', + text: t('questRatDropRatEgg') + } + ], + gp: 80, + exp: 800 + } + }, + octopus: { + text: t('questOctopusText'), + notes: t('questOctopusNotes'), + completion: t('questOctopusCompletion'), + value: 4, + boss: { + name: t('questOctopusBoss'), + hp: 1200, + str: 2.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Octopus', + text: t('questOctopusDropOctopusEgg') + }, { + type: 'eggs', + key: 'Octopus', + text: t('questOctopusDropOctopusEgg') + }, { + type: 'eggs', + key: 'Octopus', + text: t('questOctopusDropOctopusEgg') + } + ], + gp: 80, + exp: 800 + } + }, + dilatory_derby: { + text: t('questSeahorseText'), + notes: t('questSeahorseNotes'), + completion: t('questSeahorseCompletion'), + value: 4, + 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 + } + }, + atom1: { + text: t('questAtom1Text'), + notes: t('questAtom1Notes'), + value: 4, + lvl: 15, + collect: { + soapBars: { + text: t('questAtom1CollectSoapBars'), + count: 20 + } + }, + drop: { + items: [ + { + type: 'quests', + key: "atom2", + text: t('questAtom1Drop') + } + ], + gp: 7, + exp: 50 + } + }, + atom2: { + text: t('questAtom2Text'), + notes: t('questAtom2Notes'), + previous: 'atom1', + value: 4, + lvl: 15, + boss: { + name: t('questAtom2Boss'), + hp: 300, + str: 1 + }, + drop: { + items: [ + { + type: 'quests', + key: "atom3", + text: t('questAtom2Drop') + } + ], + gp: 20, + exp: 100 + } + }, + atom3: { + text: t('questAtom3Text'), + notes: t('questAtom3Notes'), + previous: 'atom2', + completion: t('questAtom3Completion'), + value: 4, + lvl: 15, + boss: { + name: t('questAtom3Boss'), + 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 + } + }, + harpy: { + text: t('questHarpyText'), + notes: t('questHarpyNotes'), + completion: t('questHarpyCompletion'), + value: 4, + boss: { + name: t('questHarpyBoss'), + 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: { + text: t('questRoosterText'), + notes: t('questRoosterNotes'), + completion: t('questRoosterCompletion'), + value: 4, + boss: { + name: t('questRoosterBoss'), + hp: 300, + str: 1.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Rooster', + text: t('questRoosterDropRoosterEgg') + }, { + type: 'eggs', + key: 'Rooster', + text: t('questRoosterDropRoosterEgg') + }, { + type: 'eggs', + key: 'Rooster', + text: t('questRoosterDropRoosterEgg') + } + ], + gp: 25, + exp: 125 + } + }, + spider: { + text: t('questSpiderText'), + notes: t('questSpiderNotes'), + completion: t('questSpiderCompletion'), + value: 4, + boss: { + name: t('questSpiderBoss'), + hp: 400, + str: 1.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Spider', + text: t('questSpiderDropSpiderEgg') + }, { + type: 'eggs', + key: 'Spider', + text: t('questSpiderDropSpiderEgg') + }, { + type: 'eggs', + key: 'Spider', + text: t('questSpiderDropSpiderEgg') + } + ], + gp: 31, + exp: 200 + } + }, + moonstone1: { + text: t('questMoonstone1Text'), + notes: t('questMoonstone1Notes'), + value: 4, + lvl: 60, + collect: { + moonstone: { + text: t('questMoonstone1CollectMoonstone'), + count: 500 + } + }, + drop: { + items: [ + { + type: 'quests', + key: "moonstone2", + text: t('questMoonstone1DropMoonstone2Quest') + } + ], + gp: 50, + exp: 100 + } + }, + moonstone2: { + text: t('questMoonstone2Text'), + notes: t('questMoonstone2Notes'), + value: 4, + lvl: 65, + previous: 'moonstone1', + boss: { + name: t('questMoonstone2Boss'), + hp: 1500, + str: 3 + }, + drop: { + items: [ + { + type: 'quests', + key: 'moonstone3', + text: t('questMoonstone2DropMoonstone3Quest') + } + ], + gp: 500, + exp: 1000 + } + }, + moonstone3: { + text: t('questMoonstone3Text'), + notes: t('questMoonstone3Notes'), + completion: t('questMoonstone3Completion'), + previous: 'moonstone2', + value: 4, + lvl: 70, + boss: { + name: t('questMoonstone3Boss'), + 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 + } + }, + goldenknight1: { + text: t('questGoldenknight1Text'), + notes: t('questGoldenknight1Notes'), + value: 4, + lvl: 40, + collect: { + testimony: { + text: t('questGoldenknight1CollectTestimony'), + count: 300 + } + }, + drop: { + items: [ + { + type: 'quests', + key: "goldenknight2", + text: t('questGoldenknight1DropGoldenknight2Quest') + } + ], + gp: 15, + exp: 120 + } + }, + goldenknight2: { + text: t('questGoldenknight2Text'), + notes: t('questGoldenknight2Notes'), + value: 4, + previous: 'goldenknight1', + lvl: 45, + boss: { + name: t('questGoldenknight2Boss'), + hp: 1000, + str: 3 + }, + drop: { + items: [ + { + type: 'quests', + key: 'goldenknight3', + text: t('questGoldenknight2DropGoldenknight3Quest') + } + ], + gp: 75, + exp: 750 + } + }, + goldenknight3: { + text: t('questGoldenknight3Text'), + notes: t('questGoldenknight3Notes'), + completion: t('questGoldenknight3Completion'), + previous: 'goldenknight2', + value: 4, + lvl: 50, + boss: { + name: t('questGoldenknight3Boss'), + 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 + } + }, + basilist: { + text: t('questBasilistText'), + notes: t('questBasilistNotes'), + completion: t('questBasilistCompletion'), + canBuy: false, + value: 4, + boss: { + name: t('questBasilistBoss'), + hp: 100, + str: 0.5 + }, + drop: { + gp: 8, + exp: 42 + } + }, + owl: { + text: t('questOwlText'), + notes: t('questOwlNotes'), + completion: t('questOwlCompletion'), + value: 4, + boss: { + name: t('questOwlBoss'), + hp: 500, + str: 1.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Owl', + text: t('questOwlDropOwlEgg') + }, { + type: 'eggs', + key: 'Owl', + text: t('questOwlDropOwlEgg') + }, { + type: 'eggs', + key: 'Owl', + text: t('questOwlDropOwlEgg') + } + ], + gp: 37, + exp: 275 + } + }, + penguin: { + text: t('questPenguinText'), + notes: t('questPenguinNotes'), + completion: t('questPenguinCompletion'), + value: 4, + boss: { + name: t('questPenguinBoss'), + hp: 400, + str: 1.5 + }, + drop: { + items: [ + { + type: 'eggs', + key: 'Penguin', + text: t('questPenguinDropPenguinEgg') + }, { + type: 'eggs', + key: 'Penguin', + text: t('questPenguinDropPenguinEgg') + }, { + type: 'eggs', + key: 'Penguin', + text: t('questPenguinDropPenguinEgg') + } + ], + gp: 31, + exp: 200 + } + }, + trex: { + text: t('questTRexText'), + notes: t('questTRexNotes'), + completion: t('questTRexCompletion'), + value: 4, + 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 + } + }, + trex_undead: { + text: t('questTRexUndeadText'), + notes: t('questTRexUndeadNotes'), + completion: t('questTRexUndeadCompletion'), + value: 4, + 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 + } + } +}; + +_.each(api.quests, function(v, key) { + var b; + _.defaults(v, { + key: key, + canBuy: true + }); + b = v.boss; + if (b) { + _.defaults(b, { + str: 1, + def: 1 + }); + if (b.rage) { + return _.defaults(b.rage, { + title: t('bossRageTitle'), + description: t('bossRageDescription') + }); + } + } +}); + +api.backgrounds = { + backgrounds062014: { + beach: { + text: t('backgroundBeachText'), + notes: t('backgroundBeachNotes') + }, + fairy_ring: { + text: t('backgroundFairyRingText'), + notes: t('backgroundFairyRingNotes') + }, + forest: { + text: t('backgroundForestText'), + notes: t('backgroundForestNotes') + } + }, + backgrounds072014: { + open_waters: { + text: t('backgroundOpenWatersText'), + notes: t('backgroundOpenWatersNotes') + }, + coral_reef: { + text: t('backgroundCoralReefText'), + notes: t('backgroundCoralReefNotes') + }, + seafarer_ship: { + text: t('backgroundSeafarerShipText'), + notes: t('backgroundSeafarerShipNotes') + } + }, + backgrounds082014: { + volcano: { + text: t('backgroundVolcanoText'), + notes: t('backgroundVolcanoNotes') + }, + clouds: { + text: t('backgroundCloudsText'), + notes: t('backgroundCloudsNotes') + }, + dusty_canyons: { + text: t('backgroundDustyCanyonsText'), + notes: t('backgroundDustyCanyonsNotes') + } + }, + backgrounds092014: { + thunderstorm: { + text: t('backgroundThunderstormText'), + notes: t('backgroundThunderstormNotes') + }, + autumn_forest: { + text: t('backgroundAutumnForestText'), + notes: t('backgroundAutumnForestNotes') + }, + harvest_fields: { + text: t('backgroundHarvestFieldsText'), + notes: t('backgroundHarvestFieldsNotes') + } + }, + backgrounds102014: { + graveyard: { + text: t('backgroundGraveyardText'), + notes: t('backgroundGraveyardNotes') + }, + haunted_house: { + text: t('backgroundHauntedHouseText'), + notes: t('backgroundHauntedHouseNotes') + }, + pumpkin_patch: { + text: t('backgroundPumpkinPatchText'), + notes: t('backgroundPumpkinPatchNotes') + } + }, + backgrounds112014: { + harvest_feast: { + text: t('backgroundHarvestFeastText'), + notes: t('backgroundHarvestFeastNotes') + }, + sunset_meadow: { + text: t('backgroundSunsetMeadowText'), + notes: t('backgroundSunsetMeadowNotes') + }, + starry_skies: { + text: t('backgroundStarrySkiesText'), + notes: t('backgroundStarrySkiesNotes') + } + }, + backgrounds122014: { + iceberg: { + text: t('backgroundIcebergText'), + notes: t('backgroundIcebergNotes') + }, + twinkly_lights: { + text: t('backgroundTwinklyLightsText'), + notes: t('backgroundTwinklyLightsNotes') + }, + south_pole: { + text: t('backgroundSouthPoleText'), + notes: t('backgroundSouthPoleNotes') + } + }, + backgrounds012015: { + ice_cave: { + text: t('backgroundIceCaveText'), + notes: t('backgroundIceCaveNotes') + }, + frigid_peak: { + text: t('backgroundFrigidPeakText'), + notes: t('backgroundFrigidPeakNotes') + }, + snowy_pines: { + text: t('backgroundSnowyPinesText'), + notes: t('backgroundSnowyPinesNotes') + } + }, + backgrounds022015: { + blacksmithy: { + text: t('backgroundBlacksmithyText'), + notes: t('backgroundBlacksmithyNotes') + }, + crystal_cave: { + text: t('backgroundCrystalCaveText'), + notes: t('backgroundCrystalCaveNotes') + }, + distant_castle: { + text: t('backgroundDistantCastleText'), + notes: t('backgroundDistantCastleNotes') + } + } +}; + +api.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(api.subscriptionBlocks, function(b, k) { + return b.key = k; +}); + +repeat = { + m: true, + t: true, + w: true, + th: true, + f: true, + s: true, + su: true +}; + +api.userDefaults = { + habits: [ + { + type: 'habit', + text: t('defaultHabit1Text'), + notes: t('defaultHabit1Notes'), + value: 0, + up: true, + down: false, + attribute: 'per' + }, { + type: 'habit', + text: t('defaultHabit2Text'), + notes: t('defaultHabit2Notes'), + value: 0, + up: false, + down: true, + attribute: 'con' + }, { + type: 'habit', + text: t('defaultHabit3Text'), + notes: t('defaultHabit3Notes'), + value: 0, + up: true, + down: true, + attribute: 'str' + } + ], + dailys: [ + { + type: 'daily', + text: t('defaultDaily1Text'), + notes: t('defaultDaily1Notes'), + value: 0, + completed: false, + repeat: repeat, + attribute: 'per' + }, { + type: 'daily', + text: t('defaultDaily2Text'), + notes: t('defaultDaily2Notes'), + value: 3, + completed: false, + repeat: repeat, + attribute: 'con' + }, { + type: 'daily', + text: t('defaultDaily3Text'), + notes: t('defaultDaily3Notes'), + value: -10, + completed: false, + repeat: repeat, + attribute: 'int' + }, { + type: 'daily', + text: t('defaultDaily4Text'), + notes: t('defaultDaily4Notes'), + checklist: [ + { + completed: true, + text: t('defaultDaily4Checklist1') + }, { + completed: false, + text: t('defaultDaily4Checklist2') + }, { + completed: false, + text: t('defaultDaily4Checklist3') + } + ], + completed: false, + repeat: repeat, + attribute: 'str' + } + ], + todos: [ + { + type: 'todo', + text: t('defaultTodo1Text'), + notes: t('defaultTodoNotes'), + completed: false, + attribute: 'int' + }, { + type: 'todo', + text: t('defaultTodo2Text'), + notes: t('defaultTodoNotes'), + checklist: [ + { + completed: false, + text: t('defaultTodo2Checklist1') + }, { + completed: false, + text: t('defaultTodo2Checklist2') + }, { + completed: false, + text: t('defaultTodo2Checklist3') + } + ], + completed: false, + attribute: 'per' + }, { + type: 'todo', + text: t('defaultTodo3Text'), + notes: t('defaultTodoNotes'), + checklist: [ + { + completed: false, + text: t('defaultTodo3Checklist1') + }, { + completed: false, + text: t('defaultTodo3Checklist2') + }, { + completed: false, + text: t('defaultTodo3Checklist3') + } + ], + completed: false, + attribute: 'per' + }, { + type: 'todo', + text: t('defaultTodo4Text'), + notes: t('defaultTodoNotes'), + checklist: [ + { + completed: false, + text: t('defaultTodo4Checklist1') + }, { + completed: false, + text: t('defaultTodo4Checklist2') + }, { + completed: false, + text: t('defaultTodo4Checklist3') + } + ], + completed: false, + attribute: 'per' + }, { + type: 'todo', + text: t('defaultTodo5Text'), + notes: t('defaultTodoNotes'), + completed: false, + attribute: 'per' + } + ], + rewards: [ + { + type: 'reward', + text: t('defaultReward1Text'), + notes: t('defaultReward1Notes'), + value: 20 + }, { + type: 'reward', + text: t('defaultReward2Text'), + notes: t('defaultReward2Notes'), + value: 10 + } + ], + tags: [ + { + name: t('defaultTag1') + }, { + name: t('defaultTag2') + }, { + name: t('defaultTag3') + } + ] +}; + + +},{"./i18n.coffee":5,"lodash":2,"moment":3}],5:[function(require,module,exports){ +var _; + +_ = 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'; + } + string = !module.exports.strings ? module.exports.translations[locale][stringName] : module.exports.strings[stringName]; + clonedVars = _.clone(vars) || {}; + clonedVars.locale = locale; + if (string) { + try { + return _.template(string, clonedVars); + } catch (_error) { + e = _error; + return 'Error processing string. Please report to http://github.com/HabitRPG/habitrpg.'; + } + } else { + stringNotFound = !module.exports.strings ? module.exports.translations[locale].stringNotFound : module.exports.strings.stringNotFound; + try { + return _.template(stringNotFound, { + string: stringName + }); + } catch (_error) { + e = _error; + return 'Error processing string. Please report to http://github.com/HabitRPG/habitrpg.'; + } + } + } +}; + + +},{"lodash":2}],6:[function(require,module,exports){ +(function (process){ +var $w, api, content, i18n, moment, preenHistory, sanitizeOptions, sortOrder, _, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +moment = require('moment'); + +_ = require('lodash'); + +content = require('./content.coffee'); + +i18n = require('./i18n.coffee'); + +api = module.exports = {}; + +api.i18n = i18n; + +$w = api.$w = function(s) { + return s.split(' '); +}; + +api.dotSet = function(obj, path, val) { + var arr; + arr = path.split('.'); + return _.reduce(arr, (function(_this) { + return function(curr, next, index) { + if ((arr.length - 1) === index) { + curr[next] = val; + } + return curr[next] != null ? curr[next] : curr[next] = {}; + }; + })(this), obj); +}; + +api.dotGet = function(obj, path) { + return _.reduce(path.split('.'), ((function(_this) { + return function(curr, next) { + return curr != null ? curr[next] : void 0; + }; + })(this)), obj); +}; + + +/* + Reflists are arrays, but stored as objects. Mongoose has a helluvatime working with arrays (the main problem for our + syncing issues) - so the goal is to move away from arrays to objects, since mongoose can reference elements by ID + no problem. To maintain sorting, we use these helper functions: + */ + +api.refPush = function(reflist, item, prune) { + if (prune == null) { + prune = 0; + } + item.sort = _.isEmpty(reflist) ? 0 : _.max(reflist, 'sort').sort + 1; + if (!(item.id && !reflist[item.id])) { + item.id = api.uuid(); + } + return reflist[item.id] = item; +}; + +api.planGemLimits = { + convRate: 20, + convCap: 25 +}; + + +/* + ------------------------------------------------------ + Time / Day + ------------------------------------------------------ + */ + + +/* + Each time we're performing date math (cron, task-due-days, etc), we need to take user preferences into consideration. + Specifically {dayStart} (custom day start) and {timezoneOffset}. This function sanitizes / defaults those values. + {now} is also passed in for various purposes, one example being the test scripts scripts testing different "now" times + */ + +sanitizeOptions = function(o) { + var dayStart, now, timezoneOffset, _ref; + dayStart = !_.isNaN(+o.dayStart) && (0 <= (_ref = +o.dayStart) && _ref <= 24) ? +o.dayStart : 0; + timezoneOffset = o.timezoneOffset ? +o.timezoneOffset : +moment().zone(); + now = o.now ? moment(o.now).zone(timezoneOffset) : moment(+(new Date)).zone(timezoneOffset); + return { + dayStart: dayStart, + timezoneOffset: timezoneOffset, + now: now + }; +}; + +api.startOfWeek = api.startOfWeek = function(options) { + var o; + if (options == null) { + options = {}; + } + o = sanitizeOptions(options); + return moment(o.now).startOf('week'); +}; + +api.startOfDay = function(options) { + var dayStart, o; + if (options == null) { + options = {}; + } + o = sanitizeOptions(options); + dayStart = moment(o.now).startOf('day').add({ + hours: o.dayStart + }); + if (moment(o.now).hour() < o.dayStart) { + dayStart.subtract({ + days: 1 + }); + } + return dayStart; +}; + +api.dayMapping = { + 0: 'su', + 1: 'm', + 2: 't', + 3: 'w', + 4: 'th', + 5: 'f', + 6: 's' +}; + + +/* + Absolute diff from "yesterday" till now + */ + +api.daysSince = function(yesterday, options) { + var o; + if (options == null) { + options = {}; + } + o = sanitizeOptions(options); + return Math.abs(api.startOfDay(_.defaults({ + now: yesterday + }, o)).diff(api.startOfDay(_.defaults({ + now: o.now + }, o)), 'days')); +}; + + +/* + Should the user do this taks on this date, given the task's repeat options and user.preferences.dayStart? + */ + +api.shouldDo = function(day, repeat, options) { + var o, selected; + if (options == null) { + options = {}; + } + if (!repeat) { + return false; + } + o = sanitizeOptions(options); + selected = repeat[api.dayMapping[api.startOfDay(_.defaults({ + now: day + }, o)).day()]]; + return selected; +}; + + +/* + ------------------------------------------------------ + Scoring + ------------------------------------------------------ + */ + +api.tnl = function(lvl) { + return Math.round(((Math.pow(lvl, 2) * 0.25) + (10 * lvl) + 139.75) / 10) * 10; +}; + + +/* + A hyperbola function that creates diminishing returns, so you can't go to infinite (eg, with Exp gain). + {max} The asymptote + {bonus} All the numbers combined for your point bonus (eg, task.value * user.stats.int * critChance, etc) + {halfway} (optional) the point at which the graph starts bending + */ + +api.diminishingReturns = function(bonus, max, halfway) { + if (halfway == null) { + halfway = max / 2; + } + return max * (bonus / (bonus + halfway)); +}; + +api.monod = function(bonus, rateOfIncrease, max) { + return rateOfIncrease * max * bonus / (rateOfIncrease * bonus + max); +}; + + +/* +Preen history for users with > 7 history entries +This takes an infinite array of single day entries [day day day day day...], and turns it into a condensed array +of averages, condensing more the further back in time we go. Eg, 7 entries each for last 7 days; 1 entry each week +of this month; 1 entry for each month of this year; 1 entry per previous year: [day*7 week*4 month*12 year*infinite] + */ + +preenHistory = function(history) { + var newHistory, preen, thisMonth; + history = _.filter(history, function(h) { + return !!h; + }); + newHistory = []; + preen = function(amount, groupBy) { + var groups; + groups = _.chain(history).groupBy(function(h) { + return moment(h.date).format(groupBy); + }).sortBy(function(h, k) { + return k; + }).value(); + groups = groups.slice(-amount); + groups.pop(); + return _.each(groups, function(group) { + newHistory.push({ + date: moment(group[0].date).toDate(), + value: _.reduce(group, (function(m, obj) { + return m + obj.value; + }), 0) / group.length + }); + return true; + }); + }; + preen(50, "YYYY"); + preen(moment().format('MM'), "YYYYMM"); + thisMonth = moment().format('YYYYMM'); + newHistory = newHistory.concat(_.filter(history, function(h) { + return moment(h.date).format('YYYYMM') === thisMonth; + })); + return newHistory; +}; + + +/* + Update the in-browser store with new gear. FIXME this was in user.fns, but it was causing strange issues there + */ + +sortOrder = _.reduce(content.gearTypes, (function(m, v, k) { + m[v] = k; + return m; +}), {}); + +api.updateStore = function(user) { + var changes; + if (!user) { + return; + } + changes = []; + _.each(content.gearTypes, function(type) { + var found; + found = _.find(content.gear.tree[type][user.stats["class"]], function(item) { + return !user.items.gear.owned[item.key]; + }); + if (found) { + changes.push(found); + } + return true; + }); + changes = changes.concat(_.filter(content.gear.flat, function(v) { + var _ref; + return ((_ref = v.klass) === 'special' || _ref === 'mystery') && !user.items.gear.owned[v.key] && (typeof v.canOwn === "function" ? v.canOwn(user) : void 0); + })); + changes.push(content.potion); + return _.sortBy(changes, function(c) { + return sortOrder[c.type]; + }); +}; + + +/* +------------------------------------------------------ +Content +------------------------------------------------------ + */ + +api.content = content; + + +/* +------------------------------------------------------ +Misc Helpers +------------------------------------------------------ + */ + +api.uuid = function() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { + var r, v; + r = Math.random() * 16 | 0; + v = (c === "x" ? r : r & 0x3 | 0x8); + return v.toString(16); + }); +}; + +api.countExists = function(items) { + return _.reduce(items, (function(m, v) { + return m + (v ? 1 : 0); + }), 0); +}; + + +/* +Even though Mongoose handles task defaults, we want to make sure defaults are set on the client-side before +sending up to the server for performance + */ + +api.taskDefaults = function(task) { + var defaults, _ref, _ref1, _ref2; + if (task == null) { + task = {}; + } + if (!(task.type && ((_ref = task.type) === 'habit' || _ref === 'daily' || _ref === 'todo' || _ref === 'reward'))) { + task.type = 'habit'; + } + defaults = { + id: api.uuid(), + text: task.id != null ? task.id : '', + notes: '', + priority: 1, + challenge: {}, + attribute: 'str', + dateCreated: new Date() + }; + _.defaults(task, defaults); + if (task.type === 'habit') { + _.defaults(task, { + up: true, + down: true + }); + } + if ((_ref1 = task.type) === 'habit' || _ref1 === 'daily') { + _.defaults(task, { + history: [] + }); + } + if ((_ref2 = task.type) === 'daily' || _ref2 === 'todo') { + _.defaults(task, { + completed: false + }); + } + if (task.type === 'daily') { + _.defaults(task, { + streak: 0, + repeat: { + su: 1, + m: 1, + t: 1, + w: 1, + th: 1, + f: 1, + s: 1 + } + }); + } + task._id = task.id; + if (task.value == null) { + task.value = task.type === 'reward' ? 10 : 0; + } + if (!_.isNumber(task.priority)) { + task.priority = 1; + } + return task; +}; + +api.percent = function(x, y, dir) { + var roundFn; + switch (dir) { + case "up": + roundFn = Math.ceil; + break; + case "down": + roundFn = Math.floor; + break; + default: + roundFn = Math.round; + } + if (x === 0) { + x = 1; + } + return Math.max(0, roundFn(x / y * 100)); +}; + + +/* +Remove whitespace #FIXME are we using this anywwhere? Should we be? + */ + +api.removeWhitespace = function(str) { + if (!str) { + return ''; + } + return str.replace(/\s/g, ''); +}; + + +/* +Encode the download link for .ics iCal file + */ + +api.encodeiCalLink = function(uid, apiToken) { + var loc, _ref; + loc = (typeof window !== "undefined" && window !== null ? window.location.host : void 0) || (typeof process !== "undefined" && process !== null ? (_ref = process.env) != null ? _ref.BASE_URL : void 0 : void 0) || ''; + return encodeURIComponent("http://" + loc + "/v1/users/" + uid + "/calendar.ics?apiToken=" + apiToken); +}; + + +/* +Gold amount from their money + */ + +api.gold = function(num) { + if (num) { + return Math.floor(num); + } else { + return "0"; + } +}; + + +/* +Silver amount from their money + */ + +api.silver = function(num) { + if (num) { + return ("0" + Math.floor((num - Math.floor(num)) * 100)).slice(-2); + } else { + return "00"; + } +}; + + +/* +Task classes given everything about the class + */ + +api.taskClasses = function(task, filters, dayStart, lastCron, showCompleted, main) { + var classes, completed, enabled, filter, repeat, type, value, _ref; + if (filters == null) { + filters = []; + } + if (dayStart == null) { + dayStart = 0; + } + if (lastCron == null) { + lastCron = +(new Date); + } + if (showCompleted == null) { + showCompleted = false; + } + if (main == null) { + main = false; + } + if (!task) { + return; + } + type = task.type, completed = task.completed, value = task.value, repeat = task.repeat; + if (main) { + if (!task._editing) { + for (filter in filters) { + enabled = filters[filter]; + if (enabled && !((_ref = task.tags) != null ? _ref[filter] : void 0)) { + return 'hidden'; + } + } + } + } + classes = type; + if (task._editing) { + classes += " beingEdited"; + } + if (type === 'todo' || type === 'daily') { + if (completed || (type === 'daily' && !api.shouldDo(+(new Date), task.repeat, { + dayStart: dayStart + }))) { + classes += " completed"; + } else { + classes += " uncompleted"; + } + } else if (type === 'habit') { + if (task.down && task.up) { + classes += ' habit-wide'; + } + if (!task.down && !task.up) { + classes += ' habit-narrow'; + } + } + if (value < -20) { + classes += ' color-worst'; + } else if (value < -10) { + classes += ' color-worse'; + } else if (value < -1) { + classes += ' color-bad'; + } else if (value < 1) { + classes += ' color-neutral'; + } else if (value < 5) { + classes += ' color-good'; + } else if (value < 10) { + classes += ' color-better'; + } else { + classes += ' color-best'; + } + return classes; +}; + + +/* +Friendly timestamp + */ + +api.friendlyTimestamp = function(timestamp) { + return moment(timestamp).format('MM/DD h:mm:ss a'); +}; + + +/* +Does user have new chat messages? + */ + +api.newChatMessages = function(messages, lastMessageSeen) { + if (!((messages != null ? messages.length : void 0) > 0)) { + return false; + } + return (messages != null ? messages[0] : void 0) && (messages[0].id !== lastMessageSeen); +}; + + +/* +are any tags active? + */ + +api.noTags = function(tags) { + return _.isEmpty(tags) || _.isEmpty(_.filter(tags, function(t) { + return t; + })); +}; + + +/* +Are there tags applied? + */ + +api.appliedTags = function(userTags, taskTags) { + var arr; + arr = []; + _.each(userTags, function(t) { + if (t == null) { + return; + } + if (taskTags != null ? taskTags[t.id] : void 0) { + return arr.push(t.name); + } + }); + return arr.join(', '); +}; + +api.countPets = function(originalCount, pets) { + var count, pet; + count = originalCount != null ? originalCount : _.size(pets); + for (pet in content.questPets) { + if (pets[pet]) { + count--; + } + } + for (pet in content.specialPets) { + if (pets[pet]) { + count--; + } + } + return count; +}; + +api.countMounts = function(originalCount, mounts) { + var count2, mount; + count2 = originalCount != null ? originalCount : _.size(mounts); + for (mount in content.questPets) { + if (mounts[mount]) { + count2--; + } + } + for (mount in content.specialMounts) { + if (mounts[mount]) { + count2--; + } + } + return count2; +}; + +api.countTriad = function(pets) { + var count3, egg, potion; + count3 = 0; + for (egg in content.dropEggs) { + for (potion in content.hatchingPotions) { + if (pets[egg + "-" + potion] > 0) { + count3++; + } + } + } + return count3; +}; + + +/* +------------------------------------------------------ +User (prototype wrapper to give it ops, helper funcs, and virtuals +------------------------------------------------------ + */ + + +/* +User is now wrapped (both on client and server), adding a few new properties: + * getters (_statsComputed, tasks, etc) + * user.fns, which is a bunch of helper functions + These were originally up above, but they make more sense belonging to the user object so we don't have to pass + the user object all over the place. In fact, we should pull in more functions such as cron(), updateStats(), etc. + * user.ops, which is super important: + +If a function is inside user.ops, it has magical properties. If you call it on the client it updates the user object in +the browser and when it's done it automatically POSTs to the server, calling src/controllers/user.js#OP_NAME (the exact same name +of the op function). The first argument req is {query, body, params}, it's what the express controller function +expects. This means we call our functions as if we were calling an Express route. Eg, instead of score(task, direction), +we call score({params:{id:task.id,direction:direction}}). This also forces us to think about our routes (whether to use +params, query, or body for variables). see http://stackoverflow.com/questions/4024271/rest-api-best-practices-where-to-put-parameters + +If `src/controllers/user.js#OP_NAME` doesn't exist on the server, it's automatically added. It runs the code in user.ops.OP_NAME +to update the user model server-side, then performs `user.save()`. You can see this in action for `user.ops.buy`. That +function doesn't exist on the server - so the client calls it, it updates user in the browser, auto-POSTs to server, server +handles it by calling `user.ops.buy` again (to update user on the server), and then saves. We can do this for +everything that doesn't need any code difference from what's in user.ops.OP_NAME for special-handling server-side. If we +*do* need special handling, just add `src/controllers/user.js#OP_NAME` to override the user.ops.OP_NAME, and be +sure to call user.ops.OP_NAME at some point within the overridden function. + +TODO + * Is this the best way to wrap the user object? I thought of using user.prototype, but user is an object not a Function. + user on the server is a Mongoose model, so we can use prototype - but to do it on the client, we'd probably have to + move to $resource for user + * Move to $resource! + */ + +api.wrap = function(user, main) { + if (main == null) { + main = true; + } + if (user._wrapped) { + return; + } + user._wrapped = true; + if (main) { + user.ops = { + update: function(req, cb) { + _.each(req.body, function(v, k) { + user.fns.dotSet(k, v); + return true; + }); + return typeof cb === "function" ? cb(null, user) : void 0; + }, + sleep: function(req, cb) { + user.preferences.sleep = !user.preferences.sleep; + return typeof cb === "function" ? cb(null, {}) : void 0; + }, + revive: function(req, cb) { + var cl, gearOwned, item, losableItems, lostItem, lostStat, _base; + if (!(user.stats.hp <= 0)) { + return typeof cb === "function" ? cb({ + code: 400, + message: "Cannot revive if not dead" + }) : void 0; + } + _.merge(user.stats, { + hp: 50, + exp: 0, + gp: 0 + }); + if (user.stats.lvl > 1) { + user.stats.lvl--; + } + lostStat = user.fns.randomVal(_.reduce(['str', 'con', 'per', 'int'], (function(m, k) { + if (user.stats[k]) { + m[k] = k; + } + return m; + }), {})); + if (lostStat) { + user.stats[lostStat]--; + } + cl = user.stats["class"]; + gearOwned = (typeof (_base = user.items.gear.owned).toObject === "function" ? _base.toObject() : void 0) || user.items.gear.owned; + losableItems = {}; + _.each(gearOwned, function(v, k) { + var itm; + if (v) { + itm = content.gear.flat['' + k]; + if (itm) { + if ((itm.value > 0 || k === 'weapon_warrior_0') && (itm.klass === cl || (itm.klass === 'special' && (!itm.specialClass || itm.specialClass === cl)))) { + return losableItems['' + k] = '' + k; + } + } + } + }); + lostItem = user.fns.randomVal(losableItems); + if (item = content.gear.flat[lostItem]) { + user.items.gear.owned[lostItem] = false; + if (user.items.gear.equipped[item.type] === lostItem) { + user.items.gear.equipped[item.type] = "" + item.type + "_base_0"; + } + if (user.items.gear.costume[item.type] === lostItem) { + user.items.gear.costume[item.type] = "" + item.type + "_base_0"; + } + } + if (typeof user.markModified === "function") { + user.markModified('items.gear'); + } + return typeof cb === "function" ? cb((item ? { + code: 200, + message: i18n.t('messageLostItem', { + itemText: item.text(req.language) + }, req.language) + } : null), user) : void 0; + }, + reset: function(req, cb) { + var gear; + user.habits = []; + user.dailys = []; + user.todos = []; + user.rewards = []; + user.stats.hp = 50; + user.stats.lvl = 1; + user.stats.gp = 0; + user.stats.exp = 0; + gear = user.items.gear; + _.each(['equipped', 'costume'], function(type) { + gear[type].armor = 'armor_base_0'; + gear[type].weapon = 'weapon_base_0'; + gear[type].head = 'head_base_0'; + return gear[type].shield = 'shield_base_0'; + }); + if (typeof gear.owned === 'undefined') { + gear.owned = {}; + } + _.each(gear.owned, function(v, k) { + if (gear.owned[k]) { + gear.owned[k] = false; + } + return true; + }); + gear.owned.weapon_warrior_0 = true; + if (typeof user.markModified === "function") { + user.markModified('items.gear.owned'); + } + user.preferences.costume = false; + return typeof cb === "function" ? cb(null, user) : void 0; + }, + reroll: function(req, cb, ga) { + if (user.balance < 1) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('notEnoughGems', req.language) + }) : void 0; + } + user.balance--; + _.each(user.tasks, function(task) { + if (task.type !== 'reward') { + return task.value = 0; + } + }); + user.stats.hp = 50; + if (typeof cb === "function") { + cb(null, user); + } + return ga != null ? ga.event('purchase', 'reroll').send() : void 0; + }, + rebirth: function(req, cb, ga) { + var flags, gear, lvl, stats; + if (user.balance < 2 && user.stats.lvl < 100) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('notEnoughGems', req.language) + }) : void 0; + } + if (user.stats.lvl < 100) { + user.balance -= 2; + } + if (user.stats.lvl < 100) { + lvl = user.stats.lvl; + } else { + lvl = 100; + } + _.each(user.tasks, function(task) { + if (task.type !== 'reward') { + task.value = 0; + } + if (task.type === 'daily') { + return task.streak = 0; + } + }); + stats = user.stats; + stats.buffs = {}; + stats.hp = 50; + stats.lvl = 1; + stats["class"] = 'warrior'; + _.each(['per', 'int', 'con', 'str', 'points', 'gp', 'exp', 'mp'], function(value) { + return stats[value] = 0; + }); + gear = user.items.gear; + _.each(['equipped', 'costume'], function(type) { + gear[type] = {}; + gear[type].armor = 'armor_base_0'; + gear[type].weapon = 'weapon_warrior_0'; + gear[type].head = 'head_base_0'; + return gear[type].shield = 'shield_base_0'; + }); + if (user.items.currentPet) { + user.ops.equip({ + params: { + type: 'pet', + key: user.items.currentPet + } + }); + } + if (user.items.currentMount) { + user.ops.equip({ + params: { + type: 'mount', + key: user.items.currentMount + } + }); + } + _.each(gear.owned, function(v, k) { + if (gear.owned[k]) { + gear.owned[k] = false; + return true; + } + }); + gear.owned.weapon_warrior_0 = true; + if (typeof user.markModified === "function") { + user.markModified('items.gear.owned'); + } + user.preferences.costume = false; + flags = user.flags; + if (!(user.achievements.ultimateGear || user.achievements.beastMaster)) { + flags.rebirthEnabled = false; + } + flags.itemsEnabled = false; + flags.dropsEnabled = false; + flags.classSelected = false; + flags.levelDrops = {}; + if (!user.achievements.rebirths) { + user.achievements.rebirths = 1; + user.achievements.rebirthLevel = lvl; + } else if (lvl > user.achievements.rebirthLevel || lvl === 100) { + user.achievements.rebirths++; + user.achievements.rebirthLevel = lvl; + } + user.stats.buffs = {}; + if (typeof cb === "function") { + cb(null, user); + } + return ga != null ? ga.event('purchase', 'Rebirth').send() : void 0; + }, + allocateNow: function(req, cb) { + _.times(user.stats.points, user.fns.autoAllocate); + user.stats.points = 0; + if (typeof user.markModified === "function") { + user.markModified('stats'); + } + return typeof cb === "function" ? cb(null, user.stats) : void 0; + }, + clearCompleted: function(req, cb) { + _.remove(user.todos, function(t) { + var _ref; + return t.completed && !((_ref = t.challenge) != null ? _ref.id : void 0); + }); + if (typeof user.markModified === "function") { + user.markModified('todos'); + } + return typeof cb === "function" ? cb(null, user.todos) : void 0; + }, + sortTask: function(req, cb) { + var from, id, movedTask, task, tasks, to, _ref; + id = req.params.id; + _ref = req.query, to = _ref.to, from = _ref.from; + task = user.tasks[id]; + if (!task) { + return typeof cb === "function" ? cb({ + code: 404, + message: i18n.t('messageTaskNotFound', req.language) + }) : void 0; + } + if (!((to != null) && (from != null))) { + return typeof cb === "function" ? cb('?to=__&from=__ are required') : void 0; + } + tasks = user["" + task.type + "s"]; + movedTask = tasks.splice(from, 1)[0]; + if (to === -1) { + tasks.push(movedTask); + } else { + tasks.splice(to, 0, movedTask); + } + return typeof cb === "function" ? cb(null, tasks) : void 0; + }, + updateTask: function(req, cb) { + var task, _ref; + if (!(task = user.tasks[(_ref = req.params) != null ? _ref.id : void 0])) { + return typeof cb === "function" ? cb({ + code: 404, + message: i18n.t('messageTaskNotFound', req.language) + }) : void 0; + } + _.merge(task, _.omit(req.body, ['checklist', 'id', 'type'])); + if (req.body.checklist) { + task.checklist = req.body.checklist; + } + if (typeof task.markModified === "function") { + task.markModified('tags'); + } + return typeof cb === "function" ? cb(null, task) : void 0; + }, + deleteTask: function(req, cb) { + var i, task, _ref; + task = user.tasks[(_ref = req.params) != null ? _ref.id : void 0]; + if (!task) { + return typeof cb === "function" ? cb({ + code: 404, + message: i18n.t('messageTaskNotFound', req.language) + }) : void 0; + } + i = user[task.type + "s"].indexOf(task); + if (~i) { + user[task.type + "s"].splice(i, 1); + } + return typeof cb === "function" ? cb(null, {}) : void 0; + }, + addTask: function(req, cb) { + var task; + task = api.taskDefaults(req.body); + user["" + task.type + "s"].unshift(task); + if (user.preferences.newTaskEdit) { + task._editing = true; + } + if (user.preferences.tagsCollapsed) { + task._tags = true; + } + if (user.preferences.advancedCollapsed) { + task._advanced = true; + } + if (typeof cb === "function") { + cb(null, task); + } + return task; + }, + addTag: function(req, cb) { + if (user.tags == null) { + user.tags = []; + } + user.tags.push({ + name: req.body.name, + id: req.body.id || api.uuid() + }); + return typeof cb === "function" ? cb(null, user.tags) : void 0; + }, + sortTag: function(req, cb) { + var from, to, _ref; + _ref = req.query, to = _ref.to, from = _ref.from; + if (!((to != null) && (from != null))) { + return typeof cb === "function" ? cb('?to=__&from=__ are required') : void 0; + } + user.tags.splice(to, 0, user.tags.splice(from, 1)[0]); + return typeof cb === "function" ? cb(null, user.tags) : void 0; + }, + updateTag: function(req, cb) { + var i, tid; + tid = req.params.id; + i = _.findIndex(user.tags, { + id: tid + }); + if (!~i) { + return typeof cb === "function" ? cb({ + code: 404, + message: i18n.t('messageTagNotFound', req.language) + }) : void 0; + } + user.tags[i].name = req.body.name; + return typeof cb === "function" ? cb(null, user.tags[i]) : void 0; + }, + deleteTag: function(req, cb) { + var i, tag, tid; + tid = req.params.id; + i = _.findIndex(user.tags, { + id: tid + }); + if (!~i) { + return typeof cb === "function" ? cb({ + code: 404, + message: i18n.t('messageTagNotFound', req.language) + }) : void 0; + } + tag = user.tags[i]; + delete user.filters[tag.id]; + user.tags.splice(i, 1); + _.each(user.tasks, function(task) { + return delete task.tags[tag.id]; + }); + _.each(['habits', 'dailys', 'todos', 'rewards'], function(type) { + return typeof user.markModified === "function" ? user.markModified(type) : void 0; + }); + return typeof cb === "function" ? cb(null, user.tags) : void 0; + }, + addWebhook: function(req, cb) { + var wh; + wh = user.preferences.webhooks; + api.refPush(wh, { + url: req.body.url, + enabled: req.body.enabled || true, + id: req.body.id + }); + if (typeof user.markModified === "function") { + user.markModified('preferences.webhooks'); + } + return typeof cb === "function" ? cb(null, user.preferences.webhooks) : void 0; + }, + updateWebhook: function(req, cb) { + _.merge(user.preferences.webhooks[req.params.id], req.body); + if (typeof user.markModified === "function") { + user.markModified('preferences.webhooks'); + } + return typeof cb === "function" ? cb(null, user.preferences.webhooks) : void 0; + }, + deleteWebhook: function(req, cb) { + delete user.preferences.webhooks[req.params.id]; + if (typeof user.markModified === "function") { + user.markModified('preferences.webhooks'); + } + return typeof cb === "function" ? cb(null, user.preferences.webhooks) : void 0; + }, + clearPMs: function(req, cb) { + user.inbox.messages = {}; + if (typeof user.markModified === "function") { + user.markModified('inbox.messages'); + } + return typeof cb === "function" ? cb(null, user.inbox.messages) : void 0; + }, + deletePM: function(req, cb) { + delete user.inbox.messages[req.params.id]; + if (typeof user.markModified === "function") { + user.markModified('inbox.messages.' + req.params.id); + } + return typeof cb === "function" ? cb(null, user.inbox.messages) : void 0; + }, + blockUser: function(req, cb) { + var i; + i = user.inbox.blocks.indexOf(req.params.uuid); + if (~i) { + user.inbox.blocks.splice(i, 1); + } else { + user.inbox.blocks.push(req.params.uuid); + } + if (typeof user.markModified === "function") { + user.markModified('inbox.blocks'); + } + return typeof cb === "function" ? cb(null, user.inbox.blocks) : void 0; + }, + feed: function(req, cb) { + var egg, evolve, food, message, pet, potion, userPets, _ref, _ref1, _ref2; + _ref = req.params, pet = _ref.pet, food = _ref.food; + food = content.food[food]; + _ref1 = pet.split('-'), egg = _ref1[0], potion = _ref1[1]; + userPets = user.items.pets; + if (!userPets[pet]) { + return typeof cb === "function" ? cb({ + code: 404, + message: i18n.t('messagePetNotFound', req.language) + }) : void 0; + } + if (!((_ref2 = user.items.food) != null ? _ref2[food.key] : void 0)) { + return typeof cb === "function" ? cb({ + code: 404, + message: i18n.t('messageFoodNotFound', req.language) + }) : void 0; + } + if (content.specialPets[pet] || (egg === "Egg")) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('messageCannotFeedPet', req.language) + }) : void 0; + } + if (user.items.mounts[pet]) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('messageAlreadyMount', req.language) + }) : void 0; + } + message = ''; + evolve = function() { + userPets[pet] = -1; + user.items.mounts[pet] = true; + if (pet === user.items.currentPet) { + user.items.currentPet = ""; + } + return message = i18n.t('messageEvolve', { + egg: egg + }, req.language); + }; + if (food.key === 'Saddle') { + evolve(); + } else { + if (food.target === potion) { + userPets[pet] += 5; + message = i18n.t('messageLikesFood', { + egg: egg, + foodText: food.text(req.language) + }, req.language); + } else { + userPets[pet] += 2; + message = i18n.t('messageDontEnjoyFood', { + egg: egg, + foodText: food.text(req.language) + }, req.language); + } + if (userPets[pet] >= 50 && !user.items.mounts[pet]) { + evolve(); + } + } + user.items.food[food.key]--; + return typeof cb === "function" ? cb({ + code: 200, + message: message + }, userPets[pet]) : void 0; + }, + buySpecialSpell: function(req, cb) { + var item, key, message, _base; + key = req.params.key; + item = content.special[key]; + if (user.stats.gp < item.value) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('messageNotEnoughGold', req.language) + }) : void 0; + } + user.stats.gp -= item.value; + if ((_base = user.items.special)[key] == null) { + _base[key] = 0; + } + user.items.special[key]++; + if (typeof user.markModified === "function") { + user.markModified('items.special'); + } + message = i18n.t('messageBought', { + itemText: item.text(req.language) + }, req.language); + return typeof cb === "function" ? cb({ + code: 200, + message: message + }, _.pick(user, $w('items stats'))) : void 0; + }, + purchase: function(req, cb, ga) { + var convCap, convRate, item, key, price, type, _ref, _ref1, _ref2, _ref3; + _ref = req.params, type = _ref.type, key = _ref.key; + if (type === 'gems' && key === 'gem') { + _ref1 = api.planGemLimits, convRate = _ref1.convRate, convCap = _ref1.convCap; + convCap += user.purchased.plan.consecutive.gemCapExtra; + if (!((_ref2 = user.purchased) != null ? (_ref3 = _ref2.plan) != null ? _ref3.customerId : void 0 : void 0)) { + return typeof cb === "function" ? cb({ + code: 401, + message: "Must subscribe to purchase gems with GP" + }, req) : void 0; + } + if (!(user.stats.gp >= convRate)) { + return typeof cb === "function" ? cb({ + code: 401, + message: "Not enough Gold" + }) : void 0; + } + if (user.purchased.plan.gemsBought >= convCap) { + return typeof cb === "function" ? cb({ + code: 401, + message: "You've reached the Gold=>Gem conversion cap (" + convCap + ") for this month. We have this to prevent abuse / farming. The cap will reset within the first three days of next month." + }) : void 0; + } + user.balance += .25; + user.purchased.plan.gemsBought++; + user.stats.gp -= convRate; + return typeof cb === "function" ? cb({ + code: 200, + message: "+1 Gems" + }, _.pick(user, $w('stats balance'))) : void 0; + } + if (type !== 'eggs' && type !== 'hatchingPotions' && type !== 'food' && type !== 'quests' && type !== 'gear') { + return typeof cb === "function" ? cb({ + code: 404, + message: ":type must be in [eggs,hatchingPotions,food,quests,gear]" + }, req) : void 0; + } + if (type === 'gear') { + item = content.gear.flat[key]; + if (user.items.gear.owned[key]) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('alreadyHave', req.language) + }) : void 0; + } + price = (item.twoHanded ? 2 : 1) / 4; + } else { + item = content[type][key]; + price = item.value / 4; + } + if (!item) { + return typeof cb === "function" ? cb({ + code: 404, + message: ":key not found for Content." + type + }, req) : void 0; + } + if (user.balance < price) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('notEnoughGems', req.language) + }) : void 0; + } + user.balance -= price; + if (type === 'gear') { + user.items.gear.owned[key] = true; + } else { + if (!(user.items[type][key] > 0)) { + user.items[type][key] = 0; + } + user.items[type][key]++; + } + if (typeof cb === "function") { + cb(null, _.pick(user, $w('items balance'))); + } + return ga != null ? ga.event('purchase', key).send() : void 0; + }, + releasePets: function(req, cb) { + var pet; + if (user.balance < 1) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('notEnoughGems', req.language) + }) : void 0; + } else { + user.balance--; + for (pet in content.pets) { + user.items.pets[pet] = 0; + } + if (!user.achievements.beastMasterCount) { + user.achievements.beastMasterCount = 0; + } + user.achievements.beastMasterCount++; + user.items.currentPet = ""; + } + return typeof cb === "function" ? cb(null, user) : void 0; + }, + releaseMounts: function(req, cb) { + var mount; + if (user.balance < 1) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('notEnoughGems', req.language) + }) : void 0; + } else { + user.balance -= 1; + user.items.currentMount = ""; + for (mount in content.pets) { + user.items.mounts[mount] = null; + } + if (!user.achievements.mountMasterCount) { + user.achievements.mountMasterCount = 0; + } + user.achievements.mountMasterCount++; + } + return typeof cb === "function" ? cb(null, user) : void 0; + }, + releaseBoth: function(req, cb) { + var animal, giveTriadBingo; + if (user.balance < 1.5) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('notEnoughGems', req.language) + }) : void 0; + } else { + giveTriadBingo = true; + user.balance -= 1.5; + user.items.currentMount = ""; + user.items.currentPet = ""; + for (animal in content.pets) { + if (user.items.pets[animal] === -1) { + giveTriadBingo = false; + } + user.items.pets[animal] = 0; + user.items.mounts[animal] = null; + } + if (!user.achievements.beastMasterCount) { + user.achievements.beastMasterCount = 0; + } + user.achievements.beastMasterCount++; + if (!user.achievements.mountMasterCount) { + user.achievements.mountMasterCount = 0; + } + user.achievements.mountMasterCount++; + if (giveTriadBingo) { + if (!user.achievements.triadBingoCount) { + user.achievements.triadBingoCount = 0; + } + user.achievements.triadBingoCount++; + } + } + return typeof cb === "function" ? cb(null, user) : void 0; + }, + buy: function(req, cb) { + var item, key, message; + key = req.params.key; + item = key === 'potion' ? content.potion : content.gear.flat[key]; + if (!item) { + return typeof cb === "function" ? cb({ + code: 404, + message: "Item '" + key + " not found (see https://github.com/HabitRPG/habitrpg-shared/blob/develop/script/content.coffee)" + }) : void 0; + } + if (user.stats.gp < item.value) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('messageNotEnoughGold', req.language) + }) : void 0; + } + if ((item.canOwn != null) && !item.canOwn(user)) { + return typeof cb === "function" ? cb({ + code: 401, + message: "You can't own this item" + }) : void 0; + } + if (item.key === 'potion') { + user.stats.hp += 15; + if (user.stats.hp > 50) { + user.stats.hp = 50; + } + } else { + user.items.gear.equipped[item.type] = item.key; + user.items.gear.owned[item.key] = true; + message = user.fns.handleTwoHanded(item, null, req); + if (message == null) { + message = i18n.t('messageBought', { + itemText: item.text(req.language) + }, req.language); + } + if (!user.achievements.ultimateGear && item.last) { + user.fns.ultimateGear(); + } + } + user.stats.gp -= item.value; + return typeof cb === "function" ? cb({ + code: 200, + message: message + }, _.pick(user, $w('items achievements stats'))) : void 0; + }, + buyMysterySet: function(req, cb) { + var mysterySet, _ref; + if (!(user.purchased.plan.consecutive.trinkets > 0)) { + return typeof cb === "function" ? cb({ + code: 401, + message: "You don't have enough Mystic Hourglasses" + }) : void 0; + } + mysterySet = (_ref = content.timeTravelerStore(user.items.gear.owned)) != null ? _ref[req.params.key] : void 0; + if ((typeof window !== "undefined" && window !== null ? window.confirm : void 0) != null) { + if (!window.confirm("Buy this full set of items for 1 Mystic Hourglass?")) { + return; + } + } + if (!mysterySet) { + return typeof cb === "function" ? cb({ + code: 404, + message: "Mystery set not found, or set already owned" + }) : void 0; + } + _.each(mysterySet.items, function(i) { + return user.items.gear.owned[i.key] = true; + }); + user.purchased.plan.consecutive.trinkets--; + return typeof cb === "function" ? cb(null, _.pick(user, $w('items purchased.plan.consecutive'))) : void 0; + }, + sell: function(req, cb) { + var key, type, _ref; + _ref = req.params, key = _ref.key, type = _ref.type; + if (type !== 'eggs' && type !== 'hatchingPotions' && type !== 'food') { + return typeof cb === "function" ? cb({ + code: 404, + message: ":type not found. Must bes in [eggs, hatchingPotions, food]" + }) : void 0; + } + if (!user.items[type][key]) { + return typeof cb === "function" ? cb({ + code: 404, + message: ":key not found for user.items." + type + }) : void 0; + } + user.items[type][key]--; + user.stats.gp += content[type][key].value; + return typeof cb === "function" ? cb(null, _.pick(user, $w('stats items'))) : void 0; + }, + equip: function(req, cb) { + var item, key, message, type, _ref; + _ref = [req.params.type || 'equipped', req.params.key], type = _ref[0], key = _ref[1]; + switch (type) { + case 'mount': + if (!user.items.mounts[key]) { + return typeof cb === "function" ? cb({ + code: 404, + message: ":You do not own this mount." + }) : void 0; + } + user.items.currentMount = user.items.currentMount === key ? '' : key; + break; + case 'pet': + if (!user.items.pets[key]) { + return typeof cb === "function" ? cb({ + code: 404, + message: ":You do not own this pet." + }) : void 0; + } + user.items.currentPet = user.items.currentPet === key ? '' : key; + break; + case 'costume': + case 'equipped': + item = content.gear.flat[key]; + if (!user.items.gear.owned[key]) { + return typeof cb === "function" ? cb({ + code: 404, + message: ":You do not own this gear." + }) : void 0; + } + if (user.items.gear[type][item.type] === key) { + user.items.gear[type][item.type] = "" + item.type + "_base_0"; + message = i18n.t('messageUnEquipped', { + itemText: item.text(req.language) + }, req.language); + } else { + user.items.gear[type][item.type] = item.key; + message = user.fns.handleTwoHanded(item, type, req); + } + if (typeof user.markModified === "function") { + user.markModified("items.gear." + type); + } + } + return typeof cb === "function" ? cb((message ? { + code: 200, + message: message + } : null), user.items) : void 0; + }, + hatch: function(req, cb) { + var egg, hatchingPotion, pet, _ref; + _ref = req.params, egg = _ref.egg, hatchingPotion = _ref.hatchingPotion; + if (!(egg && hatchingPotion)) { + return typeof cb === "function" ? cb({ + code: 404, + message: "Please specify query.egg & query.hatchingPotion" + }) : void 0; + } + if (!(user.items.eggs[egg] > 0 && user.items.hatchingPotions[hatchingPotion] > 0)) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('messageMissingEggPotion', req.language) + }) : void 0; + } + pet = "" + egg + "-" + hatchingPotion; + if (user.items.pets[pet] && user.items.pets[pet] > 0) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('messageAlreadyPet', req.language) + }) : void 0; + } + user.items.pets[pet] = 5; + user.items.eggs[egg]--; + user.items.hatchingPotions[hatchingPotion]--; + return typeof cb === "function" ? cb({ + code: 200, + message: i18n.t('messageHatched', req.language) + }, user.items) : void 0; + }, + unlock: function(req, cb, ga) { + var alreadyOwns, cost, fullSet, k, path, split, v; + path = req.query.path; + fullSet = ~path.indexOf(","); + cost = ~path.indexOf('background.') ? fullSet ? 3.75 : 1.75 : fullSet ? 1.25 : 0.5; + alreadyOwns = !fullSet && user.fns.dotGet("purchased." + path) === true; + if (user.balance < cost && !alreadyOwns) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('notEnoughGems', req.language) + }) : void 0; + } + if (fullSet) { + _.each(path.split(","), function(p) { + user.fns.dotSet("purchased." + p, true); + return true; + }); + } else { + if (alreadyOwns) { + split = path.split('.'); + v = split.pop(); + k = split.join('.'); + if (k === 'background' && v === user.preferences.background) { + v = ''; + } + user.fns.dotSet("preferences." + k, v); + return typeof cb === "function" ? cb(null, req) : void 0; + } + user.fns.dotSet("purchased." + path, true); + } + user.balance -= cost; + if (typeof user.markModified === "function") { + user.markModified('purchased'); + } + if (typeof cb === "function") { + cb(null, _.pick(user, $w('purchased preferences'))); + } + return ga != null ? ga.event('purchase', path).send() : void 0; + }, + changeClass: function(req, cb, ga) { + var klass, _ref; + klass = (_ref = req.query) != null ? _ref["class"] : void 0; + if (klass === 'warrior' || klass === 'rogue' || klass === 'wizard' || klass === 'healer') { + user.stats["class"] = klass; + user.flags.classSelected = true; + _.each(["weapon", "armor", "shield", "head"], function(type) { + var foundKey; + foundKey = false; + _.findLast(user.items.gear.owned, function(v, k) { + if (~k.indexOf(type + "_" + klass) && v === true) { + return foundKey = k; + } + }); + user.items.gear.equipped[type] = foundKey ? foundKey : type === "weapon" ? "weapon_" + klass + "_0" : type === "shield" && klass === "rogue" ? "shield_rogue_0" : "" + type + "_base_0"; + if (type === "weapon" || (type === "shield" && klass === "rogue")) { + user.items.gear.owned["" + type + "_" + klass + "_0"] = true; + } + return true; + }); + } else { + if (user.preferences.disableClasses) { + user.preferences.disableClasses = false; + user.preferences.autoAllocate = false; + } else { + if (!(user.balance >= .75)) { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('notEnoughGems', req.language) + }) : void 0; + } + user.balance -= .75; + } + _.merge(user.stats, { + str: 0, + con: 0, + per: 0, + int: 0, + points: user.stats.lvl + }); + user.flags.classSelected = false; + if (ga != null) { + ga.event('purchase', 'changeClass').send(); + } + } + return typeof cb === "function" ? cb(null, _.pick(user, $w('stats flags items preferences'))) : void 0; + }, + disableClasses: function(req, cb) { + user.stats["class"] = 'warrior'; + user.flags.classSelected = true; + user.preferences.disableClasses = true; + user.preferences.autoAllocate = true; + user.stats.str = user.stats.lvl; + user.stats.points = 0; + return typeof cb === "function" ? cb(null, _.pick(user, $w('stats flags preferences'))) : void 0; + }, + allocate: function(req, cb) { + var stat; + stat = req.query.stat || 'str'; + if (user.stats.points > 0) { + user.stats[stat]++; + user.stats.points--; + if (stat === 'int') { + user.stats.mp++; + } + } + return typeof cb === "function" ? cb(null, _.pick(user, $w('stats'))) : void 0; + }, + readValentine: function(req, cb) { + user.items.special.valentineReceived.shift(); + if (typeof user.markModified === "function") { + user.markModified('items.special.valentineReceived'); + } + return typeof cb === "function" ? cb(null, 'items.special') : void 0; + }, + openMysteryItem: function(req, cb, ga) { + var item, _ref, _ref1; + item = (_ref = user.purchased.plan) != null ? (_ref1 = _ref.mysteryItems) != null ? _ref1.shift() : void 0 : void 0; + if (!item) { + return typeof cb === "function" ? cb({ + code: 400, + message: "Empty" + }) : void 0; + } + item = content.gear.flat[item]; + user.items.gear.owned[item.key] = true; + if (typeof user.markModified === "function") { + user.markModified('purchased.plan.mysteryItems'); + } + if (typeof window !== 'undefined') { + (user._tmp != null ? user._tmp : user._tmp = {}).drop = { + type: 'gear', + dialog: "" + (item.text(req.language)) + " inside!" + }; + } + return typeof cb === "function" ? cb(null, user.items.gear.owned) : void 0; + }, + readNYE: function(req, cb) { + user.items.special.nyeReceived.shift(); + if (typeof user.markModified === "function") { + user.markModified('items.special.nyeReceived'); + } + return typeof cb === "function" ? cb(null, 'items.special') : void 0; + }, + score: function(req, cb) { + var addPoints, calculateDelta, calculateReverseDelta, changeTaskValue, delta, direction, id, mpDelta, multiplier, num, options, stats, subtractPoints, task, th, _ref; + _ref = req.params, id = _ref.id, direction = _ref.direction; + task = user.tasks[id]; + options = req.query || {}; + _.defaults(options, { + times: 1, + cron: false + }); + user._tmp = {}; + stats = { + gp: +user.stats.gp, + hp: +user.stats.hp, + exp: +user.stats.exp + }; + task.value = +task.value; + task.streak = ~~task.streak; + if (task.priority == null) { + task.priority = 1; + } + if (task.value > stats.gp && task.type === 'reward') { + return typeof cb === "function" ? cb({ + code: 401, + message: i18n.t('messageNotEnoughGold', req.language) + }) : void 0; + } + delta = 0; + calculateDelta = function() { + var currVal, nextDelta, _ref1; + currVal = task.value < -47.27 ? -47.27 : task.value > 21.27 ? 21.27 : task.value; + nextDelta = Math.pow(0.9747, currVal) * (direction === 'down' ? -1 : 1); + if (((_ref1 = task.checklist) != null ? _ref1.length : void 0) > 0) { + if (direction === 'down' && task.type === 'daily' && options.cron) { + nextDelta *= 1 - _.reduce(task.checklist, (function(m, i) { + return m + (i.completed ? 1 : 0); + }), 0) / task.checklist.length; + } + if (task.type === 'todo') { + nextDelta *= 1 + _.reduce(task.checklist, (function(m, i) { + return m + (i.completed ? 1 : 0); + }), 0); + } + } + return nextDelta; + }; + calculateReverseDelta = function() { + var calc, closeEnough, currVal, diff, nextDelta, testVal, _ref1; + currVal = task.value < -47.27 ? -47.27 : task.value > 21.27 ? 21.27 : task.value; + testVal = currVal + Math.pow(0.9747, currVal) * (direction === 'down' ? -1 : 1); + closeEnough = 0.00001; + while (true) { + calc = testVal + Math.pow(0.9747, testVal); + diff = currVal - calc; + if (Math.abs(diff) < closeEnough) { + break; + } + if (diff > 0) { + testVal -= diff; + } else { + testVal += diff; + } + } + nextDelta = testVal - currVal; + if (((_ref1 = task.checklist) != null ? _ref1.length : void 0) > 0) { + if (task.type === 'todo') { + nextDelta *= 1 + _.reduce(task.checklist, (function(m, i) { + return m + (i.completed ? 1 : 0); + }), 0); + } + } + return nextDelta; + }; + changeTaskValue = function() { + return _.times(options.times, function() { + var nextDelta, _ref1; + nextDelta = !options.cron && direction === 'down' ? calculateReverseDelta() : calculateDelta(); + if (task.type !== 'reward') { + if (user.preferences.automaticAllocation === true && user.preferences.allocationMode === 'taskbased' && !(task.type === 'todo' && direction === 'down')) { + user.stats.training[task.attribute] += nextDelta; + } + if (direction === 'up' && !(task.type === 'habit' && !task.down)) { + user.party.quest.progress.up = user.party.quest.progress.up || 0; + if ((_ref1 = task.type) === 'daily' || _ref1 === 'todo') { + user.party.quest.progress.up += nextDelta * (1 + (user._statsComputed.str / 200)); + } + } + task.value += nextDelta; + } + return delta += nextDelta; + }); + }; + addPoints = function() { + var afterStreak, currStreak, gpMod, intBonus, perBonus, streakBonus, _crit; + _crit = (delta > 0 ? user.fns.crit() : 1); + if (_crit > 1) { + user._tmp.crit = _crit; + } + intBonus = 1 + (user._statsComputed.int * .025); + stats.exp += Math.round(delta * intBonus * task.priority * _crit * 6); + perBonus = 1 + user._statsComputed.per * .02; + gpMod = delta * task.priority * _crit * perBonus; + return stats.gp += task.streak ? (currStreak = direction === 'down' ? task.streak - 1 : task.streak, streakBonus = currStreak / 100 + 1, afterStreak = gpMod * streakBonus, currStreak > 0 ? gpMod > 0 ? user._tmp.streakBonus = afterStreak - gpMod : void 0 : void 0, afterStreak) : gpMod; + }; + subtractPoints = function() { + var conBonus, hpMod; + conBonus = 1 - (user._statsComputed.con / 250); + if (conBonus < .1) { + conBonus = 0.1; + } + hpMod = delta * conBonus * task.priority * 2; + return stats.hp += Math.round(hpMod * 10) / 10; + }; + switch (task.type) { + case 'habit': + changeTaskValue(); + if (delta > 0) { + addPoints(); + } else { + subtractPoints(); + } + th = (task.history != null ? task.history : task.history = []); + if (th[th.length - 1] && moment(th[th.length - 1].date).isSame(new Date, 'day')) { + th[th.length - 1].value = task.value; + } else { + th.push({ + date: +(new Date), + value: task.value + }); + } + if (typeof user.markModified === "function") { + user.markModified("habits." + (_.findIndex(user.habits, { + id: task.id + })) + ".history"); + } + break; + case 'daily': + if (options.cron) { + changeTaskValue(); + subtractPoints(); + if (!user.stats.buffs.streaks) { + task.streak = 0; + } + } else { + changeTaskValue(); + if (direction === 'down') { + delta = calculateDelta(); + } + addPoints(); + if (direction === 'up') { + task.streak = task.streak ? task.streak + 1 : 1; + if ((task.streak % 21) === 0) { + user.achievements.streak = user.achievements.streak ? user.achievements.streak + 1 : 1; + } + } else { + if ((task.streak % 21) === 0) { + user.achievements.streak = user.achievements.streak ? user.achievements.streak - 1 : 0; + } + task.streak = task.streak ? task.streak - 1 : 0; + } + } + break; + case 'todo': + if (options.cron) { + changeTaskValue(); + } else { + task.dateCompleted = direction === 'up' ? new Date : void 0; + changeTaskValue(); + if (direction === 'down') { + delta = calculateDelta(); + } + addPoints(); + multiplier = _.max([ + _.reduce(task.checklist, (function(m, i) { + return m + (i.completed ? 1 : 0); + }), 1), 1 + ]); + mpDelta = _.max([multiplier, .01 * user._statsComputed.maxMP * multiplier]); + mpDelta *= user._tmp.crit || 1; + if (direction === 'down') { + mpDelta *= -1; + } + user.stats.mp += mpDelta; + if (user.stats.mp >= user._statsComputed.maxMP) { + user.stats.mp = user._statsComputed.maxMP; + } + if (user.stats.mp < 0) { + user.stats.mp = 0; + } + } + break; + case 'reward': + changeTaskValue(); + stats.gp -= Math.abs(task.value); + num = parseFloat(task.value).toFixed(2); + if (stats.gp < 0) { + stats.hp += stats.gp; + stats.gp = 0; + } + } + user.fns.updateStats(stats, req); + if (typeof window === 'undefined') { + if (direction === 'up') { + user.fns.randomDrop({ + task: task, + delta: delta + }, req); + } + } + if (typeof cb === "function") { + cb(null, user); + } + return delta; + } + }; + } + user.fns = { + getItem: function(type) { + var item; + item = content.gear.flat[user.items.gear.equipped[type]]; + if (!item) { + return content.gear.flat["" + type + "_base_0"]; + } + return item; + }, + handleTwoHanded: function(item, type, req) { + var message, weapon, _ref; + if (type == null) { + type = 'equipped'; + } + if (item.type === "shield" && ((_ref = (weapon = content.gear.flat[user.items.gear[type].weapon])) != null ? _ref.twoHanded : void 0)) { + user.items.gear[type].weapon = 'weapon_base_0'; + message = i18n.t('messageTwoHandled', { + gearText: weapon.text(req.language) + }, req.language); + } + if (item.twoHanded) { + user.items.gear[type].shield = "shield_base_0"; + message = i18n.t('messageTwoHandled', { + gearText: item.text(req.language) + }, req.language); + } + return message; + }, + + /* + Because the same op needs to be performed on the client and the server (critical hits, item drops, etc), + we need things to be "random", but technically predictable so that they don't go out-of-sync + */ + predictableRandom: function(seed) { + var x; + if (!seed || seed === Math.PI) { + seed = _.reduce(user.stats, (function(m, v) { + if (_.isNumber(v)) { + return m + v; + } else { + return m; + } + }), 0); + } + x = Math.sin(seed++) * 10000; + return x - Math.floor(x); + }, + crit: function(stat, chance) { + if (stat == null) { + stat = 'str'; + } + if (chance == null) { + chance = .03; + } + if (user.fns.predictableRandom() <= chance * (1 + user._statsComputed[stat] / 100)) { + return 1.5 + (.02 * user._statsComputed[stat]); + } else { + return 1; + } + }, + + /* + Get a random property from an object + returns random property (the value) + */ + randomVal: function(obj, options) { + var array, rand; + array = (options != null ? options.key : void 0) ? _.keys(obj) : _.values(obj); + rand = user.fns.predictableRandom(options != null ? options.seed : void 0); + array.sort(); + return array[Math.floor(rand * array.length)]; + }, + + /* + This allows you to set object properties by dot-path. Eg, you can run pathSet('stats.hp',50,user) which is the same as + user.stats.hp = 50. This is useful because in our habitrpg-shared functions we're returning changesets as {path:value}, + so that different consumers can implement setters their own way. Derby needs model.set(path, value) for example, where + Angular sets object properties directly - in which case, this function will be used. + */ + dotSet: function(path, val) { + return api.dotSet(user, path, val); + }, + dotGet: function(path) { + return api.dotGet(user, path); + }, + randomDrop: function(modifiers, req) { + var acceptableDrops, chance, drop, dropK, dropMultiplier, quest, rarity, task, _base, _base1, _base2, _name, _name1, _name2, _ref, _ref1, _ref2, _ref3; + task = modifiers.task; + chance = _.min([Math.abs(task.value - 21.27), 37.5]) / 150 + .02; + chance *= task.priority * (1 + (task.streak / 100 || 0)) * (1 + (user._statsComputed.per / 100)) * (1 + (user.contributor.level / 40 || 0)) * (1 + (user.achievements.rebirths / 20 || 0)) * (1 + (user.achievements.streak / 200 || 0)) * (user._tmp.crit || 1) * (1 + .5 * (_.reduce(task.checklist, (function(m, i) { + return m + (i.completed ? 1 : 0); + }), 0) || 0)); + chance = api.diminishingReturns(chance, 0.75); + quest = content.quests[(_ref = user.party.quest) != null ? _ref.key : void 0]; + if ((quest != null ? quest.collect : void 0) && user.fns.predictableRandom(user.stats.gp) < chance) { + dropK = user.fns.randomVal(quest.collect, { + key: true + }); + user.party.quest.progress.collect[dropK]++; + if (typeof user.markModified === "function") { + user.markModified('party.quest.progress'); + } + } + dropMultiplier = ((_ref1 = user.purchased) != null ? (_ref2 = _ref1.plan) != null ? _ref2.customerId : void 0 : void 0) ? 2 : 1; + if ((api.daysSince(user.items.lastDrop.date, user.preferences) === 0) && (user.items.lastDrop.count >= dropMultiplier * (5 + Math.floor(user._statsComputed.per / 25) + (user.contributor.level || 0)))) { + return; + } + if (((_ref3 = user.flags) != null ? _ref3.dropsEnabled : void 0) && user.fns.predictableRandom(user.stats.exp) < chance) { + rarity = user.fns.predictableRandom(user.stats.gp); + if (rarity > .6) { + drop = user.fns.randomVal(_.where(content.food, { + canDrop: true + })); + if ((_base = user.items.food)[_name = drop.key] == null) { + _base[_name] = 0; + } + user.items.food[drop.key] += 1; + drop.type = 'Food'; + drop.dialog = i18n.t('messageDropFood', { + dropArticle: drop.article, + dropText: drop.text(req.language), + dropNotes: drop.notes(req.language) + }, req.language); + } else if (rarity > .3) { + drop = user.fns.randomVal(_.where(content.eggs, { + canBuy: true + })); + if ((_base1 = user.items.eggs)[_name1 = drop.key] == null) { + _base1[_name1] = 0; + } + user.items.eggs[drop.key]++; + drop.type = 'Egg'; + drop.dialog = i18n.t('messageDropEgg', { + dropText: drop.text(req.language), + dropNotes: drop.notes(req.language) + }, req.language); + } else { + acceptableDrops = rarity < .02 ? ['Golden'] : rarity < .09 ? ['Zombie', 'CottonCandyPink', 'CottonCandyBlue'] : rarity < .18 ? ['Red', 'Shade', 'Skeleton'] : ['Base', 'White', 'Desert']; + drop = user.fns.randomVal(_.pick(content.hatchingPotions, (function(v, k) { + return __indexOf.call(acceptableDrops, k) >= 0; + }))); + if ((_base2 = user.items.hatchingPotions)[_name2 = drop.key] == null) { + _base2[_name2] = 0; + } + user.items.hatchingPotions[drop.key]++; + drop.type = 'HatchingPotion'; + drop.dialog = i18n.t('messageDropPotion', { + dropText: drop.text(req.language), + dropNotes: drop.notes(req.language) + }, req.language); + } + user._tmp.drop = drop; + user.items.lastDrop.date = +(new Date); + return user.items.lastDrop.count++; + } + }, + + /* + Updates user stats with new stats. Handles death, leveling up, etc + {stats} new stats + {update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately + */ + autoAllocate: function() { + return user.stats[(function() { + var diff, ideal, preference, stats, suggested; + switch (user.preferences.allocationMode) { + case "flat": + stats = _.pick(user.stats, $w('con str per int')); + return _.invert(stats)[_.min(stats)]; + case "classbased": + ideal = [user.stats.lvl / 7 * 3, user.stats.lvl / 7 * 2, user.stats.lvl / 7, user.stats.lvl / 7]; + preference = (function() { + switch (user.stats["class"]) { + case "wizard": + return ["int", "per", "con", "str"]; + case "rogue": + return ["per", "str", "int", "con"]; + case "healer": + return ["con", "int", "str", "per"]; + default: + return ["str", "con", "per", "int"]; + } + })(); + diff = [user.stats[preference[0]] - ideal[0], user.stats[preference[1]] - ideal[1], user.stats[preference[2]] - ideal[2], user.stats[preference[3]] - ideal[3]]; + suggested = _.findIndex(diff, (function(val) { + if (val === _.min(diff)) { + return true; + } + })); + if (~suggested) { + return preference[suggested]; + } else { + return "str"; + } + case "taskbased": + suggested = _.invert(user.stats.training)[_.max(user.stats.training)]; + _.merge(user.stats.training, { + str: 0, + int: 0, + con: 0, + per: 0 + }); + return suggested || "str"; + default: + return "str"; + } + })()]++; + }, + updateStats: function(stats, req) { + var tnl; + if (stats.hp <= 0) { + return user.stats.hp = 0; + } + user.stats.hp = stats.hp; + user.stats.gp = stats.gp >= 0 ? stats.gp : 0; + tnl = api.tnl(user.stats.lvl); + if (stats.exp >= tnl) { + user.stats.exp = stats.exp; + while (stats.exp >= tnl) { + stats.exp -= tnl; + user.stats.lvl++; + tnl = api.tnl(user.stats.lvl); + if (user.preferences.automaticAllocation) { + user.fns.autoAllocate(); + } else { + user.stats.points = user.stats.lvl - (user.stats.con + user.stats.str + user.stats.per + user.stats.int); + } + user.stats.hp = 50; + } + } + user.stats.exp = stats.exp; + if (user.flags == null) { + user.flags = {}; + } + if (!user.flags.customizationsNotification && (user.stats.exp > 5 || user.stats.lvl > 1)) { + user.flags.customizationsNotification = true; + } + if (!user.flags.itemsEnabled && (user.stats.exp > 10 || user.stats.lvl > 1)) { + user.flags.itemsEnabled = true; + } + if (!user.flags.partyEnabled && user.stats.lvl >= 3) { + user.flags.partyEnabled = true; + } + if (!user.flags.dropsEnabled && user.stats.lvl >= 4) { + user.flags.dropsEnabled = true; + if (user.items.eggs["Wolf"] > 0) { + user.items.eggs["Wolf"]++; + } else { + user.items.eggs["Wolf"] = 1; + } + } + if (!user.flags.classSelected && user.stats.lvl >= 10) { + user.flags.classSelected; + } + _.each({ + vice1: 30, + atom1: 15, + moonstone1: 60, + goldenknight1: 40 + }, function(lvl, k) { + var _base, _base1, _ref; + if (!((_ref = user.flags.levelDrops) != null ? _ref[k] : void 0) && user.stats.lvl >= lvl) { + if ((_base = user.items.quests)[k] == null) { + _base[k] = 0; + } + user.items.quests[k]++; + ((_base1 = user.flags).levelDrops != null ? _base1.levelDrops : _base1.levelDrops = {})[k] = true; + if (typeof user.markModified === "function") { + user.markModified('flags.levelDrops'); + } + return user._tmp.drop = _.defaults(content.quests[k], { + type: 'Quest', + dialog: i18n.t('messageFoundQuest', { + questText: content.quests[k].text(req.language) + }, req.language) + }); + } + }); + if (!user.flags.rebirthEnabled && (user.stats.lvl >= 50 || user.achievements.ultimateGear || user.achievements.beastMaster)) { + user.flags.rebirthEnabled = true; + } + if (user.stats.lvl >= 100 && !user.flags.freeRebirth) { + return user.flags.freeRebirth = true; + } + }, + + /* + ------------------------------------------------------ + Cron + ------------------------------------------------------ + */ + + /* + At end of day, add value to all incomplete Daily & Todo tasks (further incentive) + For incomplete Dailys, deduct experience + Make sure to run this function once in a while as server will not take care of overnight calculations. + And you have to run it every time client connects. + {user} + */ + cron: function(options) { + var clearBuffs, daysMissed, expTally, lvl, lvlDiv2, now, perfect, plan, progress, todoTally, _base, _base1, _base2, _base3, _progress, _ref, _ref1, _ref2; + if (options == null) { + options = {}; + } + now = +options.now || +(new Date); + daysMissed = api.daysSince(user.lastCron, _.defaults({ + now: now + }, user.preferences)); + if (!(daysMissed > 0)) { + return; + } + user.auth.timestamps.loggedin = new Date(); + user.lastCron = now; + if (user.items.lastDrop.count > 0) { + user.items.lastDrop.count = 0; + } + perfect = true; + clearBuffs = { + str: 0, + int: 0, + per: 0, + con: 0, + stealth: 0, + streaks: false + }; + plan = (_ref = user.purchased) != null ? _ref.plan : void 0; + if (plan != null ? plan.customerId : void 0) { + if (moment(plan.dateUpdated).format('MMYYYY') !== moment().format('MMYYYY')) { + plan.gemsBought = 0; + plan.dateUpdated = new Date(); + _.defaults(plan.consecutive, { + count: 0, + offset: 0, + trinkets: 0, + gemCapExtra: 0 + }); + plan.consecutive.count++; + if (plan.consecutive.offset > 0) { + plan.consecutive.offset--; + } else if (plan.consecutive.count % 3 === 0) { + plan.consecutive.trinkets++; + plan.consecutive.gemCapExtra += 5; + if (plan.consecutive.gemCapExtra > 25) { + plan.consecutive.gemCapExtra = 25; + } + } + } + if (plan.dateTerminated && moment(plan.dateTerminated).isBefore(+(new Date))) { + _.merge(plan, { + planId: null, + customerId: null, + paymentMethod: null + }); + _.merge(plan.consecutive, { + count: 0, + offset: 0, + gemCapExtra: 0 + }); + if (typeof user.markModified === "function") { + user.markModified('purchased.plan'); + } + } + } + if (user.preferences.sleep === true) { + user.stats.buffs = clearBuffs; + return; + } + todoTally = 0; + if ((_base = user.party.quest.progress).down == null) { + _base.down = 0; + } + user.todos.concat(user.dailys).forEach(function(task) { + var absVal, completed, delta, id, repeat, scheduleMisses, type; + if (!task) { + return; + } + id = task.id, type = task.type, completed = task.completed, repeat = task.repeat; + if ((type === 'daily') && !completed && user.stats.buffs.stealth && user.stats.buffs.stealth--) { + return; + } + if (!completed) { + scheduleMisses = daysMissed; + if ((type === 'daily') && repeat) { + scheduleMisses = 0; + _.times(daysMissed, function(n) { + var thatDay; + thatDay = moment(now).subtract({ + days: n + 1 + }); + if (api.shouldDo(thatDay, repeat, user.preferences)) { + return scheduleMisses++; + } + }); + } + if (scheduleMisses > 0) { + if (type === 'daily') { + perfect = false; + } + delta = user.ops.score({ + params: { + id: task.id, + direction: 'down' + }, + query: { + times: scheduleMisses, + cron: true + } + }); + if (type === 'daily') { + user.party.quest.progress.down += delta; + } + } + } + switch (type) { + case 'daily': + (task.history != null ? task.history : task.history = []).push({ + date: +(new Date), + value: task.value + }); + task.completed = false; + return _.each(task.checklist, (function(i) { + i.completed = false; + return true; + })); + case 'todo': + absVal = completed ? Math.abs(task.value) : task.value; + return todoTally += absVal; + } + }); + user.habits.forEach(function(task) { + if (task.up === false || task.down === false) { + if (Math.abs(task.value) < 0.1) { + return task.value = 0; + } else { + return task.value = task.value / 2; + } + } + }); + ((_base1 = (user.history != null ? user.history : user.history = {})).todos != null ? _base1.todos : _base1.todos = []).push({ + date: now, + value: todoTally + }); + expTally = user.stats.exp; + lvl = 0; + while (lvl < (user.stats.lvl - 1)) { + lvl++; + expTally += api.tnl(lvl); + } + ((_base2 = user.history).exp != null ? _base2.exp : _base2.exp = []).push({ + date: now, + value: expTally + }); + if (!((_ref1 = user.purchased) != null ? (_ref2 = _ref1.plan) != null ? _ref2.customerId : void 0 : void 0)) { + user.fns.preenUserHistory(); + if (typeof user.markModified === "function") { + user.markModified('history'); + } + if (typeof user.markModified === "function") { + user.markModified('dailys'); + } + } + user.stats.buffs = perfect ? ((_base3 = user.achievements).perfect != null ? _base3.perfect : _base3.perfect = 0, user.achievements.perfect++, user.stats.lvl < 100 ? lvlDiv2 = Math.ceil(user.stats.lvl / 2) : lvlDiv2 = 50, { + str: lvlDiv2, + int: lvlDiv2, + per: lvlDiv2, + con: lvlDiv2, + stealth: 0, + streaks: false + }) : clearBuffs; + user.stats.mp += _.max([10, .1 * user._statsComputed.maxMP]); + if (user.stats.mp > user._statsComputed.maxMP) { + user.stats.mp = user._statsComputed.maxMP; + } + progress = user.party.quest.progress; + _progress = _.cloneDeep(progress); + _.merge(progress, { + down: 0, + up: 0 + }); + progress.collect = _.transform(progress.collect, (function(m, v, k) { + return m[k] = 0; + })); + return _progress; + }, + preenUserHistory: function(minHistLen) { + if (minHistLen == null) { + minHistLen = 7; + } + _.each(user.habits.concat(user.dailys), function(task) { + var _ref; + if (((_ref = task.history) != null ? _ref.length : void 0) > minHistLen) { + task.history = preenHistory(task.history); + } + return true; + }); + _.defaults(user.history, { + todos: [], + exp: [] + }); + if (user.history.exp.length > minHistLen) { + user.history.exp = preenHistory(user.history.exp); + } + if (user.history.todos.length > minHistLen) { + return user.history.todos = preenHistory(user.history.todos); + } + }, + ultimateGear: function() { + var gear, lastGearClassTypeMatrix, ownedLastGear, shouldGrant; + gear = typeof window !== "undefined" && window !== null ? user.items.gear.owned : user.items.gear.owned.toObject(); + ownedLastGear = _.chain(content.gear.flat).pick(_.keys(gear)).values().filter(function(gear) { + return gear.last; + }); + lastGearClassTypeMatrix = {}; + _.each(content.classes, function(klass) { + lastGearClassTypeMatrix[klass] = {}; + return _.each(['armor', 'weapon', 'shield', 'head'], function(type) { + lastGearClassTypeMatrix[klass][type] = false; + return true; + }); + }); + ownedLastGear.each(function(gear) { + if (gear.twoHanded) { + lastGearClassTypeMatrix[gear.klass]["shield"] = true; + } + return lastGearClassTypeMatrix[gear.klass][gear.type] = true; + }); + shouldGrant = _(lastGearClassTypeMatrix).values().reduce((function(ans, klass) { + return ans || _(klass).values().reduce((function(ans, gearType) { + return ans && gearType; + }), true); + }), false).valueOf(); + return user.achievements.ultimateGear = shouldGrant; + }, + nullify: function() { + user.ops = null; + user.fns = null; + return user = null; + } + }; + Object.defineProperty(user, '_statsComputed', { + get: function() { + var computed; + computed = _.reduce(['per', 'con', 'str', 'int'], (function(_this) { + return function(m, stat) { + m[stat] = _.reduce($w('stats stats.buffs items.gear.equipped.weapon items.gear.equipped.armor items.gear.equipped.head items.gear.equipped.shield'), function(m2, path) { + var item, val; + val = user.fns.dotGet(path); + return m2 + (~path.indexOf('items.gear') ? (item = content.gear.flat[val], (+(item != null ? item[stat] : void 0) || 0) * ((item != null ? item.klass : void 0) === user.stats["class"] || (item != null ? item.specialClass : void 0) === user.stats["class"] ? 1.5 : 1)) : +val[stat] || 0); + }, 0); + if (user.stats.lvl < 100) { + m[stat] += (user.stats.lvl - 1) / 2; + } else { + m[stat] += 50; + } + return m; + }; + })(this), {}); + computed.maxMP = computed.int * 2 + 30; + return computed; + } + }); + return Object.defineProperty(user, 'tasks', { + get: function() { + var tasks; + tasks = user.habits.concat(user.dailys).concat(user.todos).concat(user.rewards); + return _.object(_.pluck(tasks, "id"), tasks); + } + }); +}; + + +}).call(this,require('_process')) +},{"./content.coffee":4,"./i18n.coffee":5,"_process":7,"lodash":2,"moment":3}],7:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; + +function drainQueue() { + if (draining) { + return; + } + draining = true; + var currentQueue; + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + var i = -1; + while (++i < len) { + currentQueue[i](); + } + len = queue.length; + } + draining = false; +} +process.nextTick = function (fun) { + queue.push(fun); + if (!draining) { + setTimeout(drainQueue, 0); + } +}; + +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + },{}]},{},[1]); diff --git a/common/locales/cs/backgrounds.json b/common/locales/cs/backgrounds.json index b5f11e5d3e..168c77bc6b 100644 --- a/common/locales/cs/backgrounds.json +++ b/common/locales/cs/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Mrazivý vrch", "backgroundFrigidPeakNotes": "Vrchol mrazivého vrchu", "backgroundSnowyPinesText": "Zasněžené jedle", - "backgroundSnowyPinesNotes": "Přístřeší mezi zasněženými jedlemi" + "backgroundSnowyPinesNotes": "Přístřeší mezi zasněženými jedlemi", + "backgrounds022015": "SET 9: Released February 2015", + "backgroundBlacksmithyText": "Blacksmithy", + "backgroundBlacksmithyNotes": "Labor in the Blacksmithy.", + "backgroundCrystalCaveText": "Crystal Cave", + "backgroundCrystalCaveNotes": "Explore a Crystal Cave.", + "backgroundDistantCastleText": "Distant Castle", + "backgroundDistantCastleNotes": "Defend a Distant Castle." } \ No newline at end of file diff --git a/common/locales/cs/content.json b/common/locales/cs/content.json index 2c1a605cc8..bfa30562e4 100644 --- a/common/locales/cs/content.json +++ b/common/locales/cs/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "bystrý", "questEggTRexText": "Tyranosaur", "questEggTRexAdjective": "s malými ručičkami", - "eggNotes": "Najdi líhnoucí lektvar, nalij ho na vejce a z něj se vylíhne <%= eggAdjective() %> <%= eggText() %>.", + "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Základní", "hatchingPotionWhite": "Bílý", "hatchingPotionDesert": "Pouštní", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Cukrově růžový", "hatchingPotionCottonCandyBlue": "Cukrově modrý", "hatchingPotionGolden": "Zlatý", - "hatchingPotionNotes": "Nalij ho na vejce a vylíhne se ti <%= potText() %> mazlíček.", + "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> pet.", "foodMeat": "Maso", "foodMilk": "Mléko", "foodPotatoe": "Brambora", diff --git a/common/locales/cs/settings.json b/common/locales/cs/settings.json index 27eb89ea5c..fdb65b58cc 100644 --- a/common/locales/cs/settings.json +++ b/common/locales/cs/settings.json @@ -46,6 +46,8 @@ "showHeader": "Zobrazit horní info panel", "changePass": "Změnit heslo", "changeUsername": "Change Login Name", + "changeEmail": "Change Email Address", + "newEmail": "New Email Address", "oldPass": "Staré heslo", "newPass": "Nové heslo", "confirmPass": "Potvrď nové heslo", @@ -67,8 +69,12 @@ "deleteDo": "Udělej to, vymaž můj účet!", "enterNumber": "Prosím, zadej číslo mezi 0 a 24", "fillAll": "Prosím, vyplň všechna pole", - "passSuccess": "Heslo bylo úspěšně změněno", + "passwordSuccess": "Password successfully changed", "usernameSuccess": "Login Name successfully changed", + "emailSuccess": "Email successfully changed", + "detachFacebook": "De-register Facebook", + "detachedFacebook": "Successully removed Facebook from your account", + "addedLocalAuth": "Successully added local authentication", "data": "Data", "exportData": "Export dat", "emailChange1": "To change your email address, please send an email to", @@ -88,6 +94,8 @@ "invitedParty": "Invited To Party", "invitedGuild": "Invited To Guild", "importantAnnouncements": "Important Announcements", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Reminders to check in to HabitRPG", "unsubscribeAllEmails": "Check to Unsubscribe from Emails", "unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.", diff --git a/common/locales/da/backgrounds.json b/common/locales/da/backgrounds.json index 51d7f5bdea..d157958d80 100644 --- a/common/locales/da/backgrounds.json +++ b/common/locales/da/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Iskold Bjergtop", "backgroundFrigidPeakNotes": "Kom til tops på en Iskold Bjergtop.", "backgroundSnowyPinesText": "Tilsneede Grantræer", - "backgroundSnowyPinesNotes": "Find læ mellem Tilsneede Grantræer." + "backgroundSnowyPinesNotes": "Find læ mellem Tilsneede Grantræer.", + "backgrounds022015": "Sæt 9: Udgivet Februar 2015", + "backgroundBlacksmithyText": "Grovsmedje", + "backgroundBlacksmithyNotes": "Arbejd i Grovsmedjen.", + "backgroundCrystalCaveText": "Krystalgrotte", + "backgroundCrystalCaveNotes": "Udforsk en Krystalgrotte.", + "backgroundDistantCastleText": "Fjernt Slot", + "backgroundDistantCastleNotes": "Forsvar et Fjernt Slot." } \ No newline at end of file diff --git a/common/locales/da/content.json b/common/locales/da/content.json index ea47d755fb..ac9088d5ef 100644 --- a/common/locales/da/content.json +++ b/common/locales/da/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "Skarpsindig", "questEggTRexText": "Tyrannosaurus", "questEggTRexAdjective": "kortarmet", - "eggNotes": "Find en udrugningseliksir til at hælde på dit æg, og det vil udklække en <%= eggAdjective() %> <%= eggText() %>.", + "eggNotes": "Find en udrugningseliksir til at hælde på dit æg, og det vil udklække en <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Almindelig", "hatchingPotionWhite": "Hvid", "hatchingPotionDesert": "Ørken", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Candyfloss-lyserød", "hatchingPotionCottonCandyBlue": "Candyfloss-blå", "hatchingPotionGolden": "Gylden", - "hatchingPotionNotes": "Hæld på et æg, og det vil udklække til et <%= potText() %> kæledyr. ", + "hatchingPotionNotes": "Hæld på et æg, og det vil udklække til et <%= potText(locale) %> kæledyr.", "foodMeat": "Kød", "foodMilk": "Mælk", "foodPotatoe": "Kartoffel", diff --git a/common/locales/da/settings.json b/common/locales/da/settings.json index 3b19dbed1c..18a67b36fe 100644 --- a/common/locales/da/settings.json +++ b/common/locales/da/settings.json @@ -46,6 +46,8 @@ "showHeader": "Vis Sidehoved", "changePass": "Skift Kodeord", "changeUsername": "Skift Loginnavn", + "changeEmail": "Skift email-adresse", + "newEmail": "Ny email-adresse", "oldPass": "Gammelt Kodeord", "newPass": "Nyt Kodeord", "confirmPass": "Bekræft Nyt Kodeord", @@ -67,8 +69,12 @@ "deleteDo": "Gør det, slet min konto!", "enterNumber": "Indtast venligst et tal mellem 0 og 24", "fillAll": "Udfyld venligst alle felter", - "passSuccess": "Dit kodeord er nu ændret", + "passwordSuccess": "Dit Kodeord er skiftet", "usernameSuccess": "Dit Loginnavn er nu ændret", + "emailSuccess": "Din Email er skiftet", + "detachFacebook": "Afregistrér Facebook", + "detachedFacebook": "Facebook er nu fjernet fra din konto", + "addedLocalAuth": "Lokal godkendelse er nu tilføjet", "data": "Data", "exportData": "Eksportér Data", "emailChange1": "For at ændre din email-adresse bedes du sende en email til", @@ -88,6 +94,8 @@ "invitedParty": "Gruppeinvitation", "invitedGuild": "Klaninvitation", "importantAnnouncements": "Vigtige Meddelelser", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Påmindelser om at tjekek ind på HabitRPG", "unsubscribeAllEmails": "Markér for at afmelde emails", "unsubscribeAllEmailsText": "Ved at markere denne boks er jeg indforstået med, at ved at afmelde alle emails vil HabitRPG aldrig være i stand til at informere mig via email om vigtige ændringer på siden eller min konto.", diff --git a/common/locales/de/backgrounds.json b/common/locales/de/backgrounds.json index 2874b55b1a..b3e93f5018 100644 --- a/common/locales/de/backgrounds.json +++ b/common/locales/de/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Eisiger Gipfel", "backgroundFrigidPeakNotes": "Besteige einen eisigen Gipfel.", "backgroundSnowyPinesText": "Verschneite Fichten", - "backgroundSnowyPinesNotes": "Suche Zuflucht unter verschneiten Fichten." + "backgroundSnowyPinesNotes": "Suche Zuflucht unter verschneiten Fichten.", + "backgrounds022015": "SET 9: Released February 2015", + "backgroundBlacksmithyText": "Schmiede", + "backgroundBlacksmithyNotes": "Schufte in der Schmiede.", + "backgroundCrystalCaveText": "Kristallhöhle", + "backgroundCrystalCaveNotes": "Entdecke eine Kristallhöhle.", + "backgroundDistantCastleText": "Fernes Schloss", + "backgroundDistantCastleNotes": "Verteidige ein fernes Schloss." } \ No newline at end of file diff --git a/common/locales/de/content.json b/common/locales/de/content.json index 5ac4787649..1ca98dfe73 100644 --- a/common/locales/de/content.json +++ b/common/locales/de/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "scharfsinning", "questEggTRexText": "Tyrannosaurus", "questEggTRexAdjective": "kleinarmig", - "eggNotes": "Übergieße dieses Ei mit einem Schlüpftrank und ein <%= eggAdjective() %> <%= eggText() %> wird schlüpfen.", + "eggNotes": "Übergieße dieses Ei mit einem Schlüpftrank und ein <%= eggAdjective(locale) %> <%= eggText(locale) %> wird schlüpfen.", "hatchingPotionBase": "Normaler", "hatchingPotionWhite": "Weißer", "hatchingPotionDesert": "Wüstenfarbener", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Zuckerwattenrosaner", "hatchingPotionCottonCandyBlue": "Zuckerwattenblauer", "hatchingPotionGolden": "Goldener", - "hatchingPotionNotes": "Gieße dies über ein Ei und es wird ein <%= potText() %> Tierwelpe daraus schlüpfen.", + "hatchingPotionNotes": "Gieße das über ein Ei und es wird ein <%= potText(locale) %> Tierwelpe daraus schlüpfen.", "foodMeat": "Fleisch", "foodMilk": "Milch", "foodPotatoe": "Kartoffel", diff --git a/common/locales/de/front.json b/common/locales/de/front.json index 2db61c7cf5..38a9c70632 100644 --- a/common/locales/de/front.json +++ b/common/locales/de/front.json @@ -90,7 +90,7 @@ "footerSocial": "Soziales", "socialTitle": "HabitRPG - Spiele dein Leben", "watchVideos": "Sehen Sie sich die Videos an", - "presskit": "Press Kit", - "presskitText": "Thanks for your interest in HabitRPG! The following images can be used for articles or videos about HabitRPG. For more information, please contact Siena Leslie at leslie@habitrpg.com.", - "presskitDownload": "Download all images:" + "presskit": "Pressemappe", + "presskitText": "Danke für euer Interesse an HabitRPG! Die folgenden Bilder können für Artikel oder Videos über HabitRPG verwendet werden. Für weitere Informationen kontaktiert bitte Siena Leslie unter leslie@habitrpg.com.", + "presskitDownload": "Alle Bilder herunterladen:" } \ No newline at end of file diff --git a/common/locales/de/questscontent.json b/common/locales/de/questscontent.json index fc8e3e64c8..7696ab5fc2 100644 --- a/common/locales/de/questscontent.json +++ b/common/locales/de/questscontent.json @@ -11,7 +11,7 @@ "questEvilSanta2CollectBranches": "Zerbrochene Zweige", "questEvilSanta2DropBearCubPolarPet": "Eisbär (Haustier)", "questGryphonText": "Der Feurige Greif", - "questGryphonNotes": "Der große Herr aller Bestien, baconsaur, kommt zu deiner Gruppe und fragt hilfesuchend: \"Abenteurer, ihr müsst mir helfen! Mein preisgekrönter Greif ist ausgebrochen und terrorisiert nun Habit City! Wenn ihr sie aufhaltet, kann ich euch mit ein paar ihrer Eier belohnen!\"", + "questGryphonNotes": "Der große Herr aller Bestien, baconsaur, kommt zu deiner Gruppe, denn er sucht nach Hilfe. \"Abenteurer, bitte, ihr müsst mir helfen! Mein preisgekrönter Greif ist ausgebrochen und terrorisiert nun Habit City! Wenn ihr sie aufhaltet, kann ich euch mit einigen von ihren Eiern belohnen!\"", "questGryphonCompletion": "Das mächtige Tier schleigt besiegt zu seinem Meister zurück. \"Ich bin beeindruckt! Gut gemacht, Abenteurer!\" ruft baconsaur, \"Bitte nehmt ein paar Greifeneier als Dank an. Ich bin sicher, Ihr werdet Euch gut um sie kümmern!\"", "questGryphonBoss": "Feuriger Greif", "questGryphonDropGryphonEgg": "Greif (Ei)", @@ -26,7 +26,7 @@ "questGhostStagBoss": "Geisterhirsch", "questGhostStagDropDeerEgg": "Hirsch (Ei)", "questRatText": "Der Rattenkönig", - "questRatNotes": "Müll! Berge von unerfüllten täglichen Aufgaben häufen sich überall in Habitica. Das Problem ist mittlerweile so ernst geworden, dass ganze Horden von Ratten über das Land herfallen. Du bemerkst, dass @Pandah eines der Tierchen liebevoll streichelt. Sie erklärt, Ratten seien eigentlich brave Tierchen, die sich von unerfüllten täglichen Aufgaben ernähren. Das tatsächliche Problem ist, dass einige dieser Aufgaben in die Kanalisation gerutscht sind und sich ein großes gefährliches Nest gebildet hat. Als Du nun tiefer in die Kanalisation hinabsteigst wirst Du von einer riesigen Ratte mit blutroten Augen und üblen gelben Zähnen angegriffen, die das Nest verteidigt. Wirst Du fliehen, oder dem sagenhaften Rattenkönig entgegentreten?", + "questRatNotes": "Müll! Berge von unerfüllten täglichen Aufgaben häufen sich überall in Habitica. Das Problem ist mittlerweile so ernst geworden, dass ganze Horden von Ratten über das Land herfallen. Du bemerkst, dass @Pandah eines der Tierchen liebevoll streichelt. Sie erklärt, Ratten seien eigentlich sanfte Tierchen, die sich von unerfüllten täglichen Aufgaben ernähren. Das tatsächliche Problem ist, dass einige dieser Aufgaben in die Kanalisation gerutscht sind und sich ein großes, gefährliches Nest gebildet hat. Als Du nun tiefer in die Kanalisation hinabsteigst, wirst Du von einer riesigen Ratte mit blutroten Augen und übel zugerichteten, gelben Zähnen angegriffen, die das Nest verteidigt. Wirst Du fliehen, oder dem sagenumwobenen Rattenkönig entgegentreten?", "questRatCompletion": "Your final strike saps the gargantuan rat's strength, his eyes fading to a dull grey. The beast splits into many tiny rats, which scurry off in fright. You notice @Pandah standing behind you, looking at the once mighty creature. She explains that the citizens of Habitica have been inspired by your courage and are quickly completing all their unchecked Dailies. She warns you that we must be vigilant, for should we let down our guard, the Rat King will return. As payment, @Pandah offers you several rat eggs. Noticing your uneasy expression, she smiles, \"They make wonderful pets.\"", "questRatBoss": "Rattenkönig", "questRatDropRatEgg": "Ratte (Ei)", diff --git a/common/locales/de/settings.json b/common/locales/de/settings.json index 9ce97ccccd..54f67a0b5f 100644 --- a/common/locales/de/settings.json +++ b/common/locales/de/settings.json @@ -46,6 +46,8 @@ "showHeader": "Header anzeigen", "changePass": "Passwort ändern", "changeUsername": "Login Name ändern", + "changeEmail": "E-Mail-Adresse ändern", + "newEmail": "Neue E-Mail-Adresse", "oldPass": "Altes Passwort", "newPass": "Neues Passwort", "confirmPass": "Neues Passwort bestätigen", @@ -67,8 +69,12 @@ "deleteDo": "Ja, löscht jetzt meine Konto!", "enterNumber": "Bitte gib' eine Zahl zwischen 0 und 24 ein", "fillAll": "Bitte fülle alle Felder aus", - "passSuccess": "Passwort erfolgreich geändert", + "passwordSuccess": "Das Passwort wurde erfolgreich geändert", "usernameSuccess": "Dein Login Name wurde erfolgreich geändert!", + "emailSuccess": "Die E-Mail-Adresse wurde erfolgreich geändert", + "detachFacebook": "Facebook ent-registrieren", + "detachedFacebook": "Facebook wurde erfolgreich von deinem Konto entfernt", + "addedLocalAuth": "Successully added local authentication", "data": "Daten", "exportData": "Daten exportieren", "emailChange1": "Um Deine Email-Adresse zu ändern, schicke bitte eine Email an", @@ -88,6 +94,8 @@ "invitedParty": "In die Gruppe eingeladen", "invitedGuild": "In die Gilde eingeladen", "importantAnnouncements": "Wichtige Ankündigungen", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Erinnerungen, HabitRPG zu überprüfen", "unsubscribeAllEmails": "Häkchen setzen, um keine weiteren Emails zu erhalten", "unsubscribeAllEmailsText": "Indem ich hier ein Häkchen gesetzt habe, bestätige ich, dass ich verstanden habe, dass ich aus allen HabitRPG Email-Listen ausgetragen wurde. HabitRPG kann mir keine Emails mehr zu wichtigen Änderungen der Seite oder meines Accounts schicken.", diff --git a/common/locales/en/content.json b/common/locales/en/content.json index be79d23c42..a2ee7b3d20 100644 --- a/common/locales/en/content.json +++ b/common/locales/en/content.json @@ -72,7 +72,7 @@ "questEggTRexText": "Tyrannosaur", "questEggTRexAdjective": "tiny-armed", - "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective() %> <%= eggText() %>.", + "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Base", "hatchingPotionWhite": "White", @@ -85,7 +85,7 @@ "hatchingPotionCottonCandyBlue": "Cotton Candy Blue", "hatchingPotionGolden": "Golden", - "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText() %> pet.", + "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> pet.", "foodMeat": "Meat", "foodMilk": "Milk", diff --git a/common/locales/en/settings.json b/common/locales/en/settings.json index 8ab5ae6640..60de66e6d5 100644 --- a/common/locales/en/settings.json +++ b/common/locales/en/settings.json @@ -94,6 +94,8 @@ "invitedParty": "Invited To Party", "invitedGuild": "Invited To Guild", "importantAnnouncements": "Important Announcements", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Reminders to check in to HabitRPG", "unsubscribeAllEmails": "Check to Unsubscribe from Emails", "unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.", diff --git a/common/locales/en@pirate/backgrounds.json b/common/locales/en@pirate/backgrounds.json index 18ae150c93..42d5a98403 100644 --- a/common/locales/en@pirate/backgrounds.json +++ b/common/locales/en@pirate/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Frigid Peak", "backgroundFrigidPeakNotes": "Summit a Frigid Peak.", "backgroundSnowyPinesText": "Snowy Pines", - "backgroundSnowyPinesNotes": "Shelter amid Snowy Pines." + "backgroundSnowyPinesNotes": "Shelter amid Snowy Pines.", + "backgrounds022015": "SET 9: Released February 2015", + "backgroundBlacksmithyText": "Blacksmithy", + "backgroundBlacksmithyNotes": "Labor in the Blacksmithy.", + "backgroundCrystalCaveText": "Crystal Cave", + "backgroundCrystalCaveNotes": "Explore a Crystal Cave.", + "backgroundDistantCastleText": "Distant Castle", + "backgroundDistantCastleNotes": "Defend a Distant Castle." } \ No newline at end of file diff --git a/common/locales/en@pirate/content.json b/common/locales/en@pirate/content.json index 51b4aad6ba..db1f618deb 100644 --- a/common/locales/en@pirate/content.json +++ b/common/locales/en@pirate/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "perspicacious", "questEggTRexText": "Tyrannosaur", "questEggTRexAdjective": "tiny-armed", - "eggNotes": "Find a hatchin' potion to pour on 'tis egg, 'n it gunna hatch into a <%= eggAdjective() %> <%= eggText() %>.", + "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Base", "hatchingPotionWhite": "White", "hatchingPotionDesert": "Desert", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Cotton Candy Pink", "hatchingPotionCottonCandyBlue": "Cotton Candy Blue", "hatchingPotionGolden": "Golden", - "hatchingPotionNotes": "Pour 'tis on an egg, 'n it gunna hatch as a <%= potText() %> pet.", + "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> pet.", "foodMeat": "Meat", "foodMilk": "Milk", "foodPotatoe": "Potato", diff --git a/common/locales/en@pirate/settings.json b/common/locales/en@pirate/settings.json index 3d3d24fa83..177c05849b 100644 --- a/common/locales/en@pirate/settings.json +++ b/common/locales/en@pirate/settings.json @@ -46,6 +46,8 @@ "showHeader": "Show Header", "changePass": "Change Passcode", "changeUsername": "Change Login Name", + "changeEmail": "Change Email Address", + "newEmail": "New Email Address", "oldPass": "Old Passcode", "newPass": "New Passcode", "confirmPass": "Confirm yer New Passcode", @@ -67,8 +69,12 @@ "deleteDo": "Do it, delete me account!", "enterNumber": "Please enter a number 'tween 0 an' 24", "fillAll": "Please fill out all fields", - "passSuccess": "Passcode successfully changed", + "passwordSuccess": "Password successfully changed", "usernameSuccess": "Login Name successfully changed", + "emailSuccess": "Email successfully changed", + "detachFacebook": "De-register Facebook", + "detachedFacebook": "Successully removed Facebook from your account", + "addedLocalAuth": "Successully added local authentication", "data": "Data", "exportData": "Export Data", "emailChange1": "To change your email address, please send an email to", @@ -88,6 +94,8 @@ "invitedParty": "Invited To Party", "invitedGuild": "Invited To Guild", "importantAnnouncements": "Important Announcements", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Reminders to check in to HabitRPG", "unsubscribeAllEmails": "Check to Unsubscribe from Emails", "unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.", diff --git a/common/locales/en_GB/backgrounds.json b/common/locales/en_GB/backgrounds.json index 8bfce4290a..9df595b505 100644 --- a/common/locales/en_GB/backgrounds.json +++ b/common/locales/en_GB/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Frigid Peak", "backgroundFrigidPeakNotes": "Summit a Frigid Peak.", "backgroundSnowyPinesText": "Snowy Pines", - "backgroundSnowyPinesNotes": "Shelter amid Snowy Pines." + "backgroundSnowyPinesNotes": "Shelter amid Snowy Pines.", + "backgrounds022015": "SET 9: Released February 2015", + "backgroundBlacksmithyText": "Blacksmithy", + "backgroundBlacksmithyNotes": "Labor in the Blacksmithy.", + "backgroundCrystalCaveText": "Crystal Cave", + "backgroundCrystalCaveNotes": "Explore a Crystal Cave.", + "backgroundDistantCastleText": "Distant Castle", + "backgroundDistantCastleNotes": "Defend a Distant Castle." } \ No newline at end of file diff --git a/common/locales/en_GB/content.json b/common/locales/en_GB/content.json index 809d3c9ad6..6d8cfe0770 100644 --- a/common/locales/en_GB/content.json +++ b/common/locales/en_GB/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "perspicacious", "questEggTRexText": "Tyrannosaur", "questEggTRexAdjective": "tiny-armed", - "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective() %> <%= eggText() %>.", + "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Base", "hatchingPotionWhite": "White", "hatchingPotionDesert": "Desert", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Fairy Floss Pink", "hatchingPotionCottonCandyBlue": "Fairy Floss Blue", "hatchingPotionGolden": "Golden", - "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText() %> pet.", + "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> pet.", "foodMeat": "Meat", "foodMilk": "Milk", "foodPotatoe": "Potato", diff --git a/common/locales/en_GB/settings.json b/common/locales/en_GB/settings.json index a1ca241185..5e8d47375e 100644 --- a/common/locales/en_GB/settings.json +++ b/common/locales/en_GB/settings.json @@ -46,6 +46,8 @@ "showHeader": "Show Header", "changePass": "Change Password", "changeUsername": "Change Login Name", + "changeEmail": "Change Email Address", + "newEmail": "New Email Address", "oldPass": "Old Password", "newPass": "New Password", "confirmPass": "Confirm New Password", @@ -67,8 +69,12 @@ "deleteDo": "Do it, delete my account!", "enterNumber": "Please enter a number between 0 and 24", "fillAll": "Please fill out all fields", - "passSuccess": "Password successfully changed", + "passwordSuccess": "Password successfully changed", "usernameSuccess": "Login Name successfully changed", + "emailSuccess": "Email successfully changed", + "detachFacebook": "De-register Facebook", + "detachedFacebook": "Successully removed Facebook from your account", + "addedLocalAuth": "Successully added local authentication", "data": "Data", "exportData": "Export Data", "emailChange1": "To change your email address, please send an email to", @@ -88,6 +94,8 @@ "invitedParty": "Invited To Party", "invitedGuild": "Invited To Guild", "importantAnnouncements": "Important Announcements", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Reminders to check in to HabitRPG", "unsubscribeAllEmails": "Check to Unsubscribe from Emails", "unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.", diff --git a/common/locales/es/backgrounds.json b/common/locales/es/backgrounds.json index 4e5dfa84d7..ed5b4f31c3 100644 --- a/common/locales/es/backgrounds.json +++ b/common/locales/es/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Pico frígido", "backgroundFrigidPeakNotes": "Escala un pico frígido.", "backgroundSnowyPinesText": "Pinos nevados", - "backgroundSnowyPinesNotes": "Refúgiate entre pinos nevados." + "backgroundSnowyPinesNotes": "Refúgiate entre pinos nevados.", + "backgrounds022015": "SET 9: Released February 2015", + "backgroundBlacksmithyText": "Blacksmithy", + "backgroundBlacksmithyNotes": "Labor in the Blacksmithy.", + "backgroundCrystalCaveText": "Crystal Cave", + "backgroundCrystalCaveNotes": "Explore a Crystal Cave.", + "backgroundDistantCastleText": "Distant Castle", + "backgroundDistantCastleNotes": "Defend a Distant Castle." } \ No newline at end of file diff --git a/common/locales/es/content.json b/common/locales/es/content.json index 4cc6de72ce..6916bea0f8 100644 --- a/common/locales/es/content.json +++ b/common/locales/es/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "perspicaz", "questEggTRexText": "Tiranosaurio", "questEggTRexAdjective": "con brazos pequeños", - "eggNotes": "Encuentra una poción para verter sobre este huevo y saldrá un <%= eggText() %> <%= eggAdjective() %>.", + "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Base", "hatchingPotionWhite": "Blanco", "hatchingPotionDesert": "del Desierto", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Rosa Algodón de Azúcar", "hatchingPotionCottonCandyBlue": "Azul Algodón de Azúcar", "hatchingPotionGolden": "de Oro", - "hatchingPotionNotes": "Echa esto en un huevo, y eclosionará como una mascota <%= potText() %>.", + "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> pet.", "foodMeat": "Carne", "foodMilk": "Leche", "foodPotatoe": "Patata", diff --git a/common/locales/es/generic.json b/common/locales/es/generic.json index 689dc42313..de143192c2 100644 --- a/common/locales/es/generic.json +++ b/common/locales/es/generic.json @@ -44,9 +44,9 @@ "veteranText": "Ha sobrevivido a Habit The Grey (nuestro sito web pre-Angular) y se ha ganado muchas cicatrices por sus fallos.", "originalUser": "¡Usuario original!", "originalUserText": "Uno de los primeros usuarios... ¡digamos que fue un alpha tester!", - "habitBirthday": "HabitRPG Birthday Bash", - "habitBirthdayText": "Celebrated the HabitRPG Birthday Bash!", - "habitBirthdayPluralText": "Celebrated <%= number %> HabitRPG Birthday Bashes!", + "habitBirthday": "Festejo de Cumpleaños de HabitRPG", + "habitBirthdayText": "Participó en el Festejo de Cumpleaños de HabitRPG", + "habitBirthdayPluralText": "¡Participó en <%= number %> Festejo(s) de Cumpleaños de HabitRPG!", "achievementDilatory": "Salvador de Dilatoria", "achievementDilatoryText": "¡Ayudó a derrotar al Dread Drag'on de Dilatoria durante el evento Summer Splash del 2014!", "costumeContest": "Concurso de Disfraces 2014", diff --git a/common/locales/es/settings.json b/common/locales/es/settings.json index d0ca3506dc..dafee85c10 100644 --- a/common/locales/es/settings.json +++ b/common/locales/es/settings.json @@ -46,6 +46,8 @@ "showHeader": "Mostrar encabezamiento", "changePass": "Cambiar contraseña", "changeUsername": "Change Login Name", + "changeEmail": "Change Email Address", + "newEmail": "New Email Address", "oldPass": "Contraseña antigua", "newPass": "Contraseña nueva", "confirmPass": "Confirmar la nueva contraseña", @@ -67,8 +69,12 @@ "deleteDo": "¡Hazlo, elimina mi cuenta!", "enterNumber": "Por favor, introduce un número entre 0 y 24", "fillAll": "Por favor, rellene todos los campos", - "passSuccess": "Contraseña cambiada con éxito", + "passwordSuccess": "Password successfully changed", "usernameSuccess": "Login Name successfully changed", + "emailSuccess": "Email successfully changed", + "detachFacebook": "De-register Facebook", + "detachedFacebook": "Successully removed Facebook from your account", + "addedLocalAuth": "Successully added local authentication", "data": "Datos", "exportData": "Exportar Datos", "emailChange1": "To change your email address, please send an email to", @@ -88,6 +94,8 @@ "invitedParty": "Invited To Party", "invitedGuild": "Invited To Guild", "importantAnnouncements": "Important Announcements", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Reminders to check in to HabitRPG", "unsubscribeAllEmails": "Check to Unsubscribe from Emails", "unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.", diff --git a/common/locales/es/tasks.json b/common/locales/es/tasks.json index 9f68636f90..835ac028c8 100644 --- a/common/locales/es/tasks.json +++ b/common/locales/es/tasks.json @@ -42,7 +42,7 @@ "datedNotSorted": "Dated To-Dos are NOT sorted by date. Sorting will probably be implemented in future.", "due": "Por vencer", "grey": "Gris", - "score": "Score", + "score": "Puntaje", "rewards": "Recompensas", "ingamerewards": "Equipamiento y Habilidades", "gold": "Oro", diff --git a/common/locales/es_419/backgrounds.json b/common/locales/es_419/backgrounds.json index 2d20c1fbf6..3d46625f38 100644 --- a/common/locales/es_419/backgrounds.json +++ b/common/locales/es_419/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Cima congelada", "backgroundFrigidPeakNotes": "Alcanza el pico de una cima congelada.", "backgroundSnowyPinesText": "Pinos nevados", - "backgroundSnowyPinesNotes": "Refúgiate en medio de unos pinos nevados. " + "backgroundSnowyPinesNotes": "Refúgiate en medio de unos pinos nevados. ", + "backgrounds022015": "SET 9: Released February 2015", + "backgroundBlacksmithyText": "Blacksmithy", + "backgroundBlacksmithyNotes": "Labor in the Blacksmithy.", + "backgroundCrystalCaveText": "Crystal Cave", + "backgroundCrystalCaveNotes": "Explore a Crystal Cave.", + "backgroundDistantCastleText": "Distant Castle", + "backgroundDistantCastleNotes": "Defend a Distant Castle." } \ No newline at end of file diff --git a/common/locales/es_419/content.json b/common/locales/es_419/content.json index e3b54140a6..588ef6eb28 100644 --- a/common/locales/es_419/content.json +++ b/common/locales/es_419/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "perspicaz", "questEggTRexText": "Tiranosaurio", "questEggTRexAdjective": "Brazos pequeños", - "eggNotes": "Encuentra una poción para verter sobre este huevo y nacerá un <%= eggText() %> <%= eggAdjective() %>.", + "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Básico", "hatchingPotionWhite": "Blanco", "hatchingPotionDesert": "Desierto", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Algodón de azúcar rosa", "hatchingPotionCottonCandyBlue": "Algodón de azúcar azul", "hatchingPotionGolden": "Dorado", - "hatchingPotionNotes": "Echa esto en un huevo, y nacerá una mascota <%= potText() %>.", + "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> pet.", "foodMeat": "Carne", "foodMilk": "Leche", "foodPotatoe": "Papa", diff --git a/common/locales/es_419/defaulttasks.json b/common/locales/es_419/defaulttasks.json index c6def45756..a6e1870a25 100644 --- a/common/locales/es_419/defaulttasks.json +++ b/common/locales/es_419/defaulttasks.json @@ -16,10 +16,10 @@ "defaultDaily4Checklist1": "Estiramiento", "defaultDaily4Checklist2": "Abdominales", "defaultDaily4Checklist3": "Flexiones", - "defaultTodoNotes": "You can either complete this To-Do, edit it, or remove it.", + "defaultTodoNotes": "Usted puede completar este Pendiente, editarlo, o removerlo.", "defaultTodo1Text": "Join HabitRPG (Check me off!)", "defaultTodo2Text": "Set up a Habit", - "defaultTodo2Checklist1": "create a Habit", + "defaultTodo2Checklist1": "Crear un Habito.", "defaultTodo2Checklist2": "make it \"+\" only, \"-\" only, or \"+/-\" under Edit", "defaultTodo2Checklist3": "set difficulty under Advanced Options", "defaultTodo3Text": "Set up a Daily", @@ -27,7 +27,7 @@ "defaultTodo3Checklist2": "if so, add a Daily (don't add too many at first!)", "defaultTodo3Checklist3": "set its due days under Edit", "defaultTodo4Text": "Set up a To-Do (can be checked off without ticking all checkboxes!)", - "defaultTodo4Checklist1": "create a To-Do", + "defaultTodo4Checklist1": "Crear un Pendiente.", "defaultTodo4Checklist2": "set difficulty under Advanced Options", "defaultTodo4Checklist3": "optional: set a Due Date", "defaultTodo5Text": "Start a Party (private group) with your friends (Social > Party)", diff --git a/common/locales/es_419/settings.json b/common/locales/es_419/settings.json index 3a3ad31368..61ff15c34e 100644 --- a/common/locales/es_419/settings.json +++ b/common/locales/es_419/settings.json @@ -45,7 +45,9 @@ "misc": "Varios", "showHeader": "Mostrar cabecera", "changePass": "Cambiar contraseña", - "changeUsername": "Change Login Name", + "changeUsername": "Cambiar nombre de usuario", + "changeEmail": "Change Email Address", + "newEmail": "New Email Address", "oldPass": "Contraseña antigua", "newPass": "Contraseña nueva", "confirmPass": "Confirmar la nueva contraseña", @@ -67,33 +69,39 @@ "deleteDo": "¡Hazlo, elimina mi cuenta!", "enterNumber": "Por favor, introduce un número entre 0 y 24", "fillAll": "Por favor, rellene todos los campos", - "passSuccess": "Contraseña cambiada exitosamente", + "passwordSuccess": "Password successfully changed", "usernameSuccess": "Login Name successfully changed", + "emailSuccess": "Email successfully changed", + "detachFacebook": "De-register Facebook", + "detachedFacebook": "Successully removed Facebook from your account", + "addedLocalAuth": "Successully added local authentication", "data": "Datos", "exportData": "Exportar datos", "emailChange1": "To change your email address, please send an email to", "emailChange2": "admin@habitrpg.com", "emailChange3": "including both your old and new email address as well as your User ID.", - "username": "Login Name", + "username": "Nombre de usuario", "email": "Email", "registeredWithFb": "Registered with Facebook", "loginNameDescription1": "This is what you use to login to HabitRPG. Go to", - "loginNameDescription2": "User->Profile", + "loginNameDescription2": "Usuario->Perfil", "loginNameDescription3": "to change the name that appears in your avatar and chat messages.", "emailNotifications": "Email Notifications", "wonChallenge": "You Won a Challenge", - "newPM": "Received Private Message", + "newPM": "Mensaje privado recibido", "giftedGems": "Gifted Gems", "giftedSubscription": "Gifted Subscription", "invitedParty": "Invited To Party", "invitedGuild": "Invited To Guild", - "importantAnnouncements": "Important Announcements", + "importantAnnouncements": "Anuncios importantes", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Reminders to check in to HabitRPG", "unsubscribeAllEmails": "Check to Unsubscribe from Emails", "unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.", "subscriptionRateText": "Recurring $<%= price %> every <%= months %> months", - "benefits": "Benefits", - "coupon": "Coupon", + "benefits": "Beneficios", + "coupon": "Cupón", "couponPlaceholder": "Enter Coupon Code", "couponText": "We sometimes have events and give out coupon codes for special gear. (eg, those who stop by our Wondercon booth)" } \ No newline at end of file diff --git a/common/locales/fr/backgrounds.json b/common/locales/fr/backgrounds.json index 3a06580f27..3d85763ec1 100644 --- a/common/locales/fr/backgrounds.json +++ b/common/locales/fr/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Pic Glacé", "backgroundFrigidPeakNotes": "Atteignez le sommet d'un Pic Glacé.", "backgroundSnowyPinesText": "Pins Enneigés", - "backgroundSnowyPinesNotes": "Réfugiez-vous sous des Pins Enneigés." + "backgroundSnowyPinesNotes": "Réfugiez-vous sous des Pins Enneigés.", + "backgrounds022015": "SET 9: Sortie en Février 2015", + "backgroundBlacksmithyText": "Blacksmithy", + "backgroundBlacksmithyNotes": "Labor in the Blacksmithy.", + "backgroundCrystalCaveText": "Grotte de crystal", + "backgroundCrystalCaveNotes": "Explorer la Grotte de Crystal", + "backgroundDistantCastleText": "Château Distant", + "backgroundDistantCastleNotes": "Défendre le Château Distant" } \ No newline at end of file diff --git a/common/locales/fr/content.json b/common/locales/fr/content.json index 61738f8933..16eaca5086 100644 --- a/common/locales/fr/content.json +++ b/common/locales/fr/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "perspicace", "questEggTRexText": "Tyrannosaure", "questEggTRexAdjective": "court-sur-pattes", - "eggNotes": "Trouvez une potion d’éclosion à verser sur cet œuf et il en sortira un <%= eggText() %> <%= eggAdjective() %>.", + "eggNotes": "Trouver une potion d'éclosion à verser sur cette œuf, et il va en sortir un <%= eggAdjective(locale) %> <%= eggText(locale) %>", "hatchingPotionBase": "de Base", "hatchingPotionWhite": "Blanc", "hatchingPotionDesert": "du Désert", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Rose Barbe à Papa", "hatchingPotionCottonCandyBlue": "Bleu Barbe à Papa", "hatchingPotionGolden": "Doré", - "hatchingPotionNotes": "Versez-la sur un œuf et il en sortira un familier <%= potText() %>.", + "hatchingPotionNotes": "Versez-la sur un œuf, et il en sortira un familier <%= potText(locale) %>", "foodMeat": "Viande", "foodMilk": "Lait", "foodPotatoe": "Patate", diff --git a/common/locales/fr/questscontent.json b/common/locales/fr/questscontent.json index cb97deb3c8..0e635dd0b0 100644 --- a/common/locales/fr/questscontent.json +++ b/common/locales/fr/questscontent.json @@ -27,7 +27,7 @@ "questGhostStagDropDeerEgg": "Cerf (Œuf)", "questRatText": "Le Roi des Rats", "questRatNotes": "Des ordures ! De massives piles de Quotidiennes non remplies s'étalent au travers d'Habitica. Le problème est devenu si sérieux que des hordes de rats sont maintenant visibles partout. Vous remarquez @Pandah caressant affectueusement l'une des bêtes. Elle explique que les rats sont de gentilles créatures qui se nourrissent de Quotidiennes non effectuées. Le vrai problème est que ces Quotidiennes sont tombées dans les égouts, créant une dangereuse fosse qui doit être nettoyée. Alors que vous descendez dans les égouts, un énorme rat aux yeux rougis par le sang et aux dents jaunes mutilées vous attaque, défendant sa horde. Vous recroquevillerez-vous de peur ou ferez-vous face au légendaire Roi des Rats ? ", - "questRatCompletion": "Your final strike saps the gargantuan rat's strength, his eyes fading to a dull grey. The beast splits into many tiny rats, which scurry off in fright. You notice @Pandah standing behind you, looking at the once mighty creature. She explains that the citizens of Habitica have been inspired by your courage and are quickly completing all their unchecked Dailies. She warns you that we must be vigilant, for should we let down our guard, the Rat King will return. As payment, @Pandah offers you several rat eggs. Noticing your uneasy expression, she smiles, \"They make wonderful pets.\"", + "questRatCompletion": "Votre coup final vient à bout de la force du gigantesque rat, tandis que ses yeux se ternissent. La bête se scinde en une multitude de minuscules rats, qui se dispersent en couinant avec frayeur. Vous remarquez @Pandah se tenant derrière vous, observant ce qu'il reste de la puissante créature. Elle vous explique que les citoyens d'Habitica ont été inspiré par votre courage et se hâte désormais d'accomplir leurs quêtes inachevées. Elle vous prévient que vous devez rester vigilant, car dès que nous baisserons notre garde, le Roi des Rats reviendra. en guise de paiement, @Pandah vous offres de nombreux œufs de rat. Remarquant votre expression inquiète, elle vous sourit, \"Ils font de merveilleux familiers.\"", "questRatBoss": "Roi des Rats", "questRatDropRatEgg": "Rat (Œuf)", "questOctopusText": "L'Appel d'Octothulu", @@ -60,7 +60,7 @@ "questVice2DropVice3Quest": "Vice, partie 3 (Parchemin)", "questVice3Text": "Le Réveil de Vice", "questVice3Notes": "Après de nombreux efforts, votre équipe a découvert l'antre de Vice. Le monstre massif toise votre équipe avec dégoût. Tandis que des ombres tourbillonnent autour de vous, vous entendez une voix murmurer dans votre tête : \"Encore des idiots d'habitants d'Habitica qui viennent me rendre visite? Comme c'est mignon. Vous auriez été plus avisés de ne pas venir\". Le titan écailleux rejette la tête en arrière et se prépare à attaquer. C'est votre chance ! Donnez tout ce que vous avez et battez Vice une bonne fois pour toutes !", - "questVice3Completion": "The shadows dissipate from the cavern and a steely silence falls. My word, you've done it! You have defeated Vice! You and your party may finally breath a sigh of relief. Enjoy your victory, brave Habiteers, but take the lessons you've learned from battling Vice and move forward. There are still Habits to be done and potentially worse evils to conquer!", + "questVice3Completion": "Les ténèbres se dissipent de la caverne et un silence de plomb tombe. Ma parole, vous avez réussi ! Vous avez vaincu Vice ! Vous et votre équipe peut finalement laisser échapper un soupir de soulagement. Profitez de votre victoire, braves Habiteurs, mais emportez les enseignements de ce combat contre Vice et allez de l'avant. Il y a toujours des Habitudes à remplir et potentiellement de plus grands maux à conquérir !", "questVice3Boss": "Vice, la Vouivre des Ténèbres", "questVice3DropWeaponSpecial2": "Hampe du Dragon de Stephen Weber", "questVice3DropDragonEgg": "Dragon (Œuf)", diff --git a/common/locales/fr/settings.json b/common/locales/fr/settings.json index a343677570..5615a66562 100644 --- a/common/locales/fr/settings.json +++ b/common/locales/fr/settings.json @@ -46,6 +46,8 @@ "showHeader": "Montrer le Bandeau", "changePass": "Changer le mot de passe", "changeUsername": "Changer le nom d'utilisateur", + "changeEmail": "Changer votre adresse e-mail", + "newEmail": "Nouvelle adresse e-mail", "oldPass": "Ancien mot de passe", "newPass": "Nouveau mot de passe", "confirmPass": "Confirmer le nouveau mot de passe", @@ -67,8 +69,12 @@ "deleteDo": "Allez-y, supprimez mon compte !", "enterNumber": "Veuillez entrer un chiffre entre 0 et 24", "fillAll": "Veuillez remplir tous les champs", - "passSuccess": "Mot de passe changé avec succès ", + "passwordSuccess": "Mot de passe modifié avec succès", "usernameSuccess": "Nom d'utilisateur changé avec succès", + "emailSuccess": "E-mail modifiée avec succès", + "detachFacebook": "Inscription / connexion via Facebook", + "detachedFacebook": "Facebook retiré de votre compte avec succès", + "addedLocalAuth": "Authentification locale ajoutée avec succès", "data": "Données", "exportData": "Exporter les Données", "emailChange1": "Pour modifier votre adresse mail, envoyez un mail à", @@ -88,7 +94,9 @@ "invitedParty": "Invitation dans une Équipe", "invitedGuild": "Invitation dans une Guilde", "importantAnnouncements": "Annonces Importantes", - "remindersToLogin": "Reminders to check in to HabitRPG", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", + "remindersToLogin": "Penser à vérifier HabitRPG", "unsubscribeAllEmails": "Cocher pour se désabonner des e-mails", "unsubscribeAllEmailsText": "En cochant cette case, je certifie comprendre qu'en me désabonnant de tous les e-mails, HabitRPG n'aura jamais la possibilité de m'avertir par e-mail de changements importants au niveau du site ou de mon compte.", "subscriptionRateText": "$<%= price %> tous les <%= months %> mois", diff --git a/common/locales/he/backgrounds.json b/common/locales/he/backgrounds.json index 1596961e42..4f2a065795 100644 --- a/common/locales/he/backgrounds.json +++ b/common/locales/he/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "פסגת הר קפוא", "backgroundFrigidPeakNotes": "להגיע לראש פסגת הר קפוא.", "backgroundSnowyPinesText": "אורנים מושלגים", - "backgroundSnowyPinesNotes": "מקלט בין פינס מושלג." + "backgroundSnowyPinesNotes": "מקלט בין פינס מושלג.", + "backgrounds022015": "SET 9: Released February 2015", + "backgroundBlacksmithyText": "Blacksmithy", + "backgroundBlacksmithyNotes": "Labor in the Blacksmithy.", + "backgroundCrystalCaveText": "Crystal Cave", + "backgroundCrystalCaveNotes": "Explore a Crystal Cave.", + "backgroundDistantCastleText": "Distant Castle", + "backgroundDistantCastleNotes": "Defend a Distant Castle." } \ No newline at end of file diff --git a/common/locales/he/content.json b/common/locales/he/content.json index c33bd37b38..98e6cf584c 100644 --- a/common/locales/he/content.json +++ b/common/locales/he/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "בַּעַל תְפִיסָה חַדָה", "questEggTRexText": "Tyrannosaur", "questEggTRexAdjective": "tiny-armed", - "eggNotes": "מצא/י שיקוי בקיעה, בזוק/בזקי אותו על הביצה הזו, והיא תהפוך ל <%= eggText() %> <%= eggAdjective() %>.", + "eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into a <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "רגיל", "hatchingPotionWhite": "לבן", "hatchingPotionDesert": "מדברי", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "שמבלולו ורוד", "hatchingPotionCottonCandyBlue": "שמבלולו כחול", "hatchingPotionGolden": "זהוב", - "hatchingPotionNotes": "בזוק/בזקי שיקוי זה על ביצה והיא תבקע כחיה <%= potText() %>.", + "hatchingPotionNotes": "Pour this on an egg, and it will hatch as a <%= potText(locale) %> pet.", "foodMeat": "בשר", "foodMilk": "חלב", "foodPotatoe": "תפוח אדמה", diff --git a/common/locales/he/pets.json b/common/locales/he/pets.json index cac490c55a..d278624ba9 100644 --- a/common/locales/he/pets.json +++ b/common/locales/he/pets.json @@ -12,7 +12,7 @@ "cerberusPup": "גור קרברוס", "hydra": "הידרה", "mantisShrimp": "חסילון-גמל-שלמה", - "mammoth": "Woolly Mammoth", + "mammoth": "ממותה שעירה", "rarePetPop1": "לחצו על הכפה הזהובה ותוכלו ללמוד כיצד להשיג חיה נדירה זו - דרך תרומה לHabitRPG!", "rarePetPop2": "איך לקבל את חיית המחמד הזו!", "potion": "שיקוי <%= potionType %>", diff --git a/common/locales/he/settings.json b/common/locales/he/settings.json index e49b7d0c81..f5905399a6 100644 --- a/common/locales/he/settings.json +++ b/common/locales/he/settings.json @@ -46,6 +46,8 @@ "showHeader": "הראה כותרת", "changePass": "שנה סיסמה", "changeUsername": "Change Login Name", + "changeEmail": "Change Email Address", + "newEmail": "New Email Address", "oldPass": "סיסמה ישנה", "newPass": "סיסמה חדשה", "confirmPass": "אשרר סיסמה חדשה", @@ -67,8 +69,12 @@ "deleteDo": "עשה זאת, מחק את המשתמש שלי!", "enterNumber": "אנא הכנס/י מספר בין 0 ל24", "fillAll": "אנא מלא/י את כל השדות", - "passSuccess": "הסיסמא שונתה בהצלחה", + "passwordSuccess": "Password successfully changed", "usernameSuccess": "Login Name successfully changed", + "emailSuccess": "Email successfully changed", + "detachFacebook": "De-register Facebook", + "detachedFacebook": "Successully removed Facebook from your account", + "addedLocalAuth": "Successully added local authentication", "data": "מידע", "exportData": "ייצוא מידע", "emailChange1": "To change your email address, please send an email to", @@ -88,6 +94,8 @@ "invitedParty": "Invited To Party", "invitedGuild": "Invited To Guild", "importantAnnouncements": "Important Announcements", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Reminders to check in to HabitRPG", "unsubscribeAllEmails": "Check to Unsubscribe from Emails", "unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.", diff --git a/common/locales/hu/backgrounds.json b/common/locales/hu/backgrounds.json index 64c811aa13..ed485670af 100644 --- a/common/locales/hu/backgrounds.json +++ b/common/locales/hu/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "Rideg Hegycsúcs", "backgroundFrigidPeakNotes": "Mássz meg egy Rideg Csúcsot ", "backgroundSnowyPinesText": "Havas Fenyves", - "backgroundSnowyPinesNotes": "Húzódj meg a Havas Fenyvesben." + "backgroundSnowyPinesNotes": "Húzódj meg a Havas Fenyvesben.", + "backgrounds022015": "Készlet 9: Kiadva 2015 februárjában", + "backgroundBlacksmithyText": "Kovácsműhely", + "backgroundBlacksmithyNotes": "Dolgozz a Kovácsműhelyben", + "backgroundCrystalCaveText": "Kristály Barlang", + "backgroundCrystalCaveNotes": "Fedezz fel egy Kristály Barlangot", + "backgroundDistantCastleText": "Távoli Kastély", + "backgroundDistantCastleNotes": "Védj meg egy távoli kastélyt" } \ No newline at end of file diff --git a/common/locales/hu/character.json b/common/locales/hu/character.json index e65620fbba..afe4f961d7 100644 --- a/common/locales/hu/character.json +++ b/common/locales/hu/character.json @@ -132,5 +132,5 @@ "critBonus": "Kritikus sebzés! Bónusz:", "displayNameDescription1": "Ez jelenik meg amikor a Fogadó, a céh vagy a party chat-et használod, ezen felül az avatárodon is ez látszik. Menj a ", "displayNameDescription2": "Beállítások->Oldal", - "displayNameDescription3": "és lapozz le a Regisztrációs részhez a login neved megváltoztatásához." + "displayNameDescription3": "menübe és lapozz le a Regisztrációs részhez a login neved megváltoztatásához." } \ No newline at end of file diff --git a/common/locales/hu/communityguidelines.json b/common/locales/hu/communityguidelines.json index 684686099a..d1b5807a74 100644 --- a/common/locales/hu/communityguidelines.json +++ b/common/locales/hu/communityguidelines.json @@ -15,7 +15,7 @@ "commGuideHeadingMeet": "Találkozz a Moderátorokkal!", "commGuidePara006": "Habitica has some tireless knight-errants who join forces with the staff members to keep the community calm, contented, and free of trolls. Each has a specific domain, but will sometimes be called to serve in other social spheres. Staff and Mods will often precede official statements with the words \"Mod Talk\" or \"Mod Hat On\".", "commGuidePara007": "A Stáb címkéje lila, koronával. A rangjuk \"Hősies\".", - "commGuidePara008": "Mods have dark blue tags marked with stars. Their title is \"Guardian\". The only exception is Bailey, who, as an NPC, has a black and green tag marked with a star.", + "commGuidePara008": "A moderátorok címkéje sötétkék, csillagokkal. A rangjuk \"Őrző\". Az egyedüli kivetél Bailey, aki egy NJK, címkéje fekete-zöld csillaggal megjelölve.", "commGuidePara009": "A jelenlegi Stáb Tagok (balról jobbra):", "commGuidePara009a": "Trellon", "commGuidePara009b": "Githubon", @@ -24,16 +24,16 @@ "commGuidePara011a": "Fogadó chaten", "commGuidePara011b": "Githubon/Wikian", "commGuidePara011c": "Wikian", - "commGuidePara012": "If you have an issue or concern about a particular Mod, please send an email to Lemoness (leslie@habitrpg.com).", - "commGuidePara013": "In a community as big as Habitica, users come and go, and sometimes a moderator needs to lay down their noble mantle and relax. The following are Moderators Emeritus. They no longer act with the power of a Moderator, but we would still like to honor their work!", - "commGuidePara014": "Moderátor", + "commGuidePara012": "Ha kérdésed vagy problémád van az egyik Moderátorral, akkor kérlek küldj egy email Lemoness-nek (leslie@habitrpg.com).", + "commGuidePara013": "Egy ilyen nagy közösségben mint a Habitica, a felhasználok jönnek mennek, és néha a moderátoroknak is le kell tenniük nemes köpenyüket és pihenniük. Ők a Moderators Emeritus-ok, azaz a Nyugalmazott Moderátorok. Nekik mar nincs meg a Moderátori hatalmuk, de tiszteljük őket továbbra is az elvégzett munkájukért!", + "commGuidePara014": "Nyugalmazott Moderátorok:", "commGuideHeadingPublicSpaces": "Nyilvános helyek Habitica-n", - "commGuidePara015": "Habitica has two kinds of social spaces: public, and private. Public spaces include the Tavern, Public Guilds, GitHub, Trello, and the Wiki. Private spaces are Private Guilds and party chat.", - "commGuidePara016": "When navigating the public spaces in Habitica, there are some general rules to keep everyone safe and happy. These should be easy for adventurers like you!", - "commGuidePara017": "Respect each other. Be courteous, kind, friendly, and helpful. Remember: Habiticans come from all backgrounds and have had wildly divergent experiences. This is part of what makes HabitRPG so cool! Building a community means respecting and celebrating our differences as well as our similarities. Here are some easy ways to respect each other:", + "commGuidePara015": "Habitca-n ket fele közösségi hely van: nyilvános és privát. Nyilvános helyek például a Kocsma, a Nyilvános Céhek, GitHub, Trello es a Wiki. A privát helyek a Privát Céhek és a csoport chat.", + "commGuidePara016": "Amikor a Habitica nyilvános helyein mozogsz, akkor be kell tartanod néhány egyszerű szabályt, hogy mindenki biztonságban és boldogan érezhesse magát. Ez könnyű kell, hogy legyen olyan kalandoroknak, mint Neked!", + "commGuidePara017": "Tiszteljétek egymást. Légy udvarias, kedves, barátságos és segítőkész. Ne feledd: Habitica lakói mindenfelől érkeztek és nagyon eltérő tapasztalatokkal rendelkeznek. Ez az a plusz, amitől a HabitRPG annyira menő. Egy közösséget építeni annyit jelent, hogy tiszteljük és ünnepeljük a különbözőségeinket és hasonlóságunkat. Íme néhány egyszerű tanács, hogy tiszteljük egymást:", "commGuideList02A": "Tartsd be az összes Általános Szerződési Feltételt.", "commGuideList02B": "Do not post images or text that are violent, threatening, or sexually explicit/suggestive, or that promote discrimination, bigotry, racism, hatred, harassment or harm against any individual or group. Not even as a joke. This includes slurs as well as statements. Not everyone has the same sense of humor, and so something that you consider a joke may be hurtful to another. Attack your Dailies, not each other.", - "commGuideList02C": "Keep discussions appropriate for all ages. We have many young Habiticans who use the site! Let's not tarnish any innocents or hinder any Habiticans in their goals.", + "commGuideList02C": "A megfogalmazások bármilyen korú lakónak feleljenek meg. Habitica sok fiatal lakója használja az oldalt. Ne ártsunk az ártatlanoknak, és ne hátráltassunk egy lakost sem a célja elérésében.", "commGuideList02D": "Avoid profanity. This includes milder, religious-based oaths that may be acceptable elsewhere-we have people from all religious and cultural backgrounds, and we want to make sure that all of them feel comfortable in public spaces. Additionally, slurs will be dealt with very severely, as they are also a violation of the Terms of Service.", "commGuideList02E": "Avoid extended discussions of divisive topics outside of the Back Corner. If you feel that someone has said something rude or hurtful, do not engage them. A single, polite comment, such as \"That joke makes me feel uncomfortable,\" is fine, but being harsh or unkind in response to harsh or unkind comments heightens tensions and makes HabitRPG a more negative space. Kindness and politeness helps others understand where you are coming from.", "commGuideList02F": "Comply immediately with any Mod request to cease a discussion or move it to the Back Corner. Last words, parting shots and conclusive zingers should all be delivered (courteously) at your \"table\" in the Back Corner, if allowed.", @@ -66,7 +66,7 @@ "commGuidePara042": "All have their own guidelines outlined, and the Public Spaces rules apply. Users should avoid going off-topic in any of the boards or cards. Trust us, the boards get crowded enough as it is! Prolonged conversations should be moved to the Back Corner Guild.", "commGuideHeadingGitHub": "Github", "commGuidePara043": "HabitRPG uses GitHub to track bugs and contribute code. It's the smithy where the tireless Blacksmiths forge the features! All the Public Spaces rules apply. Be sure to be polite to the Blacksmiths -- they have a lot of work to do, keeping the site running! Hooray, Blacksmiths!", - "commGuidePara044": "A következő userek a HabitRPG repo tagjai:", + "commGuidePara044": "A következő felhasználók a HabitRPG repo tagjai:", "commGuideHeadingWiki": "Wiki", "commGuidePara045": "The HabitRPG wiki collects information about the site. It also hosts a few forums similar to the guilds on HabitRPG. Hence, all the Public Space rules apply.", "commGuidePara046": "The HabitRPG wiki can be considered to be a database of all things HabitRPG. It provides information about site features, guides to play the game, tips on how you can contribute to HabitRPG and also provides a place for you to advertise your guild or party and vote on topics.", @@ -80,7 +80,7 @@ "commGuideList04F": "Read the wiki contribution page before making major changes", "commGuideList04G": "Impartial tone within wiki pages", "commGuideList04H": "Ensuring that wiki content is relevant to the whole site of HabitRPG and not pertaining to a particular guild or party (such information can be moved to the forums)", - "commGuidePara049": "The following people are the current wiki administrators:", + "commGuidePara049": "A következő személyek a jelenlegi Wiki adminisztrátorok:", "commGuidePara018": "Wiki Administrators Emeritus are", "commGuideHeadingInfractionsEtc": "Infractions, Consequences, and Restoration", "commGuideHeadingInfractions": "Jogsértések", @@ -88,7 +88,7 @@ "commGuidePara051": "There are a variety of infractions, and they are dealt with depending on their severity. These are not conclusive lists, and Mods have a certain amount of discretion. The Mods will take context into account when evaluating infractions.", "commGuideHeadingSevereInfractions": "Súlyos Jogsértések", "commGuidePara052": "Severe infractions greatly harm the safety of Habitica's community and users, and therefore have severe consequences as a result.", - "commGuidePara053": "The following are examples of some severe infractions. This is not a comprehensive list.", + "commGuidePara053": "A következők példák a Súlyos Jogsértésekre. A lista nem teljes körű.", "commGuideList05A": "Az Általános Szerződési Feltételek megszegése", "commGuideList05B": "Gyűlölet beszéd/képek, zaklatás, Cyber-Bullying, flamelés és trollkodás", "commGuideList05C": "A Próbaidő feltételeinek megszegése", @@ -107,7 +107,7 @@ "commGuideList07A": "First-time violation of Public Space Guidelines", "commGuideList07B": "Any statements or actions that trigger a \"Please Don't\". When a Mod has to say \"Please Don't do this\" to a user, it can count as a very minor infraction for that user. An example might be \"Mod Talk: Please Don't keep arguing in favor of this feature idea after we've told you several times that it isn't feasible.\" In many cases, the Please Don't will be the minor consequence as well, but if Mods have to say \"Please Don't\" to the same user enough times, the triggering Minor Infractions will start to count as Moderate Infractions.", "commGuideHeadingConsequences": "Következmények", - "commGuidePara058": "Habitica-n -- mint a való világban -- minden cselekvésnek van következménye, mint ahogy a futástól fitt leszel, a sok cukortól elromlik a fogad, vagy a sok tanulással átmész a vizsgán.", + "commGuidePara058": "Habitica-n -- mint a való világban -- minden cselekvésnek van következménye, mint ahogy a futástól fitt leszel, a sok cukortól elszuvasodik a fogad, vagy a sok tanulással átmész a vizsgán.", "commGuidePara059": "Hasonlóan, minden szabálysertésnek közvetlen következménye van. Néhány következményt alább kiemeltünk", "commGuidePara060": "Ha szabálysertésed következménye közepes vagy súlyos, akkor kapsz egy emailt amiben elmagyarázzuk a következőket:", "commGuideList08A": "a szabálysertésed", diff --git a/common/locales/hu/content.json b/common/locales/hu/content.json index a9a24e16fd..8febf370ab 100644 --- a/common/locales/hu/content.json +++ b/common/locales/hu/content.json @@ -47,9 +47,9 @@ "questEggOwlAdjective": "bölcs", "questEggPenguinText": "Pingvin", "questEggPenguinAdjective": "éles eszű", - "questEggTRexText": "Tirannoszaur", + "questEggTRexText": "Tyrannosaurus", "questEggTRexAdjective": "kis-kezű", - "eggNotes": "Keress egy keltetőfőzetet ehhez a tojáshoz, és egy <%= eggAdjective() %> <%= eggText() %> kel majd ki belőle.", + "eggNotes": "Keress egy keltetőfőzetet ehhez a tojáshoz, és egy <%= eggAdjective(locale) %> <%= eggText(locale) %> kel majd ki belőle.", "hatchingPotionBase": "Alap", "hatchingPotionWhite": "Fehér", "hatchingPotionDesert": "Sivatag", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Rózsaszín vattacukor", "hatchingPotionCottonCandyBlue": "Kék vattacukor", "hatchingPotionGolden": "Arany", - "hatchingPotionNotes": "Öntsd ezt egy tojásra, és egy <%= potText() %> háziállat fog belőle kikelni.", + "hatchingPotionNotes": "Öntsd ezt egy tojásra, és egy <%= potText(locale) %> háziállat fog belőle kikelni.", "foodMeat": "Hús", "foodMilk": "Tej", "foodPotatoe": "Burgonya", diff --git a/common/locales/hu/contrib.json b/common/locales/hu/contrib.json index 4c25f5c3b3..fc9400cf8d 100644 --- a/common/locales/hu/contrib.json +++ b/common/locales/hu/contrib.json @@ -9,7 +9,7 @@ "championFifth": "Amikor az ötödik hozzájárulásodat telepítjük, akkor a Kristály Pajzs megvásárolhatóvá válik a Jutalmak boltjában. Jutalmul kapsz továbbá 4 Drágakövet. is.", "championSixth": "Amikor a hatodik hozzájárulásodat telepítjük, akkor megkapod a Hydra Háziállatot. Jutalmul kapsz továbbá 4 Drágakövet. is.", "legendary": "Legendás", - "legSeventh": "When your seventh set of submissions is deployed, you will receive 4 Gems and become a member of the honored Contributor's Guild and be privy to the behind-the-scenes details of HabitRPG! Further contributions do not increase your tier, but you may continue to earn Gem bounties and titles.", + "legSeventh": "Amikor a hetedik hozzájárulásodat telepítjük, akkor kapsz 4 Drágakövet és a megtisztelő Közreműködők Céhében kapsz tagságot és betekinthetsz a HabitRPG színfalak mögé. A további hozzájárulásaid nem növelik a szintedet, de továbbra is kaphatsz Drágaköveket és titulusokat.", "moderator": "Moderátor", "guardian": "Védelmező", "guardianText": "A Moderátorok nagy körültekintéssel lettek kiválasztva a magas szintű közreműködők közül, ezért kérjük, hogy adjátok meg nekik a megfelelő tiszteletet és vegyétek figyelembe a tanácsaikat.", @@ -18,7 +18,7 @@ "heroicText": "A Hősies szint a HabitRPG stáb illetve a stáb-szintű közreműködők sajátja. Ha ezzel a szinttel rendelkezel akkor arra kineveztek (vagy felvettek rá!).", "npcText": "Az NJK-k a legmagasabb szinten támogatták a Kickstarter projektet. Láthatod az avatárjaikat, az oldal különböző részein.", "modalContribAchievement": "Közreműködői Kitűntetés!", - "contribModal": "<%= name %>, te csodálatos ember! A HabitRPG-nek nyújtott segítségedért mostantól <%= level %> szintű közreműködő vagy. Nézd meg", + "contribModal": "Király vagy, <%= name %>;! Mostantól te egy <%= level %> szintű közreműködő vagy, amiért segítetted a HabtRPG-t. Nézd meg", "contribLink": "milyen díjakat értél el a közreműködésedért!", "contribName": "Közreműködő", "contribText": "Támogatta a HabitRPG-t (kód, dizájn, pixel képek, jogi tanács, dokumentumok, stb). Kell ez a kitűző?", @@ -42,7 +42,7 @@ "moreDetails2": "További részletek(8-9)", "contributions": "Hozzájárulások", "admin": "Adminisztrátor", - "notGems": "is in USD, not in Gems. Aka, if this number is 1, it means 4 gems. Only use this option when manually granting gems to players, don't use it when granting contributor tiers. Contrib tiers will automatically add gems.", + "notGems": "USD-ben értve, nem Drágakövekben. Tehát, ha ez a szám 1, az 4 drágakövet jelent. Csak akkor használd ezt az opciót, ha kézzel adsz drágaköveket játékosoknak, ne használd, ha támogatói szinteket adsz. Támogatói szintek automatikusan adnak Drágaköveket szintenként.", "hideAds": "Reklámok elrejtése", "gamemaster": "Játék mester(üzemeltetők/moderátorok)", "backerTier": "Támogatói szint", diff --git a/common/locales/hu/defaulttasks.json b/common/locales/hu/defaulttasks.json index 3c23dd75b8..133d2657eb 100644 --- a/common/locales/hu/defaulttasks.json +++ b/common/locales/hu/defaulttasks.json @@ -16,21 +16,21 @@ "defaultDaily4Checklist1": "Nyújtás", "defaultDaily4Checklist2": "Felülés", "defaultDaily4Checklist3": "Fekvőtámasz", - "defaultTodoNotes": "You can either complete this To-Do, edit it, or remove it.", - "defaultTodo1Text": "Join HabitRPG (Check me off!)", + "defaultTodoNotes": "Teljesítheted ezt a tennivalót, szerkesztheted, vagy eltávolíthatod.", + "defaultTodo1Text": "Csatlakozz a HabitRPG-hez (Pipálj ki!)", "defaultTodo2Text": "Hozz létre egy Szokást", "defaultTodo2Checklist1": "Hozz létre egy Szokást", "defaultTodo2Checklist2": "A Szerkesztésben állítsd be csak \"+\", csak \"-\" vagy \"+/-\"-osra", "defaultTodo2Checklist3": "Állítsd be a nehézséget a Haladó Beállításokban", "defaultTodo3Text": "Hozz létre egy Napi Feladatot", - "defaultTodo3Checklist1": "decide whether to use Dailies (they hurt you if you don't do them every day)", - "defaultTodo3Checklist2": "if so, add a Daily (don't add too many at first!)", - "defaultTodo3Checklist3": "set its due days under Edit", - "defaultTodo4Text": "Set up a To-Do (can be checked off without ticking all checkboxes!)", + "defaultTodo3Checklist1": "Döntsd el, hogy akarsz-e Napi feladatokat használni (sebeznek, ha nem csinálod meg őket minden nap) ", + "defaultTodo3Checklist2": "ha ha igen, akkor hozz létre egy Napi feladatot (ne hozz létre túl sokat rögtön az elején!)", + "defaultTodo3Checklist3": "Állíts be határidőt a Szerkesztés menüpont alatt", + "defaultTodo4Text": "Hozz létre egy tennivalót (kihúzható az összes jelölőnégyzet kipipálása nélkül!)", "defaultTodo4Checklist1": "Hozz létre egy Tennivalót", "defaultTodo4Checklist2": "Állítsd be a nehézséget a Haladó Beállításokban", - "defaultTodo4Checklist3": "optional: set a Due Date", - "defaultTodo5Text": "Start a Party (private group) with your friends (Social > Party)", + "defaultTodo4Checklist3": "Opcionális: Állíts be határidőt", + "defaultTodo5Text": "Alapíts egy csapatot (privát csoportot) a barátaiddal (Közösségi > Csoport)", "defaultReward1Text": "1 Trónok harca epizód", "defaultReward1Notes": "A Testre szabott jutalmaknak sokféle formája van. Néhányan várnak a kedvenc műsoruk megnézésével addig, amíg össze nem gyűlik az arany, hogy ki tudják fizetni.", "defaultReward2Text": "Süti", diff --git a/common/locales/hu/front.json b/common/locales/hu/front.json index 7e42909c3a..6c82dd53d3 100644 --- a/common/locales/hu/front.json +++ b/common/locales/hu/front.json @@ -90,7 +90,7 @@ "footerSocial": "Közösség", "socialTitle": "HabitRPG | Játszd az életed", "watchVideos": "Nézz videókat", - "presskit": "Press Kit", - "presskitText": "Thanks for your interest in HabitRPG! The following images can be used for articles or videos about HabitRPG. For more information, please contact Siena Leslie at leslie@habitrpg.com.", - "presskitDownload": "Download all images:" + "presskit": "Sajtókészlet", + "presskitText": "Köszönjük érdeklődését a HabitRPG iránt! Amennyiben cikket ír vagy videót készít a HabitRPG-ről használja az alábbi képeket. További információkért kérjük lépjen kapcsolatba Siena Leeslie-vel a leslie@habitrpg.com címen. ", + "presskitDownload": "Összes kép letöltése:" } \ No newline at end of file diff --git a/common/locales/hu/gear.json b/common/locales/hu/gear.json index 175fb918b7..f09ea2c6cf 100644 --- a/common/locales/hu/gear.json +++ b/common/locales/hu/gear.json @@ -69,13 +69,13 @@ "weaponSpecialCriticalText": "Brutális Programhiba-zúzó Kalapács", "weaponSpecialCriticalNotes": "Ez a hős levágott egy kritikus Github ellenséget ott, ahol sok más harcos elhalálozott. Ez a hibatöredékek szilánkjaiból megmunkált kalapács hatalmasat üt. Növeli az erődet és az érzékelésedet <%= attrs %> ponttal.", "weaponSpecialYetiText": "Jetiszelídítő dárda", - "weaponSpecialYetiNotes": "This spear allows its user to command any yeti. Increases Strength by <%= str %>. Limited Edition 2013-2014 Winter Gear.", + "weaponSpecialYetiNotes": "Ez a dárda lehetővé teszi felhasználójának, hogy irányítson bármely yetit. Növeli az erőt <%= str %> ponttal. Korlátozott kiadású 2013-2014-es Téli Felszerelés.", "weaponSpecialSkiText": "Az Orgyilkos Síbotja", - "weaponSpecialSkiNotes": "A weapon capable of destroying hordes of enemies! It also helps the user make very nice parallel turns. Increases Strength by <%= str %>. Limited Edition 2013-2014 Winter Gear.", + "weaponSpecialSkiNotes": "Ez a fegyver képes az ellenségeid egész hordáját megsemmisíteni, továbbá a használója jó párhuzamos fordulásokat tud végrehajtani vele. Növeli az erődet <%= str %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés.", "weaponSpecialCandycaneText": "Varázsló cukorbot", - "weaponSpecialCandycaneNotes": "A powerful mage's staff. Powerfully DELICIOUS, we mean! Two-handed weapon. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2013-2014 Winter Gear.", + "weaponSpecialCandycaneNotes": "Erősen ÍZLETES, tényleg! Kétkezes fegyver. Növeli az intelligenciádat <%= int %>, az észlelésedet <%= per %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés.", "weaponSpecialSnowflakeText": "Hópehely varázspálca", - "weaponSpecialSnowflakeNotes": "This wand sparkles with unlimited healing power. Increases Intelligence by <%= int %>. Limited Edition 2013-2014 Winter Gear.", + "weaponSpecialSnowflakeNotes": "Ez a varázspálca végtelen gyógyítóerőtől szikrázik. Növeli az intelligenciádat <%= int %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés!", "weaponSpecialSpringRogueText": "Kampós karmok", "weaponSpecialSpringRogueNotes": "Kiváló falmászáshoz, vagy szőnyegszaggatáshoz. Növeli az erődet <%= str %> ponttal. Korlátozott példányszámú 2014-es Tavaszi Felszerelés.", "weaponSpecialSpringWarriorText": "Répa kard", @@ -101,13 +101,13 @@ "weaponSpecialFallHealerText": "Szkarabeusz varázsbot", "weaponSpecialFallHealerNotes": "A szkarabeusz ezen a varázspálcán megvédi és gyógyítja a használóját. <%= int %> pontot ad az intelligenciához. Korlátozott 2014 Őszi Felszerelés.", "weaponSpecialWinter2015RogueText": "Jégszurony", - "weaponSpecialWinter2015RogueNotes": "You truly, definitely, absolutely just picked these up off of the ground. Increases Strength by <%= str %>. Limited Edition 2014-2015 Winter Gear.", + "weaponSpecialWinter2015RogueNotes": "Te tényleg csak felvetted a földről ezeket. Növeli az erőt <%= str %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", "weaponSpecialWinter2015WarriorText": "Gumibogyó kard", - "weaponSpecialWinter2015WarriorNotes": "This delicious sword probably attracts monsters... but you're up for the challenge! Increases Strength by <%= str %>. Limited Edition 2014-2015 Winter Gear.", + "weaponSpecialWinter2015WarriorNotes": "Ez az ízletes kard valószínűleg vonzza a szörnyeket...de Te elfogadod ezt a kihívást! Növeli az erőt <%= str %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", "weaponSpecialWinter2015MageText": "Téli ragyogású bot", - "weaponSpecialWinter2015MageNotes": "The light of this crystal staff fills hearts with cheer. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2014-2015 Winter Gear.", + "weaponSpecialWinter2015MageNotes": "Ennek a kristálybotnak a fénye megtölti a szíveket örömmel. Növeli az intelligenciát <%= int %> ponttal és az észlelést <%= per %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", "weaponSpecialWinter2015HealerText": "Csillapító jogar", - "weaponSpecialWinter2015HealerNotes": "This scepter warms sore muscles and soothes away stress. Increases Intelligence by <%= int %>. Limited Edition 2014-2015 Winter Gear.", + "weaponSpecialWinter2015HealerNotes": "Ez a jogar melengeti a fájó izmokat és csillapítja a stresszt. Növeli az intelligenciát <%= int %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", "weaponMystery201411Text": "A lakmározás vasvillája", "weaponMystery201411Notes": "Szúrd le az ellenségeidet vagy túrj bele kedvenc eledeleidbe - ezzel a sokoldalú vasvillával mindent megtehetsz! Nem ad bónuszt. 2014 Novemberi előfizetői tárgy.", "weaponMystery301404Text": "Steampunk sétabot", @@ -162,17 +162,17 @@ "armorSpecial2Text": "Jean Chalard nemesi tunikája", "armorSpecial2Notes": "Igazán pihepuha leszel tőle! Növeli az inteligenciádat és a szervezettségedet <%= attrs %> ponttal.", "armorSpecialYetiText": "Jetiszelídítő köpeny", - "armorSpecialYetiNotes": "Fuzzy and fierce. Increases Constitution by <%= con %>. Limited Edition 2013-2014 Winter Gear.", + "armorSpecialYetiNotes": "Bolyhos és vad. Növeli a szervezettséget <%= con %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés.", "armorSpecialSkiText": "Az orgyilkos anorákja", - "armorSpecialSkiNotes": "Full of secret daggers and ski trail maps. Increases Perception by <%= per %>. Limited Edition 2013-2014 Winter Gear.", + "armorSpecialSkiNotes": "Tele van titkos tőrökkel és sítérképekkel. Növeli az észlelésedet <%= per %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés.", "armorSpecialCandycaneText": "Cukorbot köpeny", - "armorSpecialCandycaneNotes": "Spun from sugar and silk. Increases Intelligence by <%= int %>. Limited Edition 2013-2014 Winter Gear.", + "armorSpecialCandycaneNotes": "Cukorból és selyemből szőve. Növeli az intelligenciádat <%= int %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés.", "armorSpecialSnowflakeText": "Hópehely köpeny", - "armorSpecialSnowflakeNotes": "A robe to keep you warm, even in a blizzard. Increases Constitution by <%= con %>. Limited Edition 2013-2014 Winter Gear.", + "armorSpecialSnowflakeNotes": "Köpeny, mely még egy hóviharban is melegen tart. Növeli a szervezettséget <%= con %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés", "armorSpecialBirthdayText": "Abszurd buliköpeny", - "armorSpecialBirthdayNotes": "Happy Birthday, HabitRPG! Wear these Absurd Party Robes to celebrate this wonderful day. Confers no benefit.", - "armorSpecialBirthday2015Text": "Silly Party Robes", - "armorSpecialBirthday2015Notes": "Happy Birthday, HabitRPG! Wear these Silly Party Robes to celebrate this wonderful day. Confers no benefit.", + "armorSpecialBirthdayNotes": "Boldog Szülinapot, HabitRPG! Viseld ezt az Abszurd Partiköpenyt, hogy megünnepeld ezt a csodás napot. Nem ad semmi előnyt.", + "armorSpecialBirthday2015Text": "Idétlen Buliköpeny", + "armorSpecialBirthday2015Notes": "Boldog Szülinapot, HabitRPG! Viseld ezt az Idétlen Partiköpenyt, hogy megünnepeld ezt a csodás napot. Nem ad semmi előnyt.", "armorSpecialGaymerxText": "Szivárvány harci páncél.", "armorSpecialGaymerxNotes": "A GaymerX ünnepi szezon alkalmával ez a spéci páncél sugárzó szívárványszín mintában pompázik. A GaymerX egy játék konferencia, ami az LGBTQ-t ünnepli és itt a játék mindenkinek szabad. Az InterContinental-ban tartják, San Francisco belvárosában, Július 11-13-ig. Nem ad semmilyen bónuszt.", "armorSpecialSpringRogueText": "Karcsú macska kosztüm", @@ -199,14 +199,14 @@ "armorSpecialFallMageNotes": "Ennek a köpenynek sok zsebe van, hogy több adag gőteszemet és békanyelvet lehessen benne tartani. Növeli az intelligenciát <%= int %> ponttal. Korlátozott Példányszámú 2014-ös Őszi felszerelés.", "armorSpecialFallHealerText": "Fátyolszerű Felszerelés", "armorSpecialFallHealerNotes": "Rohanj a csatába előre bekötözve! <%= con %> pontot ad a szervezettséghez. Korlátozott 2014 Őszi Felszerelés.", - "armorSpecialWinter2015RogueText": "Icicle Drake Armor", - "armorSpecialWinter2015RogueNotes": "This armor is freezing cold, but it will definitely be worth it when you uncover the untold riches at the center of the Icicle Drake hives. Not that you are looking for any such untold riches, because you are truly, definitely, absolutely a genuine Icicle Drake, okay?! Stop asking questions! Increases Perception by <%= per %>. Limited Edition 2014-2015 Winter Gear.", + "armorSpecialWinter2015RogueText": "Jeges Sárkány Páncél", + "armorSpecialWinter2015RogueNotes": "Ez a páncél rettentő fagyos, de mindenképp megéri viselni amikor megleled a tömérdek kincset a Jégtüskés Sárkányok fészkének közepén. Nem mintha bármiféle tömérdek kincs után kutakodnál, hiszen te igazán, biztosan és abszolút egy valódi Jégtüskés Sárkány vagy, érted?! Ne kérdezz többet! Növeli az észlelésedet <%= per %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés!", "armorSpecialWinter2015WarriorText": "Mézeskalács páncél", - "armorSpecialWinter2015WarriorNotes": "Cozy and warm, straight from the oven! Increases Constitution by <%= con %>. Limited Edition 2014-2015 Winter Gear.", - "armorSpecialWinter2015MageText": "Boreal Robe", - "armorSpecialWinter2015MageNotes": "You can see the glimmering lights of the north in this robe. Increases Intelligence by <%= int %>. Limited Edition 2014-2015 Winter Gear.", - "armorSpecialWinter2015HealerText": "Skating Outfit", - "armorSpecialWinter2015HealerNotes": "Ice-skating is very relaxing, but you shouldn't try it without this protective gear in case you get attacked by the icicle drakes. Increases Constitution by <%= con %>. Limited Edition 2014-2015 Winter Gear.", + "armorSpecialWinter2015WarriorNotes": "Kényelmes és meleg, egyenesen a sütőből! Növeli a szervezettséget <%= con %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", + "armorSpecialWinter2015MageText": "Örökzöld köpeny", + "armorSpecialWinter2015MageNotes": "Az északi fény játékát látod ezen a köpenyen. Növeli az intelligenciádat <%= int %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés!", + "armorSpecialWinter2015HealerText": "Korcsolya szerelés", + "armorSpecialWinter2015HealerNotes": "A jégkorcsolya nagyon pihentető, de nem érdemes kipróbálni enélkül a védőfelszerelés nélkül főleg ha bármikor megtámadhatnak a Jégtüskés Sárkányok. Növeli a szervezettséget <%= con %> ponttal. Korlátozott példányszámú 2014-2015-ös Téli Felszerelés.", "armorMystery201402Text": "Hirvivő köpeny", "armorMystery201402Notes": "Csillámlóak és erősek, ezeknek a köpenyeknek sok zsebük van levelek hordásához. Nem ad bónuszt. 2014 februári előfizetői tárgy.", "armorMystery201403Text": "Erdőjáró páncél", @@ -225,10 +225,10 @@ "armorMystery201410Notes": "Pikkelyes, nyálkás és erős! Nem ad bónuszt. 2014 októberi előfizetői tárgy.", "armorMystery201412Text": "Pingvin öltözet", "armorMystery201412Notes": "Pingvin vagy! Nem ad bónuszt. 2014 decemberi előfizetői tárgy.", - "armorMystery201501Text": "Starry Armor", - "armorMystery201501Notes": "Galaxies shimmer in the metal of this armor, strengthening the wearer's resolve. Confers no benefit. January 2015 Subscriber Item.", + "armorMystery201501Text": "Csillagos Páncél", + "armorMystery201501Notes": "Galaxisok csillannak meg e páncél acélján, erősítve ezzel viselője elhatározását. Nem ad semmi előnyt. 2015 januári előfizetői tárgy.", "armorMystery301404Text": "Steampunk öltözet", - "armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.", + "armorMystery301404Notes": "Jól vasalt és lenyűgöző, mi! Nem ad semmi előnyt. 3015 februári előfizetői tárgy.", "headgear": "Fejviselet", "headBase0Text": "Nincs sisak", "headBase0Notes": "Nincs fejfedő", @@ -281,13 +281,13 @@ "headSpecialNyeText": "Abszurd buli sapka", "headSpecialNyeNotes": "Megkaptad az Abszurd bulisapkát! Viseld büszkén, miközben átlépsz az Újévbe!", "headSpecialYetiText": "Jetiszelídítő sisak", - "headSpecialYetiNotes": "An adorably fearsome hat. Increases Strength by <%= str %>. Limited Edition 2013-2014 Winter Gear.", + "headSpecialYetiNotes": "Aranyosan félelmetes sapka. Növeli az erődet <%= str %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés!", "headSpecialSkiText": "Orgyilkos símaszk", - "headSpecialSkiNotes": "Keeps the wearer's identity secret... and their face toasty. Increases Perception by <%= per %>. Limited Edition 2013-2014 Winter Gear.", + "headSpecialSkiNotes": "Elrejti a viselője személyazonosságát és frissen tartja az arcbőrt. Növeli az észlelésedet <%= per %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés!", "headSpecialCandycaneText": "Cukorbot kalap", - "headSpecialCandycaneNotes": "This is the most delicious hat in the world. It's also known to appear and disappear mysteriously. Increases Perception by <%= per %>. Limited Edition 2013-2014 Winter Gear.", + "headSpecialCandycaneNotes": "Ez a legízletesebb süveg a világon, valamint arról a furcsa tulajdonságáról ismert, hogy néha eltűnik. Növeli az észlelésedet <%= per %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés!", "headSpecialSnowflakeText": "Hópehely korona", - "headSpecialSnowflakeNotes": "The wearer of this crown is never cold. Increases Intelligence by <%= int %>. Limited Edition 2013-2014 Winter Gear.", + "headSpecialSnowflakeNotes": "A korona hordója sosem fázik meg. Növeli az intelligenciádat <%= int %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés!", "headSpecialSpringRogueText": "Óvatos cicák maszkja", "headSpecialSpringRogueNotes": "Egy cicáról senki nem gondolná, hogy betörő! Növeli az észlelést <%= per %> ponttal. Korlátozott példányszámú 2014-es Tavaszi Felszerelés.", "headSpecialSpringWarriorText": "Lóhere-acél Sisak", @@ -305,25 +305,25 @@ "headSpecialSummerHealerText": "Korall korona", "headSpecialSummerHealerNotes": "A viselője képessé válik a sérült korallzátonyok meggyógyítására. Növeli az intelligenciádat <%= int %> ponttal. Korlátozott Példányszámú 2014 Nyári Felszerelés.", "headSpecialFallRogueText": "Vérvörös Csuklya", - "headSpecialFallRogueNotes": "A Vampire Smiter's identity must always be hidden. Increases Perception by <%= per %>. Limited Edition 2014 Autumn Gear.", + "headSpecialFallRogueNotes": "Egy Vámpír Sújtó kiléte mindig rejtve kell legyen. Növeli az észlelésedet <%= per %> ponttal. Korlátozott Példányszámú 2014 Őszi felszerelés!", "headSpecialFallWarriorText": "A Tudomány Szörnyű Skalpja", - "headSpecialFallWarriorNotes": "Graft on this helm! It's only SLIGHTLY used. Increases Strength by <%= str %>. Limited Edition 2014 Autumn Gear.", + "headSpecialFallWarriorNotes": "Ezt a sisakot csipázd! Csak ÉPPENHOGY használt. Növeli az erődet <%= str %> ponttal. Korlátozott Példányszámú 2014 Őszi Felszerelés.", "headSpecialFallMageText": "Hegyes kalap", "headSpecialFallMageNotes": "Varázslat van beleszőve ennek a kalapnak minden fonalába. <%= per %> pontot ad az észleléshez. Korlátozott 2014 Őszi Felszerelés.", "headSpecialFallHealerText": "Géz fejre", - "headSpecialFallHealerNotes": "Highly sanitary and very fashionable. Increases Intelligence by <%= int %>. Limited Edition 2014 Autumn Gear.", - "headSpecialNye2014Text": "Silly Party Hat", - "headSpecialNye2014Notes": "You've received a Silly Party Hat! Wear it with pride while ringing in the New Year! Confers no benefit.", - "headSpecialWinter2015RogueText": "Icicle Drake Mask", - "headSpecialWinter2015RogueNotes": "You are truly, definitely, absolutely a genuine Icicle Drake. You are not infiltrating the Icicle Drake hives. You have no interest at all in the hoards of riches rumored to lie in their frigid tunnels. Rawr. Increases Perception by <%= per %>. Limited Edition 2014-2015 Winter Gear.", + "headSpecialFallHealerNotes": "Nagyon higiénikus és iszonyúan divatos. <%= int %> pontot ad az intelligenciához. Korlátozott 2014 Őszi Felszerelés.", + "headSpecialNye2014Text": "Idétlen Bulisüveg", + "headSpecialNye2014Notes": "Megkaptad az Idióta bulisapkát! Viseld büszkén, miközben átlépsz az Újévbe! Nem ad semmi előnyt.", + "headSpecialWinter2015RogueText": "Jégtüskés Sárkány Maszk", + "headSpecialWinter2015RogueNotes": "Te igazán, biztosan és abszolút egy valódi Jégtüskés Sárkány vagy. Nem a Jégtüskés sárkányok fészkébe próbálsz beszivárogni. Semennyire sem érdekel az hatalmas vagyon mely a fagyos alagútjaikban állítólag hever. Rarr. Növeli az észlelésedet <%= per %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés!", "headSpecialWinter2015WarriorText": "Mézeskalács sisak", - "headSpecialWinter2015WarriorNotes": "Think, think, think as hard as you can. Increases Strength by <%= str %>. Limited Edition 2014-2015 Winter Gear.", + "headSpecialWinter2015WarriorNotes": "Gondolkodj, gondolkodj, gondolkodj olyan keményen ahogy csak tudsz. Növeli az erőt <%= str %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", "headSpecialWinter2015MageText": "Auróra kalap", - "headSpecialWinter2015MageNotes": "The fabric of this hat shifts and glows when the wearer studies. Increases Perception by <%= per %>. Limited Edition 2014-2015 Winter Gear.", - "headSpecialWinter2015HealerText": "Snuggly Earmuffs", - "headSpecialWinter2015HealerNotes": "These warm earmuffs keep out chills and distracting noises. Increases Intelligence by <%= int %>. Limited Edition 2014-2015 Winter Gear.", + "headSpecialWinter2015MageNotes": "E sapka anyaga változik és világít amikor a viselője tanul. Növeli az észlelésedet <%= per %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés!", + "headSpecialWinter2015HealerText": "Körülölelő Fülvédő", + "headSpecialWinter2015HealerNotes": "Ezek a meleg fülvédők megvédenek a hidegrázástól és a zavaró hangoktól. Növeli az intelligenciát <%= int %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", "headSpecialGaymerxText": "Szívárványos harcisisak", - "headSpecialGaymerxNotes": "In celebration of pride season and GaymerX, this special helmet is decorated with a radiant, colorful rainbow pattern! GaymerX is a game convention celebrating LGBTQ and gaming and is open to everyone. It takes place at the InterContinental in downtown San Francisco on July 11-13! Confers no benefit.", + "headSpecialGaymerxNotes": "A GaymerX ünnepi szezon alkalmával ez a spéci sisak sugárzó szivárványszín mintában pompázik. A GaymerX egy játék konferencia, ami az LGBTQ-t ünnepli és itt a játék mindenkinek szabad. Az InterContinental-ban tartják, San Francisco belvárosában, Július 11-13-ig. Nem ad semmilyen bónuszt.", "headMystery201402Text": "Szárnyas sisak", "headMystery201402Notes": "Ez a szárnyas diadém szélsebessé tesz! Nem ad bónuszt. 2014 februári előfizetői tárgy.", "headMystery201405Text": "Az elme tüze", @@ -335,17 +335,17 @@ "headMystery201408Text": "Napkorona", "headMystery201408Notes": "Ez a lángoló korona hatalmas akaraterővel ruházza fel a viselőjét. 2014 Augusztusi Előfizetői tárgy. Nem ad semmilyen előnyt.", "headMystery201411Text": "A Sportolás Acél Sisakja", - "headMystery201411Notes": "This is the traditional helmet worn in the beloved Habitican sport of Balance Ball, which consists of covering yourself with heavy protective gear and then committing to a healthy work-life balance..... WHILE PURSUED BY HIPPOGRIFFS. Confers no benefit. November 2014 Subscriber Item.", + "headMystery201411Notes": "Ezt a tradicionális sisakot a közkedvelt Habitikai sport az Egyensúly Labda közben hordják, mely során nehéz védőfelszerelésbe öltözve elkötelezed magad az egészséges munka-magánélet egyensúly mellett...... MIKÖZBEN HIPPOGRIFFEK ÜLDÖZNEK. Nem ad semmi előnyt. 2014 Novemberi előfizetői tárgy.", "headMystery201412Text": "Pingvin kalap", "headMystery201412Notes": "Na ki a pingvin? Nem ad bónuszt. 2014 decemberi előfizetői tárgy.", - "headMystery201501Text": "Starry Helm", - "headMystery201501Notes": "The constellations flicker and swirl in this helm, guiding the wearer's thoughts towards focus. Confers no benefit. January 2015 Subscriber Item.", - "headMystery301404Text": "Fancy Top Hat", - "headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.", - "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.", - "offhand": "shield-hand item", - "shieldBase0Text": "No Shield-Hand Equipment", + "headMystery201501Text": "Csillagos Sisak", + "headMystery201501Notes": "A csillagképek hunyorognak és kavarognak ebben a sisakban, fókuszálva a viselő gondolatait. Nem ad semmi előnyt. 2015 januári előfizetői tárgy.", + "headMystery301404Text": "Elegáns Cilinder", + "headMystery301404Notes": "Egy elegáns cilinder a legnemesebb előkelőségeknek! 3015 januári előfizetői tárgy. Nem ad semmi előnyt.", + "headMystery301405Text": "Egyszerű Cilinder", + "headMystery301405Notes": "Egy egyszerű cilinder, pont ideális más elegáns fejszerelésekhez. Nem ad semmi előnyt. 3015 májusi előfizetői tárgy.", + "offhand": "Balkezes tárgy", + "shieldBase0Text": "Nincs balkezes felszerelés", "shieldBase0Notes": "Nincs pajzs vagy másodlagos fegyver.", "shieldWarrior1Text": "Fapajzs", "shieldWarrior1Notes": "Kerek vastag fapajzs. Növeli a szervezettséget <%= con %> ponttal.", @@ -371,12 +371,12 @@ "shieldSpecial0Notes": "A halál függönyén túli rémeket mutat az ellenségeidnek, hogy féljenek. Növeli az észlelésedet <%= per %> ponttal.", "shieldSpecial1Text": "Kristály pajzs", "shieldSpecial1Notes": "Összezúzza a nyilakat és visszaveri a pesszimisták szavait. Növeli az összes tulajdonságodat <%= attrs %> ponttal.", - "shieldSpecialGoldenknightText": "Mustaine's Milestone Mashing Morning Star", - "shieldSpecialGoldenknightNotes": "Meetings, monsters, malaise: managed! Mash! Increases Constitution and Perception by <%= attrs %> each.", + "shieldSpecialGoldenknightText": "Mustaine Mérföldkő Morzsoló Tüskés Buzogánya", + "shieldSpecialGoldenknightNotes": "Találkozók, szörnyek, rossz közérzet: megoldva! Bumm! Növeli az Észlelésedet és a Szervezettségedet <%= attrs %> ponttal.", "shieldSpecialYetiText": "Jetiszelídítő pajzs", - "shieldSpecialYetiNotes": "This shield reflects light from the snow. Increases Constitution by <%= con %>. Limited Edition 2013-2014 Winter Gear.", + "shieldSpecialYetiNotes": "Ez a pajzs visszaveri a hó fényét. Növeli a szervezettséget <%= con %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés.", "shieldSpecialSnowflakeText": "Hópehely pajzs", - "shieldSpecialSnowflakeNotes": "Every shield is unique. Increases Constitution by <%= con %>. Limited Edition 2013-2014 Winter Gear.", + "shieldSpecialSnowflakeNotes": "Minden pajzs egyedi. Növeli a szervezettséget <%= con %> ponttal. Korlátozott Példányszámú 2013-2014-es Téli felszerelés.", "shieldSpecialSpringRogueText": "Kampókarmok", "shieldSpecialSpringRogueNotes": "Kiváló falmászáshoz és szőnyegaprításhoz. Növeli az erődet <%= str %> ponttal. Korlátozott példányszámú 2014-es Tavaszi Felszerelés.", "shieldSpecialSpringWarriorText": "Tojás pajzs", @@ -394,15 +394,15 @@ "shieldSpecialFallWarriorText": "A Tudomány Erős Főzete", "shieldSpecialFallWarriorNotes": "Rejtélyesen ráömlik a laborköpenyekre. <%= con %> pontot ad a szervezettséghez. Korlátozott 2014 Őszi Felszerelés.", "shieldSpecialFallHealerText": "Ékköves pajzs", - "shieldSpecialFallHealerNotes": "This glittery shield was found in an ancient tomb. Increases Constitution by <%= con %>. Limited Edition 2014 Autumn Gear.", - "shieldSpecialWinter2015RogueText": "Ice Spike", - "shieldSpecialWinter2015RogueNotes": "You truly, definitely, absolutely just picked these up off of the ground. Increases Strength by <%= str %>. Limited Edition 2014-2015 Winter Gear.", + "shieldSpecialFallHealerNotes": "Ezt a csillogó pajzsot egy ősi sírban találták. Növeli a szervezettséget <%= con %> ponttal. Korlátozott 2014 Őszi Felszerelés.", + "shieldSpecialWinter2015RogueText": "Jég Tüske", + "shieldSpecialWinter2015RogueNotes": "Te tényleg csak felvetted a földről ezeket. Növeli az erőt <%= str %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", "shieldSpecialWinter2015WarriorText": "Gumibogyó pajzs", - "shieldSpecialWinter2015WarriorNotes": "This seemingly-sugary shield is actually made of nutritious, gelatinous vegetables. Increases Constitution by <%= con %>. Limited Edition 2014-2015 Winter Gear.", - "shieldSpecialWinter2015HealerText": "Soothing Shield", - "shieldSpecialWinter2015HealerNotes": "This shield deflects the freezing wind. Increases Constitution by <%= con %>. Limited Edition 2014-2015 Winter Gear.", + "shieldSpecialWinter2015WarriorNotes": "Ez az édesnek-látszó pajzs valójában tápláló kocsonyás zöldségekből készült. Növeli a szervezettséget <%= con %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", + "shieldSpecialWinter2015HealerText": "Csillapító Pajzs", + "shieldSpecialWinter2015HealerNotes": "Ez a pajzs eltéríti a fagyos szeleket. Növeli a szervezettséget <%= con %> ponttal. Korlátozott Példányszámú 2014-2015-ös Téli felszerelés.", "shieldMystery301405Text": "Óra pajzs", - "shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.", + "shieldMystery301405Notes": "Az Idő veled van, ha ezt a toronyló óra pajzsot viseled! Nem ad semmi előnyt. 3015 júniusi előfizetői tárgy.", "backBase0Text": "Nincs háti kiegészítő", "backBase0Notes": "Nincs háti kiegészítő.", "backMystery201402Text": "Arany szárnyak", @@ -412,17 +412,17 @@ "backMystery201410Text": "Goblin szárnyak", "backMystery201410Notes": "Hasíts keresztül az éjszakán ezekkel az erős szárnyakkal. Nem ad bónuszt. 2014 októberi előfizetői tárgy.", "backSpecialWonderconRedText": "Tekintélyes köpeny", - "backSpecialWonderconRedNotes": "Swishes with strength and beauty. Confers no benefit. Special Edition Convention Item.", + "backSpecialWonderconRedNotes": "Erőt és szépségtől sugárzik. Nem ad semmi előnyt. Külön kiadású tárgy.", "backSpecialWonderconBlackText": "Trükkös lepel", - "backSpecialWonderconBlackNotes": "Spun of shadows and whispers. Confers no benefit. Special Edition Convention Item.", + "backSpecialWonderconBlackNotes": "Árnyakból és suttogásokból fonott. Nem ad semmi előnyt. Külön kiadású tárgy.", "bodyBase0Text": "Nincs test kiegésztő", "bodyBase0Notes": "Nincs test kiegésztő.", "bodySpecialWonderconRedText": "Rubin nyaklánc", - "bodySpecialWonderconRedNotes": "An attractive ruby collar! Confers no benefit. Special Edition Convention Item.", + "bodySpecialWonderconRedNotes": "Egy feltűnő rubin nyaklánc. Nem ad semmi előnyt. Külön kiadású tárgy.", "bodySpecialWonderconGoldText": "Arany nyaklánc", - "bodySpecialWonderconGoldNotes": "An attractive gold collar! Confers no benefit. Special Edition Convention Item.", + "bodySpecialWonderconGoldNotes": "Egy feltűnő arany nyaklánc. Nem ad semmi előnyt. Külön kiadású tárgy.", "bodySpecialWonderconBlackText": "Ébenfekete nyaklánc", - "bodySpecialWonderconBlackNotes": "An attractive ebony collar! Confers no benefit. Special Edition Convention Item.", + "bodySpecialWonderconBlackNotes": "Egy feltűnő ébenfekete nyaklánc. Nem ad semmi előnyt. Külön kiadású tárgy.", "bodySpecialSummerMageText": "Csillogó kis köpeny", "bodySpecialSummerMageNotes": "Sem sósvíztől, sem édesvíztől nem lesz patinás ez a fémes kis köpeny. Nem ad semmilyen bónuszt. Korlátozott Példányszámú 2014 Nyári Felszerelés.", "bodySpecialSummerHealerText": "Korall nyaklánc", @@ -443,18 +443,18 @@ "headAccessoryMystery201404Notes": "Ezek a csápok segítenek a viselőjének észrevenni a veszélyes figyelemeltereléseket. Nem ad bónuszt. 2014 áprilisi előfizetői tárgy.", "headAccessoryMystery201409Text": "Őszi agancsok", "headAccessoryMystery201409Notes": "Ezek az erős agancsok a levelekkel együtt változtatják a színüket. Nem ad bónuszt. 2014 szeptemberi előfizetői tárgy.", - "headAccessoryMystery301405Text": "Headwear Goggles", + "headAccessoryMystery301405Text": "Fejre-Szemüveg", "headAccessoryMystery301405Notes": "\"A szemüvegek a szemhez vannak,\" mondták \"Senki sem akar olyan szemüvegeket amit csak a fejeden hordhatsz,\" mondták. Ha! Jól megmutattad nekik!. Nem ad bónuszt. 3015 augusztusi előfizetői tárgy.", "eyewearBase0Text": "Nincs szemviselet.", "eyewearBase0Notes": "Nincs szemviselet.", - "eyewearSpecialSummerRogueText": "Roguish Eyepatch", - "eyewearSpecialSummerRogueNotes": "It doesn't take a scallywag to see how stylish this is! Confers no benefit. Limited Edition 2014 Summer Gear.", - "eyewearSpecialSummerWarriorText": "Dashing Eyepatch", - "eyewearSpecialSummerWarriorNotes": "It doesn't take a rapscallion to see how stylish this is! Confers no benefit. Limited Edition 2014 Summer Gear.", - "eyewearSpecialWonderconRedText": "Mighty Mask", - "eyewearSpecialWonderconRedNotes": "What a powerful face accessory! Confers no benefit. Special Edition Convention Item.", + "eyewearSpecialSummerRogueText": "Huncut szemkötő", + "eyewearSpecialSummerRogueNotes": "Nem kell csibésznek lenned, hogy meglásd ez mennyire stílusos. Nem ad semmi előnyt. Korlátozott Példányszámú 2014 Nyári Felszerelés.", + "eyewearSpecialSummerWarriorText": "Káprázatos Szemkötő", + "eyewearSpecialSummerWarriorNotes": "Nem kell egy senkiházinak lenned, hogy meglásd ez mennyire stílusos! Nem ad semmi előnyt. Korlátozott Példányszámú 2014 Nyári Felszerelés.", + "eyewearSpecialWonderconRedText": "Hatalmas Maszk", + "eyewearSpecialWonderconRedNotes": "Milyen erős arcfelszerelés! Nem ad semmi előnyt. Külön kiadású tárgy.", "eyewearSpecialWonderconBlackText": "Sompolygó Maszk", - "eyewearSpecialWonderconBlackNotes": "Your motives are definitely legitimate. Confers no benefit. Special Edition Convention Item.", + "eyewearSpecialWonderconBlackNotes": "Az indítékaid határozottan törvényesek. Nem ad semmi előnyt. Külön kiadású tárgy.", "eyewearMystery301404Text": "Szemüveg", "eyewearMystery301404Notes": "Nincs tetszetősebb szemviselett egy szemüvegnél - kivéve, talán a monokli. Nem ad bónuszt. 3015 áprilisi előfizetői tárgy.", "eyewearMystery301405Text": "Monokli", diff --git a/common/locales/hu/generic.json b/common/locales/hu/generic.json index 56a8c08efe..40e132269d 100644 --- a/common/locales/hu/generic.json +++ b/common/locales/hu/generic.json @@ -44,9 +44,9 @@ "veteranText": "Mállasztotta a Szürke Szokást (az Angular előtti weblapunkat), és szerzett néhány sebhelyet a hibáitól.", "originalUser": "Eredeti felhasználó!", "originalUserText": "Az egyik nagyon korai felhasználó. Ő tud mesélni az alfa tesztről!", - "habitBirthday": "HabitRPG Birthday Bash", - "habitBirthdayText": "Celebrated the HabitRPG Birthday Bash!", - "habitBirthdayPluralText": "Celebrated <%= number %> HabitRPG Birthday Bashes!", + "habitBirthday": "HabitRPG Születésnapi Banzáj", + "habitBirthdayText": "Megünnepelte a HabitRPG Születésnapi Banzájt!", + "habitBirthdayPluralText": " <%= number %> alkalommal ünnepelte meg a HabitRPG Születésnapi Banzájt!", "achievementDilatory": "A halogatók megmentője", "achievementDilatoryText": "Segített legyőzni a Rettenet Késlekedő Sárkányát a 2014 Nyári Loccsanás esemény alatt.", "costumeContest": "2014 Jelmez Verseny", @@ -70,7 +70,7 @@ "audioTheme": "Hang téma", "audioTheme_off": "Kikapcsol", "audioTheme_danielTheBard": "Daniel a bárd", - "audioTheme_wattsTheme": "Watts' Theme", + "audioTheme_wattsTheme": "Watts' Téma", "askQuestion": "Tegyél fel egy kérdést", "reportBug": "Programhiba jelentése", "contributeToHRPG": "Hozzájárulás a HabitRPG-hez", @@ -88,6 +88,6 @@ "November": "November", "December": "December", "dateFormat": "Dátum formátum", - "achievementStressbeast": "Savior of Stoïkalm", - "achievementStressbeastText": "Helped defeat the Abominable Stressbeast during the 2015 Winter Wonderland Event!" + "achievementStressbeast": "A Maradjnyugtonok megmentője", + "achievementStressbeastText": "Segített legyőzni az Utálatos Stresszörnyet a 2015-ös Winter Wonderland esemény keretein belül." } \ No newline at end of file diff --git a/common/locales/hu/groups.json b/common/locales/hu/groups.json index d3c92230d6..1ff3944486 100644 --- a/common/locales/hu/groups.json +++ b/common/locales/hu/groups.json @@ -67,10 +67,10 @@ "sortJoined": "Rendezés a csapathoz csatlakozás ideje alapján", "sortName": "Rendezés avatár név alapján", "sortBackgrounds": "Rendezés háttér alapján", - "sortHabitrpgJoined": "Sort by HabitRPG date joined", - "sortHabitrpgLastLoggedIn": "Sort by last time user logged in", - "ascendingSort": "Sort Ascending", - "descendingSort": "Sort Descending", + "sortHabitrpgJoined": "HabitRPG-hez csatlakozás szerinti rendezés", + "sortHabitrpgLastLoggedIn": "Utolsó bejelentkezés szerinti rendezés", + "ascendingSort": "Növekvő sorrendbe rendezés", + "descendingSort": "Csökkenő sorrendbe rendezés", "confirmGuild": "Létre hozol egy céhet 4 drágakőért?", "leaveGroupCha": "Csoport kihívások elhagyása és...", "confirm": "Megerősítés", diff --git a/common/locales/hu/limited.json b/common/locales/hu/limited.json index 1b09180848..5945477ce2 100644 --- a/common/locales/hu/limited.json +++ b/common/locales/hu/limited.json @@ -18,7 +18,7 @@ "seasonalShopTitle": "<%= linkStart %>Szezonális Varázslónő<%= linkEnd %>", "seasonalShopClosedText": "A Szezonális Bolt jelenleg zárva van! Nem tudom, hogy hol van jelenleg a Szezonális Varázslónő, de fogadni mernék, hogy visszatér a következő <%= linkStart %>Nagy Gálára<%= linkEnd %>!", "seasonalShopText": "Üdv a Szezonális Boltban! Mostantól január 31-ig rengeteg szezonális kiadású téli áru kapható itt. Ezután egy évig nem lesznek kaphatók, úgyhogy csapj le rájuk!", - "seasonalShopRebirth": "If you've used the Orb of Rebirth, you can repurchase this equipment in the Rewards Column after you unlock the Item Shop. Initially, you'll only be able to purchase the items for your current class (Warrior by default), but fear not, the other class-specific items will become available if you switch to that class.", + "seasonalShopRebirth": "Ha használtad az Újjászületés Gömbjét, újra megveheted az elvesztett felszereléseidet a Jutalom Oszlopban miután újra hozzáfértél a Tárgy Bolthoz. Eleinte csak az aktuális kasztodhoz (alapesetben ez a Harcos) tartozó tárgyak lesznek elérhetőek, de ne aggódj a többi kaszt-specifikus tárgy is elérhetővé válik ha átváltasz a megfelelő kasztra.", "candycaneSet": "Botcukor (Varázsló)", "skiSet": "Orgyilkos (Tolvaj)", "snowflakeSet": "Hópehely (Gyógyító)", diff --git a/common/locales/hu/npc.json b/common/locales/hu/npc.json index a4b42441c9..25a1c65422 100644 --- a/common/locales/hu/npc.json +++ b/common/locales/hu/npc.json @@ -25,7 +25,7 @@ "card": "Kártya", "paymentMethods": "Fizetési módok:", "welcomeHabit": "Üdvözlet a HabitRPG oldalán", - "welcomeHabitT1": "Welcome to HabitRPG, a habit tracker that treats your tasks like a Role Playing Game. I'm", + "welcomeHabitT1": "Üdvözöllek a HabitRPG-ben, ami egy szokás nyomon követő, ami a feladataidat úgy kezeli, mint egy szerepjátékot. Én vagyok", "welcomeHabitT2": "az idegenvezetőd!", "yourAvatar": "Az avatárod", "yourAvatarText": "Ez az avatárod. Ez képvisel téged Habitica világában. Ahogy teljesíted a céljaid, az avatárod feljődni fog, szintet lép, aranyra tesz szert és felszereli magát az előtte álló kihívásokra.", @@ -37,8 +37,8 @@ "expPointsText": "A sárga csík mutatja az avatárod tapasztalati pontjait. Ha sikerül elvégezni egy feladatot, akkor aranyat és tapasztalatot kapsz. Amikor a csík betelik, akkor szintet lépsz. A szintlépéssel tudod elérni a HabitRPG új és érdekes funkcióit.", "typeGoals": "Feladattípusok", "typeGoalsText": "A HabitRPG három külön módot ad a feladataid követésére. Ezeket három oszlopban látod: Szokások, Napi feladatok és Tennivalók", - "tourHabits": "Habits are tasks that you constantly track. They can be given plus or minus values, allowing you to gain experience and gold for good Habits or lose health for bad ones.", - "tourDailies": "Dailies are tasks that you want to complete once a day. Checking off a Daily reaps experience and gold. Failing to check off your Daily before the day resets results in a loss of health. You can change your day start settings from the Settings menu (click the gear-shaped icon, then click \"Site\").", + "tourHabits": "A Szokások olyan feladatokta, amiket folyamatosan követsz. Adhatsz nekik pozitív és negatív értéket, így kaphatsz tapasztalatot és aranyat a jó szokásokért és veszíthetsz életerőt a rosszakért.", + "tourDailies": "A Napi feladatok olyan tevékenységek, amiket naponta egyszer akarsz összehozni. Ha kipipálsz egy Napi feladatot, akkor tapasztalatot és aranyat kapsz. Ha nem sikerül a nap végéig kipipálnod, akkor sebződsz. Az új nap kezdetének időpontját a Beállítások menüből éred el (kattints a fogaskerék formájú ikonra, majd az \"Oldal\" gombra)", "tourTodos": "A Tennivalók egyszeri feladatok, amiket egyszer majd elvégzel. Lehet dátumhoz kötni őket, de ez nem kötelező. A Tennivalókkal gyorsan és könnyen kaphatsz tapasztalati pontokat.", "tourRewards": "Az arany, amit szereztél arra alkalmas, hogy megjutalmazd magad egyedi, vagy játékbeli jutalmakkal. Vásárold őket szabadon, a jutalmazás fontos a jó szokások kialakításában.", "hoverOver": "Mozgasd az egeret a kommentekhez", diff --git a/common/locales/hu/pets.json b/common/locales/hu/pets.json index 1d4775e197..d555a02dec 100644 --- a/common/locales/hu/pets.json +++ b/common/locales/hu/pets.json @@ -29,18 +29,18 @@ "beastMasterProgress": "Bestiamester Haladás", "beastAchievement": "Megkaptad a \"Bestiamester\" Kitűntetést, amiért összegyűjtötted az összes háziállatot!", "beastMasterName": "Bestiamester", - "beastMasterText": "90 háziállat megtalálva (őrülten nehéz, gratulálj ennek a felhasználónak!)", - "beastMasterText2": "and has released their pets a total of <%= count %> times", - "mountMasterProgress": "Mount Master Progress", - "mountAchievement": "You have earned the \"Mount Master\" achievement for taming all the mounts!", - "mountMasterName": "Mount Master", - "mountMasterText": "Has tamed all 90 mounts (even more difficult, congratulate this user!)", - "mountMasterText2": "and has released all 90 of their mounts a total of <%= count %> times", - "beastMountMasterName": "Beast Master and Mount Master", - "triadBingoName": "Triad Bingo", - "triadBingoText": "Has found all 90 pets, all 90 mounts, and found all 90 pets AGAIN (HOW DID YOU DO THAT!)", - "triadBingoText2": "and has released a full stable a total of <%= count %> times", - "triadBingoAchievement": "You have earned the \"Triad Bingo\" achievement for finding all the pets, taming all the mounts, and finding all the pets again!", + "beastMasterText": "megtalálta mind a 90 háziállatot (őrülten nehéz, gratulálj ennek a felhasználónak!)", + "beastMasterText2": "és elengedte a háziállatait <%= count %> alkalommal", + "mountMasterProgress": "Hátasmester Haladás", + "mountAchievement": "Megkaptad a \"Hátasmester\" kitüntetést, amiért megszelídítetted az összes hátast!", + "mountMasterName": "Hátasmester", + "mountMasterText": "Megtalálta a mind a 90 hátast (még annál is nehezebb, gratulálj ennek a felhasználónak!)", + "mountMasterText2": "és elengedte mind a 90 hátasát <%= count %> alkalommal", + "beastMountMasterName": "Bestiamester és Hátasmester", + "triadBingoName": "Triád Bingó", + "triadBingoText": "Megtalálta mind a 90 háziállatot, mind a 90 hátast, és ÚJRA megtalálta az összes háziállatot (EZT MEG HOGYAN CSINÁLTAD?!)", + "triadBingoText2": "és elengedte az összes állatát <%= count %> alkalommal", + "triadBingoAchievement": "Megkaptad a \"Triád Bingó\" kitüntetést, amiért megtaláltad az össze háziállatot, megszelídítetted az összes hátast, majd megtaláltad az összes háziállatot újra!", "dropsEnabled": "Mostantól tárgyakat találhatsz!", "itemDrop": "Egy tárgyat találtál.", "firstDrop": "Feloldottad a tárgyesés rendszert. Ha elkészülsz egy feladattal, akkor mostantól van egy kis esélyed tárgyat találni. Most épp találtál egy <%= eggText %> tojást! <%= eggNotes %>", @@ -51,14 +51,14 @@ "petName": "<%= potion %> <%= egg %>", "mountName": "<%= potion %> <%= mount %>", "petKeyName": "Kulcs a ólakhoz", - "petKeyPop": "Let your pets roam free, release them to start their own adventure, and give yourself the thrill of Beast Master once more!", - "petKeyBegin": "Key to the Kennels: Experience <%= title %> Once More!", - "petKeyInfo": "Miss the thrill of collecting pets? Now you can let them go, and have those drops be meaningful again!", - "petKeyInfo2": "Use the Key to the Kennels to reset your non-quest collectible pets and/or mounts to zero. (Quest-only and Rare pets and mounts are not affected.)", - "petKeyInfo3": "There are three Keys to the Kennels: Release Pets Only (4 Gems), Release Mounts Only (4 Gems), or Release Both Pets and Mounts (6 Gems). Using a Key lets you stack the Beast Master and Mount Master achievements. The Triad Bingo achievement will only stack if you use the \"Release Both Pets and Mounts\" key and have collected all 90 pets a second time. Show the world just how much of collection master you are! But choose wisely, because once you use a Key and open the kennel or stable doors, you won't be able to get them back without collecting them all again...", + "petKeyPop": "Engedd szabadon az állataidat, hogy a saját kalandjukat folytassák és add meg magadnak újra a Bestiamester izgalmát!", + "petKeyBegin": "Kulcs a ólakhoz: legyél újra <%= title %>!", + "petKeyInfo": "Hiányolod a háziállatok gyűjtésének izgalmát? Most el tudod őket engedni, hogy a talált tárgyak újra jelentőségteljesnek lehessenek!", + "petKeyInfo2": "Használd a Kulcsot az Ólakhoz, hogy elengedd az összes nem-küldetéses gyűjthető háziállatodat és/vagy hátasodat. (A Küldetéshez kötött és Ritka háziállatokra és hátasokra nincs hatással.)", + "petKeyInfo3": "Háromféle Kulcs van: szabadon engedheted Csak a háziállataidat (4 Drágakő), Csak a hátasaidat (4 Drágakő), vagy a háziállataidat a hátasaiddal együtt (6 Drágakőért). \nA kulcsok használatával újra megszerezhetővé válnak a Bestiamester és Hátasmester kitüntetések. A Triád Bingó kitüntetést csak akkor tudod újra megszerezni, ha azt a kulcsot használod, mely egyszerre engedi el a háziállataidat és a hátasaidat és összegyűjtötted mind a 90 háziállatod másodjára is. Mutasd meg a világnak mekkora gyűjtő-mester vagy! De válassz bölcsen, mert ha egyszer felhasználsz egy Kulcsot és kinyitod az ól vagy az istálló ajtaját nem fogod tudni visszaszerezni őket anélkül, hogy újra összegyűjtenéd őket...", "petKeyPets": "Háziállataim elengedése", - "petKeyMounts": "Release My Mounts", - "petKeyBoth": "Release Both", + "petKeyMounts": "Hátasaim elengedése", + "petKeyBoth": "Mindkettő elengedése", "petKeyNeverMind": "Még Nem", "gemsEach": "drágakő egyenként" } \ No newline at end of file diff --git a/common/locales/hu/quests.json b/common/locales/hu/quests.json index e0ba9dd7b4..ab12930c2a 100644 --- a/common/locales/hu/quests.json +++ b/common/locales/hu/quests.json @@ -14,12 +14,12 @@ "questStart": "Miután minden tag elfogadta, vagy elutasította, a küldetés elkezdődik. Csak azok vehetnek részt benne, akik az \"elfogad\" opciót választották, és a tárgyakat is csak ők kapják meg. Ha egy tag túl sokáig várakozik (inaktív?), akkor indíthatsz nélkülük az \"Indít\" gomb megnyomásával.", "begin": "Indít", "bossHP": "Főellenség életereje", - "bossStrength": "Boss Strength", - "collect": "Collect", + "bossStrength": "Főellenség ereje", + "collect": "Gyűjts be", "collected": "Begyűjtve", - "bossDmg1": "To hurt a boss, complete your Dailies and To-Dos. Higher task damage means higher boss damage (completing reds, Mage spells, Warrior attacks, etc). The boss will deal damage to every quest participant for every Daily you've missed (multiplied by the boss's Strength) in addition to your regular damage, so keep your party healthy by completing your Dailies! All damage to and from a boss is tallied on cron (your day roll-over).", + "bossDmg1": "Hogy sebezd a főellenséget, teljesítsd a Napi feladataidat és a Teendőidet. A nagyobb feladat sebzés nagyobb főellenség sebzést is jelent (piros feladatok elvégzése, Mágus varázslatok, Harcos támadások, stb.). A főszörny a küldetés minden résztvevőjét sebezni fogja minden elmulasztott Napi feladatért (megszorozva a Főellenség erejével), a normál sebzés mellé, szóval tartsd a csapatod egészségesen a Napi feladatok elvégzésével! Minden sebzés a nap végén számolódik (a napfordulódon)", "bossDmg2": "Csak a résztvevők harcolnak a főellenséggel és ők osztják meg a küldetés zsákmányát is.", - "tavernBossInfo": "To hurt a world boss, complete your Dailies and To-Dos. Higher task damage means higher boss damage (completing reds, Mage spells, Warrior attacks, etc). For each Daily you've missed (multiplied by the boss's Strength), the boss's Rage will increase. Once his Rage reaches max, something bad will happen - so complete your Dailies! All damage to and from a boss is tallied on cron (your day roll-over).", + "tavernBossInfo": "Hogy sebezd a világi főellenséget, teljesítsd a Napi feladataidat és a Teendőidet. A nagyobb feladat sebzés nagyobb főellenség sebzést is jelent (piros feladatok elvégzése, Mágus varázslatok, Harcos támadások, stb.). Minden elmulasztott Napi feladatod (szorozva a szörny erejével) tovább haragítja a főszörnyet. Ha eléri a maximális őrjöngést, akkor valami nagyon rossz fog történni - szóval végezd el a Napi feladataidat! Minden sebzés a nap végén számolódik (a napfordulódon)", "bossColl1": "Tárgygyűjtéshez végezd el a pozitív feladataidat. Küldetés tárgyak ugyanúgy esnek, mint normál tárgyak; bár ezeket nem látod a következő napig, amikor minden, amit találtál össze lesz vonva és hozzátéve a halomhoz.", "bossColl2": "Csak résztvevők kapják meg a tárgyat és részesülnek a kihívás zsákmányából.", "abort": "Megszakít", diff --git a/common/locales/hu/questscontent.json b/common/locales/hu/questscontent.json index f01a37212f..e6cab5e638 100644 --- a/common/locales/hu/questscontent.json +++ b/common/locales/hu/questscontent.json @@ -69,7 +69,7 @@ "questMoonstone1Notes": "
A terrible affliction has struck Habiticans. Bad Habits thought long-dead are rising back up with a vengeance. Dishes lie unwashed, textbooks linger unread, and procrastination runs rampant!
You track some of your own returning Bad Habits to the Swamps of Stagnation and discover the culprit: the ghostly Necromancer, Recidivate. You rush in, weapons swinging, but they slide through her specter uselessly.
\"Don’t bother,\" she hisses with a dry rasp. \"Without a chain of moonstones, nothing can harm me – and master jeweler @aurakami scattered all the moonstones across Habitica long ago!\" Panting, you retreat... but you know what you must do.
", "questMoonstone1CollectMoonstone": "Holdkövek", "questMoonstone1DropMoonstone2Quest": "The Moonstone Chain Part 2: Recidivate the Necromancer (Scroll)", - "questMoonstone2Text": "Recidivate The Necromancer", + "questMoonstone2Text": "Visszavető a Nekromanta", "questMoonstone2Notes": "The brave weaponsmith @Inventrix helps you fashion the enchanted moonstones into a chain. You’re ready to confront Recidivate at last, but as you enter the Swamps of Stagnation, a terrible chill sweeps over you.
Rotting breath whispers in your ear. \"Back again? How delightful...\" You spin and lunge, and under the light of the moonstone chain, your weapon strikes solid flesh. \"You may have bound me to the world once more,\" Recidivate snarls, \"but now it is time for you to leave it!\"
", "questMoonstone2Boss": "A Nekromanta", "questMoonstone2DropMoonstone3Quest": "The Moonstone Chain Part 3: Recidivate Transformed (Scroll)", diff --git a/common/locales/hu/rebirth.json b/common/locales/hu/rebirth.json index 499ad48931..bfcbdfeee9 100644 --- a/common/locales/hu/rebirth.json +++ b/common/locales/hu/rebirth.json @@ -24,7 +24,7 @@ "reborn": "Újjászülettél, maximális szint <%= reLevel %>", "welcome100": "Üdvözlünk a 100-as szinten!", "intro100": "Most, hogy elérted a 100. szintet, rendelkezésedre áll a lehetőség, hogy az Újjászületés Gömbjét használd ingyenesen, akármikor.", - "followup100": "While you can continue to level up, it will no longer boost your stats and no more content will unlock, to keep Habit fun for folks of all play styles.", + "followup100": "Habár folytathatod a szintlépéseket, az többé már nem fogja tápolni a tulajdonságaidat és nem tudsz több tartalmat feloldani, hogy a Habit szórakoztató maradjon mindenkinek játékstílustól függetlenül.", "rebirth100Info": "Ha készen állsz arra, hogy új kalandot kezdj, akkor Újjászülethetsz most...vagy megláthatod, hogy még meddig juthatsz el.", "rebirthWait": "Várok...", "rebirthNow": "Újjászületés most!" diff --git a/common/locales/hu/settings.json b/common/locales/hu/settings.json index 0fd19a3943..a1ab016b76 100644 --- a/common/locales/hu/settings.json +++ b/common/locales/hu/settings.json @@ -41,15 +41,17 @@ "json": "(JSON)", "customDayStart": "Egyedi nap indítás", "24HrClock": "24 órás óra", - "clockInfo": "HabitRPG defaults to check and reset your Dailies at midnight each day. You can customize that here (Enter number between 0 and 24).", + "clockInfo": "A HabitRPG automatikusan ellenőrzi és alaphelyzetbe állítja a Napi feladataidat minden nap éjfélkor. Ezt megváltoztathatod itt (írj be egy 0 és 24 közötti számot)", "misc": "Egyéb", "showHeader": "Mutasd a fejlécet", "changePass": "Jelszó megváltoztatása", - "changeUsername": "Change Login Name", + "changeUsername": "Bejelentkezési név megváltoztatása", + "changeEmail": "Email cím megváltoztatása", + "newEmail": "Új Email cím", "oldPass": "Régi jelszó", "newPass": "Új jelszó", "confirmPass": "Új jelszó megerősítése", - "newUsername": "New Login Name", + "newUsername": "Új bejelentkezési név", "dangerZone": "Veszélyzóna", "resetText1": "VIGYÁZAT! Ez alapállapotra állítja a fiókod sok részét. Nem ajánljuk, de pár embernek hasznos lehet az elején, miután még csak egy rövid ideig játszott.", "resetText2": "El fogod veszíteni az összes szintedet, aranyadat és tapasztalati pontjaid. Minden feladatod véglegesen törlődik az előzményekkel együtt. Minden tárgyadat elveszíted, de ezeket később visszavásárolhatod a korlátozott példányszámú tárgyak és a Rejtélyes tárgyak esetében is, amiket most birtokolsz (megfelelő kasztúnak kell lenned, hogy a kaszt-specifikus tárgyakat megvehesd). A jelenlegi kasztod, háziállataid és hátasaid megmaradnak. Esetleg jobban jársz egy Újjászületés gömbjével, mely biztonságosabb opció és megőrzi a feladataidat is.", @@ -67,33 +69,39 @@ "deleteDo": "Csináld, töröld a fiókomat!", "enterNumber": "Kérlek üss be egy 0 és 24 közötti számot", "fillAll": "Kérlek töltsd ki a az össszes mezőt", - "passSuccess": "A jelszó sikeresen módosítva", - "usernameSuccess": "Login Name successfully changed", + "passwordSuccess": "A jelszó sikeresen módosítva", + "usernameSuccess": "sikeresen megváltoztattad a bejelentkezési nevedet", + "emailSuccess": "Az Email cím sikeresen módosítva", + "detachFacebook": "Facebook regisztráció visszavonása", + "detachedFacebook": "Sikeresen eltávolítottuk a Facebook kapcsolatot a fiókról", + "addedLocalAuth": "Sikeresen hozzáadtuk a helyi azonosítást", "data": "Adatok", "exportData": "Adatok exportálása", - "emailChange1": "To change your email address, please send an email to", - "emailChange2": "admin@habitrpg.com", - "emailChange3": "including both your old and new email address as well as your User ID.", - "username": "Login Name", + "emailChange1": "Az email címed megváltoztatásához kérjük küldj egy emailt a", + "emailChange2": "admin@habitrpg.com-ra", + "emailChange3": "a régi és az új email címeddel és a felhasználói azonosítóddal.", + "username": "Bejelentkezési név", "email": "Email", - "registeredWithFb": "Registered with Facebook", - "loginNameDescription1": "This is what you use to login to HabitRPG. Go to", - "loginNameDescription2": "User->Profile", - "loginNameDescription3": "to change the name that appears in your avatar and chat messages.", - "emailNotifications": "Email Notifications", - "wonChallenge": "You Won a Challenge", - "newPM": "Received Private Message", - "giftedGems": "Gifted Gems", - "giftedSubscription": "Gifted Subscription", - "invitedParty": "Invited To Party", - "invitedGuild": "Invited To Guild", - "importantAnnouncements": "Important Announcements", - "remindersToLogin": "Reminders to check in to HabitRPG", - "unsubscribeAllEmails": "Check to Unsubscribe from Emails", - "unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.", - "subscriptionRateText": "Recurring $<%= price %> every <%= months %> months", - "benefits": "Benefits", - "coupon": "Coupon", - "couponPlaceholder": "Enter Coupon Code", - "couponText": "We sometimes have events and give out coupon codes for special gear. (eg, those who stop by our Wondercon booth)" + "registeredWithFb": "Facebook-al regisztráltál", + "loginNameDescription1": "Ez az amivel be tudsz lépni a HabitRPG oldalra. Menj a ", + "loginNameDescription2": "Felhasználó->Profil", + "loginNameDescription3": "oldalra hogy megváltoztasd a nevedet ami a avatarodnál és a chat üzeneteknél megjelenik.", + "emailNotifications": "Email értesítések", + "wonChallenge": "Megnyertél egy Kihívást", + "newPM": "Kaptál egy Privát üzenetet", + "giftedGems": "Ajándékoztál Drágaköveket", + "giftedSubscription": "Ajándékoztál Előfizetést", + "invitedParty": "Meghívva egy csapatba", + "invitedGuild": "Meghívva egy céhbe", + "importantAnnouncements": "Fontos Bejelentések", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", + "remindersToLogin": "Emlékeztetők a HabitRPG-be történő bejelentkezésre", + "unsubscribeAllEmails": "Pipáld ki hogyha le akarsz iratkozni az Email-ekről", + "unsubscribeAllEmailsText": "Ennek a mezőnek a kipipálásával elismerem, hogy megértettem azt, hogyha leiratkozom minden emailről, akkor a HabitRPG nem fog tudni értesíteni engem Email-en keresztül semmilyen fontos változásról az oldallal vagy a felhasználói fiókommal kapcsolatban.", + "subscriptionRateText": "Ismétlődő $<%= price %> minden <%= months %>. hónapban", + "benefits": "Előnyök", + "coupon": "Kupon", + "couponPlaceholder": "Írd be a Kupon kódodat", + "couponText": "Időnként speciális eseményeket és kupon kódokat osztogatunk speciális felszerelésekhez. ( pl: azoknak akik meglátogatnak minket a Wondercon-os standunknál)" } \ No newline at end of file diff --git a/common/locales/hu/subscriber.json b/common/locales/hu/subscriber.json index c940c46ff5..db29f91e4a 100644 --- a/common/locales/hu/subscriber.json +++ b/common/locales/hu/subscriber.json @@ -8,7 +8,7 @@ "disableAds": "Reklámok kikapcsolása", "disableAdsText": "A reklámok le vannak tiltva amíg van aktív előfizetésed (egyes régi felhasználóknál nincsenek reklámok).", "buyGemsGold": "Drágakő vásárlása aranyért", - "buyGemsGoldText": "(1 Gem costs <%= gemCost %> Gold) Addresses the \"pay to win\" concern, as everything is now achievable through hard work. There's a <%= gemLimit %> Gem monthly conversion cap to prevent farming.", + "buyGemsGoldText": "(1 Drágakő <%= gemCost %> Aranyba kerül). Megoldja a \"fizess a győzelemért\" problémát, mert így kemény munkával minden elérhetővé válik. Egy <%= gemLimit %> Drágaköves havi konverziós limittel előzzük meg a farmolást.", "retainHistory": "Összes előzmény megőrzése", "retainHistoryText": "Az összes felhasználói előzményt elérhetővé teszi grafikonokban és exporthoz. A nem-előfizetők előzményei törlődnek, hogy az adatbázist optimalizáljuk.", "doubleDrops": "Napi tárgy találati korlátozás megduplázva", diff --git a/common/locales/hu/tasks.json b/common/locales/hu/tasks.json index e33247c6bf..63df1e5a8b 100644 --- a/common/locales/hu/tasks.json +++ b/common/locales/hu/tasks.json @@ -36,13 +36,13 @@ "todos": "Tennivalók", "newTodo": "Új Tennivaló", "dueDate": "Határidő", - "remaining": "Active", - "complete": "Done", - "dated": "Dated", - "datedNotSorted": "Dated To-Dos are NOT sorted by date. Sorting will probably be implemented in future.", + "remaining": "Aktív", + "complete": "Befejezett", + "dated": "Határidős", + "datedNotSorted": "A határidős Tennivalók nincsenek időrendi sorrendbe rendezve. Ez a funkció valószínűleg később lesz megvalósítva.", "due": "Hátralevő", "grey": "Szürke", - "score": "Score", + "score": "Pontszám", "rewards": "Jutalmak", "ingamerewards": "Felszerelések és képességek", "gold": "Arany", diff --git a/common/locales/it/backgrounds.json b/common/locales/it/backgrounds.json index 1d59378eeb..d7668eaedd 100644 --- a/common/locales/it/backgrounds.json +++ b/common/locales/it/backgrounds.json @@ -1,59 +1,66 @@ { "backgrounds": "Sfondi", - "backgrounds062014": "SET 1: Giugno 2014", + "backgrounds062014": "SERIE 1: Giugno 2014", "backgroundBeachText": "Spiaggia", "backgroundBeachNotes": "Rilassati su una calda spiaggia.", "backgroundFairyRingText": "Cerchio fatato", "backgroundFairyRingNotes": "Danza in un luogo magico.", "backgroundForestText": "Foresta", "backgroundForestNotes": "Gironzola attraverso la foresta estiva.", - "backgrounds072014": "SET 2: Luglio 2014", + "backgrounds072014": "SERIE 2: Luglio 2014", "backgroundCoralReefText": "Barriera corallina", "backgroundCoralReefNotes": "Nuota tra i coralli.", "backgroundOpenWatersText": "Mare aperto", "backgroundOpenWatersNotes": "Ammira le grandi distese d'acqua.", "backgroundSeafarerShipText": "Nave da esplorazione", "backgroundSeafarerShipNotes": "Salpa verso i grandi mari.", - "backgrounds082014": "SET 3: Agosto 2014", + "backgrounds082014": "SERIE 3: Agosto 2014", "backgroundCloudsText": "Nuvole", "backgroundCloudsNotes": "Librati attraverso le nuvole.", - "backgroundDustyCanyonsText": "Canyon polveroso", - "backgroundDustyCanyonsNotes": "Vaga per i canyon.", + "backgroundDustyCanyonsText": "Gola polverosa", + "backgroundDustyCanyonsNotes": "Vaga per le gole.", "backgroundVolcanoText": "Vulcano", "backgroundVolcanoNotes": "Scaldati all'interno di un vulcano.", - "backgrounds092014": "SET 4: Settembre 2014", + "backgrounds092014": "SERIE 4: Settembre 2014", "backgroundThunderstormText": "Tempesta", "backgroundThunderstormNotes": "Padroneggia i fulmini.", "backgroundAutumnForestText": "Foresta autunnale", "backgroundAutumnForestNotes": "Gironzola attraverso la foresta autunnale.", "backgroundHarvestFieldsText": "Terre coltivate", "backgroundHarvestFieldsNotes": "Coltiva i tuoi campi.", - "backgrounds102014": "SET 5: Ottobre 2014", + "backgrounds102014": "SERIE 5: Ottobre 2014", "backgroundGraveyardText": "Cimitero", "backgroundGraveyardNotes": "Visita un cimitero spaventoso.", "backgroundHauntedHouseText": "Casa Stregata", "backgroundHauntedHouseNotes": "Esplora furtivamente una casa stregata.", "backgroundPumpkinPatchText": "Campo di zucche", "backgroundPumpkinPatchNotes": "Trasforma le zucche nei campi in lanterne.", - "backgrounds112014": "SET 6: Novembre 2014", + "backgrounds112014": "SERIE 6: Novembre 2014", "backgroundHarvestFeastText": "Festa del Raccolto", "backgroundHarvestFeastNotes": "Goditi una festa del raccolto.", "backgroundStarrySkiesText": "Cielo Stellato", "backgroundStarrySkiesNotes": "Scruta il cielo stellato.", "backgroundSunsetMeadowText": "Campi al tramonto", "backgroundSunsetMeadowNotes": "Ammira i campi al tramonto.", - "backgrounds122014": "SET 7: Dicembre 2014", - "backgroundIcebergText": "Iceberg", - "backgroundIcebergNotes": "Cavalca un iceberg.", + "backgrounds122014": "SERIE 7: Dicembre 2014", + "backgroundIcebergText": "Blocco di ghiaccio", + "backgroundIcebergNotes": "Cavalca un blocco di ghiaccio.", "backgroundTwinklyLightsText": "Brillanti Luci Invernali", "backgroundTwinklyLightsNotes": "Passeggia tra alberi adornati di luci festive.", "backgroundSouthPoleText": "Polo Sud", "backgroundSouthPoleNotes": "Visita il ghiacciato Polo Sud.", - "backgrounds012015": "SET 8: Gennaio 2015", + "backgrounds012015": "SERIE 8: Gennaio 2015", "backgroundIceCaveText": "Caverna di Ghiaccio", "backgroundIceCaveNotes": "Addentrati in una caverna ghiacciata.", "backgroundFrigidPeakText": "Picco Gelido", "backgroundFrigidPeakNotes": "Raggiungi il Picco Gelido.", "backgroundSnowyPinesText": "Pini Innevati", - "backgroundSnowyPinesNotes": "Rifugiati tra i pini innevati." + "backgroundSnowyPinesNotes": "Rifugiati tra i pini innevati.", + "backgrounds022015": "SERIE 9: Febbraio 2015", + "backgroundBlacksmithyText": "Fucina", + "backgroundBlacksmithyNotes": "Lavora nell'officina del fabbro.", + "backgroundCrystalCaveText": "Cava di cristallo", + "backgroundCrystalCaveNotes": "Esplora una cava di cristallo.", + "backgroundDistantCastleText": "Castello lontano", + "backgroundDistantCastleNotes": "Difendi un castello lontano." } \ No newline at end of file diff --git a/common/locales/it/content.json b/common/locales/it/content.json index 751c757c36..103935e6cf 100644 --- a/common/locales/it/content.json +++ b/common/locales/it/content.json @@ -48,8 +48,8 @@ "questEggPenguinText": "Pinguino", "questEggPenguinAdjective": "un perspicace", "questEggTRexText": "Tirannosauro", - "questEggTRexAdjective": "un antico", - "eggNotes": "Trova una pozione per far schiudere questo uovo, e nascerà <%= eggAdjective() %> <%= eggText() %>.", + "questEggTRexAdjective": "un preistorico", + "eggNotes": "Trova una pozione per far schiudere questo uovo, e nascerà <%= eggAdjective(locale) %> <%= eggText(locale) %>.", "hatchingPotionBase": "Base", "hatchingPotionWhite": "Bianco", "hatchingPotionDesert": "Deserto", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Rosa Zucchero Filato", "hatchingPotionCottonCandyBlue": "Blu Zucchero Filato", "hatchingPotionGolden": "Oro", - "hatchingPotionNotes": "Versa questa pozione su un uovo, e nascerà un animale <%= potText() %>.", + "hatchingPotionNotes": "Versa questa pozione su un uovo, e nascerà un animale <%= potText(locale) %>.", "foodMeat": "Carne", "foodMilk": "Latte", "foodPotatoe": "Patata", diff --git a/common/locales/it/generic.json b/common/locales/it/generic.json index 74173eb379..5758fd72ff 100644 --- a/common/locales/it/generic.json +++ b/common/locales/it/generic.json @@ -20,7 +20,7 @@ "none": "Nessuno", "or": "Oppure", "and": "e", - "loginSuccess": "Login eseguito con successo!", + "loginSuccess": "Accesso eseguito con successo!", "youSure": "Sei sicuro?", "submit": "Invia", "close": "Chiudi", @@ -66,7 +66,7 @@ "notifications": "Notifiche", "noNotifications": "Non ci sono nuovi messaggi.", "clear": "Pulisci", - "endTour": "Fine tour", + "endTour": "Fine giro", "audioTheme": "Tema sonoro", "audioTheme_off": "Off", "audioTheme_danielTheBard": "Daniel il Bardo", diff --git a/common/locales/it/settings.json b/common/locales/it/settings.json index 68fafda5cd..89abe40a64 100644 --- a/common/locales/it/settings.json +++ b/common/locales/it/settings.json @@ -46,6 +46,8 @@ "showHeader": "Mostra header", "changePass": "Cambia password", "changeUsername": "Modifica il Nome Utente", + "changeEmail": "Cambia indirizzo email", + "newEmail": "Nuovo indirizzo email", "oldPass": "Vecchia password", "newPass": "Nuova password", "confirmPass": "Conferma la nuova password", @@ -67,8 +69,12 @@ "deleteDo": "Sì, elimina il mio account!", "enterNumber": "Inserisci un numero compreso tra 0 e 24", "fillAll": "Compila tutti i campi", - "passSuccess": "Password modificata con successo", + "passwordSuccess": "Password successfully changed", "usernameSuccess": "Nome Utente modificato con successo", + "emailSuccess": "Email successfully changed", + "detachFacebook": "De-register Facebook", + "detachedFacebook": "Successully removed Facebook from your account", + "addedLocalAuth": "Successully added local authentication", "data": "Dati utente", "exportData": "Esporta dati", "emailChange1": "Per cambiare il tuo indirizzo email, per favore manda un'email a", @@ -88,6 +94,8 @@ "invitedParty": "Invitato in una squadra", "invitedGuild": "Invitato in una Gilda", "importantAnnouncements": "Annunci importanti", + "questStarted": "Your Quest has Begun", + "invitedQuest": "Invited to Quest", "remindersToLogin": "Promemoria per accedere ad HabitRPG", "unsubscribeAllEmails": "Non ricevere nessuna email", "unsubscribeAllEmailsText": "Selezionando questa opzione, confermo di essere cosciente del fatto che, disattivando le notifiche via email, HabitRPG non sarà mai in grado di notificarmi via email cambiamenti importanti riguardo al sito o al mio account.", diff --git a/common/locales/nl/backgrounds.json b/common/locales/nl/backgrounds.json index 44e59ab545..bacd9d18c1 100644 --- a/common/locales/nl/backgrounds.json +++ b/common/locales/nl/backgrounds.json @@ -55,5 +55,12 @@ "backgroundFrigidPeakText": "IJzige bergtop", "backgroundFrigidPeakNotes": "Beklim een ijzige bergtop.", "backgroundSnowyPinesText": "Besneeuwde dennen", - "backgroundSnowyPinesNotes": "Schuil tussen besneeuwde dennen." + "backgroundSnowyPinesNotes": "Schuil tussen besneeuwde dennen.", + "backgrounds022015": "SET 9: Uitgebracht in februari 2015", + "backgroundBlacksmithyText": "Smidse", + "backgroundBlacksmithyNotes": "Ga hard aan het werk in de smidse", + "backgroundCrystalCaveText": "Kristallen grot", + "backgroundCrystalCaveNotes": "Verken een kristallen grot", + "backgroundDistantCastleText": "Kasteel in de verte", + "backgroundDistantCastleNotes": "Verdedig een kasteel in de verte" } \ No newline at end of file diff --git a/common/locales/nl/character.json b/common/locales/nl/character.json index 62f90eab8b..4ffeecf816 100644 --- a/common/locales/nl/character.json +++ b/common/locales/nl/character.json @@ -130,7 +130,7 @@ "youCastTarget": "Je hebt <%= spell %> uitgesproken over <%= target %>.", "youCastParty": "Je hebt <%= spell %> uitgesproken over de groep.", "critBonus": "Voltreffer! Bonus:", - "displayNameDescription1": "This is what appears in messages you post in the Tavern, guilds, and party chat, along with what is displayed on your avatar. Go to", - "displayNameDescription2": "Settings->Site", - "displayNameDescription3": "and scroll down to the Registration section to change your login name." + "displayNameDescription1": "Dit is te zien in berichten die je plaatst in de herberg, gildes en de groepschat, en op je avatar. Ga naar", + "displayNameDescription2": "Instellingen->Site", + "displayNameDescription3": "en scroll naar beneden naar Registratie om je inlognaam te veranderen." } \ No newline at end of file diff --git a/common/locales/nl/communityguidelines.json b/common/locales/nl/communityguidelines.json index 3cb8f0c002..fc395f596a 100644 --- a/common/locales/nl/communityguidelines.json +++ b/common/locales/nl/communityguidelines.json @@ -1,6 +1,6 @@ { "iAcceptCommunityGuidelines": "Ik stem ermee in me aan de gemeenschapsrichtlijnen te houden", - "tavernCommunityGuidelinesPlaceholder": "Friendly reminder: this is an all-ages chat, so please keep content and language appropriate! Consult the Community Guidelines below if you have questions.", + "tavernCommunityGuidelinesPlaceholder": "Vriendelijke herinnering: dit is een chat voor alle leeftijden, dus houd alsjeblieft de inhoud en taal gepast. Raadpleeg de gemeenschapsrichtlijnen hieronder indien je vragen hebt.", "commGuideHeadingWelcome": "Welkom in Habitica!", "commGuidePara001": "Wees gegroet, avonturier! Welkom in Habitica, het land van productiviteit, een gezonde levensstijl, en de incidentele op hol geslagen griffioen. We hebben een vrolijke gemeenschap van behulpzame mensen die elkaar ondersteunen op weg naar zelfverbetering. ", "commGuidePara002": "Om iedereen in de gemeenschap veilig, gelukkig en productief te houden, hebben we enkele richtlijnen. We hebben ze zorgvuldig samengesteld om zo vriendelijk en leesbaar mogelijk te zijn. Neem alsjeblieft even de tijd om ze door te lezen.", @@ -151,7 +151,7 @@ "commGuideList13D": "Gebruikers met een voorwaardelijke straf kunnen de volgende rang niet bereiken. Beheerders hebben het recht om vooruitgang te bevriezen als gebruikers overtredingen begaan. Als dit gebeurt zal de gebruiker altijd op de hoogte gebracht worden van de beslissing en hoe dat te corrigeren. Het is ook mogelijk dat rangen afgenomen worden door overtredingen of voorwaardelijke straffen. ", "commGuideHeadingFinal": "Het laaste stuk", "commGuidePara067": "Dat waren ze dan, dappere Habiticaan - de gemeenschapsrichtlijnen! Veeg het zweet van je voorhoofd en geef jezelf wat XP als beloning voor het lezen hiervan. Als je vragen of zorgen hebt over deze gemeenschapsrichtlijnen, stuur dan een mail naar Lemoness (leslie@habitrpg.com) en ze zal je met plezier vertellen hoe alles werkt. ", - "commGuidePara068": "Now go forth, brave adventurer, and slay some Dailies!", + "commGuidePara068": "Trek de wijde wereld in, dappere avonturier, en versla je dagelijkse taken!", "commGuideHeadingLinks": "Nuttige links", "commGuidePara069": "De volgende talentvolle artiesten hebben een bijdrage geleverd aan deze illustraties:", "commGuideLink01": "Het Newbies-gilde", diff --git a/common/locales/nl/content.json b/common/locales/nl/content.json index ed49c0809e..a6e4068e53 100644 --- a/common/locales/nl/content.json +++ b/common/locales/nl/content.json @@ -49,7 +49,7 @@ "questEggPenguinAdjective": "oplettende", "questEggTRexText": "Tyrannosaurus", "questEggTRexAdjective": "kortarmige", - "eggNotes": "Vind een uitbroedtoverdrank om op dit ei te gieten, en er zal een <%= eggAdjective() %> <%= eggText() %> uitkomen.", + "eggNotes": "Vind een uitbroedtoverdrank om op dit ei te gieten, en er zal een <%= eggAdjective(locale) %> <%= eggText(locale) %> uitkomen.", "hatchingPotionBase": "Normale", "hatchingPotionWhite": "Witte", "hatchingPotionDesert": "Woestijnkleurige", @@ -60,7 +60,7 @@ "hatchingPotionCottonCandyPink": "Suikerspinroze", "hatchingPotionCottonCandyBlue": "Suikerspinblauwe", "hatchingPotionGolden": "Gouden", - "hatchingPotionNotes": "Giet dit over een ei, en er zal een <%= potText() %> dierlijke metgezel uitkomen.", + "hatchingPotionNotes": "Giet dit over een ei, en het zal uitkomen als een <%= potText(locale) %> dier.", "foodMeat": "Vlees", "foodMilk": "Melk", "foodPotatoe": "Aardappel", diff --git a/common/locales/nl/contrib.json b/common/locales/nl/contrib.json index 6973e9aef3..6d47dd6e73 100644 --- a/common/locales/nl/contrib.json +++ b/common/locales/nl/contrib.json @@ -9,16 +9,16 @@ "championFifth": "Wanneer je vijfde set inzendingen wordt geïmplementeerd, wordt het kristallen schild beschikbaar gesteld voor aankoop in de beloningswinkel. Als beloning voor het voortzetten van je werk ontvang je daarnaast 4 edelstenen.", "championSixth": "Wanneer je zesde set inzendingen wordt geïmplementeerd ontvang je een Hydra als huisdier. Ook krijg je 4 edelstenen.", "legendary": "Legendarisch", - "legSeventh": "When your seventh set of submissions is deployed, you will receive 4 Gems and become a member of the honored Contributor's Guild and be privy to the behind-the-scenes details of HabitRPG! Further contributions do not increase your tier, but you may continue to earn Gem bounties and titles.", + "legSeventh": "Wanneer je zevende set inzendingen wordt geïmplementeerd, ontvang je 4 edelstenen en word je lid van het geëerde Bijdragersgilde. Je wordt ingewijd in wat zich achter de schermen van HabitRPG zoal allemaal afspeelt! Voor verdere bijdragen krijg je er geen bijdragersniveaus bij, maar kun je nog steeds edelstenen en titels verdienen.", "moderator": "Beheerder", "guardian": "Bewaker", - "guardianText": "Moderators were selected carefully from high tier contributors, so please give them your respect and listen to their suggestions.", + "guardianText": "Beheerders zijn zorgvuldig geselecteerd uit mensen met een hoog bijdragersniveau, dus wees alsjeblieft respectvol en luister naar hun suggesties. ", "staff": "Medewerkers", "heroic": "Heroïsch", - "heroicText": "The Heroic tier contains HabitRPG staff and staff-level contributors. If you have this title, you were appointed to it (or hired!).", + "heroicText": "Het Heroïsche niveau is voor HabitRPG-medewerkers en bijdragers van medewerkersniveau. Als je deze titel hebt, ben je benoemd tot deze titel (of aangenomen bij HabitRPG!).", "npcText": "NPC's hebben het Kickstarterproject van HabitRPG op het hoogste niveau gesteund. Hun avatars waken over sitefuncties!", "modalContribAchievement": "Bijdragersprestatie!", - "contribModal": "<%= name %>, jij geweldig persoon! Je bent nu een niveau <%= level %> bijdrager omdat je HabitRPG helpt. Zie", + "contribModal": "<%= name %>, jij geweldig persoon! Je bent nu een bijdrager van rang <%= level %> omdat je HabitRPG geholpen hebt. Zie", "contribLink": "welke prijzen je hebt verdiend voor je bijdrage!", "contribName": "Bijdrager", "contribText": "Heeft een bijdrage geleverd aan HabitRPG (code, ontwerp, pixelkunst, juridisch advies, documenten, etc). Wil je deze badge ook verdienen? ", @@ -42,7 +42,7 @@ "moreDetails2": "meer details (8-9)", "contributions": "Bijdrages", "admin": "Beheerder", - "notGems": "is in USD, not in Gems. Aka, if this number is 1, it means 4 gems. Only use this option when manually granting gems to players, don't use it when granting contributor tiers. Contrib tiers will automatically add gems.", + "notGems": "is in Amerikaanse dollars ($), niet in edelstenen. Dus als dit getal 1 is, betekent het 4 Edelstenen. Gebruik deze optie alleen als je handmatig edelstenen aan gebruikers geeft, niet als je bijdragersrangen toekent. Bijdragersrangen geven automatisch edelstenen.", "hideAds": "Verberg advertenties", "gamemaster": "Spelmeester (medewerker/beheerder)", "backerTier": "Ondersteunersniveau", diff --git a/common/locales/nl/defaulttasks.json b/common/locales/nl/defaulttasks.json index fa1e94e841..4d6e3653e7 100644 --- a/common/locales/nl/defaulttasks.json +++ b/common/locales/nl/defaulttasks.json @@ -16,21 +16,21 @@ "defaultDaily4Checklist1": "Rekoefeningen", "defaultDaily4Checklist2": "Sit-ups", "defaultDaily4Checklist3": "Push-ups", - "defaultTodoNotes": "Je kan deze To-Do afmaken, bijwerken of verwijderen.", - "defaultTodo1Text": "Aanmelden bij HabitRPG (Streep mij af)", - "defaultTodo2Text": "een gewoonte opzetten", + "defaultTodoNotes": "Je kunt deze to-do afmaken, bijwerken of verwijderen.", + "defaultTodo1Text": "Aanmelden bij HabitRPG (Streep mij af!)", + "defaultTodo2Text": "Een gewoonte opzetten", "defaultTodo2Checklist1": "een gewoonte aanmaken", - "defaultTodo2Checklist2": "maak het alleen \"+\", alleen \"-\" or zowel \"+/-\" onder Aanpassen", + "defaultTodo2Checklist2": "geef aan of hij alleen \"+\", alleen \"-\" or zowel \"+/-\" moet hebben onder Aanpassen", "defaultTodo2Checklist3": "stel moeilijkheid in onder \"Geavanceerde Instellingen\"", - "defaultTodo3Text": "Stel een Dagelijkse in", - "defaultTodo3Checklist1": "kies of je Dagelijksen wil gebruiken (ze doen je pijn als je ze niet elke dag doet)", - "defaultTodo3Checklist2": "als dat zo is, stel dan een Dagelijkse in (niet teveel in een keer!)", - "defaultTodo3Checklist3": "stel de deadline in onder Aanpassen", - "defaultTodo4Text": "Stel een Taak op (kan afgestrteept worden zonder de afzonderlijke onderdelen af te strepen!)", - "defaultTodo4Checklist1": "maak een Taak aan", - "defaultTodo4Checklist2": "stel de moeilijkheid in onder Geavanceerde Instellingen", + "defaultTodo3Text": "Maak een Dagelijkse Taak aan", + "defaultTodo3Checklist1": "beslis of je Dagelijkse Taken wilt gebruiken (die doen je pijn als je ze niet elke dag doet)", + "defaultTodo3Checklist2": "als dat zo is, stel dan een Dagelijkse Taak in (niet te veel in een keer!)", + "defaultTodo3Checklist3": "stel onder Aanpassen een deadline in", + "defaultTodo4Text": "Maak een To-do aan (kan afgestreept worden zonder de afzonderlijke onderdelen af te strepen!)", + "defaultTodo4Checklist1": "maak een To-do aan", + "defaultTodo4Checklist2": "stel moeilijkheid in onder Geavanceerde Instellingen", "defaultTodo4Checklist3": "optioneel: stel een deadline in", - "defaultTodo5Text": "Start een partij (prive groep) met je vrienden (Sociaal > Feestje)", + "defaultTodo5Text": "Start een privégroep met je vrienden (Sociaal > Groep)", "defaultReward1Text": "1 aflevering van Game of Thrones", "defaultReward1Notes": "Zelfgekozen beloningen bestaan in vele vormen. Sommige mensen wachten met het kijken van hun favoriete serie totdat ze het goud hebben om er voor te betalen.", "defaultReward2Text": "Taart", diff --git a/common/locales/nl/front.json b/common/locales/nl/front.json index e2e41e5911..f15a64484c 100644 --- a/common/locales/nl/front.json +++ b/common/locales/nl/front.json @@ -90,7 +90,7 @@ "footerSocial": "Sociaal", "socialTitle": "HabitRPG - Je leven is een spel", "watchVideos": "Video's bekijken", - "presskit": "Press Kit", - "presskitText": "Thanks for your interest in HabitRPG! The following images can be used for articles or videos about HabitRPG. For more information, please contact Siena Leslie at leslie@habitrpg.com.", - "presskitDownload": "Download all images:" + "presskit": "Persmap", + "presskitText": "Bedankt voor je interesse in HabitRPG! De volgende afbeeldingen mogen gebruikt worden voor artikelen of video's over HabitRPG. Voor meer informatie kun je contact opnemen met Siena Leslie via leslie@habitrpg.com.", + "presskitDownload": "Alle afbeeldingen downloaden:" } \ No newline at end of file diff --git a/common/locales/nl/gear.json b/common/locales/nl/gear.json index 78cbd39342..9f0ff0da4f 100644 --- a/common/locales/nl/gear.json +++ b/common/locales/nl/gear.json @@ -170,9 +170,9 @@ "armorSpecialSnowflakeText": "Sneeuwvlokmantel", "armorSpecialSnowflakeNotes": "Een mantel om je warm te houden, zelfs in een sneeuwstorm. Verhoogt Lichaam met <%= con %>. Beperkte oplage winteruitrusting 2013-2014.", "armorSpecialBirthdayText": "Absurde feestmantels", - "armorSpecialBirthdayNotes": "Happy Birthday, HabitRPG! Wear these Absurd Party Robes to celebrate this wonderful day. Confers no benefit.", - "armorSpecialBirthday2015Text": "Silly Party Robes", - "armorSpecialBirthday2015Notes": "Happy Birthday, HabitRPG! Wear these Silly Party Robes to celebrate this wonderful day. Confers no benefit.", + "armorSpecialBirthdayNotes": "Gefeliciteerd met je verjaardag, HabitRPG! Draag deze absurde feestmantel om deze prachtige dag te vieren. Verleent geen voordelen.", + "armorSpecialBirthday2015Text": "Dwaze feestmantel", + "armorSpecialBirthday2015Notes": "Gefeliciteerd met je verjaardag, HabitRPG! Draag deze dwaze feestmantel om deze prachtige dag te vieren. Verleent geen voordelen.", "armorSpecialGaymerxText": "Harnas van de Regenboogkrijger", "armorSpecialGaymerxNotes": "Om het pride-seizoen en GaymerX te herdenken heeft dit harnas een stralend en kleurrijk regenboogpatroon! GaymerX is een spelconferentie in het teken van LHBTQ en gamen, en iedereen is welkom. Het vindt plaats in het InterContinental in hartje San Francisco op 11-13 juli! Verleent geen voordelen.", "armorSpecialSpringRogueText": "Kittig pakje", @@ -225,8 +225,8 @@ "armorMystery201410Notes": "Geschubd, slijmerig en sterk! Verleent geen voordelen. Abonnee-uitrusting oktober 2014. ", "armorMystery201412Text": "Pinguïnpak", "armorMystery201412Notes": "Je bent een pinguïn! Verleent geen voordelen. Abonnee-uitrusting december 2014.", - "armorMystery201501Text": "Starry Armor", - "armorMystery201501Notes": "Galaxies shimmer in the metal of this armor, strengthening the wearer's resolve. Confers no benefit. January 2015 Subscriber Item.", + "armorMystery201501Text": "Sterrenharnas", + "armorMystery201501Notes": "Sterrenstelsels glinsteren in het metaal van dit harnas en versterken de vastberadenheid van de drager. Verleent geen voordelen. Abonnee-uitrusting januari 2015.", "armorMystery301404Text": "Steampunkpak", "armorMystery301404Notes": "Net en zwierig, niet? Verleent geen voordelen. Abonnee-uitrusting februari 3015.", "headgear": "hoofdbescherming", @@ -338,8 +338,8 @@ "headMystery201411Notes": "Dit is de traditionele helm die gedragen wordt bij de Habiticaanse volkssport balansbal, waarbij spelers zich bedekken met zware bepantsering en proberen een gezonde werk-privébalans aan te houden... TERWIJL ZE ACHTERNAGEZETEN WORDEN DOOR HIPPOGRIEFEN! Verleent geen voordelen. Abonnee-uitrusting november 2014.", "headMystery201412Text": "Pinguïnhoed", "headMystery201412Notes": "Wie is een pinguïn? Verleent geen voordelen. Abonnee-uitrusting december 2014.", - "headMystery201501Text": "Starry Helm", - "headMystery201501Notes": "The constellations flicker and swirl in this helm, guiding the wearer's thoughts towards focus. Confers no benefit. January 2015 Subscriber Item.", + "headMystery201501Text": "Sterrenhelm", + "headMystery201501Notes": "Sterrenbeelden flonkeren en wervelen in deze helm, en helpen de drager zijn gedachten te concentreren. Verleent geen voordelen. Abonnee-uitrusting januari 2015.", "headMystery301404Text": "Chique hoge hoed", "headMystery301404Notes": "Een chique hoge hoed voor lieden van deftigen huize! Abonnee-uitrusting januari 3015. Verleent geen voordelen.", "headMystery301405Text": "Standaard hoge hoed", diff --git a/common/locales/nl/generic.json b/common/locales/nl/generic.json index cd89e62a6c..1e71ff153d 100644 --- a/common/locales/nl/generic.json +++ b/common/locales/nl/generic.json @@ -44,9 +44,9 @@ "veteranText": "Heeft Habit De Grijze doorstaan (onze website van vóór Angular), en heeft vele littekens opgelopen door de bugs daar.", "originalUser": "Oorspronkelijke gebruiker!", "originalUserText": "Een van de oorspronkelijke zeer early adopters. Een echte alpha tester!", - "habitBirthday": "HabitRPG Birthday Bash", - "habitBirthdayText": "Celebrated the HabitRPG Birthday Bash!", - "habitBirthdayPluralText": "Celebrated <%= number %> HabitRPG Birthday Bashes!", + "habitBirthday": "HabitRPG-verjaardagsfeest", + "habitBirthdayText": "Heeft meegedaan aan het verjaardagsfeest van HabitRPG!", + "habitBirthdayPluralText": "Heeft <%= number %> de verjaardag van HabitRPG gevierd!", "achievementDilatory": "Redder van Dralen", "achievementDilatoryText": "Heeft geholpen de Donkere Draak van Dralen te verslaan tijdens het Zomerse Spetterevenement 2014!", "costumeContest": "Verkleedwedstrijd 2014", @@ -70,7 +70,7 @@ "audioTheme": "Achtergrondmuziek", "audioTheme_off": "Uit", "audioTheme_danielTheBard": "Daniël de Bard", - "audioTheme_wattsTheme": "Watts' Theme", + "audioTheme_wattsTheme": "Achtergrondmuziek van Watts", "askQuestion": "Vraag stellen", "reportBug": "Fout melden", "contributeToHRPG": "Bijdragen aan HabitRPG", diff --git a/common/locales/nl/limited.json b/common/locales/nl/limited.json index 625f7032da..b363bb04a6 100644 --- a/common/locales/nl/limited.json +++ b/common/locales/nl/limited.json @@ -18,7 +18,7 @@ "seasonalShopTitle": "<%= linkStart %>Seizoenstovenares<%= linkEnd %>", "seasonalShopClosedText": "De Seizoenswinkel is momenteel gesloten!! Ik weet niet waar de Seizoenstovenares momenteel is, maar ik durf te wedden dat ze er tijdens het volgende <%= linkStart %>Grote Gala<%= linkEnd %> weer is!", "seasonalShopText": "Welkom bij de Seizoenswinkel! Vanaf nu tot en met 31 januari hebben we veel winter-editie seizoensgoederen op voorraad. Daarna zijn ze pas weer terug over een jaar, dus grijp je kans terwijl ze nog warm zijn! Of, ehm, koud.", - "seasonalShopRebirth": "If you've used the Orb of Rebirth, you can repurchase this equipment in the Rewards Column after you unlock the Item Shop. Initially, you'll only be able to purchase the items for your current class (Warrior by default), but fear not, the other class-specific items will become available if you switch to that class.", + "seasonalShopRebirth": "Als je een Bol der Hergeboorte gebruikt hebt, kun je deze uitrustingsstukken weer kopen als je de Markt hebt vrijgespeeld. In het begin kun je alleen de uitrustingsstukken van je huidige klasse kopen (dat is standaard Krijger), maar vrees niet, de uitrustingsstukken die bij een andere klasse horen komen weer beschikbaar als je die klasse kiest.", "candycaneSet": "Zuurstok (Magiër)", "skiSet": "Skimoordenaar (Dief)", "snowflakeSet": "Sneeuwvolk (Heler)", diff --git a/common/locales/nl/npc.json b/common/locales/nl/npc.json index 9d6e94ba4b..f5d04bbf5e 100644 --- a/common/locales/nl/npc.json +++ b/common/locales/nl/npc.json @@ -37,8 +37,8 @@ "expPointsText": "In de gele balk zie je de ervaringspunten van je avatar. Als je een taak succesvol uitvoert, verkrijg je goud en ervaringspunten. Als je ervaringsbalk helemaal vol is, krijg je er een niveau bij. Door nieuwe niveaus te bereiken speel je nieuwe opties in HabitRPG vrij. ", "typeGoals": "Soorten taken", "typeGoalsText": "In HabitRPG kun je je taken op drie manieren bijhouden. Ze vallen in de kolommen Gewoontes, Dagelijkse Taken of To-do's.", - "tourHabits": "Habits are tasks that you constantly track. They can be given plus or minus values, allowing you to gain experience and gold for good Habits or lose health for bad ones.", - "tourDailies": "Dailies are tasks that you want to complete once a day. Checking off a Daily reaps experience and gold. Failing to check off your Daily before the day resets results in a loss of health. You can change your day start settings from the Settings menu (click the gear-shaped icon, then click \"Site\").", + "tourHabits": "Gewoontes zijn taken die je continu bijhoudt. Je kunt ze positieve en negatieve waarden geven, waardoor je ervaring of goud kunt krijgen voor goede gewoontes of gezondheid kunt verliezen voor slechte gewoontes.", + "tourDailies": "Dagelijkse Taken zijn taken die je elke dag een keer wilt doen. Het afvinken van een Dagelijkse Taak levert je ervaring en goud op. Als je een Dagelijkse Taak niet voltooit voordat de dag eindigt, verlies je gezondheidspunten. Je kunt de dagstartopties veranderen in het menu Instellingen (klik op het tandwiel-pictogram, en klik dan op 'Site').", "tourTodos": "To-do's zijn eenmalige taken die je op termijn een keer moet doen. Hoewel het mogelijk is om een einddatum aan een To-do te verbinden, is dat niet verplicht. To-do's zijn een snelle en eenvoudige manier om meer ervaring te krijgen.", "tourRewards": "Al het goud dat je hebt verdiend geeft je de mogelijkheid om jezelf te belonen met aangepaste prijzen of prijzen die bij het spel horen. Koop ze rijkelijk - jezelf belonen is een integraal onderdeel in het vormen van goede gewoontes.", "hoverOver": "Beweeg je muis over commentaar", diff --git a/common/locales/nl/pets.json b/common/locales/nl/pets.json index 578dcf88ca..9cafc24828 100644 --- a/common/locales/nl/pets.json +++ b/common/locales/nl/pets.json @@ -32,7 +32,7 @@ "beastMasterText": "Heeft alle 90 huisdieren gevonden (ontzettend moeilijk, feliciteer deze gebruiker!)", "beastMasterText2": "en heeft zijn of haar huisdieren in totaal <%= count %> keer vrijgelaten", "mountMasterProgress": "Voortgang tot rijdiermeester", - "mountAchievement": "You have earned the \"Mount Master\" achievement for taming all the mounts!", + "mountAchievement": "Je hebt de prestatie \"Rijdiermeester\" behaald voor het temmen van alle rijdieren!", "mountMasterName": "Rijdiermeester", "mountMasterText": "Heeft alle 90 rijdieren getemd (nog veel moeilijker, dus feliciteer deze gebruiker!)", "mountMasterText2": "en heeft alle 90 rijdieren in totaal <%= count %> keer vrijgelaten", @@ -40,7 +40,7 @@ "triadBingoName": "Drie keer bingo", "triadBingoText": "Heeft alle 90 huisdieren en alle 90 rijdieren gevonden, en daarna NOG een keer alle huisdieren gevonden (HOE HEB JE DAT VOOR ELKAAR GEKREGEN!)", "triadBingoText2": "en heeft in totaal <%= count %> keer de volle stal vrijgelaten", - "triadBingoAchievement": "You have earned the \"Triad Bingo\" achievement for finding all the pets, taming all the mounts, and finding all the pets again!", + "triadBingoAchievement": "Je hebt de prestatie 'Drie keer bingo' gehaald door alle huisdieren te vinden, alle rijdieren te temmen en daarna weer alle huisdieren te vinden!", "dropsEnabled": "Vondsten vrijgespeeld!", "itemDrop": "Je hebt iets gevonden!", "firstDrop": "Je hebt het vondstensysteem vrijgespeeld! Als je nu een taak volbrengt, heb je een kleine kans om een voorwerp te vinden. Je hebt net een <%= eggText %>-ei gevonden! <%= eggNotes %>", @@ -52,10 +52,10 @@ "mountName": "<%= potion %> <%= mount %>", "petKeyName": "Sleutel van de Hokken", "petKeyPop": "Laat je huisdieren vrij zodat ze hun eigen avontuur kunnen beginnen en gun jezelf nogmaals de sensatie dierenmeester te worden!", - "petKeyBegin": "Key to the Kennels: Experience <%= title %> Once More!", - "petKeyInfo": "Miss the thrill of collecting pets? Now you can let them go, and have those drops be meaningful again!", - "petKeyInfo2": "Use the Key to the Kennels to reset your non-quest collectible pets and/or mounts to zero. (Quest-only and Rare pets and mounts are not affected.)", - "petKeyInfo3": "There are three Keys to the Kennels: Release Pets Only (4 Gems), Release Mounts Only (4 Gems), or Release Both Pets and Mounts (6 Gems). Using a Key lets you stack the Beast Master and Mount Master achievements. The Triad Bingo achievement will only stack if you use the \"Release Both Pets and Mounts\" key and have collected all 90 pets a second time. Show the world just how much of collection master you are! But choose wisely, because once you use a Key and open the kennel or stable doors, you won't be able to get them back without collecting them all again...", + "petKeyBegin": "Sleutel van de hokken: maak <%= title %> nog een keer mee!", + "petKeyInfo": "Mis je de spanning van huisdieren sparen? Nu kun je ze laten gaan, zodat dingen vinden weer betekenisvol wordt!", + "petKeyInfo2": "Gebruik de sleutel van de hokken om je niet-queestegerelateerde huisdieren en/of rijdieren weer op nul te zetten. (Heeft geen effect op queestegerelateerde en zeldzame huisdieren en rijdieren.)", + "petKeyInfo3": "Er zijn drie sleutels van de hokken: alleen huisdieren vrijlaten (4 edelstenen), alleen rijdieren vrijlaten (4 edelstenen) en zowel huis- als rijdieren vrijlaten (6 edelstenen). De sleutels zorgen ervoor dat je Dierenmeester- en Rijdiermeester-prestaties op kunt stapelen. De 'Drie keer bingo'-prestatie stapelt alleen maar op als je de sleutel gebruikt die zowel de huisdieren als de rijdieren vrijlaat en alle 90 huisdieren voor een tweede keer verzameld hebt. Laat de wereld zien hoe groot jouw verzamelwoede is! Maar pas op, want als je eenmaal een sleutel gebruikt hebt om de hokken te openen, moet je ze echt weer opnieuw verzamalen om ze terug te krijgen...", "petKeyPets": "Laat huisdieren vrij", "petKeyMounts": "Rijdieren vrijlaten", "petKeyBoth": "Beide vrijlaten", diff --git a/common/locales/nl/quests.json b/common/locales/nl/quests.json index 7c9a269dce..b2853f2a51 100644 --- a/common/locales/nl/quests.json +++ b/common/locales/nl/quests.json @@ -17,9 +17,9 @@ "bossStrength": "Kracht eindbaas", "collect": "Verzamel", "collected": "Verzameld", - "bossDmg1": "To hurt a boss, complete your Dailies and To-Dos. Higher task damage means higher boss damage (completing reds, Mage spells, Warrior attacks, etc). The boss will deal damage to every quest participant for every Daily you've missed (multiplied by the boss's Strength) in addition to your regular damage, so keep your party healthy by completing your Dailies! All damage to and from a boss is tallied on cron (your day roll-over).", + "bossDmg1": "Om een eindbaas schade toe te brengen, moet je je Dagelijkse Taken en To-do's voltooien. Meer schade aan een taak betekent meer schade aan de eindbaas (rode taken voltooien, toverspreuken van de Magiër, aanvallen van de Krijger, etc.). De eindbaas brengt iedereen die meedoet aan de queeste schade toe voor iedere Dagelijkse Taak die je gemist hebt (vermenigvuldigd met de Kracht van de eindbaas), bovenop je normale schade, dus houd je groep gezond door je dagelijkse taken te doen! Alle schade van en aan een eindbaas wordt verrekend tijdens cron (je dagelijkse nieuwe start).", "bossDmg2": "Alleen deelnemers bevechten de eindbaas en delen de buit.", - "tavernBossInfo": "To hurt a world boss, complete your Dailies and To-Dos. Higher task damage means higher boss damage (completing reds, Mage spells, Warrior attacks, etc). For each Daily you've missed (multiplied by the boss's Strength), the boss's Rage will increase. Once his Rage reaches max, something bad will happen - so complete your Dailies! All damage to and from a boss is tallied on cron (your day roll-over).", + "tavernBossInfo": "Om een wereldbaas schade toe te brengen, moet je je Dagelijkse Taken en To-do's afvinken. Meer schade aan een taak betekent meer schade aan de eindbaas (rode taken voltooien, spreuken van de Magiër, aanvallen van de Krijger, enz). Voor elke Dagelijkse Taak die je mist (vermenigvuldigd met de Kracht van de eindbaas) neemt de Woede van de eindbaas toe. Als die Woede zijn maximum bereikt, gebeurt er iets naars - dus zorg ervoor dat je die dagelijkse taken doet! Alle schade aan en van een eindbaas wordt verrekend tijdens cron (je dagelijkse nieuwe start).", "bossColl1": "Om vondsten te verzamelen moet je positieve taken doen. De vondsten van de queeste werken hetzelfde als normale vondsten; je zult de vondsten echter niet zien tot de volgende dag, wanneer alles wat je hebt gevonden wordt opgeteld en aan de buit wordt toegevoegd.", "bossColl2": "Alleen deelnemers kunnen vondsten verzamelen en de buit delen.", "abort": "Afbreken", diff --git a/common/locales/nl/questscontent.json b/common/locales/nl/questscontent.json index 7aacb6a9ac..30a3098199 100644 --- a/common/locales/nl/questscontent.json +++ b/common/locales/nl/questscontent.json @@ -11,7 +11,7 @@ "questEvilSanta2CollectBranches": "Gebroken takjes", "questEvilSanta2DropBearCubPolarPet": "IJsbeer (huisdier)", "questGryphonText": "De Vurige Griffioen", - "questGryphonNotes": "The grand beast master, baconsaur, has come to your party seeking help. \"Please, adventurers, you must help me! My prized gryphon has broken free and is terrorizing Habit City! If you can stop her, I could reward you with some of her eggs!\"", + "questGryphonNotes": "De grote dierenmeester, baconsaur, vraagt je groep om hulp. \"Alsjeblieft avonturiers, jullie moeten me helpen! Mijn veelgeprezen griffioen is uitgebroken en terroriseert Habit Stad! Als jullie haar kunnen tegenhouden, beloon ik jullie met enkele van haar eieren!\"", "questGryphonCompletion": "Verslagen kruipt het machtige beest beschaamd naar zijn meester. \"Mijn hemel! Goed gedaan, avonturier!\" roept baconsaur. \"Alsjeblieft, neem wat griffioeneieren. Ik weet zeker dat je deze jonkies goed zult opvoeden!\"", "questGryphonBoss": "Vurige Griffioen", "questGryphonDropGryphonEgg": "Griffioen (ei)", @@ -26,8 +26,8 @@ "questGhostStagBoss": "Hertengeest", "questGhostStagDropDeerEgg": "Hert (ei)", "questRatText": "De Rattenkoning", - "questRatNotes": "Garbage! Massive piles of unchecked Dailies are lying all across Habitica. The problem has become so serious that hordes of rats are now seen everywhere. You notice @Pandah petting one of the beasts lovingly. She explains that rats are gentle creatures that feed on unchecked Dailies. The real problem is that the Dailies have fallen into the sewer, creating a dangerous pit that must be cleared. As you descend into the sewers, a massive rat, with blood red eyes and mangled yellow teeth, attacks you, defending its horde. Will you cower in fear or face the fabled Rat King?", - "questRatCompletion": "Your final strike saps the gargantuan rat's strength, his eyes fading to a dull grey. The beast splits into many tiny rats, which scurry off in fright. You notice @Pandah standing behind you, looking at the once mighty creature. She explains that the citizens of Habitica have been inspired by your courage and are quickly completing all their unchecked Dailies. She warns you that we must be vigilant, for should we let down our guard, the Rat King will return. As payment, @Pandah offers you several rat eggs. Noticing your uneasy expression, she smiles, \"They make wonderful pets.\"", + "questRatNotes": "Wat een rotzooi! Overal in Habitica liggen enorme bergen onafgemaakte Dagelijkse Taken. Het probleem is zo ernstig geworden dat er overal hordes ratten te zien zijn. Je ziet @Pandah een van de beesten liefdevol aaien. Ze legt uit dat ratten zachtaardige wezens zijn die zich voeden met onafgemaakte Dagelijkse Taken. Het echte probleem is dat de Dagelijkse Taken in het riool gevallen zijn, waardoor het een gevaarlijk gat is geworden dat moet worden ontruimd. Terwijl je afdaalt in het riool valt een enorme rat met bloedrode ogen en afgebroken gele tanden je aan om zijn horde te verdedigen. Deins je terug van angst, of bied je de legendarische Rattenkoning het hoofd?", + "questRatCompletion": "Je laatste slag zorgt ervoor dat alle kracht uit de reusachtige rat wegstroomt; zijn ogen verbleken tot een doffe grijze kleur. Het beest valt uiteen tot vele kleine ratten, die angstig wegglippen. Je merkt dat @Pandah achter je staat en naar het ooit-machtige dier kijkt. Ze legt uit dat de inwoners van Habitica zich geïnspireerd voelen door jouw moed en dat ze snel hun onvoltooide Dagelijkse Taken aan het afronden zijn. Ze waarschuwt je dat we op onze hoede moeten zijn; als we onze waakzaamheid laten verslappen dan komt de Rattenkoning terug. Als beloning biedt @Pandah je een aantal ratteneieren aan. Als ze je onbehaaglijke blik ziet, glimlacht ze. \"Het zijn fantastische huisdieren.\"", "questRatBoss": "Rattenkoning", "questRatDropRatEgg": "Rat (ei)", "questOctopusText": "De Roep van Octothulu", @@ -60,7 +60,7 @@ "questVice2DropVice3Quest": "Ondeugd deel 3 (Perkamentrol)", "questVice3Text": "Ondeugd Ontwaakt", "questVice3Notes": "Na veel inspanning heeft je groep de schuilplaats van Ondeugd ontdekt. Het kolossale monster bekijkt je groep met afkeer. Terwijl schaduwen om je heen wervelen, fluistert een stem in je hoofd, \"Meer dwaze inwoners van Habitica die gekomen zijn om mij te stoppen? Schattig. Het was wijzer geweest om niet te komen.\" De geschubde titaan trekt zijn hoofd terug en maakt zich klaar om aan te vallen. Dit is jouw kans! Gooi alles wat je hebt in de strijd en overwin Ondeugd voor eens en voor altijd!", - "questVice3Completion": "The shadows dissipate from the cavern and a steely silence falls. My word, you've done it! You have defeated Vice! You and your party may finally breath a sigh of relief. Enjoy your victory, brave Habiteers, but take the lessons you've learned from battling Vice and move forward. There are still Habits to be done and potentially worse evils to conquer!", + "questVice3Completion": "De schaduwen vervliegen uit de grot en een ijzeren stilte valt. Het is je gelukt! Je hebt Ondeugd verslagen! Jij en je groep kunnen eindelijk een zucht van verlichting slaken. Geniet van je overwinning, dappere Habiteers, maar onthoud de lessen die je hebt geleerd van het bevechten van Ondeugd voor de toekomst. Er zijn nog steeds gewoontes om te doen en mogelijk ergere ondeugden om te overwinnen!", "questVice3Boss": "Ondeugd, de schaduwdraak", "questVice3DropWeaponSpecial2": "Stephen Webers Schacht van de Draak", "questVice3DropDragonEgg": "Draak (ei)", @@ -75,12 +75,12 @@ "questMoonstone2DropMoonstone3Quest": "De Maanstenen Ketting deel 3: Recidive Getransformeerd (perkamentrol)", "questMoonstone3Text": "Recidive Getransformeerd", "questMoonstone3Notes": "Recidive valt verkreukeld op de grond, en je slaat naar haar met de maanstenen ketting. Tot je afschuw grijpt Recidive de edelstenen, ogen brandend van triomf.
\"Dwaas schepsel van vlees!\" schreeuwt ze. \"Deze maanstenen zorgen dat ik een fysieke vorm krijg, dat is waar, maar niet zoals jij het je voorstelt. Zoals de volle maan groeit uit het donker, zo ook gedijt mijn kracht, en uit de schaduwen roep ik de geest op van je meest gevreesde vijand!\"
Een ziekelijke groene mist rijst op vanuit het moeras, en lichaam van Recidive kronkelt en verwringt tot een vorm die je vervult van angst - het ondode lichaam van Ondeugd, op afschuwelijke wijze herrezen.
", - "questMoonstone3Completion": "Your breath comes hard and sweat stings your eyes as the undead Wyrm collapses. The remains of Recidivate dissipate into a thin grey mist that clears quickly under the onslaught of a refreshing breeze, and you hear the distant, rallying cries of Habiticans defeating their Bad Habits for once and for all.
@Baconsaur the beast master swoops down on a gryphon. \"I saw the end of your battle from the sky, and I was greatly moved. Please, take this enchanted tunic – your bravery speaks of a noble heart, and I believe you were meant to have it.\"
", + "questMoonstone3Completion": "Je ademt zwaar en zweet prikt in je ogen als de ondode draak instort. De resten van Recidive verdwijnen in een dunne grijze mist die snel verdwijnt onder de aanval van een verfrissend briesje, en je hoort de verre, opzwepende kreten van Habaticanen die voor eens en voor altijd hun slechte gewoontes verslaan.
@Baconsaur de dierenmeester voert op een griffioen een duikvlucht naar je uit. \"Ik zag het einde van je gevecht vanuit de lucht, en het heeft me zeer bewogen. Alsjeblieft, neem deze betoverde tuniek - je moed laat een nobel hart zien, en ik geloof dat je voorbestemd was om deze te hebben.\"
", "questMoonstone3Boss": "Herrezen Ondeugd", "questMoonstone3DropRottenMeat": "Bedorven vlees (voedsel)", "questMoonstone3DropZombiePotion": "Zombie-uitbroedtoverdrankje", "questGoldenknight1Text": "Een Strenge Berisping", - "questGoldenknight1Notes": "The Golden Knight has been getting on poor Habiticans' cases. Didn't do all of your Dailies? Checked off a negative Habit? She will use this as a reason to harass you about how you should follow her example. She is the shining example of a perfect Habitican, and you are naught but a failure. Well, that is not nice at all! Everyone makes mistakes. They should not have to be met with such negativity for it. Perhaps it is time you gather some testimonies from hurt Habiticans and give the Golden Knight a stern talking-to!
", + "questGoldenknight1Notes": "De Gouden Ridder is Habiticanen lastig aan het vallen. Niet al je Dagelijke Taken gedaan? Een negatieve Gewoonte afgevinkt? Allemaal redenen voor haar om je te vermanen dat je meer haar voorbeeld moet volgen. Zij is het schoolvoorbeeld van de perfecte Habiticaan, en jij bent maar een mislukkeling. Nou, dat is helemaal niet aardig! Iedereen maakt fouten. En ze moeten daarvoor niet zo'n lading negativiteit over zich heen krijgen. Misschien is het tijd om wat getuigenissen te verzamelen van gekwetste Habiticanen, en de Gouden Ridder een strenge berisping te geven!
", "questGoldenknight1CollectTestimony": "Getuigenissen", "questGoldenknight1DropGoldenknight2Quest": "De Gouden Ridder-serie deel 2: Aangetast Goud (perkamentrol)", "questGoldenknight2Text": "Gouden Ridder", @@ -143,28 +143,28 @@ "questPenguinBoss": "Vorstpinguïn", "questPenguinDropPenguinEgg": "Pinguïn (ei)", "questStressbeastText": "Het Verschikkelijke Stressbeest van de Stoïkalmse Steppen.", - "questStressbeastNotes": "Doe je Dagelijkse Taken en To-Do's om de Wereldbaas schade te doen! Onvoltooide Dagelijkse Taken zullen de Stress-Stootbalk vullen. Als deze vol is, zal de Wereldbaas een NPC aanvallen. Een Wereldbaas zal nooit individuele spelers of accounts, op welke manier dan ook, beschadigen. Alleen actieve accounts die niet in de Herberg slapen zullen meegeteld worden.