Merge branch 'develop' into carolstone-chron-run-early-issue-4488
This commit is contained in:
+329
-56
@@ -51,11 +51,28 @@ api.mystery =
|
||||
201504: {start:'2015-04-24',end:'2015-05-02', text:'Busy Bee Set'}
|
||||
201505: {start:'2015-05-25',end:'2015-06-02', text:'Green Knight Set'}
|
||||
201506: {start:'2015-06-25',end:'2015-07-02', text:'Neon Snorkeler Set'}
|
||||
201507: {start:'2015-07-24',end:'2015-08-02', text:'Rad Surfer Set'}
|
||||
201508: {start:'2015-08-23',end:'2015-09-02', text:'Cheetah Costume 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'} # not really, but the mechanic works
|
||||
_.each api.mystery, (v,k)->v.key = k
|
||||
|
||||
api.itemList =
|
||||
'weapon': {localeKey: 'weapon', isEquipment: true}
|
||||
'armor' : {localeKey: 'armor', isEquipment: true}
|
||||
'head' : {localeKey: 'headgear', isEquipment: true}
|
||||
'shield' : {localeKey: 'offhand', isEquipment: true}
|
||||
'back' : {localeKey: 'back', isEquipment: true}
|
||||
'body' : {localeKey: 'body', isEquipment: true}
|
||||
'headAccessory' : {localeKey: 'headAccessory', isEquipment: true}
|
||||
'eyewear' : {localeKey: 'eyewear', isEquipment: true}
|
||||
'hatchingPotions' : {localeKey: 'hatchingPotion', isEquipment: false}
|
||||
'eggs' : {localeKey: 'eggSingular', isEquipment: false}
|
||||
'quests' : {localeKey: 'quest', isEquipment: false}
|
||||
'food' : {localeKey: 'foodText', isEquipment: false}
|
||||
'Saddle' : {localeKey: 'foodSaddleText', isEquipment: false}
|
||||
|
||||
gear =
|
||||
weapon:
|
||||
base:
|
||||
@@ -70,14 +87,6 @@ gear =
|
||||
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:
|
||||
#Not using bows at the moment, but they would be easy to add back in to an advanced Armory feature, as Quest drops, etc.
|
||||
#0: twoHanded: true, text: "Practice Bow", notes:'Training weapon. Confers no benefit.', value:0
|
||||
#1: twoHanded: true, text: "Short Bow", notes:'Simple bow best at close ranges. Increases STR by 2.', str: 2, value:20
|
||||
#2: twoHanded: true, text: "Long Bow", notes:'Bow with a strong draw for extra distance. Increases STR by 5.', str: 5, value:50
|
||||
#3: twoHanded: true, text: "Recurve Bow", notes:'Built with advanced techniques. Increases STR by 8.', str: 8, value:80
|
||||
#4: twoHanded: true, text: "Icicle Bow", notes:'Fires arrows of piercing cold. Increases STR by 12.', str: 12, value:120
|
||||
#5: twoHanded: true, text: "Meteor Bow", notes:'Rains flame upon your foes. Increases STR by 16.', str: 16, value:160
|
||||
#6: twoHanded: true, text: "Golden Bow", notes:'As swift as sunlight and as sharp as lightning. Increases STR by 20.', str: 20, value:200, last: true
|
||||
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
|
||||
@@ -102,27 +111,29 @@ gear =
|
||||
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:
|
||||
# Backer, Contributor, and Quest Rewards
|
||||
0: text: t('weaponSpecial0Text'), notes: t('weaponSpecial0Notes', {str: 20}), str: 20, value:150, canOwn: ((u)-> +u.backer?.tier >= 70)
|
||||
1: text: t('weaponSpecial1Text'), notes: t('weaponSpecial1Notes', {attrs: 6}), str: 6, per: 6, con: 6, int: 6, value:170, canOwn: ((u)-> +u.contributor?.level >= 4)
|
||||
2: text: t('weaponSpecial2Text'), notes: t('weaponSpecial2Notes', {attrs: 25}), str: 25, per: 25, value:200, canOwn: ((u)-> (+u.backer?.tier >= 300) or u.items.gear.owned.weapon_special_2?)
|
||||
3: text: t('weaponSpecial3Text'), notes: t('weaponSpecial3Notes', {attrs: 17}), str: 17, int: 17, con: 17, value:200, canOwn: ((u)-> (+u.backer?.tier >= 300) or u.items.gear.owned.weapon_special_3?)
|
||||
critical: text: t('weaponSpecialCriticalText'), notes: t('weaponSpecialCriticalNotes', {attrs: 40}), str: 40, per: 40, value:200, canOwn: ((u)-> !!u.contributor?.critical)
|
||||
# Winter event gear
|
||||
tridentOfCrashingTides: text: t('weaponSpecialTridentOfCrashingTidesText'), notes: t('weaponSpecialTridentOfCrashingTidesNotes', {int: 15}), int: 15, value: 130, canOwn: ((u)-> u.items.gear.owned.weapon_special_tridentOfCrashingTides?)
|
||||
# Winter Wonderland
|
||||
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
|
||||
#Spring Fling
|
||||
# Spring Fling
|
||||
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
|
||||
#Summer
|
||||
# Summer Splash
|
||||
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
|
||||
#Fall
|
||||
# Fall Festival
|
||||
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
|
||||
@@ -150,43 +161,45 @@ gear =
|
||||
armoire:
|
||||
basicCrossbow: text: t('weaponArmoireBasicCrossbowText'), notes: t('weaponArmoireBasicCrossbowNotes', {str: 5, per: 5, con: 5}), value: 100, str: 5, per: 5, con: 5, canOwn: ((u)-> u.items.gear.owned.weapon_armoire_basicCrossbow?)
|
||||
lunarSceptre: text: t('weaponArmoireLunarSceptreText'), notes: t('weaponArmoireLunarSceptreNotes', {con: 7, int: 7}), value: 100, con: 7, int: 7, set: 'soothing', canOwn: ((u)-> u.items.gear.owned.weapon_armoire_lunarSceptre?)
|
||||
rancherLasso: twoHanded:true, text: t('weaponArmoireRancherLassoText'), notes: t('weaponArmoireRancherLassoNotes', {str: 5, per: 5, int: 5}), value: 100, str: 5, per: 5, int: 5, set: 'rancher', canOwn: ((u)-> u.items.gear.owned.weapon_armoire_rancherLasso?)
|
||||
mythmakerSword: text: t('weaponArmoireMythmakerSwordText'), notes: t('weaponArmoireMythmakerSwordNotes', {attrs: 6}), value: 100, str: 6, per: 6, set: 'goldenToga', canOwn: ((u)-> u.items.gear.owned.weapon_armoire_mythmakerSword?)
|
||||
ironCrook: text: t('weaponArmoireIronCrookText'), notes: t('weaponArmoireIronCrookNotes', {attrs: 7}), value: 100, str: 7, per: 7, set: 'hornedIron', canOwn: ((u)-> u.items.gear.owned.weapon_armoire_ironCrook?)
|
||||
goldWingStaff: text: t('weaponArmoireGoldWingStaffText'), notes: t('weaponArmoireGoldWingStaffNotes', {attrs:4}), value: 100, con: 4, int: 4, per: 4, str: 4, canOwn: ((u)-> u.items.gear.owned.weapon_armoire_goldWingStaff?)
|
||||
|
||||
armor:
|
||||
base:
|
||||
0: text: t('armorBase0Text'), notes: t('armorBase0Notes'), value:0
|
||||
warrior:
|
||||
#0: text: "Plain Clothing", notes:'Ordinary clothing. Confers no benefit.', value:0
|
||||
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:
|
||||
#0: text: "Plain Clothing", notes:'Ordinary clothing. Confers no benefit.', value:0
|
||||
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:
|
||||
#0: text: "Apprentice Garb", notes:'For students of magic. Confers no benefit.', value:0
|
||||
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:
|
||||
#0: text: "Novice Robe", notes:'For healers in training. Confers no benefit.', value:0
|
||||
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:
|
||||
# Backer, Contributor, and Quest Rewards
|
||||
0: text: t('armorSpecial0Text'), notes: t('armorSpecial0Notes', {con: 20}), con: 20, value:150, canOwn: ((u)-> +u.backer?.tier >= 45)
|
||||
1: text: t('armorSpecial1Text'), notes: t('armorSpecial1Notes', {attrs: 6}), con: 6, str: 6, per: 6, int: 6, value:170, canOwn: ((u)-> +u.contributor?.level >= 2)
|
||||
2: text: t('armorSpecial2Text'), notes: t('armorSpecial2Notes', {attrs: 25}), int: 25, con: 25, value:200, canOwn: ((u)-> +u.backer?.tier >= 300 or u.items.gear.owned.armor_special_2?)
|
||||
#Winter event
|
||||
finnedOceanicArmor: text: t('armorSpecialFinnedOceanicArmorText'), notes: t('armorSpecialFinnedOceanicArmorNotes', {str: 15}), str: 15, value: 130, canOwn: ((u)-> u.items.gear.owned.armor_special_finnedOceanicArmor?)
|
||||
# Winter Wonderland
|
||||
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
|
||||
@@ -197,12 +210,12 @@ gear =
|
||||
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
|
||||
# Summer
|
||||
# Summer Splash
|
||||
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
|
||||
# Fall
|
||||
# Fall Festival
|
||||
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
|
||||
@@ -239,47 +252,50 @@ gear =
|
||||
201503: text: t('armorMystery201503Text'), notes: t('armorMystery201503Notes'), mystery:'201503', value: 0
|
||||
201504: text: t('armorMystery201504Text'), notes: t('armorMystery201504Notes'), mystery:'201504', value: 0
|
||||
201506: text: t('armorMystery201506Text'), notes: t('armorMystery201506Notes'), mystery:'201506', value: 0
|
||||
201508: text: t('armorMystery201508Text'), notes: t('armorMystery201508Notes'), mystery:'201508', value: 0, int: 0
|
||||
301404: text: t('armorMystery301404Text'), notes: t('armorMystery301404Notes'), mystery:'301404', value: 0
|
||||
armoire:
|
||||
lunarArmor: text: t('armorArmoireLunarArmorText'), notes: t('armorArmoireLunarArmorNotes', {str: 7, int: 7}), value: 100, str: 7, int: 7, set: 'soothing', canOwn: ((u)-> u.items.gear.owned.armor_armoire_lunarArmor?)
|
||||
gladiatorArmor: text: t('armorArmoireGladiatorArmorText'), notes: t('armorArmoireGladiatorArmorNotes', {str: 7, per: 7}), value: 100, str: 7, per: 7, set: 'gladiator', canOwn: ((u)-> u.items.gear.owned.armor_armoire_gladiatorArmor?)
|
||||
rancherRobes: text: t('armorArmoireRancherRobesText'), notes: t('armorArmoireRancherRobesNotes', {str: 5, per: 5, int: 5}), value: 100, str: 5, per: 5, int: 5, set: 'rancher', canOwn: ((u)-> u.items.gear.owned.armor_armoire_rancherRobes?)
|
||||
goldenToga: text: t('armorArmoireGoldenTogaText'), notes: t('armorArmoireGoldenTogaNotes', {attrs: 8}), value: 100, str: 8, con: 8, set: 'goldenToga', canOwn: ((u)-> u.items.gear.owned.armor_armoire_goldenToga?)
|
||||
hornedIronArmor: text: t('armorArmoireHornedIronArmorText'), notes: t('armorArmoireHornedIronArmorNotes', {con: 9, per: 7}), value: 100, con: 9, per: 7, set: 'hornedIron', canOwn: ((u)-> u.items.gear.owned.armor_armoire_hornedIronArmor?)
|
||||
plagueDoctorOvercoat: text: t('armorArmoirePlagueDoctorOvercoatText'), notes: t('armorArmoirePlagueDoctorOvercoatNotes', {int: 6, str: 5, con: 6}), int: 6, str: 5, con: 6, set: 'plagueDoctor', canOwn: ((u)-> u.items.gear.owned.armor_armoire_plagueDoctorOvercoat?)
|
||||
|
||||
head:
|
||||
base:
|
||||
0: text: t('headBase0Text'), notes: t('headBase0Notes'), value:0
|
||||
warrior:
|
||||
#0: text: "No Helm", notes:'No headgear.', value:0
|
||||
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:
|
||||
#0: text: "No Hood", notes:'No headgear.', value:0
|
||||
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:
|
||||
#0: text: "No Hat", notes:'No headgear.', value:0
|
||||
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:
|
||||
#0: text: "No Circlet", notes:'No headgear.', value:0
|
||||
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:
|
||||
# Backer, Contributor, and Quest Rewards
|
||||
0: text: t('headSpecial0Text'), notes: t('headSpecial0Notes', {int: 20}), int: 20, value:150, canOwn: ((u)-> +u.backer?.tier >= 45)
|
||||
1: text: t('headSpecial1Text'), notes: t('headSpecial1Notes', {attrs: 6}), con: 6, str: 6, per: 6, int: 6, value:170, canOwn: ((u)-> +u.contributor?.level >= 3)
|
||||
2: text: t('headSpecial2Text'), notes: t('headSpecial2Notes', {attrs: 25}), int: 25, str: 25, value:200, canOwn: ((u)-> (+u.backer?.tier >= 300) or u.items.gear.owned.head_special_2?)
|
||||
#Winter event
|
||||
fireCoralCirclet: text: t('headSpecialFireCoralCircletText'), notes: t('headSpecialFireCoralCircletNotes', {per: 15}), per: 15, value: 130, canOwn: ((u)-> u.items.gear.owned.head_special_fireCoralCirclet?)
|
||||
# Winter Wonderland
|
||||
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
|
||||
@@ -290,12 +306,12 @@ gear =
|
||||
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
|
||||
# Summer
|
||||
# Summer Splash
|
||||
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
|
||||
# Fall
|
||||
# Fall Festival
|
||||
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
|
||||
@@ -328,6 +344,7 @@ gear =
|
||||
201412: text: t('headMystery201412Text'), notes: t('headMystery201412Notes'), mystery:'201412', value: 0
|
||||
201501: text: t('headMystery201501Text'), notes: t('headMystery201501Notes'), mystery:'201501', value: 0
|
||||
201505: text: t('headMystery201505Text'), notes: t('headMystery201505Notes'), mystery:'201505', value: 0
|
||||
201508: text: t('headMystery201508Text'), notes: t('headMystery201508Notes'), mystery:'201508', value: 0, int: 0
|
||||
301404: text: t('headMystery301404Text'), notes: t('headMystery301404Notes'), mystery:'301404', value: 0
|
||||
301405: text: t('headMystery301405Text'), notes: t('headMystery301405Notes'), mystery:'301405', value: 0
|
||||
armoire:
|
||||
@@ -335,7 +352,14 @@ gear =
|
||||
redHairbow: text: t('headArmoireRedHairbowText'), notes: t('headArmoireRedHairbowNotes', {str: 5, int: 5, con: 5}), value: 100, str: 5, int: 5, con: 5, canOwn: ((u)-> u.items.gear.owned.head_armoire_redHairbow?)
|
||||
violetFloppyHat: text: t('headArmoireVioletFloppyHatText'), notes: t('headArmoireVioletFloppyHatNotes', {per: 5, int: 5, con: 5}), value: 100, per: 5, int: 5, con: 5, canOwn: ((u)-> u.items.gear.owned.head_armoire_violetFloppyHat?)
|
||||
gladiatorHelm: text: t('headArmoireGladiatorHelmText'), notes: t('headArmoireGladiatorHelmNotes', {per: 7, int: 7}), value: 100, per: 7, int: 7, set: 'gladiator', canOwn: ((u)-> u.items.gear.owned.head_armoire_gladiatorHelm?)
|
||||
rancherHat: text: t('headArmoireRancherHatText'), notes: t('headArmoireRancherHatNotes', {str: 5, per: 5, int: 5}), value: 100, str: 5, per: 5, int: 5, canOwn: ((u)-> u.items.gear.owned.head_armoire_rancherHat?)
|
||||
rancherHat: text: t('headArmoireRancherHatText'), notes: t('headArmoireRancherHatNotes', {str: 5, per: 5, int: 5}), value: 100, str: 5, per: 5, int: 5, set: 'rancher', canOwn: ((u)-> u.items.gear.owned.head_armoire_rancherHat?)
|
||||
royalCrown: text: t('headArmoireRoyalCrownText'), notes: t('headArmoireRoyalCrownNotes', {str: 10}), value: 100, str: 10, canOwn: ((u)-> u.items.gear.owned.head_armoire_royalCrown?)
|
||||
blueHairbow: text: t('headArmoireBlueHairbowText'), notes: t('headArmoireBlueHairbowNotes', {per: 5, int: 5, con: 5}), value: 100, per: 5, int: 5, con: 5, canOwn: ((u)-> u.items.gear.owned.head_armoire_blueHairbow?)
|
||||
goldenLaurels: text: t('headArmoireGoldenLaurelsText'), notes: t('headArmoireGoldenLaurelsNotes', {attrs: 8}), value: 100, per: 8, con: 8, set: 'goldenToga', canOwn: ((u)-> u.items.gear.owned.head_armoire_goldenLaurels?)
|
||||
hornedIronHelm: text: t('headArmoireHornedIronHelmText'), notes: t('headArmoireHornedIronHelmNotes', {con: 9, str: 7}), value: 100, con: 9, str:7, set: 'hornedIron', canOwn: ((u)-> u.items.gear.owned.head_armoire_hornedIronHelm?)
|
||||
yellowHairbow: text: t('headArmoireYellowHairbowText'), notes: t('headArmoireYellowHairbowNotes', {attrs: 5}), int: 5, per: 5, str: 5, canOwn: ((u)-> u.items.gear.owned.head_armoire_yellowHairbow?)
|
||||
redFloppyHat: text: t('headArmoireRedFloppyHatText'), notes: t('headArmoireRedFloppyHatNotes', {attrs: 6}), con: 6, int: 6, per: 6, canOwn: ((u)-> u.items.gear.owned.head_armoire_redFloppyHat?)
|
||||
plagueDoctorHat: text: t('headArmoirePlagueDoctorHatText'), notes: t('headArmoirePlagueDoctorHatNotes', {int: 5, str: 6, con: 5}), int: 5, str: 6, con: 5, set: 'plagueDoctor', canOwn: ((u)-> u.items.gear.owned.head_armoire_plagueDoctorHat?)
|
||||
|
||||
shield:
|
||||
base:
|
||||
@@ -366,22 +390,24 @@ gear =
|
||||
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:
|
||||
# Backer, Contributor, and Quest Rewards
|
||||
0: text: t('shieldSpecial0Text'), notes: t('shieldSpecial0Notes', {per: 20}), per: 20, value:150, canOwn: ((u)-> +u.backer?.tier >= 45)
|
||||
1: text: t('shieldSpecial1Text'), notes: t('shieldSpecial1Notes', {attrs: 6}), con: 6, str: 6, per: 6, int:6, value:170, canOwn: ((u)-> +u.contributor?.level >= 5)
|
||||
goldenknight: text: t('shieldSpecialGoldenknightText'), notes: t('shieldSpecialGoldenknightNotes', {attrs: 25}), con: 25, per: 25, value:200, canOwn: ((u)-> u.items.gear.owned.shield_special_goldenknight?)
|
||||
#Winter event
|
||||
moonpearlShield: text: t('shieldSpecialMoonpearlShieldText'), notes: t('shieldSpecialMoonpearlShieldNotes', {con: 15}), con: 15, value: 130, canOwn: ((u)-> u.items.gear.owned.shield_special_moonpearlShield?)
|
||||
# Winter Wonderland
|
||||
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
|
||||
#Spring Fling
|
||||
# Spring Fling
|
||||
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
|
||||
#Summer
|
||||
# Summer Splash
|
||||
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
|
||||
#Fall
|
||||
# Fall Festival
|
||||
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
|
||||
@@ -410,6 +436,7 @@ gear =
|
||||
201404: text: t('backMystery201404Text'), notes: t('backMystery201404Notes'), mystery:'201404', value: 0
|
||||
201410: text: t('backMystery201410Text'), notes: t('backMystery201410Notes'), mystery:'201410', value: 0
|
||||
201504: text: t('backMystery201504Text'), notes: t('backMystery201504Notes'), mystery:'201504', value: 0
|
||||
201507: text: t('backMystery201507Text'), notes: t('backMystery201507Notes'), mystery:'201507', 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'
|
||||
@@ -472,12 +499,15 @@ gear =
|
||||
mystery:
|
||||
201503: text: t('eyewearMystery201503Text'), notes: t('eyewearMystery201503Notes'), mystery:'201503', value: 0
|
||||
201506: text: t('eyewearMystery201506Text'), notes: t('eyewearMystery201506Notes'), mystery:'201506', value: 0
|
||||
201507: text: t('eyewearMystery201507Text'), notes: t('eyewearMystery201507Notes'), mystery:'201507', value: 0
|
||||
301404: text: t('eyewearMystery301404Text'), notes: t('eyewearMystery301404Notes'), mystery:'301404', value: 0
|
||||
301405: text: t('eyewearMystery301405Text'), notes: t('eyewearMystery301405Notes'), mystery:'301405', value: 0
|
||||
armoire:
|
||||
plagueDoctorMask: text: t('eyewearArmoirePlagueDoctorMaskText'), notes: t('eyewearArmoirePlagueDoctorMaskNotes'), set: 'plagueDoctor', canOwn: ((u)-> u.items.gear.owned.eyewear_armoire_plagueDoctorMask?)
|
||||
|
||||
###
|
||||
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
|
||||
they are needed in different forms at different points in the app
|
||||
###
|
||||
api.gear =
|
||||
tree: gear
|
||||
@@ -521,8 +551,23 @@ api.timeTravelerStore = (owned) ->
|
||||
---------------------------------------------------------------
|
||||
###
|
||||
|
||||
api.potion = type: 'potion', text: t('potionText'), notes: t('potionNotes'), value: 25, key: 'potion'
|
||||
api.armoire = type: 'armoire', text: t('armoireText'), notes: t('armoireNotesEmpty'), value: 100, key: 'armoire', canOwn: ((u)-> _.contains(u.achievements.ultimateGearSets, true))
|
||||
api.potion =
|
||||
type: 'potion',
|
||||
text: t('potionText'),
|
||||
notes: t('potionNotes'),
|
||||
value: 25,
|
||||
key: 'potion'
|
||||
|
||||
api.armoire =
|
||||
type: 'armoire',
|
||||
text: t('armoireText'),
|
||||
notes: ((user, count)->
|
||||
return t('armoireNotesEmpty')() if (user.flags.armoireEmpty)
|
||||
return t('armoireNotesFull')() + count
|
||||
),
|
||||
value: 100,
|
||||
key: 'armoire',
|
||||
canOwn: ((u)-> _.contains(u.achievements.ultimateGearSets, true))
|
||||
|
||||
###
|
||||
---------------------------------------------------------------
|
||||
@@ -900,6 +945,7 @@ api.spells =
|
||||
if !target.items.special.nyeReceived
|
||||
target.items.special.nyeReceived = []
|
||||
target.items.special.nyeReceived.push user.profile.name
|
||||
target.flags.cardReceived = true
|
||||
|
||||
target.markModified? 'items.special.nyeReceived'
|
||||
user.stats.gp -= 10
|
||||
@@ -923,10 +969,75 @@ api.spells =
|
||||
if !target.items.special.valentineReceived
|
||||
target.items.special.valentineReceived = []
|
||||
target.items.special.valentineReceived.push user.profile.name
|
||||
target.flags.cardReceived = true
|
||||
|
||||
target.markModified? 'items.special.valentineReceived'
|
||||
user.stats.gp -= 10
|
||||
|
||||
greeting:
|
||||
text: t('greetingCard')
|
||||
mana: 0
|
||||
value: 10
|
||||
immediateUse: true
|
||||
silent: true
|
||||
target: 'user'
|
||||
notes: t('greetingCardNotes')
|
||||
cast: (user, target) ->
|
||||
if user == target
|
||||
user.achievements.greeting ?= 0
|
||||
user.achievements.greeting++
|
||||
else
|
||||
_.each [user,target], (t)->
|
||||
t.achievements.greeting ?= 0
|
||||
t.achievements.greeting++
|
||||
if !target.items.special.greetingReceived
|
||||
target.items.special.greetingReceived = []
|
||||
target.items.special.greetingReceived.push user.profile.name
|
||||
target.flags.cardReceived = true
|
||||
|
||||
target.markModified? 'items.special.greetingReceived'
|
||||
user.stats.gp -= 10
|
||||
|
||||
thankyou:
|
||||
text: t('thankyouCard')
|
||||
mana: 0
|
||||
value: 10
|
||||
immediateUse: true
|
||||
silent: true
|
||||
target: 'user'
|
||||
notes: t('thankyouCardNotes')
|
||||
cast: (user, target) ->
|
||||
if user == target
|
||||
user.achievements.thankyou ?= 0
|
||||
user.achievements.thankyou++
|
||||
else
|
||||
_.each [user,target], (t)->
|
||||
t.achievements.thankyou ?= 0
|
||||
t.achievements.thankyou++
|
||||
if !target.items.special.thankyouReceived
|
||||
target.items.special.thankyouReceived = []
|
||||
target.items.special.thankyouReceived.push user.profile.name
|
||||
target.flags.cardReceived = true
|
||||
|
||||
target.markModified? 'items.special.thankyouReceived'
|
||||
user.stats.gp -= 10
|
||||
|
||||
api.cardTypes =
|
||||
greeting:
|
||||
key: 'greeting'
|
||||
messageOptions: 4
|
||||
yearRound: true
|
||||
nye:
|
||||
key: 'nye'
|
||||
messageOptions: 5
|
||||
thankyou:
|
||||
key: 'thankyou'
|
||||
messageOptions: 4
|
||||
yearRound: true
|
||||
valentine:
|
||||
key: 'valentine'
|
||||
messageOptions: 4
|
||||
|
||||
# Intercept all spells to reduce user.stats.mp after casting the spell
|
||||
_.each api.spells, (spellClass) ->
|
||||
_.each spellClass, (spell, key) ->
|
||||
@@ -956,6 +1067,7 @@ api.dropEggs =
|
||||
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, (egg,key) ->
|
||||
_.defaults egg,
|
||||
canBuy:true
|
||||
@@ -984,6 +1096,8 @@ api.questEggs =
|
||||
Slime: text: t('questEggSlimeText'), adjective: t('questEggSlimeAdjective'), canBuy: false
|
||||
Sheep: text: t('questEggSheepText'), adjective: t('questEggSheepAdjective'), canBuy: false
|
||||
Cuttlefish: text: t('questEggCuttlefishText'), adjective: t('questEggCuttlefishAdjective'), canBuy: false
|
||||
Whale: text: t('questEggWhaleText'), adjective: t('questEggWhaleAdjective'), canBuy: false
|
||||
Cheetah: text: t('questEggCheetahText'), adjective: t('questEggCheetahAdjective'), canBuy: false
|
||||
|
||||
_.each api.questEggs, (egg,key) ->
|
||||
_.defaults egg,
|
||||
@@ -1005,13 +1119,16 @@ api.specialPets =
|
||||
'MantisShrimp-Base': 'mantisShrimp'
|
||||
'JackOLantern-Base': 'jackolantern'
|
||||
'Mammoth-Base': 'mammoth'
|
||||
'Tiger-Veteran': 'veteranTiger'
|
||||
|
||||
api.specialMounts =
|
||||
'BearCub-Polar': 'polarBear'
|
||||
'LionCub-Ethereal': 'etherealLion'
|
||||
'MantisShrimp-Base': 'mantisShrimp'
|
||||
'Turkey-Base': 'turkey'
|
||||
'Mammoth-Base': 'mammoth'
|
||||
'BearCub-Polar': 'polarBear'
|
||||
'LionCub-Ethereal': 'etherealLion'
|
||||
'MantisShrimp-Base': 'mantisShrimp'
|
||||
'Turkey-Base': 'turkey'
|
||||
'Mammoth-Base': 'mammoth'
|
||||
'Orca-Base': 'orca'
|
||||
'Gryphon-RoyalPurple': 'royalPurpleGryphon'
|
||||
|
||||
api.hatchingPotions =
|
||||
Base: value: 2, text: t('hatchingPotionBase')
|
||||
@@ -1094,6 +1211,7 @@ api.quests =
|
||||
completion: t("questDilatoryCompletion")
|
||||
value: 0
|
||||
canBuy: false
|
||||
category: 'world'
|
||||
boss:
|
||||
name: t("questDilatoryBoss")
|
||||
# We ran an average of progress{up,down} on users over 5 days: {up:805025,down:1324423}. /5*30 (we want the
|
||||
@@ -1136,6 +1254,7 @@ api.quests =
|
||||
completionChat: t("questStressbeastCompletionChat")
|
||||
value: 0
|
||||
canBuy: false
|
||||
category: 'world'
|
||||
boss:
|
||||
name: t("questStressbeastBoss")
|
||||
hp: 2750000
|
||||
@@ -1179,7 +1298,7 @@ api.quests =
|
||||
notes: t('questEvilSantaNotes')
|
||||
completion: t('questEvilSantaCompletion')
|
||||
value: 4 # Gem cost to buy, GP sell-back
|
||||
#mechanic: enum['perfectDailies', ...]
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questEvilSantaBoss') # name of the boss himself (eg, Vice)
|
||||
hp: 300
|
||||
@@ -1198,6 +1317,7 @@ api.quests =
|
||||
completion: t('questEvilSanta2Completion')
|
||||
value: 4
|
||||
previous: 'evilsanta'
|
||||
category: 'pet'
|
||||
collect:
|
||||
tracks: text: t('questEvilSanta2CollectTracks'), count: 20
|
||||
branches: text: t('questEvilSanta2CollectBranches'), count: 10
|
||||
@@ -1213,6 +1333,7 @@ api.quests =
|
||||
notes: t('questGryphonNotes')
|
||||
completion: t('questGryphonCompletion')
|
||||
value: 4 # Gem cost to buy, GP sell-back
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questGryphonBoss') # name of the boss himself (eg, Vice)
|
||||
hp: 300
|
||||
@@ -1232,6 +1353,7 @@ api.quests =
|
||||
notes: t('questHedgehogNotes')
|
||||
completion: t('questHedgehogCompletion')
|
||||
value: 4 # Gem cost to buy, GP sell-back
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questHedgehogBoss') # name of the boss himself (eg, Vice)
|
||||
hp: 400
|
||||
@@ -1251,6 +1373,7 @@ api.quests =
|
||||
notes: t('questGhostStagNotes')
|
||||
completion: t('questGhostStagCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questGhostStagBoss')
|
||||
hp: 1200
|
||||
@@ -1270,6 +1393,7 @@ api.quests =
|
||||
notes: t('questVice1Notes')
|
||||
value: 4
|
||||
lvl: 30
|
||||
category: 'unlockable'
|
||||
boss:
|
||||
name: t('questVice1Boss')
|
||||
hp: 750
|
||||
@@ -1285,7 +1409,8 @@ api.quests =
|
||||
text: t('questVice2Text')
|
||||
notes: t('questVice2Notes')
|
||||
value: 4
|
||||
lvl: 35
|
||||
lvl: 30
|
||||
category: 'unlockable'
|
||||
previous: 'vice1'
|
||||
collect:
|
||||
lightCrystal: text: t('questVice2CollectLightCrystal'), count: 45
|
||||
@@ -1302,7 +1427,8 @@ api.quests =
|
||||
completion: t('questVice3Completion')
|
||||
previous: 'vice2'
|
||||
value: 4
|
||||
lvl: 40
|
||||
lvl: 30
|
||||
category: 'unlockable'
|
||||
boss:
|
||||
name: t('questVice3Boss')
|
||||
hp: 1500
|
||||
@@ -1324,6 +1450,7 @@ api.quests =
|
||||
completion: t('questEggHuntCompletion')
|
||||
value: 1
|
||||
canBuy: false
|
||||
category: 'pet'
|
||||
collect:
|
||||
plainEgg: text: t('questEggHuntCollectPlainEgg'), count: 100
|
||||
drop:
|
||||
@@ -1347,6 +1474,7 @@ api.quests =
|
||||
notes: t('questRatNotes')
|
||||
completion: t('questRatCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questRatBoss')
|
||||
hp: 1200
|
||||
@@ -1366,6 +1494,7 @@ api.quests =
|
||||
notes: t('questOctopusNotes')
|
||||
completion: t('questOctopusCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questOctopusBoss')
|
||||
hp: 1200
|
||||
@@ -1385,6 +1514,7 @@ api.quests =
|
||||
notes: t('questSeahorseNotes')
|
||||
completion: t('questSeahorseCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questSeahorseBoss')
|
||||
hp: 300
|
||||
@@ -1404,6 +1534,7 @@ api.quests =
|
||||
notes: t('questAtom1Notes')
|
||||
value: 4
|
||||
lvl: 15
|
||||
category: 'unlockable'
|
||||
collect:
|
||||
soapBars: text: t('questAtom1CollectSoapBars'), count: 20
|
||||
drop:
|
||||
@@ -1418,6 +1549,7 @@ api.quests =
|
||||
previous: 'atom1'
|
||||
value: 4
|
||||
lvl: 15
|
||||
category: 'unlockable'
|
||||
boss:
|
||||
name: t('questAtom2Boss')
|
||||
hp: 300
|
||||
@@ -1435,6 +1567,7 @@ api.quests =
|
||||
completion: t('questAtom3Completion')
|
||||
value: 4
|
||||
lvl: 15
|
||||
category: 'unlockable'
|
||||
boss:
|
||||
name: t('questAtom3Boss')
|
||||
hp: 800
|
||||
@@ -1453,6 +1586,7 @@ api.quests =
|
||||
notes: t('questHarpyNotes')
|
||||
completion: t('questHarpyCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questHarpyBoss')
|
||||
hp: 600
|
||||
@@ -1472,6 +1606,7 @@ api.quests =
|
||||
notes: t('questRoosterNotes')
|
||||
completion: t('questRoosterCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questRoosterBoss')
|
||||
hp: 300
|
||||
@@ -1491,6 +1626,7 @@ api.quests =
|
||||
notes: t('questSpiderNotes')
|
||||
completion: t('questSpiderCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questSpiderBoss')
|
||||
hp: 400
|
||||
@@ -1510,6 +1646,7 @@ api.quests =
|
||||
notes: t('questMoonstone1Notes')
|
||||
value: 4
|
||||
lvl: 60
|
||||
category: 'unlockable'
|
||||
collect:
|
||||
moonstone: text: t('questMoonstone1CollectMoonstone'), count: 500
|
||||
drop:
|
||||
@@ -1522,8 +1659,9 @@ api.quests =
|
||||
text: t('questMoonstone2Text')
|
||||
notes: t('questMoonstone2Notes')
|
||||
value: 4
|
||||
lvl: 65
|
||||
lvl: 60
|
||||
previous: 'moonstone1'
|
||||
category: 'unlockable'
|
||||
boss:
|
||||
name: t('questMoonstone2Boss')
|
||||
hp: 1500
|
||||
@@ -1540,7 +1678,8 @@ api.quests =
|
||||
completion: t('questMoonstone3Completion')
|
||||
previous: 'moonstone2'
|
||||
value: 4
|
||||
lvl: 70
|
||||
lvl: 60
|
||||
category: 'unlockable'
|
||||
boss:
|
||||
name: t('questMoonstone3Boss')
|
||||
hp: 2000
|
||||
@@ -1565,6 +1704,7 @@ api.quests =
|
||||
notes: t('questGoldenknight1Notes')
|
||||
value: 4
|
||||
lvl: 40
|
||||
category: 'unlockable'
|
||||
collect:
|
||||
testimony: text: t('questGoldenknight1CollectTestimony'), count: 300
|
||||
drop:
|
||||
@@ -1578,7 +1718,8 @@ api.quests =
|
||||
notes: t('questGoldenknight2Notes')
|
||||
value: 4
|
||||
previous: 'goldenknight1'
|
||||
lvl: 45
|
||||
lvl: 40
|
||||
category: 'unlockable'
|
||||
boss:
|
||||
name: t('questGoldenknight2Boss')
|
||||
hp: 1000
|
||||
@@ -1595,7 +1736,8 @@ api.quests =
|
||||
completion: t('questGoldenknight3Completion')
|
||||
previous: 'goldenknight2'
|
||||
value: 4
|
||||
lvl: 50
|
||||
lvl: 40
|
||||
category: 'unlockable'
|
||||
boss:
|
||||
name: t('questGoldenknight3Boss')
|
||||
hp: 1700
|
||||
@@ -1616,8 +1758,11 @@ api.quests =
|
||||
text: t('questBasilistText')
|
||||
notes: t('questBasilistNotes')
|
||||
completion: t('questBasilistCompletion')
|
||||
canBuy: false
|
||||
value: 4
|
||||
category: 'unlockable'
|
||||
unlockCondition:
|
||||
condition: 'party invite'
|
||||
text: t('inviteFriends')
|
||||
boss:
|
||||
name: t('questBasilistBoss')
|
||||
hp: 100
|
||||
@@ -1631,6 +1776,7 @@ api.quests =
|
||||
notes: t('questOwlNotes')
|
||||
completion: t('questOwlCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questOwlBoss')
|
||||
hp: 500
|
||||
@@ -1650,6 +1796,7 @@ api.quests =
|
||||
notes: t('questPenguinNotes')
|
||||
completion: t('questPenguinCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questPenguinBoss')
|
||||
hp: 400
|
||||
@@ -1669,6 +1816,7 @@ api.quests =
|
||||
notes: t('questTRexNotes')
|
||||
completion: t('questTRexCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questTRexBoss')
|
||||
hp: 800
|
||||
@@ -1688,6 +1836,7 @@ api.quests =
|
||||
notes: t('questTRexUndeadNotes')
|
||||
completion: t('questTRexUndeadCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questTRexUndeadBoss')
|
||||
hp: 500
|
||||
@@ -1713,6 +1862,7 @@ api.quests =
|
||||
notes: t('questRockNotes')
|
||||
completion: t('questRockCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questRockBoss')
|
||||
hp: 400
|
||||
@@ -1732,6 +1882,7 @@ api.quests =
|
||||
notes: t('questBunnyNotes')
|
||||
completion: t('questBunnyCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questBunnyBoss')
|
||||
hp: 300
|
||||
@@ -1751,6 +1902,7 @@ api.quests =
|
||||
notes: t('questSlimeNotes')
|
||||
completion: t('questSlimeCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questSlimeBoss')
|
||||
hp: 400
|
||||
@@ -1770,6 +1922,7 @@ api.quests =
|
||||
notes: t('questSheepNotes')
|
||||
completion: t('questSheepCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questSheepBoss')
|
||||
hp: 300
|
||||
@@ -1789,6 +1942,7 @@ api.quests =
|
||||
notes: t('questKrakenNotes')
|
||||
completion: t('questKrakenCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questKrakenBoss')
|
||||
hp: 800
|
||||
@@ -1803,6 +1957,110 @@ api.quests =
|
||||
exp: 500
|
||||
unlock: t('questKrakenUnlockText')
|
||||
|
||||
whale:
|
||||
text: t('questWhaleText')
|
||||
notes: t('questWhaleNotes')
|
||||
completion: t('questWhaleCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questWhaleBoss')
|
||||
hp: 500
|
||||
str: 1.5
|
||||
drop:
|
||||
items: [
|
||||
{type: 'eggs', key: 'Whale', text: t('questWhaleDropWhaleEgg')}
|
||||
{type: 'eggs', key: 'Whale', text: t('questWhaleDropWhaleEgg')}
|
||||
{type: 'eggs', key: 'Whale', text: t('questWhaleDropWhaleEgg')}
|
||||
]
|
||||
gp: 37
|
||||
exp: 275
|
||||
unlock: t('questWhaleUnlockText')
|
||||
|
||||
dilatoryDistress1:
|
||||
text: t('questDilatoryDistress1Text')
|
||||
notes: t('questDilatoryDistress1Notes')
|
||||
completion: t('questDilatoryDistress1Completion')
|
||||
value: 4
|
||||
goldValue: 200
|
||||
category: 'gold'
|
||||
collect:
|
||||
fireCoral: text: t('questDilatoryDistress1CollectFireCoral'), count: 25
|
||||
blueFins: text: t('questDilatoryDistress1CollectBlueFins'), count: 25
|
||||
drop:
|
||||
items: [
|
||||
{type: 'gear', key: "armor_special_finnedOceanicArmor", text: t('questDilatoryDistress1DropArmor')}
|
||||
]
|
||||
gp: 0
|
||||
exp: 75
|
||||
dilatoryDistress2:
|
||||
text: t('questDilatoryDistress2Text')
|
||||
notes: t('questDilatoryDistress2Notes')
|
||||
completion: t('questDilatoryDistress2Completion')
|
||||
previous: 'dilatoryDistress1'
|
||||
value: 4
|
||||
goldValue: 300
|
||||
category: 'gold'
|
||||
boss:
|
||||
name: t('questDilatoryDistress2Boss')
|
||||
hp: 500
|
||||
rage:
|
||||
title: t("questDilatoryDistress2RageTitle")
|
||||
description: t("questDilatoryDistress2RageDescription")
|
||||
value: 50
|
||||
healing: .3
|
||||
effect:t('questDilatoryDistress2RageEffect')
|
||||
drop:
|
||||
items: [
|
||||
{type: 'hatchingPotions', key: 'Skeleton', text: t('questDilatoryDistress2DropSkeletonPotion')}
|
||||
{type: 'hatchingPotions', key: 'CottonCandyBlue', text: t('questDilatoryDistress2DropCottonCandyBluePotion')}
|
||||
{type: 'gear', key: "head_special_fireCoralCirclet", text: t('questDilatoryDistress2DropHeadgear')}
|
||||
]
|
||||
gp: 0
|
||||
exp: 500
|
||||
dilatoryDistress3:
|
||||
text: t('questDilatoryDistress3Text')
|
||||
notes: t('questDilatoryDistress3Notes')
|
||||
completion: t('questDilatoryDistress3Completion')
|
||||
previous: 'dilatoryDistress2'
|
||||
value: 4
|
||||
goldValue: 400
|
||||
category: 'gold'
|
||||
boss:
|
||||
name: t('questDilatoryDistress3Boss')
|
||||
hp: 1000
|
||||
str: 2
|
||||
drop:
|
||||
items: [
|
||||
{type: 'food', key: 'Fish', text: t('questDilatoryDistress3DropFish')}
|
||||
{type: 'food', key: 'Fish', text: t('questDilatoryDistress3DropFish')}
|
||||
{type: 'food', key: 'Fish', text: t('questDilatoryDistress3DropFish')}
|
||||
{type: 'gear', key: "weapon_special_tridentOfCrashingTides", text: t('questDilatoryDistress3DropWeapon')}
|
||||
{type: 'gear', key: "shield_special_moonpearlShield", text: t('questDilatoryDistress3DropShield')}
|
||||
]
|
||||
gp: 0
|
||||
exp: 650
|
||||
|
||||
cheetah:
|
||||
text: t('questCheetahText')
|
||||
notes: t('questCheetahNotes')
|
||||
completion: t('questCheetahCompletion')
|
||||
value: 4
|
||||
category: 'pet'
|
||||
boss:
|
||||
name: t('questCheetahBoss')
|
||||
hp: 600
|
||||
str: 1.5
|
||||
drop:
|
||||
items: [
|
||||
{type: 'eggs', key: 'Cheetah', text: t('questCheetahDropCheetahEgg')}
|
||||
{type: 'eggs', key: 'Cheetah', text: t('questCheetahDropCheetahEgg')}
|
||||
{type: 'eggs', key: 'Cheetah', text: t('questCheetahDropCheetahEgg')}
|
||||
]
|
||||
gp: 43
|
||||
exp: 350
|
||||
unlock: t('questCheetahUnlockText')
|
||||
|
||||
_.each api.quests, (v,key) ->
|
||||
_.defaults v, {key,canBuy:true}
|
||||
b = v.boss
|
||||
@@ -1811,6 +2069,10 @@ _.each api.quests, (v,key) ->
|
||||
if b.rage
|
||||
_.defaults b.rage, {title:t('bossRageTitle'),description:t('bossRageDescription')}
|
||||
|
||||
api.questsByLevel =
|
||||
_.sortBy api.quests, (quest) ->
|
||||
quest.lvl || 0
|
||||
|
||||
api.backgrounds =
|
||||
backgrounds062014:
|
||||
beach:
|
||||
@@ -1952,6 +2214,26 @@ api.backgrounds =
|
||||
sunken_ship:
|
||||
text: t('backgroundSunkenShipText')
|
||||
notes: t('backgroundSunkenShipNotes')
|
||||
backgrounds082015:
|
||||
pyramids:
|
||||
text: t('backgroundPyramidsText')
|
||||
notes: t('backgroundPyramidsNotes')
|
||||
sunset_savannah:
|
||||
text: t('backgroundSunsetSavannahText')
|
||||
notes: t('backgroundSunsetSavannahNotes')
|
||||
twinkly_party_lights:
|
||||
text: t('backgroundTwinklyPartyLightsText')
|
||||
notes: t('backgroundTwinklyPartyLightsNotes')
|
||||
backgrounds092015:
|
||||
market:
|
||||
text: t('backgroundMarketText')
|
||||
notes: t('backgroundMarketNotes')
|
||||
stable:
|
||||
text: t('backgroundStableText')
|
||||
notes: t('backgroundStableNotes')
|
||||
tavern:
|
||||
text: t('backgroundTavernText')
|
||||
notes: t('backgroundTavernNotes')
|
||||
|
||||
api.subscriptionBlocks =
|
||||
basic_earned: months:1, price:5
|
||||
@@ -1970,23 +2252,14 @@ api.userDefaults =
|
||||
]
|
||||
|
||||
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'), value: 10 }
|
||||
# {type: 'reward', text: t('defaultReward2Text'), notes: t('defaultReward2Notes'), value: 10 }
|
||||
]
|
||||
|
||||
tags: [
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
|
||||
require('coffee-script');
|
||||
var _ = require('lodash');
|
||||
var content = require('./content.coffee');
|
||||
|
||||
var DROP_ANIMALS = _.keys(content.pets);
|
||||
|
||||
function beastMasterProgress(pets) {
|
||||
var count = 0;
|
||||
_(DROP_ANIMALS).each(function(animal) {
|
||||
if(pets[animal] > 0 || pets[animal] == -1)
|
||||
count++
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function dropPetsCurrentlyOwned(pets) {
|
||||
var count = 0;
|
||||
|
||||
_(DROP_ANIMALS).each(function(animal) {
|
||||
if(pets[animal] > 0)
|
||||
count++
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
function mountMasterProgress(mounts) {
|
||||
var count = 0;
|
||||
_(DROP_ANIMALS).each(function(animal) {
|
||||
if (mounts[animal])
|
||||
count++
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function remainingGearInSet(userGear, set) {
|
||||
var gear = _.filter(content.gear.flat, function(item) {
|
||||
var setMatches = item.klass === set;
|
||||
var hasItem = userGear[item.key];
|
||||
|
||||
return setMatches && !hasItem;
|
||||
});
|
||||
|
||||
var count = _.size(gear);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
beastMasterProgress: beastMasterProgress,
|
||||
dropPetsCurrentlyOwned: dropPetsCurrentlyOwned,
|
||||
mountMasterProgress: mountMasterProgress,
|
||||
remainingGearInSet: remainingGearInSet
|
||||
};
|
||||
+272
-139
@@ -90,13 +90,12 @@ api.shouldDo = (day, dailyTask, options = {}) ->
|
||||
o = sanitizeOptions options
|
||||
startOfDayWithCDSTime = api.startOfDay(_.defaults {now:day}, o) # a moment()
|
||||
|
||||
# If the Daily does not have a Start Date (old tasks predating the Start Date feature), we assume it starts on the day being checked. This does not cause a bug with the Every X Days option because if the user had edited the task to select X days, then a start date would have been saved to the task at the same time.
|
||||
taskStartDate = dailyTask.startDate || day
|
||||
taskStartDate = moment(dailyTask.startDate).zone(o.timezoneOffset)
|
||||
|
||||
# The time portion of the Start Date is never visible to or modifiable by the user so we must ignore it.
|
||||
# Therefore, we must also ignore the time portion of the user's day start (startOfDayWithCDSTime), otherwise the date comparison will be wrong for some times.
|
||||
# NB: The user's day start date has already been converted to the PREVIOUS day's date if the time portion was before CDS.
|
||||
taskStartDate = moment(taskStartDate).startOf('day');
|
||||
taskStartDate = moment(taskStartDate).startOf('day')
|
||||
|
||||
if taskStartDate > startOfDayWithCDSTime.startOf('day')
|
||||
return false # Daily starts in the future
|
||||
@@ -128,6 +127,14 @@ api.maxLevel = 100
|
||||
api.capByLevel = (lvl) ->
|
||||
if lvl > api.maxLevel then api.maxLevel else lvl
|
||||
|
||||
###
|
||||
------------------------------------------------------
|
||||
Health cap
|
||||
------------------------------------------------------
|
||||
###
|
||||
|
||||
api.maxHealth = 50
|
||||
|
||||
###
|
||||
------------------------------------------------------
|
||||
Scoring
|
||||
@@ -190,7 +197,6 @@ preenHistory = (history) ->
|
||||
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,((m,v,k)->m[v]=k;m), {}
|
||||
#sortOrder.potion = _.size(sortOrder) #potion goes last #actually, _.sortBy puts anything else last, so this is unecessary
|
||||
api.updateStore = (user) ->
|
||||
return unless user
|
||||
changes= []
|
||||
@@ -202,8 +208,6 @@ api.updateStore = (user) ->
|
||||
# Add special items (contrib gear, backer gear, etc)
|
||||
changes = changes.concat _.filter content.gear.flat, (v) ->
|
||||
v.klass in ['special','mystery','armoire'] and !user.items.gear.owned[v.key] and v.canOwn?(user)
|
||||
changes.push content.potion
|
||||
if user.flags.armoireEnabled then changes.push content.armoire
|
||||
# Return sorted store (array)
|
||||
_.sortBy changes, (c)->sortOrder[c.type]
|
||||
|
||||
@@ -390,32 +394,10 @@ api.appliedTags = (userTags, taskTags) ->
|
||||
arr.push(t.name) if taskTags?[t.id]
|
||||
arr.join(', ')
|
||||
|
||||
api.countPets = (originalCount, pets) ->
|
||||
count = if originalCount? then originalCount else _.size(pets)
|
||||
for pet of content.questPets
|
||||
count-- if pets[pet]
|
||||
for pet of content.specialPets
|
||||
count-- if pets[pet]
|
||||
count
|
||||
|
||||
api.countMounts = (originalCount, mounts) ->
|
||||
count2 = if originalCount? then originalCount else _.size(mounts)
|
||||
for mount of content.questPets
|
||||
count2-- if mounts[mount]
|
||||
for mount of content.specialMounts
|
||||
count2-- if mounts[mount]
|
||||
count2
|
||||
|
||||
api.countTriad = (pets) ->
|
||||
count3 = 0
|
||||
for egg of content.dropEggs
|
||||
for potion of content.hatchingPotions
|
||||
if pets[egg + "-" + potion] > 0 then count3++
|
||||
count3
|
||||
|
||||
api.countArmoire = (gear) ->
|
||||
count = _.size(_.filter(content.gear.flat, ((i)->i.klass is 'armoire' and !gear[i.key])))
|
||||
count
|
||||
###
|
||||
Various counting functions
|
||||
###
|
||||
api.count = require('./count')
|
||||
|
||||
###
|
||||
------------------------------------------------------
|
||||
@@ -476,7 +458,7 @@ api.wrap = (user, main=true) ->
|
||||
user.preferences.sleep = !user.preferences.sleep
|
||||
cb? null, {}
|
||||
|
||||
revive: (req, cb) ->
|
||||
revive: (req, cb, analytics) ->
|
||||
return cb?({code:400, message: "Cannot revive if not dead"}) unless user.stats.hp <= 0
|
||||
|
||||
# Reset stats after death
|
||||
@@ -505,7 +487,15 @@ api.wrap = (user, main=true) ->
|
||||
user.items.gear.equipped[item.type] = "#{item.type}_base_0" if user.items.gear.equipped[item.type] is lostItem
|
||||
user.items.gear.costume[item.type] = "#{item.type}_base_0" if user.items.gear.costume[item.type] is lostItem
|
||||
user.markModified? 'items.gear'
|
||||
mixpanel?.track('Death',{'lostItem':lostItem})
|
||||
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
lostItem: lostItem,
|
||||
gaLabel: lostItem,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('Death', analyticsData)
|
||||
|
||||
cb? (if item then {code:200,message: i18n.t('messageLostItem', {itemText: item.text(req.language)}, req.language)} else null), user
|
||||
|
||||
reset: (req, cb) ->
|
||||
@@ -524,14 +514,14 @@ api.wrap = (user, main=true) ->
|
||||
gear[type].weapon = 'weapon_base_0'
|
||||
gear[type].head = 'head_base_0'
|
||||
gear[type].shield = 'shield_base_0'
|
||||
gear.owned = {} if typeof gear.owned == 'undefined';
|
||||
gear.owned = {} if typeof gear.owned == 'undefined'
|
||||
_.each gear.owned, (v, k)-> gear.owned[k]=false if gear.owned[k];true
|
||||
gear.owned.weapon_warrior_0 = true
|
||||
user.markModified? 'items.gear.owned'
|
||||
user.preferences.costume = false
|
||||
cb? null, user
|
||||
|
||||
reroll: (req, cb, ga) ->
|
||||
reroll: (req, cb, analytics) ->
|
||||
if user.balance < 1
|
||||
return cb? {code:401,message: i18n.t('notEnoughGems', req.language)}
|
||||
user.balance--
|
||||
@@ -539,19 +529,37 @@ api.wrap = (user, main=true) ->
|
||||
unless task.type is 'reward'
|
||||
task.value = 0
|
||||
user.stats.hp = 50
|
||||
cb? null, user
|
||||
mixpanel?.track("Acquire Item",{'itemName':'Fortify','acquireMethod':'Gems','gemCost':4})
|
||||
ga?.event('behavior', 'gems', 'reroll').send()
|
||||
|
||||
rebirth: (req, cb, ga) ->
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
acquireMethod: 'Gems',
|
||||
gemCost: 4,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('Fortify Potion', analyticsData)
|
||||
|
||||
cb? null, user
|
||||
|
||||
rebirth: (req, cb, analytics) ->
|
||||
# Cost is 8 Gems ($2)
|
||||
if (user.balance < 2 && user.stats.lvl < api.maxLevel)
|
||||
return cb? {code:401,message: i18n.t('notEnoughGems', req.language)}
|
||||
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
category: 'behavior'
|
||||
}
|
||||
# only charge people if they are under the max level - ryan
|
||||
if user.stats.lvl < api.maxLevel
|
||||
user.balance -= 2
|
||||
mixpanel?.track("Acquire Item",{'itemName':'Rebirth','acquireMethod':'Gems','gemCost':8})
|
||||
ga?.event('behavior', 'gems', 'rebirth').send()
|
||||
analyticsData.acquireMethod = 'Gems'
|
||||
analyticsData.gemCost = 8
|
||||
else
|
||||
analyticsData.gemCost = 0
|
||||
analyticsData.acquireMethod = '> 100'
|
||||
|
||||
analytics?.track('Rebirth', analyticsData)
|
||||
|
||||
# Save off user's level, for calculating achievement eligibility later
|
||||
lvl = api.capByLevel(user.stats.lvl)
|
||||
# Turn tasks yellow, zero out streaks
|
||||
@@ -578,8 +586,8 @@ api.wrap = (user, main=true) ->
|
||||
gear[type].shield = 'shield_base_0'
|
||||
if user.items.currentPet then user.ops.equip({params:{type: 'pet', key: user.items.currentPet}})
|
||||
if user.items.currentMount then user.ops.equip({params:{type: 'mount', key: user.items.currentMount}})
|
||||
# Strip owned gear down to the training sword, but preserve purchase history so user can re-purchase limited edition equipment
|
||||
_.each gear.owned, (v, k) -> if gear.owned[k] then gear.owned[k] = false; true
|
||||
# Strip owned gear down to the training sword and free items (zero gold value), but preserve purchase history so user can re-purchase limited edition equipment
|
||||
_.each gear.owned, (v, k) -> if gear.owned[k] and content.gear.flat[k].value then gear.owned[k] = false; true
|
||||
gear.owned.weapon_warrior_0 = true
|
||||
user.markModified? 'items.gear.owned'
|
||||
user.preferences.costume = false
|
||||
@@ -719,7 +727,7 @@ api.wrap = (user, main=true) ->
|
||||
addPushDevice: (req, cb) ->
|
||||
user.pushDevices = [] unless user.pushDevices
|
||||
pd = user.pushDevices
|
||||
item = {regId:req.body.regId, type:req.body.type};
|
||||
item = {regId:req.body.regId, type:req.body.type}
|
||||
i = _.findIndex pd, {regId: item.regId}
|
||||
|
||||
pd.push(item) unless i != -1
|
||||
@@ -786,7 +794,7 @@ api.wrap = (user, main=true) ->
|
||||
if userPets[pet] >= 50 and !user.items.mounts[pet]
|
||||
evolve()
|
||||
user.items.food[food.key]--
|
||||
cb? {code:200, message}, userPets[pet]
|
||||
cb? {code:200, message}, {value: userPets[pet]}
|
||||
|
||||
buySpecialSpell: (req,cb) ->
|
||||
{key} = req.params
|
||||
@@ -800,7 +808,7 @@ api.wrap = (user, main=true) ->
|
||||
cb? {code:200,message}, _.pick(user,$w 'items stats')
|
||||
|
||||
# buy is for using Gold, purchase is for Gems (I know, I know...)
|
||||
purchase: (req, cb, ga) ->
|
||||
purchase: (req, cb, analytics) ->
|
||||
{type,key} = req.params
|
||||
|
||||
if type is 'gems' and key is 'gem'
|
||||
@@ -812,7 +820,16 @@ api.wrap = (user, main=true) ->
|
||||
user.balance += .25
|
||||
user.purchased.plan.gemsBought++
|
||||
user.stats.gp -= convRate
|
||||
mixpanel?.track("Acquire Item",{'itemName':key,'acquireMethod':'Gold','goldCost':convRate})
|
||||
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: key,
|
||||
acquireMethod: 'Gold',
|
||||
goldCost: convRate,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('purchase gems', analyticsData)
|
||||
|
||||
return cb? {code:200,message:"+1 Gem"}, _.pick(user,$w 'stats balance')
|
||||
|
||||
return cb?({code:404,message:":type must be in [eggs,hatchingPotions,food,quests,gear]"},req) unless type in ['eggs','hatchingPotions','food','quests','gear']
|
||||
@@ -830,11 +847,20 @@ api.wrap = (user, main=true) ->
|
||||
else
|
||||
user.items[type][key] = 0 unless user.items[type][key] > 0
|
||||
user.items[type][key]++
|
||||
mixpanel?.track("Acquire Item",{'itemName':key,'acquireMethod':'Gems','gemCost':item.value})
|
||||
cb? null, _.pick(user,$w 'items balance')
|
||||
ga?.event('behavior', 'gems', key).send()
|
||||
|
||||
releasePets: (req, cb) ->
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: key,
|
||||
itemType: 'Market',
|
||||
acquireMethod: 'Gems',
|
||||
gemCost: item.value,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('acquire item', analyticsData)
|
||||
|
||||
cb? null, _.pick(user,$w 'items balance')
|
||||
|
||||
releasePets: (req, cb, analytics) ->
|
||||
if user.balance < 1
|
||||
return cb? {code:401,message: i18n.t('notEnoughGems', req.language)}
|
||||
else
|
||||
@@ -845,10 +871,17 @@ api.wrap = (user, main=true) ->
|
||||
user.achievements.beastMasterCount = 0
|
||||
user.achievements.beastMasterCount++
|
||||
user.items.currentPet = ""
|
||||
cb? null, user
|
||||
mixpanel?.track("Acquire Item",{'itemName':'Kennel Key','acquireMethod':'Gems','gemCost':4})
|
||||
|
||||
releaseMounts: (req, cb) ->
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
acquireMethod: 'Gems',
|
||||
gemCost: 4,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('release pets', analyticsData)
|
||||
cb? null, user
|
||||
|
||||
releaseMounts: (req, cb, analytics) ->
|
||||
if user.balance < 1
|
||||
return cb? {code:401,message: i18n.t('notEnoughGems', req.language)}
|
||||
else
|
||||
@@ -859,8 +892,16 @@ api.wrap = (user, main=true) ->
|
||||
if not user.achievements.mountMasterCount
|
||||
user.achievements.mountMasterCount = 0
|
||||
user.achievements.mountMasterCount++
|
||||
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
acquireMethod: 'Gems',
|
||||
gemCost: 4,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('release mounts', analyticsData)
|
||||
|
||||
cb? null, user
|
||||
mixpanel?.track("Acquire Item",{'itemName':'Kennel Key','acquireMethod':'Gems','gemCost':4})
|
||||
|
||||
releaseBoth: (req, cb) ->
|
||||
if user.balance < 1.5 and not user.achievements.triadBingo
|
||||
@@ -868,7 +909,13 @@ api.wrap = (user, main=true) ->
|
||||
else
|
||||
giveTriadBingo = true
|
||||
if not user.achievements.triadBingo
|
||||
mixpanel?.track("Acquire Item",{'itemName':'Kennel Key','acquireMethod':'Gems','gemCost':6})
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
acquireMethod: 'Gems',
|
||||
gemCost: 6,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('release pets & mounts', analyticsData)
|
||||
user.balance -= 1.5
|
||||
user.items.currentMount = ""
|
||||
user.items.currentPet = ""
|
||||
@@ -889,15 +936,16 @@ api.wrap = (user, main=true) ->
|
||||
cb? null, user
|
||||
|
||||
# buy is for gear, purchase is for gem-purchaseables (i know, I know...)
|
||||
buy: (req, cb) ->
|
||||
buy: (req, cb, analytics) ->
|
||||
{key} = req.params
|
||||
|
||||
item = if key is 'potion' then content.potion
|
||||
else if key is 'armoire' then content.armoire
|
||||
else content.gear.flat[key]
|
||||
return cb?({code:404, message:"Item '#{key} not found (see https://github.com/HabitRPG/habitrpg-shared/blob/develop/script/content.coffee)"}) unless item
|
||||
return cb?({code:404, message:"Item '#{key} not found (see https://github.com/HabitRPG/habitrpg/blob/develop/common/script/content.coffee)"}) unless item
|
||||
return cb?({code:401, message: i18n.t('messageNotEnoughGold', req.language)}) if user.stats.gp < item.value
|
||||
return cb?({code:401, message: "You can't buy this item"}) if item.canOwn? and !item.canOwn(user)
|
||||
armoireResp = undefined
|
||||
if item.key is 'potion'
|
||||
user.stats.hp += 15
|
||||
user.stats.hp = 50 if user.stats.hp > 50
|
||||
@@ -914,15 +962,19 @@ api.wrap = (user, main=true) ->
|
||||
user.items.gear.owned[drop.key] = true
|
||||
user.flags.armoireOpened = true
|
||||
message = i18n.t('armoireEquipment', {image: '<span class="shop_'+drop.key+' pull-left"></span>', dropText: drop.text(req.language)}, req.language)
|
||||
if api.countArmoire(user.items.gear.owned) is 0 then user.flags.armoireEmpty = true
|
||||
if api.count.remainingGearInSet(user.items.gear.owned, 'armoire') is 0 then user.flags.armoireEmpty = true
|
||||
armoireResp = {type: "gear", dropKey: drop.key, dropText: drop.text(req.language)}
|
||||
else if (!_.isEmpty(eligibleEquipment) and armoireResult < .8) or armoireResult < .5
|
||||
drop = user.fns.randomVal _.where(content.food, {canDrop:true})
|
||||
user.items.food[drop.key] ?= 0
|
||||
user.items.food[drop.key] += 1
|
||||
message = i18n.t('armoireFood', {image: '<span class="Pet_Food_'+drop.key+' pull-left"></span>', dropArticle: drop.article, dropText: drop.text(req.language)}, req.language)
|
||||
armoireResp = {type: "food", dropKey: drop.key, dropArticle: drop.article, dropText: drop.text(req.language)}
|
||||
else
|
||||
user.stats.exp += Math.floor(user.fns.predictableRandom(user.stats.exp) * 40 + 10)
|
||||
armoireExp = Math.floor(user.fns.predictableRandom(user.stats.exp) * 40 + 10)
|
||||
user.stats.exp += armoireExp
|
||||
message = i18n.t('armoireExp', req.language)
|
||||
armoireResp = {"type": "experience", "value": armoireExp}
|
||||
else
|
||||
user.items.gear.equipped[item.type] = item.key
|
||||
user.items.gear.owned[item.key] = true
|
||||
@@ -930,10 +982,42 @@ api.wrap = (user, main=true) ->
|
||||
message ?= i18n.t('messageBought', {itemText: item.text(req.language)}, req.language)
|
||||
if item.last then user.fns.ultimateGear()
|
||||
user.stats.gp -= item.value
|
||||
mixpanel?.track("Acquire Item",{'itemName':key,'acquireMethod':'Gold','goldCost':item.value})
|
||||
cb? {code:200, message}, _.pick(user,$w 'items achievements stats flags')
|
||||
|
||||
buyMysterySet: (req, cb)->
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: key,
|
||||
acquireMethod: 'Gold',
|
||||
goldCost: item.value,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('acquire item', analyticsData)
|
||||
|
||||
buyResp = _.pick(user,$w 'items achievements stats flags')
|
||||
buyResp["armoire"] = armoireResp if armoireResp
|
||||
cb? {code:200, message}, buyResp
|
||||
|
||||
buyQuest: (req, cb, analytics) ->
|
||||
{key} = req.params
|
||||
item = content.quests[key]
|
||||
return cb?({code:404, message:"Quest '#{key} not found (see https://github.com/HabitRPG/habitrpg/blob/develop/common/script/content.coffee)"}) unless item
|
||||
return cb?({code:404, message:"Quest '#{key} is not a Gold-purchasable quest (see https://github.com/HabitRPG/habitrpg/blob/develop/common/script/content.coffee)"}) unless item.category is 'gold' and item.goldValue
|
||||
return cb?({code:401, message: i18n.t('messageNotEnoughGold', req.language)}) if user.stats.gp < item.goldValue
|
||||
message = i18n.t('messageBought', {itemText: item.text(req.language)}, req.language)
|
||||
user.items.quests[item.key] ?= 0
|
||||
user.items.quests[item.key] += 1
|
||||
user.stats.gp -= item.goldValue
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: item.key,
|
||||
itemType: 'Market',
|
||||
goldCost: item.goldValue,
|
||||
acquireMethod: 'Gold',
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('acquire item', analyticsData)
|
||||
cb? {code:200, message}, user.items.quests
|
||||
|
||||
buyMysterySet: (req, cb, analytics)->
|
||||
return cb?({code:401, message:"You don't have enough Mystic Hourglasses"}) unless user.purchased.plan.consecutive.trinkets>0
|
||||
mysterySet = content.timeTravelerStore(user.items.gear.owned)?[req.params.key]
|
||||
if window?.confirm?
|
||||
@@ -941,7 +1025,15 @@ api.wrap = (user, main=true) ->
|
||||
return cb?({code:404, message:"Mystery set not found, or set already owned"}) unless mysterySet
|
||||
_.each mysterySet.items, (i)->
|
||||
user.items.gear.owned[i.key]=true
|
||||
mixpanel?.track("Acquire Item",{'itemName':i.key,'acquireMethod':'Hourglass'})
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: i.key,
|
||||
itemType: 'Subscriber Gear',
|
||||
acquireMethod: 'Hourglass',
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('acquire item', analyticsData)
|
||||
|
||||
user.purchased.plan.consecutive.trinkets--
|
||||
cb? null, _.pick(user,$w 'items purchased.plan.consecutive')
|
||||
|
||||
@@ -985,7 +1077,7 @@ api.wrap = (user, main=true) ->
|
||||
user.items.hatchingPotions[hatchingPotion]--
|
||||
cb? {code:200, message:i18n.t('messageHatched', req.language)}, user.items
|
||||
|
||||
unlock: (req, cb, ga) ->
|
||||
unlock: (req, cb, analytics) ->
|
||||
{path} = req.query
|
||||
fullSet = ~path.indexOf(",")
|
||||
cost =
|
||||
@@ -1012,17 +1104,36 @@ api.wrap = (user, main=true) ->
|
||||
user.fns.dotSet "purchased." + path, true
|
||||
user.balance -= cost
|
||||
if ~path.indexOf('gear.') then user.markModified? 'gear.owned' else user.markModified? 'purchased'
|
||||
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: path,
|
||||
itemType: 'customization',
|
||||
acquireMethod: 'Gems',
|
||||
gemCost: (cost/.25),
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('acquire item', analyticsData)
|
||||
|
||||
cb? null, _.pick(user,$w 'purchased preferences items')
|
||||
mixpanel?.track("Acquire Item",{'itemName':'Customizations','acquireMethod':'Gems','gemCost':(cost / .25)})
|
||||
ga?.event('behavior', 'gems', path).send()
|
||||
|
||||
# ------
|
||||
# Classes
|
||||
# ------
|
||||
|
||||
changeClass: (req, cb, ga) ->
|
||||
changeClass: (req, cb, analytics) ->
|
||||
klass = req.query?.class
|
||||
if klass in ['warrior','rogue','wizard','healer']
|
||||
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
class: klass,
|
||||
acquireMethod: 'Gems',
|
||||
gemCost: 3,
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('change class', analyticsData)
|
||||
|
||||
user.stats.class = klass
|
||||
user.flags.classSelected = true
|
||||
# Clear their gear and equip their new class's gear (can still equip old gear from inventory)
|
||||
@@ -1053,8 +1164,6 @@ api.wrap = (user, main=true) ->
|
||||
user.balance -= .75
|
||||
_.merge user.stats, {str: 0, con: 0, per: 0, int: 0, points: api.capByLevel(user.stats.lvl)}
|
||||
user.flags.classSelected = false
|
||||
mixpanel?.track("Acquire Item",{'itemName':klass,'acquireMethod':'Gems','gemCost':3})
|
||||
ga?.event('behavior', 'gems', 'changeClass').send()
|
||||
#'stats.points': this is handled on the server
|
||||
cb? null, _.pick(user,$w 'stats flags items preferences')
|
||||
|
||||
@@ -1075,27 +1184,31 @@ api.wrap = (user, main=true) ->
|
||||
user.stats.mp++ if stat is 'int' #increase their MP along with their max MP
|
||||
cb? null, _.pick(user,$w 'stats')
|
||||
|
||||
readValentine: (req,cb) ->
|
||||
user.items.special.valentineReceived.shift()
|
||||
user.markModified? 'items.special.valentineReceived'
|
||||
cb? null, 'items.special'
|
||||
readCard: (req, cb) ->
|
||||
{cardType} = req.params
|
||||
user.items.special["#{cardType}Received"].shift()
|
||||
user.markModified? "items.special.#{cardType}Received"
|
||||
user.flags.cardReceived = false
|
||||
cb? null, 'items.special flags.cardReceived'
|
||||
|
||||
openMysteryItem: (req,cb,ga) ->
|
||||
openMysteryItem: (req,cb,analytics) ->
|
||||
item = user.purchased.plan?.mysteryItems?.shift()
|
||||
return cb?(code:400,message:"Empty") unless item
|
||||
item = content.gear.flat[item]
|
||||
user.items.gear.owned[item.key] = true
|
||||
user.markModified? 'purchased.plan.mysteryItems'
|
||||
# Could show {code:200} message, but it's yellow with no icon. This is round-about, but prettier. FIXME
|
||||
(user._tmp?={}).drop = {type: 'gear', dialog: "#{item.text(req.language)} inside!"} if typeof window != 'undefined'
|
||||
#cb? {code:200, message:"#{item.text} inside!"}, user.items.gear.owned
|
||||
item.notificationType = 'Mystery' # needed for website/public/js/controllers/notificationCtrl.js line 59 approx.
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: item,
|
||||
itemType: 'Subscriber Gear',
|
||||
acquireMethod: 'Subscriber',
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('open mystery item', analyticsData)
|
||||
(user._tmp?={}).drop = item if typeof window != 'undefined'
|
||||
cb? null, user.items.gear.owned
|
||||
|
||||
readNYE: (req,cb) ->
|
||||
user.items.special.nyeReceived.shift()
|
||||
user.markModified? 'items.special.nyeReceived'
|
||||
cb? null, 'items.special'
|
||||
|
||||
# ------
|
||||
# Score
|
||||
# ------
|
||||
@@ -1186,7 +1299,7 @@ api.wrap = (user, main=true) ->
|
||||
unless task.type is 'reward'
|
||||
if (user.preferences.automaticAllocation is true and user.preferences.allocationMode is 'taskbased' and !(task.type is 'todo' and direction is 'down')) then user.stats.training[task.attribute] += nextDelta
|
||||
if direction is 'up' # Make progress on quest based on STR
|
||||
user.party.quest.progress.up = user.party.quest.progress.up || 0;
|
||||
user.party.quest.progress.up = user.party.quest.progress.up || 0
|
||||
user.party.quest.progress.up += (nextDelta * (1 + (user._statsComputed.str / 200))) if task.type in ['daily','todo']
|
||||
user.party.quest.progress.up += (nextDelta * (0.5 + (user._statsComputed.str / 400))) if task.type is 'habit'
|
||||
task.value += nextDelta
|
||||
@@ -1352,10 +1465,10 @@ api.wrap = (user, main=true) ->
|
||||
returns random property (the value)
|
||||
###
|
||||
randomVal: (obj, options) ->
|
||||
array = if options?.key then _.keys(obj) else _.values(obj)
|
||||
rand = user.fns.predictableRandom(options?.seed)
|
||||
array.sort()
|
||||
array[Math.floor(rand * array.length)]
|
||||
array = if options?.key then _.keys(obj) else _.values(obj)
|
||||
rand = user.fns.predictableRandom(options?.seed)
|
||||
array.sort()
|
||||
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
|
||||
@@ -1483,7 +1596,7 @@ api.wrap = (user, main=true) ->
|
||||
else "str" # if all else fails, dump into STR
|
||||
)()]++
|
||||
|
||||
updateStats: (stats, req) ->
|
||||
updateStats: (stats, req, analytics) ->
|
||||
# Game Over (death)
|
||||
return user.stats.hp=0 if stats.hp <= 0
|
||||
|
||||
@@ -1510,7 +1623,7 @@ api.wrap = (user, main=true) ->
|
||||
user.fns.autoAllocate()
|
||||
else
|
||||
# add new allocatable points. We could do user.stats.points++, but this does a fail-safe just in case
|
||||
user.stats.points = user.stats.lvl - (user.stats.con + user.stats.str + user.stats.per + user.stats.int);
|
||||
user.stats.points = user.stats.lvl - (user.stats.con + user.stats.str + user.stats.per + user.stats.int)
|
||||
if user.stats.points < 0
|
||||
user.stats.points = 0
|
||||
# This happens after dropping level with Fix Character Values and perhaps from other causes.
|
||||
@@ -1523,9 +1636,7 @@ api.wrap = (user, main=true) ->
|
||||
user.flags.customizationsNotification = true
|
||||
if !user.flags.itemsEnabled and (user.stats.exp > 10 or user.stats.lvl > 1)
|
||||
user.flags.itemsEnabled = true
|
||||
if !user.flags.partyEnabled and user.stats.lvl >= 3
|
||||
user.flags.partyEnabled = true
|
||||
if !user.flags.dropsEnabled and user.stats.lvl >= 4
|
||||
if !user.flags.dropsEnabled and user.stats.lvl >= 3
|
||||
user.flags.dropsEnabled = true
|
||||
if user.items.eggs["Wolf"] > 0 then user.items.eggs["Wolf"]++ else user.items.eggs["Wolf"] = 1
|
||||
if !user.flags.classSelected and user.stats.lvl >= 10
|
||||
@@ -1537,10 +1648,14 @@ api.wrap = (user, main=true) ->
|
||||
user.items.quests[k]++
|
||||
(user.flags.levelDrops ?= {})[k] = true
|
||||
user.markModified? 'flags.levelDrops'
|
||||
mixpanel?.track("Acquire Item",{'itemName':k,'acquireMethod':'Drop'})
|
||||
user._tmp.drop = _.defaults content.quests[k],
|
||||
type: 'Quest'
|
||||
dialog: i18n.t('messageFoundQuest', {questText: content.quests[k].text(req.language)}, req.language)
|
||||
analyticsData = {
|
||||
uuid: user._id,
|
||||
itemKey: k,
|
||||
acquireMethod: 'Level Drop',
|
||||
category: 'behavior'
|
||||
}
|
||||
analytics?.track('acquire item', analyticsData)
|
||||
user._tmp.drop = {type: 'Quest', key: k}
|
||||
if !user.flags.rebirthEnabled and (user.stats.lvl >= 50 or user.achievements.beastMaster)
|
||||
user.flags.rebirthEnabled = true
|
||||
|
||||
@@ -1620,56 +1735,66 @@ api.wrap = (user, main=true) ->
|
||||
daily.completed = false
|
||||
return
|
||||
|
||||
multiDaysCountAsOneDay = true
|
||||
# If the user does not log in for two or more days, cron (mostly) acts as if it were only one day.
|
||||
# When site-wide difficulty settings are introduced, this can be a user preference option.
|
||||
|
||||
# Tally each task
|
||||
todoTally = 0
|
||||
user.todos.forEach (task) -> # make uncompleted todos redder
|
||||
return unless task
|
||||
{id, completed} = task
|
||||
delta = user.ops.score({params:{id:task.id, direction:'down'}, query:{times:(multiDaysCountAsOneDay ? 1 : daysMissed), cron:true}})
|
||||
absVal = if (completed) then Math.abs(task.value) else task.value
|
||||
todoTally += absVal
|
||||
|
||||
dailyChecked = 0 # how many dailies were checked?
|
||||
dailyDueUnchecked = 0 # how many dailies were due but not checked?
|
||||
user.party.quest.progress.down ?= 0
|
||||
user.todos.concat(user.dailys).forEach (task) ->
|
||||
user.dailys.forEach (task) ->
|
||||
return unless task
|
||||
{id, completed} = task
|
||||
|
||||
{id, type, completed, repeat} = task
|
||||
|
||||
# Deduct points for missed Daily tasks, but not for Todos (just increase todo's value)
|
||||
# Deduct points for missed Daily tasks
|
||||
EvadeTask = 0
|
||||
scheduleMisses = daysMissed
|
||||
if completed
|
||||
if type is 'daily'
|
||||
dailyChecked += 1
|
||||
dailyChecked += 1
|
||||
else
|
||||
# for dailys which have repeat dates, need to calculate how many they've missed according to their own schedule
|
||||
if (type is 'daily') and repeat
|
||||
scheduleMisses = 0
|
||||
_.times daysMissed, (n) ->
|
||||
thatDay = moment(now).subtract({days: n + 1})
|
||||
if api.shouldDo(thatDay.toDate(), task, user.preferences)
|
||||
scheduleMisses++
|
||||
if user.stats.buffs.stealth
|
||||
user.stats.buffs.stealth--
|
||||
EvadeTask++
|
||||
if scheduleMisses > EvadeTask
|
||||
if type is 'daily'
|
||||
perfect = false
|
||||
if task.checklist?.length > 0 # Partially completed checklists dock fewer mana points
|
||||
fractionChecked = _.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),0) / task.checklist.length
|
||||
dailyDueUnchecked += (1 - fractionChecked)
|
||||
dailyChecked += fractionChecked
|
||||
else
|
||||
dailyDueUnchecked += 1
|
||||
delta = user.ops.score({params:{id:task.id, direction:'down'}, query:{times:(scheduleMisses-EvadeTask), cron:true}}); # this line occurs for todos or dailys
|
||||
user.party.quest.progress.down += delta if type is 'daily'
|
||||
# dailys repeat, so need to calculate how many they've missed according to their own schedule
|
||||
scheduleMisses = 0
|
||||
for n in [0...daysMissed]
|
||||
thatDay = moment(now).subtract({days: n + 1})
|
||||
if api.shouldDo(thatDay.toDate(), task, user.preferences)
|
||||
scheduleMisses++
|
||||
if user.stats.buffs.stealth
|
||||
user.stats.buffs.stealth--
|
||||
EvadeTask++
|
||||
if multiDaysCountAsOneDay
|
||||
break
|
||||
|
||||
switch type
|
||||
when 'daily'
|
||||
# This occurs whether or not the task is completed
|
||||
(task.history ?= []).push({ date: +new Date, value: task.value })
|
||||
task.completed = false
|
||||
if completed || (scheduleMisses > 0)
|
||||
_.each task.checklist, ((i)->i.completed=false;true) # this should not happen for grey tasks unless they are completed
|
||||
when 'todo'
|
||||
#get updated value
|
||||
absVal = if (completed) then Math.abs(task.value) else task.value
|
||||
todoTally += absVal
|
||||
if scheduleMisses > EvadeTask
|
||||
perfect = false
|
||||
if task.checklist?.length > 0 # Partially completed checklists dock fewer mana points
|
||||
fractionChecked = _.reduce(task.checklist,((m,i)->m+(if i.completed then 1 else 0)),0) / task.checklist.length
|
||||
dailyDueUnchecked += (1 - fractionChecked)
|
||||
dailyChecked += fractionChecked
|
||||
else
|
||||
dailyDueUnchecked += 1
|
||||
delta = user.ops.score({params:{id:task.id, direction:'down'}, query:{times:(multiDaysCountAsOneDay ? 1 : (scheduleMisses-EvadeTask)), cron:true}})
|
||||
|
||||
# Apply damage from a boss, less damage for Trivial priority (difficulty)
|
||||
user.party.quest.progress.down += delta * (if task.priority < 1 then task.priority else 1)
|
||||
# NB: Medium and Hard priorities do not increase damage from boss. This was by accident
|
||||
# initially, and when we realised, we could not fix it because users are used to
|
||||
# their Medium and Hard Dailies doing an Easy amount of damage from boss.
|
||||
# Easy is task.priority = 1. Anything < 1 will be Trivial (0.1) or any future
|
||||
# setting between Trivial and Easy.
|
||||
|
||||
(task.history ?= []).push({ date: +new Date, value: task.value })
|
||||
task.completed = false
|
||||
if completed || (scheduleMisses > 0)
|
||||
_.each task.checklist, ((i)->i.completed=false;true) # this should not happen for grey tasks unless they are completed
|
||||
|
||||
user.habits.forEach (task) -> # slowly reset 'onlies' value to 0
|
||||
if task.up is false or task.down is false
|
||||
@@ -1678,7 +1803,6 @@ api.wrap = (user, main=true) ->
|
||||
else
|
||||
task.value = task.value / 2
|
||||
|
||||
|
||||
# Finished tallying
|
||||
((user.history ?= {}).todos ?= []).push { date: now, value: todoTally }
|
||||
# tally experience
|
||||
@@ -1713,8 +1837,17 @@ api.wrap = (user, main=true) ->
|
||||
# Analytics
|
||||
user.flags.cronCount?=0
|
||||
user.flags.cronCount++
|
||||
options.mixpanel?.track('Cron',{'distinct_id':user._id,'resting':user.preferences.sleep})
|
||||
options.ga?.event('behavior', 'cron', 'cron', user.flags.cronCount).send(); #TODO userId for cohort
|
||||
|
||||
analyticsData = {
|
||||
category: 'behavior',
|
||||
gaLabel: 'Cron Count',
|
||||
gaValue: user.flags.cronCount,
|
||||
uuid: user._id,
|
||||
user: user,
|
||||
resting: user.preferences.sleep,
|
||||
cronCount: user.flags.cronCount
|
||||
}
|
||||
options.analytics?.track('Cron', analyticsData)
|
||||
|
||||
# After all is said and done, progress up user's effect on quest, return those values & reset the user's
|
||||
progress = user.party.quest.progress; _progress = _.cloneDeep progress
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
|
||||
if(removeWatch)
|
||||
{
|
||||
doRemoveWatch();
|
||||
doRemoveWatch();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,9 +144,9 @@
|
||||
habitrpg.filter('markdown', function() {
|
||||
return function(input){
|
||||
var html = md.toHtml(input);
|
||||
|
||||
|
||||
html = html.replace(' href',' target="_self" href');
|
||||
|
||||
|
||||
return html;
|
||||
};
|
||||
});
|
||||
|
||||
@@ -194,6 +194,11 @@ angular.module('habitrpg')
|
||||
return this.settings.auth.apiId !== "";
|
||||
},
|
||||
|
||||
getBalanceInGems: function() {
|
||||
var balance = user.balance || 0;
|
||||
return balance * 4;
|
||||
},
|
||||
|
||||
log: function (action, cb) {
|
||||
//push by one buy one if an array passed in.
|
||||
if (_.isArray(action)) {
|
||||
|
||||
Reference in New Issue
Block a user