Compare commits

..

107 Commits

Author SHA1 Message Date
SabreCat af3aedc5d4 4.225.3 2022-03-28 16:26:49 -05:00
SabreCat 0a2eceaa73 fix(achievement): correct string for Birds and add to user schema 2022-03-28 16:26:37 -05:00
SabreCat da481ce156 4.225.2 2022-03-23 20:21:00 -05:00
Sabe Jones f7f928d1bd On-the-fly fix for tasks missing from tasksOrder (#13900)
* fix(tasks): revised fix logic, accounting for groups/challenges

* fix(tasks): don't grab individual user tasks in shared list

Co-authored-by: SabreCat <sabe@habitica.com>
2022-03-23 20:17:49 -05:00
SabreCat e88b3c2c49 4.225.1 2022-03-22 16:52:54 -05:00
SabreCat d6e64482d6 chore(sprites): update CSS 2022-03-22 16:52:48 -05:00
SabreCat 4d1c5024a3 4.225.0 2022-03-22 10:37:35 -05:00
SabreCat ad9c468e77 fix(event): CSS build, small fixes 2022-03-22 10:34:44 -05:00
SabreCat e141e2407c Merge remote-tracking branch 'CuriousMagpie/2022-spring-fling-gala' into release 2022-03-22 09:41:59 -05:00
SabreCat 33da6b7959 revert of hotfix for further review 2022-03-21 16:28:41 -05:00
SabreCat 9a454daef1 partial revert of hotfix for further review 2022-03-21 16:28:20 -05:00
SabreCat 2828ae660c fix(tasks): correct list repair query 2022-03-18 17:40:09 -05:00
SabreCat 4a21ffa81d fix(build): force https for git repositories 2022-03-18 17:30:43 -05:00
SabreCat fa27aa8fe7 fix(tasks): self-healing for missing tasksOrder entries 2022-03-18 17:15:20 -05:00
CuriousMagpie c94195129f 2022 Spring Fling Content 2022-03-18 17:24:05 -04:00
CuriousMagpie deacd8964f uploaded spring fling class set images 2022-03-18 14:06:37 -04:00
SabreCat 5ea82fe87f 4.224.3 2022-03-15 16:08:58 -05:00
SabreCat a24651e395 fix(content): bundle ends March not May 2022-03-15 16:08:53 -05:00
SabreCat 6339e9066f 4.224.2 2022-03-15 15:01:11 -05:00
SabreCat c2d48480a0 chore(content): rerelease cuddle bubbles 2022-03-15 15:00:58 -05:00
SabreCat d9240f7887 fix(migration): actually count 2022-03-14 15:06:57 -05:00
SabreCat dd86b96433 4.224.1 2022-03-14 14:30:20 -05:00
SabreCat 3e082fe127 chore(event): Pi Day 2022 2022-03-14 14:29:57 -05:00
SabreCat c38781e154 4.224.0 2022-03-09 16:17:28 -06:00
SabreCat 3c7df419b7 chore(submodule): update habitica-images 2022-03-09 16:17:23 -06:00
SabreCat 52d1480844 chore(sprites): build CSS 2022-03-09 16:16:44 -06:00
CuriousMagpie d9f593d53a added migration script 2022-03-09 15:55:31 -06:00
SabreCat 7cc17d0369 feat(content): Armoire and Backgrounds 2022-03-09 15:50:31 -06:00
CuriousMagpie 43be5f0490 Add Rooster and Peacock 2022-03-08 16:52:43 -05:00
CuriousMagpie fc4145700c image update! 2022-03-08 13:06:33 -05:00
CuriousMagpie aa1b9a5e94 added achievement Birds of a Feather 2022-03-08 12:43:38 -05:00
CuriousMagpie ce57a70e64 habitica images update 2022-03-08 12:37:49 -05:00
SabreCat e66f722311 4.223.0 2022-02-28 09:49:27 -06:00
SabreCat 05a54e505c chore(mystery): update images, run sprites 2022-02-28 09:49:21 -06:00
CuriousMagpie 82e9c2e896 2022-03 Subscriber Items 2022-02-28 09:37:57 -06:00
CuriousMagpie 8dbb55f3b7 2022-03 Subscriber Items 2022-02-28 09:37:49 -06:00
SabreCat 4295b55339 4.222.2 2022-02-22 12:18:20 -06:00
SabreCat 08352c5f49 fix(subs): correct cancellation check logic and test 2022-02-22 11:26:15 -06:00
SabreCat 7080715bcc fix(tests): renewig typos 2022-02-22 10:13:32 -06:00
Phillip Thelen c6d07983b2 Fix issue with validating android sub cancellation 2022-02-22 10:12:10 -06:00
SabreCat a5c141407e 4.222.1 2022-02-17 14:38:13 -06:00
SabreCat 70be356968 chore(content): enable Mythical Marvels for end of February 2022-02-17 14:27:17 -06:00
SabreCat 1fd931d935 4.222.0 2022-02-14 15:31:19 -06:00
SabreCat 77751223d3 fix(valentines): adjust empty event daterange 2022-02-14 15:20:37 -06:00
CuriousMagpie d1ef90db29 Fixed end dates to Feb 18 2022-02-14 15:03:38 -06:00
CuriousMagpie 79cda5d1f6 updates for 2022-02 magic hatching potions & valentine's week 2022-02-14 15:03:32 -06:00
SabreCat be5756469c 4.221.3 2022-02-14 14:48:09 -06:00
SabreCat d9e2069995 fix(packages) new fix attempt from last known good 2022-02-14 14:37:26 -06:00
SabreCat d8cbc2c4b2 4.221.1 2022-02-09 11:17:26 -06:00
SabreCat 81363feb26 revert Bailey datetime PR 2022-02-09 11:17:15 -06:00
SabreCat 2ac5ebe01a 4.221.0 2022-02-08 14:10:47 -06:00
Weblate bfacfd2db8 Merge branch 'origin/develop' into Weblate. 2022-02-08 21:09:15 +01:00
dependabot[bot] eb820a2902 build(deps): bump @storybook/addon-actions in /website/client (#13839)
Bumps [@storybook/addon-actions](https://github.com/storybookjs/storybook/tree/HEAD/addons/actions) from 6.4.17 to 6.4.18.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.4.18/addons/actions)

---
updated-dependencies:
- dependency-name: "@storybook/addon-actions"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 12:14:42 -05:00
dependabot[bot] efabd7ca15 build(deps): bump winston from 3.5.0 to 3.5.1 (#13830)
Bumps [winston](https://github.com/winstonjs/winston) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/winstonjs/winston/releases)
- [Changelog](https://github.com/winstonjs/winston/blob/master/CHANGELOG.md)
- [Commits](https://github.com/winstonjs/winston/compare/v3.5.0...v3.5.1)

---
updated-dependencies:
- dependency-name: winston
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 12:13:59 -05:00
dependabot[bot] 0266c46aee build(deps): bump stripe from 8.201.0 to 8.202.0 (#13829)
Bumps [stripe](https://github.com/stripe/stripe-node) from 8.201.0 to 8.202.0.
- [Release notes](https://github.com/stripe/stripe-node/releases)
- [Changelog](https://github.com/stripe/stripe-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/stripe/stripe-node/compare/v8.201.0...v8.202.0)

---
updated-dependencies:
- dependency-name: stripe
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 12:13:43 -05:00
dependabot[bot] df3447afa6 build(deps): bump @storybook/addons in /website/client (#13824)
Bumps [@storybook/addons](https://github.com/storybookjs/storybook/tree/HEAD/lib/addons) from 6.4.17 to 6.4.18.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.4.18/lib/addons)

---
updated-dependencies:
- dependency-name: "@storybook/addons"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 12:12:37 -05:00
dependabot[bot] 6dc46a664a build(deps): bump accepts from 1.3.7 to 1.3.8 (#13823)
Bumps [accepts](https://github.com/jshttp/accepts) from 1.3.7 to 1.3.8.
- [Release notes](https://github.com/jshttp/accepts/releases)
- [Changelog](https://github.com/jshttp/accepts/blob/master/HISTORY.md)
- [Commits](https://github.com/jshttp/accepts/compare/1.3.7...1.3.8)

---
updated-dependencies:
- dependency-name: accepts
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 12:12:19 -05:00
dependabot[bot] 7e7c85a419 build(deps): bump @babel/register from 7.16.9 to 7.17.0 (#13822)
Bumps [@babel/register](https://github.com/babel/babel/tree/HEAD/packages/babel-register) from 7.16.9 to 7.17.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.17.0/packages/babel-register)

---
updated-dependencies:
- dependency-name: "@babel/register"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 12:12:04 -05:00
SabreCat 9e740e7092 fix(heroes): still more indents 2022-02-08 11:10:39 -06:00
SabreCat 169634f205 fix(heroes): remove broken td and correct indentation 2022-02-08 11:09:05 -06:00
SabreCat 094cf899d8 fix(heroes): remove duplicated column 2022-02-08 10:39:11 -06:00
Weblate 30420210f5 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (365 of 365 strings)

Translated using Weblate (Ukrainian)

Currently translated at 80.4% (2039 of 2533 strings)

Translated using Weblate (Ukrainian)

Currently translated at 75.5% (96 of 127 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (186 of 186 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (675 of 675 strings)

Translated using Weblate (Japanese)

Currently translated at 93.2% (192 of 206 strings)

Translated using Weblate (Ukrainian)

Currently translated at 73.3% (143 of 195 strings)

Translated using Weblate (Ukrainian)

Currently translated at 98.1% (109 of 111 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Ukrainian)

Currently translated at 73.4% (158 of 215 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (365 of 365 strings)

Translated using Weblate (Ukrainian)

Currently translated at 80.6% (2038 of 2527 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (214 of 214 strings)

Translated using Weblate (Ukrainian)

Currently translated at 97.7% (174 of 178 strings)

Translated using Weblate (Ukrainian)

Currently translated at 50.0% (28 of 56 strings)

Translated using Weblate (Ukrainian)

Currently translated at 84.4% (630 of 746 strings)

Translated using Weblate (Ukrainian)

Currently translated at 75.5% (96 of 127 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (372 of 372 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (186 of 186 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Japanese)

Currently translated at 91.2% (188 of 206 strings)

Translated using Weblate (Czech)

Currently translated at 92.6% (619 of 668 strings)

Translated using Weblate (German)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2527 of 2527 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (195 of 195 strings)

Translated using Weblate (Spanish)

Currently translated at 99.8% (2523 of 2527 strings)

Translated using Weblate (Spanish)

Currently translated at 99.0% (204 of 206 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (Spanish)

Currently translated at 99.8% (2522 of 2527 strings)

Translated using Weblate (Spanish)

Currently translated at 97.5% (201 of 206 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (2527 of 2527 strings)

Translated using Weblate (Japanese)

Currently translated at 99.8% (2523 of 2527 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.2% (127 of 128 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.0% (202 of 206 strings)

Translated using Weblate (Ukrainian)

Currently translated at 98.1% (109 of 111 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (372 of 372 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (372 of 372 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (195 of 195 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (365 of 365 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (214 of 214 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Ukrainian)

Currently translated at 93.6% (104 of 111 strings)

Translated using Weblate (Ukrainian)

Currently translated at 94.6% (123 of 130 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (214 of 214 strings)

Translated using Weblate (Ukrainian)

Currently translated at 83.3% (622 of 746 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (372 of 372 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Ukrainian)

Currently translated at 92.7% (103 of 111 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Ukrainian)

Currently translated at 73.4% (158 of 215 strings)

Translated using Weblate (Ukrainian)

Currently translated at 73.4% (158 of 215 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (365 of 365 strings)

Translated using Weblate (Ukrainian)

Currently translated at 75.5% (96 of 127 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Danish)

Currently translated at 98.4% (126 of 128 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (206 of 206 strings)

Translated using Weblate (Japanese)

Currently translated at 90.7% (187 of 206 strings)

Translated using Weblate (Ukrainian)

Currently translated at 75.5% (96 of 127 strings)

Translated using Weblate (Ukrainian)

Currently translated at 75.5% (96 of 127 strings)

Translated using Weblate (German)

Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (German)

Currently translated at 99.8% (2523 of 2527 strings)

Translated using Weblate (Ukrainian)

Currently translated at 74.0% (94 of 127 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (Ukrainian)

Currently translated at 72.0% (155 of 215 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (214 of 214 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (372 of 372 strings)

Translated using Weblate (Hebrew)

Currently translated at 66.7% (446 of 668 strings)

Translated using Weblate (Hebrew)

Currently translated at 62.5% (80 of 128 strings)

Translated using Weblate (Japanese)

Currently translated at 90.2% (186 of 206 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (195 of 195 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.6% (2519 of 2527 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (2527 of 2527 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (746 of 746 strings)

Co-authored-by: Asta Jensen <asta.raae@live.dk>
Co-authored-by: Jonas Nardes Braga <ionabi@gmail.com>
Co-authored-by: Kedr <sergeysamori.ua@gmail.com>
Co-authored-by: Maikel Roelofs <maikel_roelofs@live.nl>
Co-authored-by: Mara Dolichotis <marascherzer@gmail.com>
Co-authored-by: Martin Bartak <martin.bartak@gmail.com>
Co-authored-by: Nazar Paruna <nazarparuna@gmail.com>
Co-authored-by: Ofek yeshurun <ofek.yeshurun@gmail.com>
Co-authored-by: Pardinus <artemisadlg@gmail.com>
Co-authored-by: Sciuridae <sweetvshoney@163.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: mattya 226 <worldworld1114@gmail.com>
Co-authored-by: Володимир <wishreacher@gmail.com>
Co-authored-by: Естай <akseleu@yahoo.com>
Co-authored-by: そら <comi4work@gmail.com>
Co-authored-by: 张大鸣 <3063837415@qq.com>
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/da/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/de/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/es/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/he/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/nl/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/achievements/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/cs/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/he/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/character/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/content/pt_BR/
Translate-URL: https://translate.habitica.com/projects/habitica/content/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/faq/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/front/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/es/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/generic/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/groups/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/limited/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/messages/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/de/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/es/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/pets/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/es/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/uk/
Translate-URL: https://translate.habitica.com/projects/habitica/settings/zh_Hans/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/es/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ja/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/ru/
Translate-URL: https://translate.habitica.com/projects/habitica/subscriber/uk/
Translation: Habitica/Achievements
Translation: Habitica/Backgrounds
Translation: Habitica/Character
Translation: Habitica/Communityguidelines
Translation: Habitica/Content
Translation: Habitica/Faq
Translation: Habitica/Front
Translation: Habitica/Gear
Translation: Habitica/Generic
Translation: Habitica/Groups
Translation: Habitica/Limited
Translation: Habitica/Messages
Translation: Habitica/Npc
Translation: Habitica/Pets
Translation: Habitica/Questscontent
Translation: Habitica/Settings
Translation: Habitica/Subscriber
2022-02-08 14:21:01 +01:00
SabreCat fd4d139fc2 Merge remote-tracking branch 'CuriousMagpie/2022-02-backgrounds-armoire' into develop 2022-02-07 10:51:23 -06:00
Sabe Jones a8859d51b1 fix(backgrounds): string syntax consistency 2022-02-07 10:49:18 -06:00
Alys d464b98d9b add words to list of banned swear words - TRIGGER / CONTENT WARNING: assault, slurs, swearwords, etc 2022-02-06 15:50:25 +10:00
Weblate ff806ec491 Merge branch 'origin/develop' into Weblate. 2022-02-01 22:34:50 +01:00
SabreCat ca4df96902 Merge branch 'release' into develop 2022-02-01 15:29:35 -06:00
SabreCat f43a12acb2 4.220.0 2022-02-01 15:22:45 -06:00
SabreCat 82d0251fed fix(event): extend 24h because i derped 2022-02-01 15:21:53 -06:00
SabreCat 9e5948df64 chore(sprites): compile 2022-02-01 15:21:03 -06:00
SabreCat 269c420bfa fix(zodiac): tiger cubs lol 2022-02-01 15:20:08 -06:00
SabreCat 83c2e1774b Merge remote-tracking branch 'CuriousMagpie/zodiac-zookeeper' into release 2022-02-01 14:30:02 -06:00
SabreCat 2093932af6 Merge remote-tracking branch 'CuriousMagpie/2022-02-subscriber-items' into release 2022-02-01 14:29:28 -06:00
SabreCat b383574438 fix(event): it's 2022 now, lol 2022-02-01 14:27:08 -06:00
SabreCat 9a9449e001 chore(deps): update package lock 2022-02-01 14:25:16 -06:00
Weblate 91718fbe3f Translated using Weblate (Italian)
Currently translated at 100.0% (2523 of 2523 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (2523 of 2523 strings)

Co-authored-by: Chap <chalda82+nogravatar@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Естай <akseleu@yahoo.com>
Translate-URL: https://translate.habitica.com/projects/habitica/gear/it/
Translate-URL: https://translate.habitica.com/projects/habitica/gear/ru/
Translation: Habitica/Gear
2022-02-01 11:48:26 +01:00
SabreCat 844e0d7cf4 fix(dependencies): add moment-timezone 2022-01-31 22:19:03 -06:00
SabreCat c8e949a425 Merge branch 'release' into develop 2022-01-31 19:17:26 -06:00
SabreCat e2450b69b2 4.219.1 2022-01-31 19:17:15 -06:00
SabreCat 2ae36f64ad fix(birthday): market cake 2022-01-31 19:17:08 -06:00
SabreCat fb73ec3ad9 Merge remote-tracking branch 'Lyqst/news-post-datetime' into develop 2022-01-31 15:41:33 -06:00
SabreCat e7dc233fc9 Merge remote-tracking branch 'origin/feature/sprites-cdn' into develop 2022-01-31 15:40:27 -06:00
Phillip Thelen 6e43d4dc79 Add Transaction log for gem and hourglass changes (#13589)
* Log all gem transactions to database

* Also store hourglass transactions

* Fix tests

* Display transaction history in hall of heroes for admins

* add tests to new API call

* hide transaction settings tab for non admins

* fix(lint): remove console

* fix(lint): various automatic corrections

* fix(transactions): use enum expected pluralizations

* fix api unit tests

* fix lint

* fix failing test

* Fix minor inconsistencies

* Log all gem transactions to database

* Also store hourglass transactions

* Fix tests

* Display transaction history in hall of heroes for admins

* add tests to new API call

* hide transaction settings tab for non admins

* fix(lint): remove console

* fix(lint): various automatic corrections

* fix(transactions): use enum expected pluralizations

* fix api unit tests

* fix lint

* Fix minor inconsistencies

Co-authored-by: Sabe Jones <sabrecat@gmail.com>
2022-01-31 15:36:15 -06:00
Vanathi G 5beb29305d Fix selection highlight in avatar editor (#13746) 2022-01-31 15:35:17 -06:00
Aleksander Pentchev b3925d6c7a #13731 - Changed account reset button pop-up text (#13751)
Co-authored-by: Aleksander Pentchev <aleksander.pentchev@roche.com>
2022-01-31 15:33:28 -06:00
Natalie L de70ad65f5 Update Orb of Rebirth to ignore completed todos (#13773)
* added logic to exclude completed tasks from having task.value set to 0

* logic refinement

* fix(rebirth): complete D

Co-authored-by: SabreCat <sabe@habitica.com>
2022-01-31 15:33:11 -06:00
CuriousMagpie f2f3a1f0eb added Zodiac Zookeeper achievement 2022-01-28 17:14:50 -05:00
SabreCat 1a76ad5dca fix(news): use Moment timezone package 2022-01-27 15:54:03 -06:00
SabreCat 988f594298 Merge branch 'develop' into news-post-datetime 2022-01-27 15:34:18 -06:00
CuriousMagpie 4d18169ebc added set name to violetFloppyHat 2022-01-27 14:38:09 -05:00
Natalie L 84fcb1d4ad Merge branch 'HabitRPG:develop' into 2022-02-backgrounds-armoire 2022-01-27 14:35:49 -05:00
CuriousMagpie a32bde3ec2 fix typo 2022-01-27 13:02:16 -05:00
CuriousMagpie bd9911fe61 updated armoire item strings 2022-01-27 12:58:53 -05:00
CuriousMagpie 75e2261e3e added Violet Loungewear Set information to hat, suit, and pillow 2022-01-27 11:39:08 -05:00
CuriousMagpie 73a2552b30 subproject commit 2022-01-26 17:07:24 -05:00
CuriousMagpie a23522d516 fix typo 2022-01-26 17:02:46 -05:00
CuriousMagpie fce53898d8 2022-02 armoire items -- missing description strings & stats 2022-01-26 16:57:45 -05:00
CuriousMagpie 8637d55d2b changed a few stray 2021s to 2022 2022-01-26 16:45:54 -05:00
CuriousMagpie 412f9b7898 fix typo in string 2022-01-26 16:40:48 -05:00
CuriousMagpie 40588f5ca4 2022-02 backgrounds 2022-01-26 16:33:57 -05:00
CuriousMagpie 7465c8e4ed subproject commit 2022-01-26 16:15:56 -05:00
Natalie L aedbc10630 Merge branch 'HabitRPG:develop' into 2022-02-subscriber-items 2022-01-26 15:36:27 -05:00
CuriousMagpie 306241fa49 subproject commit 2022-01-26 13:06:29 -05:00
CuriousMagpie 0db8c4e2a3 add 2022-02 subscriber items 2022-01-25 17:32:31 -05:00
negue 1ec227b14c remove console 2022-01-07 22:32:02 +01:00
negue 21a3a81d5b Sprites: only create the css which points to the CDN 2022-01-07 22:12:43 +01:00
Lyqst fd4115ffcf Remove date from News title, add posting time in EST 2021-12-15 11:48:57 -03:00
220 changed files with 58285 additions and 67906 deletions
+12 -73
View File
@@ -1,15 +1,8 @@
import gulp from 'gulp';
import imagemin from 'gulp-imagemin';
import spritesmith from 'gulp.spritesmith';
import clean from 'rimraf';
import sizeOf from 'image-size';
import mergeStream from 'merge-stream';
import { sync } from 'glob';
import { each } from 'lodash';
import vinylBuffer from 'vinyl-buffer';
// https://github.com/Ensighten/grunt-spritesmith/issues/67#issuecomment-34786248
const MAX_SPRITESHEET_SIZE = 1024 * 1024 * 3;
const IMG_DIST_PATH = 'website/client/src/assets/images/sprites/';
const CSS_DIST_PATH = 'website/client/src/assets/css/sprites/';
@@ -19,49 +12,6 @@ function checkForSpecialTreatment (name) {
return name.match(regex) || name === 'head_0';
}
function calculateImgDimensions (img, addPadding) {
let dims = sizeOf(img);
const requiresSpecialTreatment = checkForSpecialTreatment(img);
if (requiresSpecialTreatment) {
const newWidth = dims.width < 90 ? 90 : dims.width;
const newHeight = dims.height < 90 ? 90 : dims.height;
dims = {
width: newWidth,
height: newHeight,
};
}
let padding = 0;
if (addPadding) {
padding = dims.width * 8 + dims.height * 8;
}
if (!dims.width || !dims.height) console.error('MISSING DIMENSIONS:', dims); // eslint-disable-line no-console
const totalPixelSize = dims.width * dims.height + padding;
return totalPixelSize;
}
function calculateSpritesheetsSrcIndicies (src) {
let totalPixels = 0;
const slices = [0];
each(src, (img, index) => {
const imageSize = calculateImgDimensions(img, true);
totalPixels += imageSize;
if (totalPixels > MAX_SPRITESHEET_SIZE) {
slices.push(index - 1);
totalPixels = imageSize;
}
});
return slices;
}
function cssVarMap (sprite) {
// For hair, skins, beards, etc. we want to output a '.customize-options.WHATEVER' class,
// which works as a 60x60 image pointing at the proper part of the 90x90 sprite.
@@ -85,33 +35,22 @@ function cssVarMap (sprite) {
}
function createSpritesStream (name, src) {
const spritesheetSliceIndicies = calculateSpritesheetsSrcIndicies(src);
const stream = mergeStream();
each(spritesheetSliceIndicies, (start, index) => {
const slicedSrc = src.slice(start, spritesheetSliceIndicies[index + 1]);
const spriteData = gulp.src(src)
.pipe(spritesmith({
imgName: `spritesmith-${name}.png`,
cssName: `spritesmith-${name}.css`,
algorithm: 'binary-tree',
padding: 1,
cssTemplate: 'website/raw_sprites/css/css.template.handlebars',
cssVarMap,
}));
const spriteData = gulp.src(slicedSrc)
.pipe(spritesmith({
imgName: `spritesmith-${name}-${index}.png`,
cssName: `spritesmith-${name}-${index}.css`,
algorithm: 'binary-tree',
padding: 1,
cssTemplate: 'website/raw_sprites/css/css.template.handlebars',
cssVarMap,
}));
const cssStream = spriteData.css
.pipe(gulp.dest(CSS_DIST_PATH));
const imgStream = spriteData.img
.pipe(vinylBuffer())
.pipe(imagemin())
.pipe(gulp.dest(IMG_DIST_PATH));
const cssStream = spriteData.css
.pipe(gulp.dest(CSS_DIST_PATH));
stream.add(imgStream);
stream.add(cssStream);
});
stream.add(cssStream);
return stream;
}
@@ -0,0 +1,178 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20220201_pet_group_achievements';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {
migration: MIGRATION_NAME,
};
if (user && user.items && user.items.pets) {
const pets = user.items.pets;
if (pets['FlyingPig-Base']
&& pets['FlyingPig-CottonCandyBlue']
&& pets['FlyingPig-CottonCandyPink']
&& pets['FlyingPig-Desert']
&& pets['FlyingPig-Golden']
&& pets['FlyingPig-Red']
&& pets['FlyingPig-Shade']
&& pets['FlyingPig-Skeleton']
&& pets['FlyingPig-White']
&& pets['FlyingPig-Zombie']
&& pets['Snake-Base']
&& pets['Snake-CottonCandyBlue']
&& pets['Snake-CottonCandyPink']
&& pets['Snake-Desert']
&& pets['Snake-Golden']
&& pets['Snake-Red']
&& pets['Snake-Shade']
&& pets['Snake-Skeleton']
&& pets['Snake-White']
&& pets['Snake-Zombie']
&& pets['Sheep-Base']
&& pets['Sheep-CottonCandyBlue']
&& pets['Sheep-CottonCandyPink']
&& pets['Sheep-Desert']
&& pets['Sheep-Golden']
&& pets['Sheep-Red']
&& pets['Sheep-Shade']
&& pets['Sheep-Skeleton']
&& pets['Sheep-White']
&& pets['Sheep-Zombie']
&& pets['Rooster-Base']
&& pets['Rooster-CottonCandyBlue']
&& pets['Rooster-CottonCandyPink']
&& pets['Rooster-Desert']
&& pets['Rooster-Golden']
&& pets['Rooster-Red']
&& pets['Rooster-Shade']
&& pets['Rooster-Skeleton']
&& pets['Rooster-White']
&& pets['Rooster-Zombie']
&& pets['Rat-Base']
&& pets['Rat-CottonCandyBlue']
&& pets['Rat-CottonCandyPink']
&& pets['Rat-Desert']
&& pets['Rat-Golden']
&& pets['Rat-Red']
&& pets['Rat-Shade']
&& pets['Rat-Skeleton']
&& pets['Rat-White']
&& pets['Rat-Zombie']
&& pets['Bunny-Base']
&& pets['Bunny-CottonCandyBlue']
&& pets['Bunny-CottonCandyPink']
&& pets['Bunny-Desert']
&& pets['Bunny-Golden']
&& pets['Bunny-Red']
&& pets['Bunny-Shade']
&& pets['Bunny-Skeleton']
&& pets['Bunny-White']
&& pets['Bunny-Zombie']
&& pets['Horse-Base']
&& pets['Horse-CottonCandyBlue']
&& pets['Horse-CottonCandyPink']
&& pets['Horse-Desert']
&& pets['Horse-Golden']
&& pets['Horse-Red']
&& pets['Horse-Shade']
&& pets['Horse-Skeleton']
&& pets['Horse-White']
&& pets['Horse-Zombie']
&& pets['Cow-Base']
&& pets['Cow-CottonCandyBlue']
&& pets['Cow-CottonCandyPink']
&& pets['Cow-Desert']
&& pets['Cow-Golden']
&& pets['Cow-Red']
&& pets['Cow-Shade']
&& pets['Cow-Skeleton']
&& pets['Cow-White']
&& pets['Cow-Zombie']
&& pets['Monkey-Base']
&& pets['Monkey-CottonCandyBlue']
&& pets['Monkey-CottonCandyPink']
&& pets['Monkey-Desert']
&& pets['Monkey-Golden']
&& pets['Monkey-Red']
&& pets['Monkey-Shade']
&& pets['Monkey-Skeleton']
&& pets['Monkey-White']
&& pets['Monkey-Zombie']
&& pets['Wolf-Base']
&& pets['Wolf-CottonCandyBlue']
&& pets['Wolf-CottonCandyPink']
&& pets['Wolf-Desert']
&& pets['Wolf-Golden']
&& pets['Wolf-Red']
&& pets['Wolf-Shade']
&& pets['Wolf-Skeleton']
&& pets['Wolf-White']
&& pets['Wolf-Zombie']
&& pets['Tiger-Base']
&& pets['Tiger-CottonCandyBlue']
&& pets['Tiger-CottonCandyPink']
&& pets['Tiger-Desert']
&& pets['Tiger-Golden']
&& pets['Tiger-Red']
&& pets['Tiger-Shade']
&& pets['Tiger-Skeleton']
&& pets['Tiger-White']
&& pets['Tiger-Zombie']
&& pets['Dragon-Base']
&& pets['Dragon-CottonCandyBlue']
&& pets['Dragon-CottonCandyPink']
&& pets['Dragon-Desert']
&& pets['Dragon-Golden']
&& pets['Dragon-Red']
&& pets['Dragon-Shade']
&& pets['Dragon-Skeleton']
&& pets['Dragon-White']
&& pets['Dragon-Zombie']) {
set['achievements.zodiacZookeeper'] = true;
}
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({ _id: user._id }, { $set: set }).exec();
}
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2021-08-01') },
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1]._id,
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
@@ -0,0 +1,138 @@
/* eslint-disable no-console */
const MIGRATION_NAME = '20220309_pet_group_achievements';
import { model as User } from '../../../website/server/models/user';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count++;
const set = {
migration: MIGRATION_NAME,
};
if (user && user.items && user.items.pets) {
const pets = user.items.pets;
if (pets['FlyingPig-Base']
&& pets['FlyingPig-CottonCandyBlue']
&& pets['FlyingPig-CottonCandyPink']
&& pets['FlyingPig-Desert']
&& pets['FlyingPig-Golden']
&& pets['FlyingPig-Red']
&& pets['FlyingPig-Shade']
&& pets['FlyingPig-Skeleton']
&& pets['FlyingPig-White']
&& pets['FlyingPig-Zombie']
&& pets['Owl-Base']
&& pets['Owl-CottonCandyBlue']
&& pets['Owl-CottonCandyPink']
&& pets['Owl-Desert']
&& pets['Owl-Golden']
&& pets['Owl-Red']
&& pets['Owl-Shade']
&& pets['Owl-Skeleton']
&& pets['Owl-White']
&& pets['Owl-Zombie']
&& pets['Parrot-Base']
&& pets['Parrot-CottonCandyBlue']
&& pets['Parrot-CottonCandyPink']
&& pets['Parrot-Desert']
&& pets['Parrot-Golden']
&& pets['Parrot-Red']
&& pets['Parrot-Shade']
&& pets['Parrot-Skeleton']
&& pets['Parrot-White']
&& pets['Parrot-Zombie']
&& pets['Rooster-Base']
&& pets['Rooster-CottonCandyBlue']
&& pets['Rooster-CottonCandyPink']
&& pets['Rooster-Desert']
&& pets['Rooster-Golden']
&& pets['Rooster-Red']
&& pets['Rooster-Shade']
&& pets['Rooster-Skeleton']
&& pets['Rooster-White']
&& pets['Rooster-Zombie']
&& pets['Pterodactyl-Base']
&& pets['Pterodactyl-CottonCandyBlue']
&& pets['Pterodactyl-CottonCandyPink']
&& pets['Pterodactyl-Desert']
&& pets['Pterodactyl-Golden']
&& pets['Pterodactyl-Red']
&& pets['Pterodactyl-Shade']
&& pets['Pterodactyl-Skeleton']
&& pets['Pterodactyl-White']
&& pets['Pterodactyl-Zombie']
&& pets['Gryphon-Base']
&& pets['Gryphon-CottonCandyBlue']
&& pets['Gryphon-CottonCandyPink']
&& pets['Gryphon-Desert']
&& pets['Gryphon-Golden']
&& pets['Gryphon-Red']
&& pets['Gryphon-Shade']
&& pets['Gryphon-Skeleton']
&& pets['Gryphon-White']
&& pets['Gryphon-Zombie']
&& pets['Falcon-Base']
&& pets['Falcon-CottonCandyBlue']
&& pets['Falcon-CottonCandyPink']
&& pets['Falcon-Desert']
&& pets['Falcon-Golden']
&& pets['Falcon-Red']
&& pets['Falcon-Shade']
&& pets['Falcon-Skeleton']
&& pets['Falcon-White']
&& pets['Falcon-Zombie']
&& pets['Peacock-Base']
&& pets['Peacock-CottonCandyBlue']
&& pets['Peacock-CottonCandyPink']
&& pets['Peacock-Desert']
&& pets['Peacock-Golden']
&& pets['Peacock-Red']
&& pets['Peacock-Shade']
&& pets['Peacock-Skeleton']
&& pets['Peacock-White']
&& pets['Peacock-Zombie']) {
set['achievements.birdsOfAFeather'] = true;
}
}
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
return await User.update({ _id: user._id }, { $set: set }).exec();
}
export default async function processUsers () {
let query = {
// migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2021-08-01') },
};
const fields = {
_id: 1,
items: 1,
};
while (true) { // eslint-disable-line no-constant-condition
const users = await User // eslint-disable-line no-await-in-loop
.find(query)
.limit(250)
.sort({_id: 1})
.select(fields)
.lean()
.exec();
if (users.length === 0) {
console.warn('All appropriate users found and modified.');
console.warn(`\n${count} users processed\n`);
break;
} else {
query._id = {
$gt: users[users.length - 1]._id,
};
}
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
}
};
+3 -3
View File
@@ -3,13 +3,13 @@ import { v4 as uuid } from 'uuid';
import { model as User } from '../../website/server/models/user';
const MIGRATION_NAME = '20210314_pi_day';
const MIGRATION_NAME = '20220314_pi_day';
const progressCount = 1000;
let count = 0;
async function updateUser (user) {
count *= 1;
count += 1;
const inc = {
'items.food.Pie_Skeleton': 1,
@@ -54,7 +54,7 @@ async function updateUser (user) {
export default async function processUsers () {
const query = {
migration: { $ne: MIGRATION_NAME },
'auth.timestamps.loggedin': { $gt: new Date('2021-02-15') },
'auth.timestamps.loggedin': { $gt: new Date('2022-02-15') },
};
const fields = {
+43 -29
View File
@@ -1,6 +1,6 @@
{
"name": "habitica",
"version": "4.219.0",
"version": "4.225.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1056,14 +1056,14 @@
}
},
"@babel/register": {
"version": "7.16.9",
"resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.9.tgz",
"integrity": "sha512-jJ72wcghdRIlENfvALcyODhNoGE5j75cYHdC+aQMh6cU/P86tiiXTp9XYZct1UxUMo/4+BgQRyNZEGx0KWGS+g==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/register/-/register-7.17.0.tgz",
"integrity": "sha512-UNZsMAZ7uKoGHo1HlEXfteEOYssf64n/PNLHGqOKq/bgYcu/4LrQWAHJwSCb3BRZK8Hi5gkJdRcwrGTO2wtRCg==",
"requires": {
"clone-deep": "^4.0.1",
"find-cache-dir": "^2.0.0",
"make-dir": "^2.1.0",
"pirates": "^4.0.0",
"pirates": "^4.0.5",
"source-map-support": "^0.5.16"
}
},
@@ -1834,12 +1834,27 @@
}
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"dependencies": {
"mime-db": {
"version": "1.51.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
"integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
},
"mime-types": {
"version": "2.1.34",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
"integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
"requires": {
"mime-db": "1.51.0"
}
}
}
},
"acorn": {
@@ -8120,8 +8135,7 @@
"ieee754": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
"optional": true
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"ignore": {
"version": "4.0.6",
@@ -10676,9 +10690,9 @@
}
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
},
"neo-async": {
"version": "2.6.2",
@@ -11545,9 +11559,9 @@
}
},
"pirates": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz",
"integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw=="
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
"integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ=="
},
"pixelsmith": {
"version": "2.4.1",
@@ -13538,9 +13552,9 @@
}
},
"stripe": {
"version": "8.201.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.201.0.tgz",
"integrity": "sha512-pF0F1DdE9zt0U6Cb0XN+REpdFkUmaqp6C7OEVOCeUpTAafjjJqrdV/WmZd7Y5MwT8XvDAxB5/v3CAXwxAp0XNg==",
"version": "8.202.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-8.202.0.tgz",
"integrity": "sha512-3YGHVnUatEn/At5+aRy+REdB2IyVa96/zls2xvQrKFTgaJzRu1MsJcK0GKg0p2B0y0VqlZo9gmdDEqphSHHvtA==",
"requires": {
"@types/node": ">=8.1.0",
"qs": "^6.6.0"
@@ -15238,9 +15252,9 @@
"integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw=="
},
"winston": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.5.0.tgz",
"integrity": "sha512-OQMbmLsIdVHvm2hSurrYZs+iZNIImXneYJ6pX7LseSMEq20HdTETXiNnNX3FDwN4LB/xDRZLF6JYOY+AI112Kw==",
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.5.1.tgz",
"integrity": "sha512-tbRtVy+vsSSCLcZq/8nXZaOie/S2tPXPFt4be/Q3vI/WtYwm7rrwidxVw2GRa38FIXcJ1kUM6MOZ9Jmnk3F3UA==",
"requires": {
"@dabh/diagnostics": "^2.0.2",
"async": "^3.2.3",
@@ -15255,13 +15269,13 @@
},
"dependencies": {
"winston-transport": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.2.tgz",
"integrity": "sha512-9jmhltAr5ygt5usgUTQbEiw/7RYXpyUbEAFRCSicIacpUzPkrnQsQZSPGEI12aLK9Jth4zNcYJx3Cvznwrl8pw==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz",
"integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==",
"requires": {
"logform": "^2.3.2",
"readable-stream": "^3.4.0",
"triple-beam": "^1.2.0"
"readable-stream": "^3.6.0",
"triple-beam": "^1.3.0"
}
}
}
+6 -6
View File
@@ -1,16 +1,16 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.219.0",
"version": "4.225.3",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.16.12",
"@babel/preset-env": "^7.16.11",
"@babel/register": "^7.16.9",
"@babel/register": "^7.17.0",
"@google-cloud/trace-agent": "^5.1.6",
"@parse/node-apn": "^5.1.0",
"@slack/webhook": "^6.1.0",
"accepts": "^1.3.5",
"accepts": "^1.3.8",
"amazon-payments": "^0.2.9",
"amplitude": "^5.2.0",
"apidoc": "^0.50.3",
@@ -67,14 +67,14 @@
"remove-markdown": "^0.3.0",
"rimraf": "^3.0.2",
"short-uuid": "^4.2.0",
"stripe": "^8.201.0",
"stripe": "^8.202.0",
"superagent": "^7.1.1",
"universal-analytics": "^0.5.3",
"useragent": "^2.1.9",
"uuid": "^8.3.2",
"validator": "^13.7.0",
"vinyl-buffer": "^1.0.1",
"winston": "^3.5.0",
"winston": "^3.5.1",
"winston-loggly-bulk": "^3.2.1",
"xml2js": "^0.4.23"
},
@@ -106,7 +106,7 @@
"start": "gulp nodemon",
"debug": "gulp nodemon --inspect",
"mongo:dev": "run-rs -v 4.2.8 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
"postinstall": "gulp build && cd website/client && npm install",
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
"apidoc": "gulp apidoc"
},
"devDependencies": {
File diff suppressed because it is too large Load Diff
+22 -1
View File
@@ -256,7 +256,7 @@ describe('Google Payments', () => {
expirationDate,
});
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
.returns([{ expirationDate: expirationDate.toDate() }]);
.returns([{ expirationDate: expirationDate.toDate(), autoRenewing: false }]);
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
.returns(true);
@@ -325,5 +325,26 @@ describe('Google Payments', () => {
headers,
});
});
it('should not cancel a user subscription with autorenew', async () => {
iap.getPurchaseData.restore();
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
.returns([{ autoRenewing: true }]);
await googlePayments.cancelSubscribe(user, headers);
expect(iapSetupStub).to.be.calledOnce;
expect(iapValidateStub).to.be.calledOnce;
expect(iapValidateStub).to.be.calledWith(iap.GOOGLE, {
data: receipt,
signature,
});
expect(iapIsValidatedStub).to.be.calledOnce;
expect(iapIsValidatedStub).to.be.calledWith({
expirationDate,
});
expect(iapGetPurchaseDataStub).to.be.calledOnce;
expect(paymentCancelSubscriptionSpy).to.not.be.called;
});
});
});
@@ -0,0 +1,38 @@
import {
generateUser,
translate as t,
} from '../../../helpers/api-integration/v4';
describe('GET /members/:memberId/purchase-history', () => {
let user;
before(async () => {
user = await generateUser({
contributor: { admin: true },
});
});
it('validates req.params.memberId', async () => {
await expect(user.get('/members/invalidUUID/purchase-history')).to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('invalidReqParams'),
});
});
it('returns error if user is not admin', async () => {
const member = await generateUser();
const nonAdmin = await generateUser();
await expect(nonAdmin.get(`/members/${member._id}/purchase-history`)).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('noAdminAccess'),
});
});
it('returns purchase history based on given user', async () => {
const member = await generateUser();
const response = await user.get(`/members/${member._id}/purchase-history`);
expect(response.length).to.equal(0);
});
});
+20 -24
View File
@@ -40,28 +40,27 @@ describe('shared.ops.buy', () => {
analytics.track.restore();
});
it('returns error when key is not provided', done => {
it('returns error when key is not provided', async () => {
try {
buy(user);
await buy(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
it('recovers 15 hp', () => {
it('recovers 15 hp', async () => {
user.stats.hp = 30;
buy(user, { params: { key: 'potion' } }, analytics);
await buy(user, { params: { key: 'potion' } }, analytics);
expect(user.stats.hp).to.eql(45);
expect(analytics.track).to.be.calledOnce;
});
it('adds equipment to inventory', () => {
it('adds equipment to inventory', async () => {
user.stats.gp = 31;
buy(user, { params: { key: 'armor_warrior_1' } });
await buy(user, { params: { key: 'armor_warrior_1' } });
expect(user.items.gear.owned).to.eql({
weapon_warrior_0: true,
@@ -90,10 +89,10 @@ describe('shared.ops.buy', () => {
});
});
it('buys Steampunk Accessories Set', () => {
it('buys Steampunk Accessories Set', async () => {
user.purchased.plan.consecutive.trinkets = 1;
buy(user, {
await buy(user, {
params: {
key: '301404',
},
@@ -108,10 +107,10 @@ describe('shared.ops.buy', () => {
expect(user.items.gear.owned).to.have.property('eyewear_mystery_301404', true);
});
it('buys a Quest scroll', () => {
it('buys a Quest scroll', async () => {
user.stats.gp = 205;
buy(user, {
await buy(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -122,11 +121,11 @@ describe('shared.ops.buy', () => {
expect(user.stats.gp).to.equal(5);
});
it('buys a special item', () => {
it('buys a special item', async () => {
user.stats.gp = 11;
const item = content.special.thankyou;
const [data, message] = buy(user, {
const [data, message] = await buy(user, {
params: {
key: 'thankyou',
},
@@ -144,15 +143,15 @@ describe('shared.ops.buy', () => {
}));
});
it('allows for bulk purchases', () => {
it('allows for bulk purchases', async () => {
user.stats.hp = 30;
buy(user, { params: { key: 'potion' }, quantity: 2 });
await buy(user, { params: { key: 'potion' }, quantity: 2 });
expect(user.stats.hp).to.eql(50);
});
it('errors if user supplies a non-numeric quantity', done => {
it('errors if user supplies a non-numeric quantity', async () => {
try {
buy(user, {
await buy(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -162,13 +161,12 @@ describe('shared.ops.buy', () => {
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('invalidQuantity'));
done();
}
});
it('errors if user supplies a negative quantity', done => {
it('errors if user supplies a negative quantity', async () => {
try {
buy(user, {
await buy(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -178,13 +176,12 @@ describe('shared.ops.buy', () => {
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('invalidQuantity'));
done();
}
});
it('errors if user supplies a decimal quantity', done => {
it('errors if user supplies a decimal quantity', async () => {
try {
buy(user, {
await buy(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -194,7 +191,6 @@ describe('shared.ops.buy', () => {
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('invalidQuantity'));
done();
}
});
});
+13 -14
View File
@@ -33,7 +33,7 @@ describe('shared.ops.buyArmoire', () => {
const YIELD_EXP = 0.9;
const analytics = { track () {} };
function buyArmoire (_user, _req, _analytics) {
async function buyArmoire (_user, _req, _analytics) {
const buyOp = new BuyArmoireOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -61,11 +61,11 @@ describe('shared.ops.buyArmoire', () => {
});
context('failure conditions', () => {
it('does not open if user does not have enough gold', done => {
it('does not open if user does not have enough gold', async () => {
user.stats.gp = 50;
try {
buyArmoire(user);
await buyArmoire(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
@@ -74,17 +74,16 @@ describe('shared.ops.buyArmoire', () => {
});
expect(user.items.food).to.be.empty;
expect(user.stats.exp).to.eql(0);
done();
}
});
});
context('non-gear awards', () => {
it('gives Experience', () => {
it('gives Experience', async () => {
const previousExp = user.stats.exp;
randomValFns.trueRandom.returns(YIELD_EXP);
buyArmoire(user);
await buyArmoire(user);
expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true });
expect(user.items.food).to.be.empty;
@@ -92,12 +91,12 @@ describe('shared.ops.buyArmoire', () => {
expect(user.stats.gp).to.equal(100);
});
it('gives food', () => {
it('gives food', async () => {
const previousExp = user.stats.exp;
randomValFns.trueRandom.returns(YIELD_FOOD);
buyArmoire(user);
await buyArmoire(user);
expect(user.items.gear.owned).to.eql({ weapon_warrior_0: true });
expect(user.items.food).to.not.be.empty;
@@ -105,12 +104,12 @@ describe('shared.ops.buyArmoire', () => {
expect(user.stats.gp).to.equal(100);
});
it('does not give equipment if all equipment has been found', () => {
it('does not give equipment if all equipment has been found', async () => {
randomValFns.trueRandom.returns(YIELD_EQUIPMENT);
user.items.gear.owned = getFullArmoire();
user.stats.gp = 150;
buyArmoire(user);
await buyArmoire(user);
expect(user.items.gear.owned).to.eql(getFullArmoire());
const armoireCount = count.remainingGearInSet(user.items.gear.owned, 'armoire');
@@ -122,13 +121,13 @@ describe('shared.ops.buyArmoire', () => {
});
context('gear awards', () => {
it('always drops equipment the first time', () => {
it('always drops equipment the first time', async () => {
delete user.flags.armoireOpened;
randomValFns.trueRandom.returns(YIELD_EXP);
expect(_.size(user.items.gear.owned)).to.equal(1);
buyArmoire(user);
await buyArmoire(user);
expect(_.size(user.items.gear.owned)).to.equal(2);
@@ -140,7 +139,7 @@ describe('shared.ops.buyArmoire', () => {
expect(user.stats.gp).to.equal(100);
});
it('gives more equipment', () => {
it('gives more equipment', async () => {
randomValFns.trueRandom.returns(YIELD_EQUIPMENT);
user.items.gear.owned = {
weapon_warrior_0: true,
@@ -150,7 +149,7 @@ describe('shared.ops.buyArmoire', () => {
expect(_.size(user.items.gear.owned)).to.equal(2);
buyArmoire(user, {}, analytics);
await buyArmoire(user, {}, analytics);
expect(_.size(user.items.gear.owned)).to.equal(3);
+17 -22
View File
@@ -11,7 +11,7 @@ import i18n from '../../../../website/common/script/i18n';
import { BuyGemOperation } from '../../../../website/common/script/ops/buy/buyGem';
import planGemLimits from '../../../../website/common/script/libs/planGemLimits';
function buyGem (user, req, analytics) {
async function buyGem (user, req, analytics) {
const buyOp = new BuyGemOperation(user, req, analytics);
return buyOp.purchase();
@@ -44,8 +44,8 @@ describe('shared.ops.buyGem', () => {
});
context('Gems', () => {
it('purchases gems', () => {
const [, message] = buyGem(user, { params: { type: 'gems', key: 'gem' } }, analytics);
it('purchases gems', async () => {
const [, message] = await buyGem(user, { params: { type: 'gems', key: 'gem' } }, analytics);
expect(message).to.equal(i18n.t('plusGem', { count: 1 }));
expect(user.balance).to.equal(userGemAmount + 0.25);
@@ -54,8 +54,8 @@ describe('shared.ops.buyGem', () => {
expect(analytics.track).to.be.calledOnce;
});
it('purchases gems with a different language than the default', () => {
const [, message] = buyGem(user, { params: { type: 'gems', key: 'gem' }, language: 'de' });
it('purchases gems with a different language than the default', async () => {
const [, message] = await buyGem(user, { params: { type: 'gems', key: 'gem' }, language: 'de' });
expect(message).to.equal(i18n.t('plusGem', { count: 1 }, 'de'));
expect(user.balance).to.equal(userGemAmount + 0.25);
@@ -63,8 +63,8 @@ describe('shared.ops.buyGem', () => {
expect(user.stats.gp).to.equal(goldPoints - planGemLimits.convRate);
});
it('makes bulk purchases of gems', () => {
const [, message] = buyGem(user, {
it('makes bulk purchases of gems', async () => {
const [, message] = await buyGem(user, {
params: { type: 'gems', key: 'gem' },
quantity: 2,
});
@@ -76,63 +76,58 @@ describe('shared.ops.buyGem', () => {
});
context('Failure conditions', () => {
it('returns an error when key is not provided', done => {
it('returns an error when key is not provided', async () => {
try {
buyGem(user, { params: { type: 'gems' } });
await buyGem(user, { params: { type: 'gems' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('missingKeyParam'));
done();
}
});
it('prevents unsubscribed user from buying gems', done => {
it('prevents unsubscribed user from buying gems', async () => {
delete user.purchased.plan.customerId;
try {
buyGem(user, { params: { type: 'gems', key: 'gem' } });
await buyGem(user, { params: { type: 'gems', key: 'gem' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('mustSubscribeToPurchaseGems'));
done();
}
});
it('prevents user with not enough gold from buying gems', done => {
it('prevents user with not enough gold from buying gems', async () => {
user.stats.gp = 15;
try {
buyGem(user, { params: { type: 'gems', key: 'gem' } });
await buyGem(user, { params: { type: 'gems', key: 'gem' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
done();
}
});
it('prevents user that have reached the conversion cap from buying gems', done => {
it('prevents user that have reached the conversion cap from buying gems', async () => {
user.stats.gp = goldPoints;
user.purchased.plan.gemsBought = gemsBought;
try {
buyGem(user, { params: { type: 'gems', key: 'gem' } });
await buyGem(user, { params: { type: 'gems', key: 'gem' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('maxBuyGems', { convCap: planGemLimits.convCap }));
done();
}
});
it('prevents user from buying an invalid quantity', done => {
it('prevents user from buying an invalid quantity', async () => {
user.stats.gp = goldPoints;
user.purchased.plan.gemsBought = gemsBought;
try {
buyGem(user, { params: { type: 'gems', key: 'gem' }, quantity: 'a' });
await buyGem(user, { params: { type: 'gems', key: 'gem' }, quantity: 'a' });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
});
+15 -23
View File
@@ -12,7 +12,7 @@ describe('shared.ops.buyHealthPotion', () => {
let user;
const analytics = { track () {} };
function buyHealthPotion (_user, _req, _analytics) {
async function buyHealthPotion (_user, _req, _analytics) {
const buyOp = new BuyHealthPotionOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -40,83 +40,75 @@ describe('shared.ops.buyHealthPotion', () => {
});
context('Potion', () => {
it('recovers 15 hp', () => {
it('recovers 15 hp', async () => {
user.stats.hp = 30;
buyHealthPotion(user, {}, analytics);
await buyHealthPotion(user, {}, analytics);
expect(user.stats.hp).to.eql(45);
expect(analytics.track).to.be.calledOnce;
});
it('does not increase hp above 50', () => {
it('does not increase hp above 50', async () => {
user.stats.hp = 45;
buyHealthPotion(user);
await buyHealthPotion(user);
expect(user.stats.hp).to.eql(50);
});
it('deducts 25 gp', () => {
it('deducts 25 gp', async () => {
user.stats.hp = 45;
buyHealthPotion(user);
await buyHealthPotion(user);
expect(user.stats.gp).to.eql(175);
});
it('does not purchase if not enough gp', done => {
it('does not purchase if not enough gp', async () => {
user.stats.hp = 45;
user.stats.gp = 5;
try {
buyHealthPotion(user);
await buyHealthPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.stats.hp).to.eql(45);
expect(user.stats.gp).to.eql(5);
done();
}
});
it('does not purchase if hp is full', done => {
it('does not purchase if hp is full', async () => {
user.stats.hp = 50;
user.stats.gp = 40;
try {
buyHealthPotion(user);
await buyHealthPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageHealthAlreadyMax'));
expect(user.stats.hp).to.eql(50);
expect(user.stats.gp).to.eql(40);
done();
}
});
it('does not allow potion purchases when hp is zero', done => {
it('does not allow potion purchases when hp is zero', async () => {
user.stats.hp = 0;
user.stats.gp = 40;
try {
buyHealthPotion(user);
await buyHealthPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageHealthAlreadyMin'));
expect(user.stats.hp).to.eql(0);
expect(user.stats.gp).to.eql(40);
done();
}
});
it('does not allow potion purchases when hp is negative', done => {
it('does not allow potion purchases when hp is negative', async () => {
user.stats.hp = -8;
user.stats.gp = 40;
try {
buyHealthPotion(user);
await buyHealthPotion(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageHealthAlreadyMin'));
expect(user.stats.hp).to.eql(-8);
expect(user.stats.gp).to.eql(40);
done();
}
});
});
+44 -52
View File
@@ -13,7 +13,7 @@ import {
import i18n from '../../../../website/common/script/i18n';
import errorMessage from '../../../../website/common/script/libs/errorMessage';
function buyGear (user, req, analytics) {
async function buyGear (user, req, analytics) {
const buyOp = new BuyMarketGearOperation(user, req, analytics);
return buyOp.purchase();
@@ -57,10 +57,10 @@ describe('shared.ops.buyMarketGear', () => {
});
context('Gear', () => {
it('adds equipment to inventory', () => {
it('adds equipment to inventory', async () => {
user.stats.gp = 31;
buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
expect(user.items.gear.owned).to.eql({
weapon_warrior_0: true,
@@ -90,10 +90,10 @@ describe('shared.ops.buyMarketGear', () => {
expect(analytics.track).to.be.calledOnce;
});
it('adds the onboarding achievement to the user and checks the onboarding status', () => {
it('adds the onboarding achievement to the user and checks the onboarding status', async () => {
user.stats.gp = 31;
buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
expect(user.addAchievement).to.be.calledOnce;
expect(user.addAchievement).to.be.calledWith('purchasedEquipment');
@@ -102,36 +102,36 @@ describe('shared.ops.buyMarketGear', () => {
expect(shared.onboarding.checkOnboardingStatus).to.be.calledWith(user);
});
it('does not add the onboarding achievement to the user if it\'s already been awarded', () => {
it('does not add the onboarding achievement to the user if it\'s already been awarded', async () => {
user.stats.gp = 31;
user.achievements.purchasedEquipment = true;
buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
await buyGear(user, { params: { key: 'armor_warrior_1' } }, analytics);
expect(user.addAchievement).to.not.be.called;
});
it('deducts gold from user', () => {
it('deducts gold from user', async () => {
user.stats.gp = 31;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
expect(user.stats.gp).to.eql(1);
});
it('auto equips equipment if user has auto-equip preference turned on', () => {
it('auto equips equipment if user has auto-equip preference turned on', async () => {
user.stats.gp = 31;
user.preferences.autoEquip = true;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
expect(user.items.gear.equipped).to.have.property('armor', 'armor_warrior_1');
});
it('updates the pinnedItems to the next item in the set if one exists', () => {
it('updates the pinnedItems to the next item in the set if one exists', async () => {
user.stats.gp = 31;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
expect(user.pinnedItems).to.deep.include({
type: 'marketGear',
@@ -139,155 +139,147 @@ describe('shared.ops.buyMarketGear', () => {
});
});
it('buyGears equipment but does not auto-equip', () => {
it('buyGears equipment but does not auto-equip', async () => {
user.stats.gp = 31;
user.preferences.autoEquip = false;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
expect(user.items.gear.equipped.property).to.not.equal('armor_warrior_1');
});
it('does not buyGear equipment twice', done => {
it('does not buyGear equipment twice', async () => {
user.stats.gp = 62;
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
try {
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('equipmentAlreadyOwned'));
done();
}
});
it('does not buy equipment of different class', done => {
it('does not buy equipment of different class', async () => {
user.stats.gp = 82;
user.stats.class = 'warrior';
try {
buyGear(user, { params: { key: 'weapon_special_winter2018Rogue' } });
await buyGear(user, { params: { key: 'weapon_special_winter2018Rogue' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('cannotBuyItem'));
done();
}
});
it('does not buy equipment in bulk', done => {
it('does not buy equipment in bulk', async () => {
user.stats.gp = 82;
try {
buyGear(user, { params: { key: 'armor_warrior_1' }, quantity: 3 });
await buyGear(user, { params: { key: 'armor_warrior_1' }, quantity: 3 });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotAbleToBuyInBulk'));
done();
}
});
// TODO after user.ops.equip is done
xit('removes one-handed weapon and shield if auto-equip is on and a two-hander is bought', () => {
xit('removes one-handed weapon and shield if auto-equip is on and a two-hander is bought', async () => {
user.stats.gp = 100;
user.preferences.autoEquip = true;
buyGear(user, { params: { key: 'shield_warrior_1' } });
await buyGear(user, { params: { key: 'shield_warrior_1' } });
user.ops.equip({ params: { key: 'shield_warrior_1' } });
buyGear(user, { params: { key: 'weapon_warrior_1' } });
await buyGear(user, { params: { key: 'weapon_warrior_1' } });
user.ops.equip({ params: { key: 'weapon_warrior_1' } });
buyGear(user, { params: { key: 'weapon_wizard_1' } });
await buyGear(user, { params: { key: 'weapon_wizard_1' } });
expect(user.items.gear.equipped).to.have.property('shield', 'shield_base_0');
expect(user.items.gear.equipped).to.have.property('weapon', 'weapon_wizard_1');
});
// TODO after user.ops.equip is done
xit('buyGears two-handed equipment but does not automatically remove sword or shield', () => {
xit('buyGears two-handed equipment but does not automatically remove sword or shield', async () => {
user.stats.gp = 100;
user.preferences.autoEquip = false;
buyGear(user, { params: { key: 'shield_warrior_1' } });
await buyGear(user, { params: { key: 'shield_warrior_1' } });
user.ops.equip({ params: { key: 'shield_warrior_1' } });
buyGear(user, { params: { key: 'weapon_warrior_1' } });
await buyGear(user, { params: { key: 'weapon_warrior_1' } });
user.ops.equip({ params: { key: 'weapon_warrior_1' } });
buyGear(user, { params: { key: 'weapon_wizard_1' } });
await buyGear(user, { params: { key: 'weapon_wizard_1' } });
expect(user.items.gear.equipped).to.have.property('shield', 'shield_warrior_1');
expect(user.items.gear.equipped).to.have.property('weapon', 'weapon_warrior_1');
});
it('does not buyGear equipment without enough Gold', done => {
it('does not buyGear equipment without enough Gold', async () => {
user.stats.gp = 20;
try {
buyGear(user, { params: { key: 'armor_warrior_1' } });
await buyGear(user, { params: { key: 'armor_warrior_1' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.items.gear.owned).to.not.have.property('armor_warrior_1');
done();
}
});
it('returns error when key is not provided', done => {
it('returns error when key is not provided', async () => {
try {
buyGear(user);
await buyGear(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
it('returns error when item is not found', done => {
it('returns error when item is not found', async () => {
const params = { key: 'armor_warrior_notExisting' };
try {
buyGear(user, { params });
await buyGear(user, { params });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(errorMessage('itemNotFound', params));
done();
}
});
it('does not buyGear equipment without the previous equipment', done => {
it('does not buyGear equipment without the previous equipment', async () => {
try {
buyGear(user, { params: { key: 'armor_warrior_2' } });
await buyGear(user, { params: { key: 'armor_warrior_2' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('previousGearNotOwned'));
done();
}
});
it('does not buyGear equipment if user does not own prior item in sequence', done => {
it('does not buyGear equipment if user does not own prior item in sequence', async () => {
user.stats.gp = 200;
try {
buyGear(user, { params: { key: 'armor_warrior_2' } });
await buyGear(user, { params: { key: 'armor_warrior_2' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('previousGearNotOwned'));
expect(user.items.gear.owned).to.not.have.property('armor_warrior_2');
done();
}
});
it('does buyGear equipment if item is a numbered special item user qualifies for', () => {
it('does buyGear equipment if item is a numbered special item user qualifies for', async () => {
user.stats.gp = 200;
user.items.gear.owned.head_special_2 = false;
buyGear(user, { params: { key: 'head_special_2' } });
await buyGear(user, { params: { key: 'head_special_2' } });
expect(user.items.gear.owned).to.have.property('head_special_2', true);
});
it('does buyGear equipment if it is an armoire item that an user previously lost', () => {
it('does buyGear equipment if it is an armoire item that an user previously lost', async () => {
user.stats.gp = 200;
user.items.gear.owned.shield_armoire_ramHornShield = false;
buyGear(user, { params: { key: 'shield_armoire_ramHornShield' } });
await buyGear(user, { params: { key: 'shield_armoire_ramHornShield' } });
expect(user.items.gear.owned).to.have.property('shield_armoire_ramHornShield', true);
});
+8 -11
View File
@@ -35,18 +35,17 @@ describe('shared.ops.buyMysterySet', () => {
context('Mystery Sets', () => {
context('failure conditions', () => {
it('does not grant mystery sets without Mystic Hourglasses', done => {
it('does not grant mystery sets without Mystic Hourglasses', async () => {
try {
buyMysterySet(user, { params: { key: '201501' } });
await buyMysterySet(user, { params: { key: '201501' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notEnoughHourglasses'));
expect(user.items.gear.owned).to.have.property('weapon_warrior_0', true);
done();
}
});
it('does not grant mystery set that has already been purchased', done => {
it('does not grant mystery set that has already been purchased', async () => {
user.purchased.plan.consecutive.trinkets = 1;
user.items.gear.owned = {
weapon_warrior_0: true,
@@ -57,30 +56,28 @@ describe('shared.ops.buyMysterySet', () => {
};
try {
buyMysterySet(user, { params: { key: '301404' } });
await buyMysterySet(user, { params: { key: '301404' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.eql(i18n.t('mysterySetNotFound'));
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
done();
}
});
it('returns error when key is not provided', done => {
it('returns error when key is not provided', async () => {
try {
buyMysterySet(user);
await buyMysterySet(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
});
context('successful purchases', () => {
it('buys Steampunk Accessories Set', () => {
it('buys Steampunk Accessories Set', async () => {
user.purchased.plan.consecutive.trinkets = 1;
buyMysterySet(user, { params: { key: '301404' } }, analytics);
await buyMysterySet(user, { params: { key: '301404' } }, analytics);
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
expect(user.items.gear.owned).to.have.property('weapon_warrior_0', true);
+9 -10
View File
@@ -13,7 +13,7 @@ describe('shared.ops.buyQuestGems', () => {
const goldPoints = 40;
const analytics = { track () {} };
function buyQuest (_user, _req, _analytics) {
async function buyQuest (_user, _req, _analytics) {
const buyOp = new BuyQuestWithGemOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -44,19 +44,19 @@ describe('shared.ops.buyQuestGems', () => {
user.pinnedItems.push({ type: 'quests', key: 'gryphon' });
});
it('purchases quests', () => {
it('purchases quests', async () => {
const key = 'gryphon';
buyQuest(user, { params: { key } });
await buyQuest(user, { params: { key } });
expect(user.items.quests[key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', () => {
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', async () => {
const key = 'dustbunnies';
user.items.quests[key] = -1;
buyQuest(user, { params: { key } });
await buyQuest(user, { params: { key } });
expect(user.items.quests[key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
@@ -73,26 +73,25 @@ describe('shared.ops.buyQuestGems', () => {
user.purchased.plan.customerId = 'customer-id';
});
it('errors when user does not have enough gems', done => {
it('errors when user does not have enough gems', async () => {
user.balance = 1;
const key = 'gryphon';
try {
buyQuest(user, {
await buyQuest(user, {
params: { key },
quantity: 2,
});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('makes bulk purchases of quests', () => {
it('makes bulk purchases of quests', async () => {
const key = 'gryphon';
buyQuest(user, {
await buyQuest(user, {
params: { key },
quantity: 3,
});
+22 -29
View File
@@ -14,7 +14,7 @@ describe('shared.ops.buyQuest', () => {
let user;
const analytics = { track () {} };
function buyQuest (_user, _req, _analytics) {
async function buyQuest (_user, _req, _analytics) {
const buyOp = new BuyQuestWithGoldOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -29,9 +29,9 @@ describe('shared.ops.buyQuest', () => {
analytics.track.restore();
});
it('buys a Quest scroll', () => {
it('buys a Quest scroll', async () => {
user.stats.gp = 205;
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -43,11 +43,11 @@ describe('shared.ops.buyQuest', () => {
expect(analytics.track).to.be.calledOnce;
});
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', () => {
it('if a user\'s count of a quest scroll is negative, it will be reset to 0 before incrementing when they buy a new one.', async () => {
user.stats.gp = 205;
const key = 'dilatoryDistress1';
user.items.quests[key] = -1;
buyQuest(user, {
await buyQuest(user, {
params: { key },
}, analytics);
expect(user.items.quests[key]).to.equal(1);
@@ -55,14 +55,14 @@ describe('shared.ops.buyQuest', () => {
expect(analytics.track).to.be.calledOnce;
});
it('buys a Quest scroll with the right quantity if a string is passed for quantity', () => {
it('buys a Quest scroll with the right quantity if a string is passed for quantity', async () => {
user.stats.gp = 1000;
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
}, analytics);
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -74,10 +74,10 @@ describe('shared.ops.buyQuest', () => {
});
});
it('does not buy a Quest scroll when an invalid quantity is passed', done => {
it('does not buy a Quest scroll when an invalid quantity is passed', async () => {
user.stats.gp = 1000;
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -88,14 +88,13 @@ describe('shared.ops.buyQuest', () => {
expect(err.message).to.equal(i18n.t('invalidQuantity'));
expect(user.items.quests).to.eql({});
expect(user.stats.gp).to.equal(1000);
done();
}
});
it('does not buy Quests without enough Gold', done => {
it('does not buy Quests without enough Gold', async () => {
user.stats.gp = 1;
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress1',
},
@@ -105,14 +104,13 @@ describe('shared.ops.buyQuest', () => {
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
expect(user.items.quests).to.eql({});
expect(user.stats.gp).to.equal(1);
done();
}
});
it('does not buy nonexistent Quests', done => {
it('does not buy nonexistent Quests', async () => {
user.stats.gp = 9999;
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'snarfblatter',
},
@@ -122,13 +120,12 @@ describe('shared.ops.buyQuest', () => {
expect(err.message).to.equal(errorMessage('questNotFound', { key: 'snarfblatter' }));
expect(user.items.quests).to.eql({});
expect(user.stats.gp).to.equal(9999);
done();
}
});
it('does not buy the Mystery of the Masterclassers', done => {
it('does not buy the Mystery of the Masterclassers', async () => {
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'lostMasterclasser1',
},
@@ -137,14 +134,13 @@ describe('shared.ops.buyQuest', () => {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('questUnlockLostMasterclasser'));
expect(user.items.quests).to.eql({});
done();
}
});
it('does not buy Gem-premium Quests', done => {
it('does not buy Gem-premium Quests', async () => {
user.stats.gp = 9999;
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'kraken',
},
@@ -154,23 +150,21 @@ describe('shared.ops.buyQuest', () => {
expect(err.message).to.equal(i18n.t('questNotGoldPurchasable', { key: 'kraken' }));
expect(user.items.quests).to.eql({});
expect(user.stats.gp).to.equal(9999);
done();
}
});
it('returns error when key is not provided', done => {
it('returns error when key is not provided', async () => {
try {
buyQuest(user);
await buyQuest(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
it('does not buy a quest without completing previous quests', done => {
it('does not buy a quest without completing previous quests', async () => {
try {
buyQuest(user, {
await buyQuest(user, {
params: {
key: 'dilatoryDistress3',
},
@@ -179,7 +173,6 @@ describe('shared.ops.buyQuest', () => {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('mustComplete', { quest: 'dilatoryDistress2' }));
expect(user.items.quests).to.eql({});
done();
}
});
});
+9 -12
View File
@@ -15,7 +15,7 @@ describe('shared.ops.buySpecialSpell', () => {
let user;
const analytics = { track () {} };
function buySpecialSpell (_user, _req, _analytics) {
async function buySpecialSpell (_user, _req, _analytics) {
const buyOp = new BuySpellOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -29,19 +29,18 @@ describe('shared.ops.buySpecialSpell', () => {
analytics.track.restore();
});
it('throws an error if params.key is missing', done => {
it('throws an error if params.key is missing', async () => {
try {
buySpecialSpell(user);
await buySpecialSpell(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(errorMessage('missingKeyParam'));
done();
}
});
it('throws an error if the spell doesn\'t exists', done => {
it('throws an error if the spell doesn\'t exists', async () => {
try {
buySpecialSpell(user, {
await buySpecialSpell(user, {
params: {
key: 'notExisting',
},
@@ -49,14 +48,13 @@ describe('shared.ops.buySpecialSpell', () => {
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(errorMessage('spellNotFound', { spellId: 'notExisting' }));
done();
}
});
it('throws an error if the user doesn\'t have enough gold', done => {
it('throws an error if the user doesn\'t have enough gold', async () => {
user.stats.gp = 1;
try {
buySpecialSpell(user, {
await buySpecialSpell(user, {
params: {
key: 'thankyou',
},
@@ -64,15 +62,14 @@ describe('shared.ops.buySpecialSpell', () => {
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotEnoughGold'));
done();
}
});
it('buys an item', () => {
it('buys an item', async () => {
user.stats.gp = 11;
const item = content.special.thankyou;
const [data, message] = buySpecialSpell(user, {
const [data, message] = await buySpecialSpell(user, {
params: {
key: 'thankyou',
},
+23 -32
View File
@@ -15,7 +15,7 @@ describe('common.ops.hourglassPurchase', () => {
let user;
const analytics = { track () {} };
function buyMount (_user, _req, _analytics) {
async function buyMount (_user, _req, _analytics) {
const buyOp = new BuyHourglassMountOperation(_user, _req, _analytics);
return buyOp.purchase();
@@ -31,116 +31,107 @@ describe('common.ops.hourglassPurchase', () => {
});
context('failure conditions', () => {
it('return error when key is not provided', done => {
it('return error when key is not provided', async () => {
try {
hourglassPurchase(user, { params: {} });
await hourglassPurchase(user, { params: {} });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.eql(errorMessage('missingKeyParam'));
done();
}
});
it('returns error when type is not provided', done => {
it('returns error when type is not provided', async () => {
try {
hourglassPurchase(user, { params: { key: 'Base' } });
await hourglassPurchase(user, { params: { key: 'Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.eql(errorMessage('missingTypeParam'));
done();
}
});
it('returns error when inccorect type is provided', done => {
it('returns error when inccorect type is provided', async () => {
try {
hourglassPurchase(user, { params: { type: 'notAType', key: 'MantisShrimp-Base' } });
await hourglassPurchase(user, { params: { type: 'notAType', key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('typeNotAllowedHourglass', { allowedTypes: _.keys(content.timeTravelStable).toString() }));
done();
}
});
it('does not grant to pets without Mystic Hourglasses', done => {
it('does not grant to pets without Mystic Hourglasses', async () => {
try {
hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } });
await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notEnoughHourglasses'));
done();
}
});
it('does not grant to mounts without Mystic Hourglasses', done => {
it('does not grant to mounts without Mystic Hourglasses', async () => {
try {
buyMount(user, { params: { key: 'MantisShrimp-Base' } });
await buyMount(user, { params: { key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notEnoughHourglasses'));
done();
}
});
it('does not grant pet that is not part of the Time Travel Stable', done => {
it('does not grant pet that is not part of the Time Travel Stable', async () => {
user.purchased.plan.consecutive.trinkets = 1;
try {
hourglassPurchase(user, { params: { type: 'pets', key: 'Wolf-Veteran' } });
await hourglassPurchase(user, { params: { type: 'pets', key: 'Wolf-Veteran' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notAllowedHourglass'));
done();
}
});
it('does not grant mount that is not part of the Time Travel Stable', done => {
it('does not grant mount that is not part of the Time Travel Stable', async () => {
user.purchased.plan.consecutive.trinkets = 1;
try {
buyMount(user, { params: { key: 'Orca-Base' } });
await buyMount(user, { params: { key: 'Orca-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('notAllowedHourglass'));
done();
}
});
it('does not grant pet that has already been purchased', done => {
it('does not grant pet that has already been purchased', async () => {
user.purchased.plan.consecutive.trinkets = 1;
user.items.pets = {
'MantisShrimp-Base': true,
};
try {
hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } });
await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('petsAlreadyOwned'));
done();
}
});
it('does not grant mount that has already been purchased', done => {
it('does not grant mount that has already been purchased', async () => {
user.purchased.plan.consecutive.trinkets = 1;
user.items.mounts = {
'MantisShrimp-Base': true,
};
try {
buyMount(user, { params: { key: 'MantisShrimp-Base' } });
await buyMount(user, { params: { key: 'MantisShrimp-Base' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.eql(i18n.t('mountsAlreadyOwned'));
done();
}
});
});
context('successful purchases', () => {
it('buys a pet', () => {
it('buys a pet', async () => {
user.purchased.plan.consecutive.trinkets = 2;
const [, message] = hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }, analytics);
const [, message] = await hourglassPurchase(user, { params: { type: 'pets', key: 'MantisShrimp-Base' } }, analytics);
expect(message).to.eql(i18n.t('hourglassPurchase'));
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
@@ -148,10 +139,10 @@ describe('common.ops.hourglassPurchase', () => {
expect(analytics.track).to.be.calledOnce;
});
it('buys a mount', () => {
it('buys a mount', async () => {
user.purchased.plan.consecutive.trinkets = 2;
const [, message] = buyMount(user, { params: { key: 'MantisShrimp-Base' } });
const [, message] = await buyMount(user, { params: { key: 'MantisShrimp-Base' } });
expect(message).to.eql(i18n.t('hourglassPurchase'));
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
expect(user.items.mounts).to.eql({ 'MantisShrimp-Base': true });
+34 -45
View File
@@ -33,118 +33,108 @@ describe('shared.ops.purchase', () => {
});
context('failure conditions', () => {
it('returns an error when type is not provided', done => {
it('returns an error when type is not provided', async () => {
try {
purchase(user, { params: {} });
await purchase(user, { params: {} });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('typeRequired'));
done();
}
});
it('returns error when unknown type is provided', done => {
it('returns error when unknown type is provided', async () => {
try {
purchase(user, { params: { type: 'randomType', key: 'gem' } });
await purchase(user, { params: { type: 'randomType', key: 'gem' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(i18n.t('notAccteptedType'));
done();
}
});
it('returns error when user attempts to purchase a piece of gear they own', done => {
it('returns error when user attempts to purchase a piece of gear they own', async () => {
user.items.gear.owned['shield_rogue_1'] = true; // eslint-disable-line dot-notation
try {
purchase(user, { params: { type: 'gear', key: 'shield_rogue_1' } });
await purchase(user, { params: { type: 'gear', key: 'shield_rogue_1' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('alreadyHave'));
done();
}
});
it('returns error when unknown item is requested', done => {
it('returns error when unknown item is requested', async () => {
try {
purchase(user, { params: { type: 'gear', key: 'randomKey' } });
await purchase(user, { params: { type: 'gear', key: 'randomKey' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(i18n.t('contentKeyNotFound', { type: 'gear' }));
done();
}
});
it('returns error when user does not have permission to buy an item', done => {
it('returns error when user does not have permission to buy an item', async () => {
try {
purchase(user, { params: { type: 'gear', key: 'eyewear_mystery_301405' } });
await purchase(user, { params: { type: 'gear', key: 'eyewear_mystery_301405' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageNotAvailable'));
done();
}
});
it('returns error when user does not have enough gems to buy an item', done => {
it('returns error when user does not have enough gems to buy an item', async () => {
try {
purchase(user, { params: { type: 'gear', key: 'headAccessory_special_wolfEars' } });
await purchase(user, { params: { type: 'gear', key: 'headAccessory_special_wolfEars' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('returns error when item is not found', done => {
it('returns error when item is not found', async () => {
const params = { key: 'notExisting', type: 'food' };
try {
purchase(user, { params });
await purchase(user, { params });
} catch (err) {
expect(err).to.be.an.instanceof(NotFound);
expect(err.message).to.equal(i18n.t('contentKeyNotFound', params));
done();
}
});
it('returns error when user supplies a non-numeric quantity', done => {
it('returns error when user supplies a non-numeric quantity', async () => {
const type = 'eggs';
const key = 'Wolf';
try {
purchase(user, { params: { type, key }, quantity: 'jamboree' }, analytics);
await purchase(user, { params: { type, key }, quantity: 'jamboree' }, analytics);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
it('returns error when user supplies a negative quantity', done => {
it('returns error when user supplies a negative quantity', async () => {
const type = 'eggs';
const key = 'Wolf';
user.balance = 10;
try {
purchase(user, { params: { type, key }, quantity: -2 }, analytics);
await purchase(user, { params: { type, key }, quantity: -2 }, analytics);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
it('returns error when user supplies a decimal quantity', done => {
it('returns error when user supplies a decimal quantity', async () => {
const type = 'eggs';
const key = 'Wolf';
user.balance = 10;
try {
purchase(user, { params: { type, key }, quantity: 2.9 }, analytics);
await purchase(user, { params: { type, key }, quantity: 2.9 }, analytics);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidQuantity'));
done();
}
});
});
@@ -164,48 +154,48 @@ describe('shared.ops.purchase', () => {
user.pinnedItems.push({ type: 'bundles', key: 'featheredFriends' });
});
it('purchases eggs', () => {
it('purchases eggs', async () => {
const type = 'eggs';
const key = 'Wolf';
purchase(user, { params: { type, key } }, analytics);
await purchase(user, { params: { type, key } }, analytics);
expect(user.items[type][key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
expect(analytics.track).to.be.calledOnce;
});
it('purchases hatchingPotions', () => {
it('purchases hatchingPotions', async () => {
const type = 'hatchingPotions';
const key = 'Base';
purchase(user, { params: { type, key } });
await purchase(user, { params: { type, key } });
expect(user.items[type][key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});
it('purchases food', () => {
it('purchases food', async () => {
const type = 'food';
const key = SEASONAL_FOOD;
purchase(user, { params: { type, key } });
await purchase(user, { params: { type, key } });
expect(user.items[type][key]).to.equal(1);
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
});
it('purchases gear', () => {
it('purchases gear', async () => {
const type = 'gear';
const key = 'headAccessory_special_tigerEars';
purchase(user, { params: { type, key } });
await purchase(user, { params: { type, key } });
expect(user.items.gear.owned[key]).to.be.true;
expect(pinnedGearUtils.removeItemByPath.calledOnce).to.equal(true);
});
it('purchases quest bundles', () => {
it('purchases quest bundles', async () => {
const startingBalance = user.balance;
const clock = sandbox.useFakeTimers(moment('2019-05-20').valueOf());
const type = 'bundles';
@@ -217,7 +207,7 @@ describe('shared.ops.purchase', () => {
'owl',
];
purchase(user, { params: { type, key } });
await purchase(user, { params: { type, key } });
forEach(questList, bundledKey => {
expect(user.items.quests[bundledKey]).to.equal(1);
@@ -240,28 +230,27 @@ describe('shared.ops.purchase', () => {
user.purchased.plan.customerId = 'customer-id';
});
it('errors when user does not have enough gems', done => {
it('errors when user does not have enough gems', async () => {
user.balance = 1;
const type = 'eggs';
const key = 'TigerCub';
try {
purchase(user, {
await purchase(user, {
params: { type, key },
quantity: 2,
});
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('makes bulk purchases of eggs', () => {
it('makes bulk purchases of eggs', async () => {
const type = 'eggs';
const key = 'TigerCub';
purchase(user, {
await purchase(user, {
params: { type, key },
quantity: 2,
});
+14 -18
View File
@@ -19,51 +19,48 @@ describe('shared.ops.changeClass', () => {
user.stats.flagSelected = false;
});
it('user is not level 10', done => {
it('user is not level 10', async () => {
user.stats.lvl = 9;
try {
changeClass(user, { query: { class: 'rogue' } });
await await changeClass(user, { query: { class: 'rogue' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('lvl10ChangeClass'));
done();
}
});
it('req.query.class is an invalid class', done => {
it('req.query.class is an invalid class', async () => {
user.flags.classSelected = false;
user.preferences.disableClasses = false;
try {
changeClass(user, { query: { class: 'cellist' } });
await changeClass(user, { query: { class: 'cellist' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidClass'));
done();
}
});
context('req.query.class is a valid class', () => {
it('errors if user.stats.flagSelected is true and user.balance < 0.75', done => {
it('errors if user.stats.flagSelected is true and user.balance < 0.75', async () => {
user.flags.classSelected = true;
user.preferences.disableClasses = false;
user.balance = 0;
try {
changeClass(user, { query: { class: 'rogue' } });
await changeClass(user, { query: { class: 'rogue' } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('changes class', () => {
it('changes class', async () => {
user.stats.class = 'healer';
user.items.gear.owned.weapon_healer_3 = true;
user.items.gear.equipped.weapon = 'weapon_healer_3';
const [data] = changeClass(user, { query: { class: 'rogue' } });
const [data] = await changeClass(user, { query: { class: 'rogue' } });
expect(data).to.eql({
preferences: user.preferences,
stats: user.stats,
@@ -81,7 +78,7 @@ describe('shared.ops.changeClass', () => {
});
context('req.query.class is missing or user.stats.flagSelected is true', () => {
it('has user.preferences.disableClasses === true', () => {
it('has user.preferences.disableClasses === true', async () => {
user.balance = 1;
user.preferences.disableClasses = true;
user.preferences.autoAllocate = true;
@@ -92,7 +89,7 @@ describe('shared.ops.changeClass', () => {
user.stats.int = 4;
user.flags.classSelected = true;
const [data] = changeClass(user);
const [data] = await changeClass(user);
expect(data).to.eql({
preferences: user.preferences,
stats: user.stats,
@@ -112,18 +109,17 @@ describe('shared.ops.changeClass', () => {
});
context('has user.preferences.disableClasses !== true', () => {
it('and less than 3 gems', done => {
it('and less than 3 gems', async () => {
user.balance = 0.5;
try {
changeClass(user);
await changeClass(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('and at least 3 gems', () => {
it('and at least 3 gems', async () => {
user.balance = 1;
user.stats.points = 45;
user.stats.str = 1;
@@ -132,7 +128,7 @@ describe('shared.ops.changeClass', () => {
user.stats.int = 4;
user.flags.classSelected = true;
const [data] = changeClass(user);
const [data] = await changeClass(user);
expect(data).to.eql({
preferences: user.preferences,
stats: user.stats,
+48 -49
View File
@@ -24,60 +24,59 @@ describe('shared.ops.rebirth', () => {
tasks = [generateHabit(), generateDaily(), generateTodo(), generateReward()];
});
it('returns an error when user balance is too low and user is less than max level', done => {
it('returns an error when user balance is too low and user is less than max level', async () => {
user.balance = 0;
try {
rebirth(user);
await rebirth(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('rebirths a user with enough gems', () => {
const [, message] = rebirth(user);
it('rebirths a user with enough gems', async () => {
const [, message] = await rebirth(user);
expect(message).to.equal(i18n.t('rebirthComplete'));
});
it('rebirths a user with not enough gems but max level', () => {
it('rebirths a user with not enough gems but max level', async () => {
user.balance = 0;
user.stats.lvl = MAX_LEVEL;
const [, message] = rebirth(user);
const [, message] = await rebirth(user);
expect(message).to.equal(i18n.t('rebirthComplete'));
expect(user.flags.lastFreeRebirth).to.exist;
});
it('rebirths a user with not enough gems but more than max level', () => {
it('rebirths a user with not enough gems but more than max level', async () => {
user.balance = 0;
user.stats.lvl = MAX_LEVEL + 1;
const [, message] = rebirth(user);
const [, message] = await rebirth(user);
expect(message).to.equal(i18n.t('rebirthComplete'));
});
it('rebirths a user using gems if over max level but rebirthed recently', () => {
it('rebirths a user using gems if over max level but rebirthed recently', async () => {
user.stats.lvl = MAX_LEVEL + 1;
user.flags.lastFreeRebirth = new Date();
const [, message] = rebirth(user);
const [, message] = await rebirth(user);
expect(message).to.equal(i18n.t('rebirthComplete'));
expect(user.balance).to.equal(0);
});
it('resets user\'s tasks values except for rewards to 0', () => {
it('resets user\'s tasks values except for rewards to 0', async () => {
tasks[0].value = 1;
tasks[1].value = 1;
tasks[2].value = 1;
tasks[3].value = 1; // Reward
rebirth(user, tasks);
await rebirth(user, tasks);
expect(tasks[0].value).to.equal(0);
expect(tasks[1].value).to.equal(0);
@@ -85,99 +84,99 @@ describe('shared.ops.rebirth', () => {
expect(tasks[3].value).to.equal(1); // Reward
});
it('resets user\'s daily streaks to 0', () => {
it('resets user\'s daily streaks to 0', async () => {
tasks[0].counterDown = 1; // Habit
tasks[0].counterUp = 1; // Habit
tasks[1].streak = 1; // Daily
rebirth(user, tasks);
await rebirth(user, tasks);
expect(tasks[0].counterDown).to.equal(0);
expect(tasks[0].counterUp).to.equal(0);
expect(tasks[1].streak).to.equal(0);
});
it('resets a user\'s buffs', () => {
it('resets a user\'s buffs', async () => {
user.stats.buffs = { test: 'test' };
rebirth(user);
await rebirth(user);
expect(user.stats.buffs).to.be.empty;
});
it('resets a user\'s health points', () => {
it('resets a user\'s health points', async () => {
user.stats.hp = 40;
rebirth(user);
await rebirth(user);
expect(user.stats.hp).to.equal(50);
});
it('resets a user\'s class', () => {
it('resets a user\'s class', async () => {
user.stats.class = 'rouge';
rebirth(user);
await rebirth(user);
expect(user.stats.class).to.equal('warrior');
});
it('resets a user\'s stats', () => {
it('resets a user\'s stats', async () => {
user.stats.class = 'rouge';
_.each(userStats, value => {
user.stats[value] = 10;
});
rebirth(user);
await rebirth(user);
_.each(userStats, value => {
user.stats[value] = 0;
});
});
it('retains a user\'s gear', () => {
it('retains a user\'s gear', async () => {
const prevGearEquipped = user.items.gear.equipped;
const prevGearCostume = user.items.gear.costume;
const prevPrefCostume = user.preferences.costume;
rebirth(user);
await rebirth(user);
expect(user.items.gear.equipped).to.deep.equal(prevGearEquipped);
expect(user.items.gear.costume).to.deep.equal(prevGearCostume);
expect(user.preferences.costume).to.equal(prevPrefCostume);
});
it('retains a user\'s gear owned', () => {
it('retains a user\'s gear owned', async () => {
user.items.gear.owned.weapon_warrior_1 = true; // eslint-disable-line camelcase
const prevGearOwned = user.items.gear.owned;
rebirth(user);
await rebirth(user);
expect(user.items.gear.owned).to.equal(prevGearOwned);
});
it('resets a user\'s current pet', () => {
it('resets a user\'s current pet', async () => {
user.items.pets[animal] = true;
user.items.currentPet = animal;
rebirth(user);
await rebirth(user);
expect(user.items.currentPet).to.be.empty;
});
it('resets a user\'s current mount', () => {
it('resets a user\'s current mount', async () => {
user.items.mounts[animal] = true;
user.items.currentMount = animal;
rebirth(user);
await rebirth(user);
expect(user.items.currentMount).to.be.empty;
});
it('resets a user\'s flags', () => {
it('resets a user\'s flags', async () => {
user.flags.itemsEnabled = true;
user.flags.classSelected = true;
user.flags.rebirthEnabled = true;
user.flags.levelDrops = { test: 'test' };
rebirth(user);
await rebirth(user);
expect(user.flags.itemsEnabled).to.be.false;
expect(user.flags.classSelected).to.be.false;
@@ -185,80 +184,80 @@ describe('shared.ops.rebirth', () => {
expect(user.flags.levelDrops).to.be.empty;
});
it('reset rebirthEnabled even if user has beastMaster', () => {
it('reset rebirthEnabled even if user has beastMaster', async () => {
user.achievements.beastMaster = 1;
user.flags.rebirthEnabled = true;
rebirth(user);
await rebirth(user);
expect(user.flags.rebirthEnabled).to.be.false;
});
it('sets rebirth achievement', () => {
rebirth(user);
it('sets rebirth achievement', async () => {
await rebirth(user);
expect(user.achievements.rebirths).to.equal(1);
expect(user.achievements.rebirthLevel).to.equal(user.stats.lvl);
});
it('increments rebirth achievements', () => {
it('increments rebirth achievements', async () => {
user.stats.lvl = 2;
user.achievements.rebirths = 1;
user.achievements.rebirthLevel = 1;
rebirth(user);
await rebirth(user);
expect(user.achievements.rebirths).to.equal(2);
expect(user.achievements.rebirthLevel).to.equal(2);
});
it('does not increment rebirth achievements when level is lower than previous', () => {
it('does not increment rebirth achievements when level is lower than previous', async () => {
user.stats.lvl = 2;
user.achievements.rebirths = 1;
user.achievements.rebirthLevel = 3;
rebirth(user);
await rebirth(user);
expect(user.achievements.rebirths).to.equal(1);
expect(user.achievements.rebirthLevel).to.equal(3);
});
it('always increments rebirth achievements when level is MAX_LEVEL', () => {
it('always increments rebirth achievements when level is MAX_LEVEL', async () => {
user.stats.lvl = MAX_LEVEL;
user.achievements.rebirths = 1;
// this value is not actually possible (actually capped at MAX_LEVEL) but makes a good test
user.achievements.rebirthLevel = MAX_LEVEL + 1;
rebirth(user);
await rebirth(user);
expect(user.achievements.rebirths).to.equal(2);
expect(user.achievements.rebirthLevel).to.equal(MAX_LEVEL);
});
it('always increments rebirth achievements when level is greater than MAX_LEVEL', () => {
it('always increments rebirth achievements when level is greater than MAX_LEVEL', async () => {
user.stats.lvl = MAX_LEVEL + 1;
user.achievements.rebirths = 1;
// this value is not actually possible (actually capped at MAX_LEVEL) but makes a good test
user.achievements.rebirthLevel = MAX_LEVEL + 2;
rebirth(user);
await rebirth(user);
expect(user.achievements.rebirths).to.equal(2);
expect(user.achievements.rebirthLevel).to.equal(MAX_LEVEL);
});
it('keeps automaticAllocation false', () => {
it('keeps automaticAllocation false', async () => {
user.preferences.automaticAllocation = false;
rebirth(user);
await rebirth(user);
expect(user.preferences.automaticAllocation).to.be.false;
});
it('sets automaticAllocation to false when true', () => {
it('sets automaticAllocation to false when true', async () => {
user.preferences.automaticAllocation = true;
rebirth(user);
await rebirth(user);
expect(user.preferences.automaticAllocation).to.be.false;
});
+19 -21
View File
@@ -23,87 +23,85 @@ describe('shared.ops.releaseMounts', () => {
user.balance = 1;
});
it('returns an error when user balance is too low', done => {
it('returns an error when user balance is too low', async () => {
user.balance = 0;
try {
releaseMounts(user);
await releaseMounts(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('returns an error when user does not have all pets', done => {
it('returns an error when user does not have all pets', async () => {
const mountsKeys = Object.keys(user.items.mounts);
delete user.items.mounts[mountsKeys[0]];
try {
releaseMounts(user);
await releaseMounts(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughMounts'));
done();
}
});
it('releases mounts', () => {
const message = releaseMounts(user)[1];
it('releases mounts', async () => {
const result = await releaseMounts(user);
expect(message).to.equal(i18n.t('mountsReleased'));
expect(result[1]).to.equal(i18n.t('mountsReleased'));
expect(user.items.mounts[animal]).to.equal(null);
});
it('removes drop currentMount', () => {
it('removes drop currentMount', async () => {
const mountInfo = content.mountInfo[user.items.currentMount];
expect(mountInfo.type).to.equal('drop');
releaseMounts(user);
await releaseMounts(user);
expect(user.items.currentMount).to.be.empty;
});
it('leaves non-drop mount equipped', () => {
it('leaves non-drop mount equipped', async () => {
const questAnimal = 'Gryphon-Base';
user.items.currentMount = questAnimal;
user.items.mounts[questAnimal] = true;
const mountInfo = content.mountInfo[user.items.currentMount];
expect(mountInfo.type).to.not.equal('drop');
releaseMounts(user);
await releaseMounts(user);
expect(user.items.currentMount).to.equal(questAnimal);
});
it('increases mountMasterCount achievement', () => {
releaseMounts(user);
it('increases mountMasterCount achievement', async () => {
await releaseMounts(user);
expect(user.achievements.mountMasterCount).to.equal(1);
});
it('does not increase mountMasterCount achievement if mount is missing (null)', () => {
it('does not increase mountMasterCount achievement if mount is missing (null)', async () => {
const mountMasterCountBeforeRelease = user.achievements.mountMasterCount;
user.items.mounts[animal] = null;
try {
releaseMounts(user);
await releaseMounts(user);
} catch (e) {
expect(user.achievements.mountMasterCount).to.equal(mountMasterCountBeforeRelease);
}
});
it('does not increase mountMasterCount achievement if mount is missing (undefined)', () => {
it('does not increase mountMasterCount achievement if mount is missing (undefined)', async () => {
const mountMasterCountBeforeRelease = user.achievements.mountMasterCount;
delete user.items.mounts[animal];
try {
releaseMounts(user);
await releaseMounts(user);
} catch (e) {
expect(user.achievements.mountMasterCount).to.equal(mountMasterCountBeforeRelease);
}
});
it('subtracts gems from balance', () => {
releaseMounts(user);
it('subtracts gems from balance', async () => {
await releaseMounts(user);
expect(user.balance).to.equal(0);
});
+20 -22
View File
@@ -23,98 +23,96 @@ describe('shared.ops.releasePets', () => {
user.balance = 1;
});
it('returns an error when user balance is too low', done => {
it('returns an error when user balance is too low', async () => {
user.balance = 0;
try {
releasePets(user);
await releasePets(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('returns an error when user does not have all pets', done => {
it('returns an error when user does not have all pets', async () => {
const petKeys = Object.keys(user.items.pets);
delete user.items.pets[petKeys[0]];
try {
releasePets(user);
await releasePets(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughPets'));
done();
}
});
it('releases pets', () => {
const message = releasePets(user)[1];
it('releases pets', async () => {
const message = await releasePets(user)[1];
expect(message).to.equal(i18n.t('petsReleased'));
expect(user.items.pets[animal]).to.equal(0);
});
it('removes drop currentPet', () => {
it('removes drop currentPet', async () => {
const petInfo = content.petInfo[user.items.currentPet];
expect(petInfo.type).to.equal('drop');
releasePets(user);
await releasePets(user);
expect(user.items.currentPet).to.be.empty;
});
it('leaves non-drop pets equipped', () => {
it('leaves non-drop pets equipped', async () => {
const questAnimal = 'Gryphon-Base';
user.items.currentPet = questAnimal;
user.items.pets[questAnimal] = 5;
const petInfo = content.petInfo[user.items.currentPet];
expect(petInfo.type).to.not.equal('drop');
releasePets(user);
await releasePets(user);
expect(user.items.currentPet).to.equal(questAnimal);
});
it('decreases user\'s balance', () => {
releasePets(user);
it('decreases user\'s balance', async () => {
await releasePets(user);
expect(user.balance).to.equal(0);
});
it('incremenets beastMasterCount', () => {
releasePets(user);
it('incremenets beastMasterCount', async () => {
await releasePets(user);
expect(user.achievements.beastMasterCount).to.equal(1);
});
it('does not increment beastMasterCount if any pet is level 0 (released)', () => {
it('does not increment beastMasterCount if any pet is level 0 (released)', async () => {
const beastMasterCountBeforeRelease = user.achievements.beastMasterCount;
user.items.pets[animal] = 0;
try {
releasePets(user);
await releasePets(user);
} catch (e) {
expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease);
}
});
it('does not increment beastMasterCount if any pet is missing (null)', () => {
it('does not increment beastMasterCount if any pet is missing (null)', async () => {
const beastMasterCountBeforeRelease = user.achievements.beastMasterCount;
user.items.pets[animal] = null;
try {
releasePets(user);
await releasePets(user);
} catch (e) {
expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease);
}
});
it('does not increment beastMasterCount if any pet is missing (undefined)', () => {
it('does not increment beastMasterCount if any pet is missing (undefined)', async () => {
const beastMasterCountBeforeRelease = user.achievements.beastMasterCount;
delete user.items.pets[animal];
try {
releasePets(user);
await releasePets(user);
} catch (e) {
expect(user.achievements.beastMasterCount).to.equal(beastMasterCountBeforeRelease);
}
+10 -11
View File
@@ -19,43 +19,42 @@ describe('shared.ops.reroll', () => {
tasks = [generateDaily(), generateReward()];
});
it('returns an error when user balance is too low', done => {
it('returns an error when user balance is too low', async () => {
user.balance = 0;
try {
reroll(user);
await reroll(user);
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('rerolls a user with enough gems', () => {
const [, message] = reroll(user);
it('rerolls a user with enough gems', async () => {
const [, message] = await reroll(user);
expect(message).to.equal(i18n.t('fortifyComplete'));
});
it('reduces a user\'s balance', () => {
reroll(user);
it('reduces a user\'s balance', async () => {
await reroll(user);
expect(user.balance).to.equal(0);
});
it('resets a user\'s health points', () => {
it('resets a user\'s health points', async () => {
user.stats.hp = 40;
reroll(user);
await reroll(user);
expect(user.stats.hp).to.equal(50);
});
it('resets user\'s taks values except for rewards to 0', () => {
it('resets user\'s taks values except for rewards to 0', async () => {
tasks[0].value = 1;
tasks[1].value = 1;
reroll(user, tasks);
await reroll(user, tasks);
expect(tasks[0].value).to.equal(0);
expect(tasks[1].value).to.equal(1);
+70 -81
View File
@@ -19,184 +19,173 @@ describe('shared.ops.unlock', () => {
user.balance = usersStartingGems;
});
it('returns an error when path is not provided', done => {
it('returns an error when path is not provided', async () => {
try {
unlock(user);
await unlock(user);
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('pathRequired'));
done();
}
});
it('does not unlock lost gear', done => {
it('does not unlock lost gear', async () => {
user.items.gear.owned.headAccessory_special_bearEars = false;
unlock(user, { query: { path: 'items.gear.owned.headAccessory_special_bearEars' } });
await unlock(user, { query: { path: 'items.gear.owned.headAccessory_special_bearEars' } });
expect(user.balance).to.equal(usersStartingGems);
done();
});
it('returns an error when user balance is too low', done => {
it('returns an error when user balance is too low', async () => {
user.balance = 0;
try {
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('notEnoughGems'));
done();
}
});
it('returns an error when user already owns a full set', done => {
it('returns an error when user already owns a full set', async () => {
let expectedBalance;
try {
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
expectedBalance = user.balance;
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('alreadyUnlocked'));
expect(user.balance).to.equal(expectedBalance);
done();
}
});
it('returns an error when user already owns a full set of gear', done => {
it('returns an error when user already owns a full set of gear', async () => {
let expectedBalance;
try {
unlock(user, { query: { path: unlockGearSetPath } });
await unlock(user, { query: { path: unlockGearSetPath } });
expectedBalance = user.balance;
unlock(user, { query: { path: unlockGearSetPath } });
await unlock(user, { query: { path: unlockGearSetPath } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('alreadyUnlocked'));
expect(user.balance).to.equal(expectedBalance);
done();
}
});
it('returns an error if an item does not exists', done => {
it('returns an error if an item does not exists', async () => {
try {
unlock(user, { query: { path: 'background.invalid_background' } });
await unlock(user, { query: { path: 'background.invalid_background' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error if there are items from multiple sets', done => {
it('returns an error if there are items from multiple sets', async () => {
try {
unlock(user, { query: { path: 'shirt.convict,skin.0ff591' } });
await unlock(user, { query: { path: 'shirt.convict,skin.0ff591' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error if gear is not from the animal set', done => {
it('returns an error if gear is not from the animal set', async () => {
try {
unlock(user, { query: { path: 'items.gear.owned.back_mystery_202004' } });
await unlock(user, { query: { path: 'items.gear.owned.back_mystery_202004' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error if the item is free', done => {
it('returns an error if the item is free', async () => {
try {
unlock(user, { query: { path: 'shirt.black' } });
await unlock(user, { query: { path: 'shirt.black' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error if an item does not belong to a set (appearances)', done => {
it('returns an error if an item does not belong to a set (appearances)', async () => {
try {
unlock(user, { query: { path: 'shirt.pink' } });
await unlock(user, { query: { path: 'shirt.pink' } });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('invalidUnlockSet'));
done();
}
});
it('returns an error when user already owns items in a full set and it would be more expensive to buy the entire set', done => {
it('returns an error when user already owns items in a full set and it would be more expensive to buy the entire set', async () => {
try {
// There are 11 shirts in the set, each cost 2 gems, the full set 5 gems
// In order for the full purchase not to be worth, we must own 9
const partialUnlockPaths = unlockPath.split(',');
unlock(user, { query: { path: partialUnlockPaths[0] } });
unlock(user, { query: { path: partialUnlockPaths[1] } });
unlock(user, { query: { path: partialUnlockPaths[2] } });
unlock(user, { query: { path: partialUnlockPaths[3] } });
unlock(user, { query: { path: partialUnlockPaths[4] } });
unlock(user, { query: { path: partialUnlockPaths[5] } });
unlock(user, { query: { path: partialUnlockPaths[6] } });
unlock(user, { query: { path: partialUnlockPaths[7] } });
unlock(user, { query: { path: partialUnlockPaths[8] } });
await unlock(user, { query: { path: partialUnlockPaths[0] } });
await unlock(user, { query: { path: partialUnlockPaths[1] } });
await unlock(user, { query: { path: partialUnlockPaths[2] } });
await unlock(user, { query: { path: partialUnlockPaths[3] } });
await unlock(user, { query: { path: partialUnlockPaths[4] } });
await unlock(user, { query: { path: partialUnlockPaths[5] } });
await unlock(user, { query: { path: partialUnlockPaths[6] } });
await unlock(user, { query: { path: partialUnlockPaths[7] } });
await unlock(user, { query: { path: partialUnlockPaths[8] } });
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('alreadyUnlockedPart'));
done();
}
});
it('does not return an error when user already owns items in a full set and it would not be more expensive to buy the entire set', () => {
it('does not return an error when user already owns items in a full set and it would not be more expensive to buy the entire set', async () => {
// There are 11 shirts in the set, each cost 2 gems, the full set 5 gems
// In order for the full purchase to be worth, we can own already 8
const partialUnlockPaths = unlockPath.split(',');
unlock(user, { query: { path: partialUnlockPaths[0] } });
unlock(user, { query: { path: partialUnlockPaths[1] } });
unlock(user, { query: { path: partialUnlockPaths[2] } });
unlock(user, { query: { path: partialUnlockPaths[3] } });
unlock(user, { query: { path: partialUnlockPaths[4] } });
unlock(user, { query: { path: partialUnlockPaths[5] } });
unlock(user, { query: { path: partialUnlockPaths[6] } });
unlock(user, { query: { path: partialUnlockPaths[7] } });
await unlock(user, { query: { path: partialUnlockPaths[0] } });
await unlock(user, { query: { path: partialUnlockPaths[1] } });
await unlock(user, { query: { path: partialUnlockPaths[2] } });
await unlock(user, { query: { path: partialUnlockPaths[3] } });
await unlock(user, { query: { path: partialUnlockPaths[4] } });
await unlock(user, { query: { path: partialUnlockPaths[5] } });
await unlock(user, { query: { path: partialUnlockPaths[6] } });
await unlock(user, { query: { path: partialUnlockPaths[7] } });
unlock(user, { query: { path: unlockPath } });
await unlock(user, { query: { path: unlockPath } });
});
it('equips an item already owned', () => {
it('equips an item already owned', async () => {
expect(user.purchased.background.giant_florals).to.not.exist;
unlock(user, { query: { path: backgroundUnlockPath } });
await unlock(user, { query: { path: backgroundUnlockPath } });
const afterBalance = user.balance;
const response = unlock(user, { query: { path: backgroundUnlockPath } });
const response = await unlock(user, { query: { path: backgroundUnlockPath } });
expect(user.balance).to.equal(afterBalance); // do not bill twice
expect(response.message).to.not.exist;
expect(user.preferences.background).to.equal('giant_florals');
});
it('un-equips a background already equipped', () => {
it('un-equips a background already equipped', async () => {
expect(user.purchased.background.giant_florals).to.not.exist;
unlock(user, { query: { path: backgroundUnlockPath } }); // unlock
await unlock(user, { query: { path: backgroundUnlockPath } }); // unlock
const afterBalance = user.balance;
unlock(user, { query: { path: backgroundUnlockPath } }); // equip
const response = unlock(user, { query: { path: backgroundUnlockPath } });
await unlock(user, { query: { path: backgroundUnlockPath } }); // equip
const response = await unlock(user, { query: { path: backgroundUnlockPath } });
expect(user.balance).to.equal(afterBalance); // do not bill twice
expect(response.message).to.not.exist;
expect(user.preferences.background).to.equal('');
});
it('unlocks a full set of appearance items', () => {
it('unlocks a full set of appearance items', async () => {
const initialShirts = Object.keys(user.purchased.shirt).length;
const [, message] = unlock(user, { query: { path: unlockPath } });
const [, message] = await unlock(user, { query: { path: unlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
const individualPaths = unlockPath.split(',');
@@ -208,11 +197,11 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 1.25);
});
it('unlocks a full set of hair items', () => {
it('unlocks a full set of hair items', async () => {
user.purchased.hair.color = {};
const initialHairColors = Object.keys(user.purchased.hair.color).length;
const [, message] = unlock(user, { query: { path: hairUnlockPath } });
const [, message] = await unlock(user, { query: { path: hairUnlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
const individualPaths = hairUnlockPath.split(',');
@@ -224,13 +213,13 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 1.25);
});
it('unlocks the facial hair set', () => {
it('unlocks the facial hair set', async () => {
user.purchased.hair.mustache = {};
user.purchased.hair.beard = {};
const initialMustache = Object.keys(user.purchased.hair.mustache).length;
const initialBeard = Object.keys(user.purchased.hair.mustache).length;
const [, message] = unlock(user, { query: { path: facialHairUnlockPath } });
const [, message] = await unlock(user, { query: { path: facialHairUnlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
const individualPaths = facialHairUnlockPath.split(',');
@@ -242,9 +231,9 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 1.25);
});
it('unlocks a full set of gear', () => {
it('unlocks a full set of gear', async () => {
const initialGear = Object.keys(user.items.gear.owned).length;
const [, message] = unlock(user, { query: { path: unlockGearSetPath } });
const [, message] = await unlock(user, { query: { path: unlockGearSetPath } });
expect(message).to.equal(i18n.t('unlocked'));
@@ -257,9 +246,9 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 1.25);
});
it('unlocks a full set of backgrounds', () => {
it('unlocks a full set of backgrounds', async () => {
const initialBackgrounds = Object.keys(user.purchased.background).length;
const [, message] = unlock(user, { query: { path: backgroundSetUnlockPath } });
const [, message] = await unlock(user, { query: { path: backgroundSetUnlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
const individualPaths = backgroundSetUnlockPath.split(',');
@@ -271,10 +260,10 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 3.75);
});
it('unlocks an item (appearance)', () => {
it('unlocks an item (appearance)', async () => {
const path = unlockPath.split(',')[0];
const initialShirts = Object.keys(user.purchased.shirt).length;
const [, message] = unlock(user, { query: { path } });
const [, message] = await unlock(user, { query: { path } });
expect(message).to.equal(i18n.t('unlocked'));
expect(Object.keys(user.purchased.shirt).length).to.equal(initialShirts + 1);
@@ -282,12 +271,12 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 0.5);
});
it('unlocks an item (hair color)', () => {
it('unlocks an item (hair color)', async () => {
user.purchased.hair.color = {};
const path = hairUnlockPath.split(',')[0];
const initialColorHair = Object.keys(user.purchased.hair.color).length;
const [, message] = unlock(user, { query: { path } });
const [, message] = await unlock(user, { query: { path } });
expect(message).to.equal(i18n.t('unlocked'));
expect(Object.keys(user.purchased.hair.color).length).to.equal(initialColorHair + 1);
@@ -295,14 +284,14 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 0.5);
});
it('unlocks an item (facial hair)', () => {
it('unlocks an item (facial hair)', async () => {
user.purchased.hair.mustache = {};
user.purchased.hair.beard = {};
const path = facialHairUnlockPath.split(',')[0];
const initialMustache = Object.keys(user.purchased.hair.mustache).length;
const initialBeard = Object.keys(user.purchased.hair.beard).length;
const [, message] = unlock(user, { query: { path } });
const [, message] = await unlock(user, { query: { path } });
expect(message).to.equal(i18n.t('unlocked'));
@@ -313,10 +302,10 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 0.5);
});
it('unlocks an item (gear)', () => {
it('unlocks an item (gear)', async () => {
const path = unlockGearSetPath.split(',')[0];
const initialGear = Object.keys(user.items.gear.owned).length;
const [, message] = unlock(user, { query: { path } });
const [, message] = await unlock(user, { query: { path } });
expect(message).to.equal(i18n.t('unlocked'));
expect(Object.keys(user.items.gear.owned).length).to.equal(initialGear + 1);
@@ -324,9 +313,9 @@ describe('shared.ops.unlock', () => {
expect(user.balance).to.equal(usersStartingGems - 0.5);
});
it('unlocks an item (background)', () => {
it('unlocks an item (background)', async () => {
const initialBackgrounds = Object.keys(user.purchased.background).length;
const [, message] = unlock(user, { query: { path: backgroundUnlockPath } });
const [, message] = await unlock(user, { query: { path: backgroundUnlockPath } });
expect(message).to.equal(i18n.t('unlocked'));
expect(Object.keys(user.purchased.background).length).to.equal(initialBackgrounds + 1);
+172 -254
View File
@@ -4723,16 +4723,16 @@
"integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w=="
},
"@storybook/addon-actions": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.4.17.tgz",
"integrity": "sha512-8TYdgzJMMKvfHvSp8N3Bsj78xGw9lNHTYkh0IE0TGGwRVOEU6xNBkao6ktXzM3gTB+6U6OZn8Y//NCzLsoTUHg==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.4.18.tgz",
"integrity": "sha512-qPw5qfbWPmyOdaXxAVAbdVLVVE31gRrkH0ESUps+FXVNypRz1/0lJ6M2VrtOHMrFbGBl94SALdqsHOx6OYZKwg==",
"requires": {
"@storybook/addons": "6.4.17",
"@storybook/api": "6.4.17",
"@storybook/components": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/addons": "6.4.18",
"@storybook/api": "6.4.18",
"@storybook/components": "6.4.18",
"@storybook/core-events": "6.4.18",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/theming": "6.4.17",
"@storybook/theming": "6.4.18",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -4857,17 +4857,17 @@
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
},
"@storybook/addons": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.17.tgz",
"integrity": "sha512-C/hji0Bc7+tssGqaD0JYd/Pz0GM46xbRpdgHSVLInYdhJrb5a9IG6INCbcB8CXeReDKWJCLAaj2+z79Wa96bFQ==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.18.tgz",
"integrity": "sha512-fd3S79P4jJCYZNA2JxA1Xnkj0UlHGQ4Vg72aroWy4OQFlgGQor1LgPfM6RaJ9rh/4k4BXYPXsS7wzI0UWKG3Lw==",
"requires": {
"@storybook/api": "6.4.17",
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/api": "6.4.18",
"@storybook/channels": "6.4.18",
"@storybook/client-logger": "6.4.18",
"@storybook/core-events": "6.4.18",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.17",
"@storybook/theming": "6.4.17",
"@storybook/router": "6.4.18",
"@storybook/theming": "6.4.18",
"@types/webpack-env": "^1.16.0",
"core-js": "^3.8.2",
"global": "^4.4.0",
@@ -4875,17 +4875,17 @@
}
},
"@storybook/api": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.17.tgz",
"integrity": "sha512-O0ssHVy40t4QD5CNdNESbJo7uZd86UWYrHCFjgeC2gmxrMgBD+ajO34N4HoQFC/F+/84om2/z8RYAGKu/WpoTA==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.18.tgz",
"integrity": "sha512-tSbsHKklBysuSmw4T+cKzMj6mQh/42m9F8+2iJns2XG/IUKpMAzFg/9dlgCTW+ay6dJwsR79JGIc9ccIe4SMgQ==",
"requires": {
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/channels": "6.4.18",
"@storybook/client-logger": "6.4.18",
"@storybook/core-events": "6.4.18",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.17",
"@storybook/router": "6.4.18",
"@storybook/semver": "^7.3.2",
"@storybook/theming": "6.4.17",
"@storybook/theming": "6.4.18",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -4899,9 +4899,9 @@
}
},
"@storybook/channels": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.17.tgz",
"integrity": "sha512-C6ON1olkkHc+FaDerkwL1yYGDL1xtFP+eMlm42ZaO06sIT9qv9EkJZ3GU/PNLTeXYMX4OsZl9kjz2whD4rN7gg==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.18.tgz",
"integrity": "sha512-Bh4l7VKKR2ImLbZ9XgL/DzT3lFv9+SLiCu1ozfpBZGHUCOLyHRnkG/h8wYvRkF9s3tpNwOtaCaqD1vkkZfr3uw==",
"requires": {
"core-js": "^3.8.2",
"ts-dedent": "^2.0.0",
@@ -4909,23 +4909,23 @@
}
},
"@storybook/client-logger": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.17.tgz",
"integrity": "sha512-awKBTOWHXHBxAIl8a/Zy/BitIw49A+0RnhPGuf8aFAw2Ym/vKR4bI8lRHVPtlR6RIHFp5rC1g32HmCQfKE22Fw==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.18.tgz",
"integrity": "sha512-ciBaASMaB2ZPksbuyDbp3++5SZxbhcihEpl+RQcAVV8g+TUyBZKIcHt8HNHicTczz5my1EydZovMh1IkSBMICA==",
"requires": {
"core-js": "^3.8.2",
"global": "^4.4.0"
}
},
"@storybook/components": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.4.17.tgz",
"integrity": "sha512-R6imELCWlHWQiprYMeeXLKgUQK4m698G/jvkc1xUxAThpTxwgROTcpw5qnJA0k+wltjGn4t6MBWKHhheGZc6Hg==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.4.18.tgz",
"integrity": "sha512-LAPKYWgB6S10Vzt0IWa1Ihf9EAuQOGxlqehTuxYLOwMOKbto8iEbGRse/XaQfxdZf/RbmOL4u+7nVRROWgOEjg==",
"requires": {
"@popperjs/core": "^2.6.0",
"@storybook/client-logger": "6.4.17",
"@storybook/client-logger": "6.4.18",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/theming": "6.4.17",
"@storybook/theming": "6.4.18",
"@types/color-convert": "^2.0.0",
"@types/overlayscrollbars": "^1.12.0",
"@types/react-syntax-highlighter": "11.0.5",
@@ -4949,9 +4949,9 @@
}
},
"@storybook/core-events": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.17.tgz",
"integrity": "sha512-k6wNjQLZZ8A/rt4gLz0M4ebTORKYYz2B9hZ3LvPJftNVqv+bTFAV4KVks6bBlvbJWpJ+eCPEyfeSP9Np2QIFMQ==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.18.tgz",
"integrity": "sha512-lCT3l0rFs6CuVpD8+mwmj1lUTomGErySTxi0KmVd2AWQj8kJL90EfS0jHSU5JIXScDvuwXDXLLmvMfqNU+zHdg==",
"requires": {
"core-js": "^3.8.2"
}
@@ -4965,11 +4965,11 @@
}
},
"@storybook/router": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.17.tgz",
"integrity": "sha512-GLhzth83BB2BbUkM/+ld2JITIbDQtzFLs/CnZZQKq6aR93Kou6VK2epHnIwrPyWbP6rsGavR/8L/UWeBdwwTrQ==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.18.tgz",
"integrity": "sha512-itvSWHhG1X/NV1sMlwP1qKtF0HfiIaAHImr0LwQ2K2F6/CI11W68dJAs4WBUdwzA0+H0Joyu/2a/6mCQHcee1A==",
"requires": {
"@storybook/client-logger": "6.4.17",
"@storybook/client-logger": "6.4.18",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -4983,14 +4983,14 @@
}
},
"@storybook/theming": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.17.tgz",
"integrity": "sha512-7+U72/VdhoMb00q1URMzdTW3OYHJogro2i2hScgKR+ndL4/dtSmetJ/1z9PuoFxLxHgdLKcwMAV0fZAjEYlhCA==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.18.tgz",
"integrity": "sha512-1o0w2eP+8sXUesdtXpZR4Yvayp1h3xvK7l9+wuHh+1uCy+EvD5UI9d1HvU5kt5fw7XAJJcInaVAmyAbpwct0TQ==",
"requires": {
"@emotion/core": "^10.1.1",
"@emotion/is-prop-valid": "^0.8.6",
"@emotion/styled": "^10.0.27",
"@storybook/client-logger": "6.4.17",
"@storybook/client-logger": "6.4.18",
"core-js": "^3.8.2",
"deep-object-diff": "^1.1.0",
"emotion-theming": "^10.0.27",
@@ -5134,9 +5134,9 @@
},
"dependencies": {
"@babel/runtime": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz",
"integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
@@ -5181,9 +5181,9 @@
},
"dependencies": {
"@babel/runtime": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz",
"integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
@@ -5213,9 +5213,9 @@
},
"dependencies": {
"@babel/runtime": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz",
"integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
@@ -5881,17 +5881,17 @@
}
},
"@storybook/addons": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.17.tgz",
"integrity": "sha512-C/hji0Bc7+tssGqaD0JYd/Pz0GM46xbRpdgHSVLInYdhJrb5a9IG6INCbcB8CXeReDKWJCLAaj2+z79Wa96bFQ==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.18.tgz",
"integrity": "sha512-fd3S79P4jJCYZNA2JxA1Xnkj0UlHGQ4Vg72aroWy4OQFlgGQor1LgPfM6RaJ9rh/4k4BXYPXsS7wzI0UWKG3Lw==",
"requires": {
"@storybook/api": "6.4.17",
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/api": "6.4.18",
"@storybook/channels": "6.4.18",
"@storybook/client-logger": "6.4.18",
"@storybook/core-events": "6.4.18",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.17",
"@storybook/theming": "6.4.17",
"@storybook/router": "6.4.18",
"@storybook/theming": "6.4.18",
"@types/webpack-env": "^1.16.0",
"core-js": "^3.8.2",
"global": "^4.4.0",
@@ -6008,17 +6008,17 @@
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
},
"@storybook/api": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.17.tgz",
"integrity": "sha512-O0ssHVy40t4QD5CNdNESbJo7uZd86UWYrHCFjgeC2gmxrMgBD+ajO34N4HoQFC/F+/84om2/z8RYAGKu/WpoTA==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.18.tgz",
"integrity": "sha512-tSbsHKklBysuSmw4T+cKzMj6mQh/42m9F8+2iJns2XG/IUKpMAzFg/9dlgCTW+ay6dJwsR79JGIc9ccIe4SMgQ==",
"requires": {
"@storybook/channels": "6.4.17",
"@storybook/client-logger": "6.4.17",
"@storybook/core-events": "6.4.17",
"@storybook/channels": "6.4.18",
"@storybook/client-logger": "6.4.18",
"@storybook/core-events": "6.4.18",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/router": "6.4.17",
"@storybook/router": "6.4.18",
"@storybook/semver": "^7.3.2",
"@storybook/theming": "6.4.17",
"@storybook/theming": "6.4.18",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -6032,9 +6032,9 @@
}
},
"@storybook/channels": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.17.tgz",
"integrity": "sha512-C6ON1olkkHc+FaDerkwL1yYGDL1xtFP+eMlm42ZaO06sIT9qv9EkJZ3GU/PNLTeXYMX4OsZl9kjz2whD4rN7gg==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.18.tgz",
"integrity": "sha512-Bh4l7VKKR2ImLbZ9XgL/DzT3lFv9+SLiCu1ozfpBZGHUCOLyHRnkG/h8wYvRkF9s3tpNwOtaCaqD1vkkZfr3uw==",
"requires": {
"core-js": "^3.8.2",
"ts-dedent": "^2.0.0",
@@ -6042,18 +6042,18 @@
}
},
"@storybook/client-logger": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.17.tgz",
"integrity": "sha512-awKBTOWHXHBxAIl8a/Zy/BitIw49A+0RnhPGuf8aFAw2Ym/vKR4bI8lRHVPtlR6RIHFp5rC1g32HmCQfKE22Fw==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.18.tgz",
"integrity": "sha512-ciBaASMaB2ZPksbuyDbp3++5SZxbhcihEpl+RQcAVV8g+TUyBZKIcHt8HNHicTczz5my1EydZovMh1IkSBMICA==",
"requires": {
"core-js": "^3.8.2",
"global": "^4.4.0"
}
},
"@storybook/core-events": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.17.tgz",
"integrity": "sha512-k6wNjQLZZ8A/rt4gLz0M4ebTORKYYz2B9hZ3LvPJftNVqv+bTFAV4KVks6bBlvbJWpJ+eCPEyfeSP9Np2QIFMQ==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.18.tgz",
"integrity": "sha512-lCT3l0rFs6CuVpD8+mwmj1lUTomGErySTxi0KmVd2AWQj8kJL90EfS0jHSU5JIXScDvuwXDXLLmvMfqNU+zHdg==",
"requires": {
"core-js": "^3.8.2"
}
@@ -6067,11 +6067,11 @@
}
},
"@storybook/router": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.17.tgz",
"integrity": "sha512-GLhzth83BB2BbUkM/+ld2JITIbDQtzFLs/CnZZQKq6aR93Kou6VK2epHnIwrPyWbP6rsGavR/8L/UWeBdwwTrQ==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.18.tgz",
"integrity": "sha512-itvSWHhG1X/NV1sMlwP1qKtF0HfiIaAHImr0LwQ2K2F6/CI11W68dJAs4WBUdwzA0+H0Joyu/2a/6mCQHcee1A==",
"requires": {
"@storybook/client-logger": "6.4.17",
"@storybook/client-logger": "6.4.18",
"core-js": "^3.8.2",
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
@@ -6085,14 +6085,14 @@
}
},
"@storybook/theming": {
"version": "6.4.17",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.17.tgz",
"integrity": "sha512-7+U72/VdhoMb00q1URMzdTW3OYHJogro2i2hScgKR+ndL4/dtSmetJ/1z9PuoFxLxHgdLKcwMAV0fZAjEYlhCA==",
"version": "6.4.18",
"resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.18.tgz",
"integrity": "sha512-1o0w2eP+8sXUesdtXpZR4Yvayp1h3xvK7l9+wuHh+1uCy+EvD5UI9d1HvU5kt5fw7XAJJcInaVAmyAbpwct0TQ==",
"requires": {
"@emotion/core": "^10.1.1",
"@emotion/is-prop-valid": "^0.8.6",
"@emotion/styled": "^10.0.27",
"@storybook/client-logger": "6.4.17",
"@storybook/client-logger": "6.4.18",
"core-js": "^3.8.2",
"deep-object-diff": "^1.1.0",
"emotion-theming": "^10.0.27",
@@ -6176,9 +6176,9 @@
},
"dependencies": {
"@babel/runtime": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"version": "7.17.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz",
"integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
@@ -14285,19 +14285,6 @@
"version": "1.1.71",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz",
"integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
@@ -16635,19 +16622,6 @@
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
@@ -18758,26 +18732,22 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
"resolved": false,
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"bundled": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"resolved": false,
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
"resolved": false,
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"bundled": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
"resolved": false,
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"bundled": true,
"optional": true,
"requires": {
"delegates": "^1.0.0",
@@ -18786,14 +18756,12 @@
},
"balanced-match": {
"version": "1.0.0",
"resolved": false,
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": false,
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
@@ -18802,38 +18770,32 @@
},
"chownr": {
"version": "1.1.1",
"resolved": false,
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
"bundled": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"resolved": false,
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"resolved": false,
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": false,
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
"resolved": false,
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"bundled": true,
"optional": true
},
"debug": {
"version": "4.1.1",
"resolved": false,
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"bundled": true,
"optional": true,
"requires": {
"ms": "^2.1.1"
@@ -18841,26 +18803,22 @@
},
"deep-extend": {
"version": "0.6.0",
"resolved": false,
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"bundled": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"resolved": false,
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"bundled": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"resolved": false,
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"bundled": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
"resolved": false,
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"bundled": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
@@ -18868,14 +18826,12 @@
},
"fs.realpath": {
"version": "1.0.0",
"resolved": false,
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"bundled": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
"resolved": false,
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"bundled": true,
"optional": true,
"requires": {
"aproba": "^1.0.3",
@@ -18890,8 +18846,7 @@
},
"glob": {
"version": "7.1.3",
"resolved": false,
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"bundled": true,
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -18904,14 +18859,12 @@
},
"has-unicode": {
"version": "2.0.1",
"resolved": false,
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"bundled": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
"resolved": false,
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"bundled": true,
"optional": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
@@ -18919,8 +18872,7 @@
},
"ignore-walk": {
"version": "3.0.1",
"resolved": false,
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"bundled": true,
"optional": true,
"requires": {
"minimatch": "^3.0.4"
@@ -18928,8 +18880,7 @@
},
"inflight": {
"version": "1.0.6",
"resolved": false,
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"bundled": true,
"optional": true,
"requires": {
"once": "^1.3.0",
@@ -18938,14 +18889,12 @@
},
"inherits": {
"version": "2.0.3",
"resolved": false,
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"bundled": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": false,
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
@@ -18953,14 +18902,12 @@
},
"isarray": {
"version": "1.0.0",
"resolved": false,
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"bundled": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
"resolved": false,
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
@@ -18968,14 +18915,12 @@
},
"minimist": {
"version": "0.0.8",
"resolved": false,
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"resolved": false,
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
@@ -18984,8 +18929,7 @@
},
"minizlib": {
"version": "1.2.1",
"resolved": false,
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"bundled": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
@@ -18993,8 +18937,7 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": false,
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
@@ -19002,14 +18945,12 @@
},
"ms": {
"version": "2.1.1",
"resolved": false,
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"bundled": true,
"optional": true
},
"needle": {
"version": "2.3.0",
"resolved": false,
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
"bundled": true,
"optional": true,
"requires": {
"debug": "^4.1.0",
@@ -19019,8 +18960,7 @@
},
"node-pre-gyp": {
"version": "0.12.0",
"resolved": false,
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
"bundled": true,
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
@@ -19037,8 +18977,7 @@
},
"nopt": {
"version": "4.0.1",
"resolved": false,
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"bundled": true,
"optional": true,
"requires": {
"abbrev": "1",
@@ -19047,14 +18986,12 @@
},
"npm-bundled": {
"version": "1.0.6",
"resolved": false,
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
"bundled": true,
"optional": true
},
"npm-packlist": {
"version": "1.4.1",
"resolved": false,
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
"bundled": true,
"optional": true,
"requires": {
"ignore-walk": "^3.0.1",
@@ -19063,8 +19000,7 @@
},
"npmlog": {
"version": "4.1.2",
"resolved": false,
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"bundled": true,
"optional": true,
"requires": {
"are-we-there-yet": "~1.1.2",
@@ -19075,20 +19011,17 @@
},
"number-is-nan": {
"version": "1.0.1",
"resolved": false,
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
"resolved": false,
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"bundled": true,
"optional": true
},
"once": {
"version": "1.4.0",
"resolved": false,
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
@@ -19096,20 +19029,17 @@
},
"os-homedir": {
"version": "1.0.2",
"resolved": false,
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"bundled": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": false,
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"bundled": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
"resolved": false,
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"bundled": true,
"optional": true,
"requires": {
"os-homedir": "^1.0.0",
@@ -19118,20 +19048,17 @@
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": false,
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"bundled": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": false,
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"bundled": true,
"optional": true
},
"rc": {
"version": "1.2.8",
"resolved": false,
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"bundled": true,
"optional": true,
"requires": {
"deep-extend": "^0.6.0",
@@ -19142,16 +19069,14 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": false,
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"bundled": true,
"optional": true
}
}
},
"readable-stream": {
"version": "2.3.6",
"resolved": false,
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"bundled": true,
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -19165,8 +19090,7 @@
},
"rimraf": {
"version": "2.6.3",
"resolved": false,
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"bundled": true,
"optional": true,
"requires": {
"glob": "^7.1.3"
@@ -19174,44 +19098,37 @@
},
"safe-buffer": {
"version": "5.1.2",
"resolved": false,
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"bundled": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
"resolved": false,
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"bundled": true,
"optional": true
},
"sax": {
"version": "1.2.4",
"resolved": false,
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"bundled": true,
"optional": true
},
"semver": {
"version": "5.7.0",
"resolved": false,
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"bundled": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"resolved": false,
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"bundled": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"resolved": false,
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"bundled": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
"resolved": false,
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
@@ -19221,8 +19138,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": false,
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
@@ -19230,8 +19146,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": false,
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
@@ -19239,14 +19154,12 @@
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": false,
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"bundled": true,
"optional": true
},
"tar": {
"version": "4.4.8",
"resolved": false,
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"bundled": true,
"optional": true,
"requires": {
"chownr": "^1.1.1",
@@ -19260,14 +19173,12 @@
},
"util-deprecate": {
"version": "1.0.2",
"resolved": false,
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"bundled": true,
"optional": true
},
"wide-align": {
"version": "1.1.3",
"resolved": false,
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"bundled": true,
"optional": true,
"requires": {
"string-width": "^1.0.2 || 2"
@@ -19275,14 +19186,12 @@
},
"wrappy": {
"version": "1.0.2",
"resolved": false,
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"bundled": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"resolved": false,
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"bundled": true,
"optional": true
}
}
@@ -29196,6 +29105,7 @@
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
@@ -29206,6 +29116,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
@@ -29214,6 +29125,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -29223,6 +29135,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
@@ -29230,22 +29143,26 @@
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"optional": true
},
"emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"optional": true
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
@@ -29256,6 +29173,7 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -29315,8 +29233,8 @@
}
},
"vuejs-datepicker": {
"version": "git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0",
"from": "git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0"
"version": "git+ssh://git@github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0",
"from": "vuejs-datepicker@git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0"
},
"w3c-hr-time": {
"version": "1.0.2",
+2 -2
View File
@@ -13,11 +13,11 @@
"storybook:serve": "vue-cli-service storybook:serve -p 6006 -c config/storybook"
},
"dependencies": {
"@storybook/addons": "6.4.17",
"@storybook/addon-actions": "6.4.17",
"@storybook/addon-actions": "6.4.18",
"@storybook/addon-knobs": "6.2.9",
"@storybook/addon-links": "6.4.17",
"@storybook/addon-notes": "5.3.21",
"@storybook/addons": "6.4.18",
"@storybook/vue": "6.3.13",
"@vue/cli-plugin-babel": "^4.5.15",
"@vue/cli-plugin-eslint": "^4.5.15",
-1
View File
@@ -530,6 +530,5 @@ export default {
<style src="intro.js/minified/introjs.min.css"></style>
<style src="axios-progress-bar/dist/nprogress.css"></style>
<style src="@/assets/scss/index.scss" lang="scss"></style>
<style src="@/assets/css/sprites/spritesmith-largeSprites-0.css"></style>
<style src="@/assets/scss/sprites.scss" lang="scss"></style>
<style src="smartbanner.js/dist/smartbanner.min.css"></style>
@@ -1,84 +0,0 @@
.promo_armoire_backgrounds_202010 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -639px;
width: 423px;
height: 147px;
}
.promo_fall_customizations {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -532px 0px;
width: 336px;
height: 207px;
}
.promo_fall_festival_2019 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -449px;
width: 360px;
height: 189px;
}
.promo_fall_festival_2020 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -361px -449px;
width: 360px;
height: 174px;
}
.promo_mystery_202009 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px -296px;
width: 282px;
height: 147px;
}
.promo_mystery_202010 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px -444px;
width: 282px;
height: 147px;
}
.promo_sandy_sidekicks_bundle {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px -148px;
width: 420px;
height: 147px;
}
.promo_skeleton_achievements {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -244px;
width: 366px;
height: 204px;
}
.promo_spooky_sparkles {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -424px -639px;
width: 423px;
height: 147px;
}
.promo_take_this {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1152px -296px;
width: 96px;
height: 69px;
}
.promo_vampire_potions {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px 0px;
width: 423px;
height: 147px;
}
.scene_positivity {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px 0px;
width: 531px;
height: 243px;
}
.scene_squall {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -532px -208px;
width: 141px;
height: 169px;
}
.scene_strength {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -869px -592px;
width: 192px;
height: 129px;
}
File diff suppressed because it is too large Load Diff
@@ -1,816 +0,0 @@
.background_halflings_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px 0px;
width: 141px;
height: 147px;
}
.background_hall_of_heroes {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px 0px;
width: 141px;
height: 147px;
}
.background_harvest_feast {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px 0px;
width: 141px;
height: 147px;
}
.background_harvest_fields {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -148px;
width: 141px;
height: 147px;
}
.background_harvest_moon {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -148px;
width: 141px;
height: 147px;
}
.background_haunted_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -148px;
width: 141px;
height: 147px;
}
.background_haunted_house {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px 0px;
width: 141px;
height: 147px;
}
.background_haunted_photo {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -148px;
width: 141px;
height: 147px;
}
.background_heart_shaped_bubbles {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -296px;
width: 141px;
height: 147px;
}
.background_heather_field {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -296px;
width: 141px;
height: 147px;
}
.background_herding_sheep_in_autumn {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -296px;
width: 141px;
height: 147px;
}
.background_holiday_hearth {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -296px;
width: 141px;
height: 147px;
}
.background_holiday_market {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px 0px;
width: 141px;
height: 147px;
}
.background_holiday_wreath {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -148px;
width: 141px;
height: 147px;
}
.background_hot_air_balloon {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -296px;
width: 141px;
height: 147px;
}
.background_hot_spring {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -444px;
width: 141px;
height: 147px;
}
.background_ice_cave {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -444px;
width: 141px;
height: 147px;
}
.background_ice_palace {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -444px;
width: 141px;
height: 147px;
}
.background_iceberg {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -444px;
width: 141px;
height: 147px;
}
.background_icicle_bridge {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -444px;
width: 141px;
height: 147px;
}
.background_idyllic_cabin {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px 0px;
width: 141px;
height: 147px;
}
.background_in_a_classroom {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -148px;
width: 141px;
height: 147px;
}
.background_in_an_ancient_tomb {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -296px;
width: 141px;
height: 147px;
}
.background_in_the_armory {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -444px;
width: 141px;
height: 147px;
}
.background_inside_a_potion_bottle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -592px;
width: 141px;
height: 147px;
}
.background_inside_an_ornament {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -592px;
width: 141px;
height: 147px;
}
.background_iridescent_clouds {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -592px;
width: 141px;
height: 147px;
}
.background_island_waterfalls {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -592px;
width: 141px;
height: 147px;
}
.background_jungle_canopy {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -592px;
width: 141px;
height: 147px;
}
.background_kelp_forest {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -592px;
width: 141px;
height: 147px;
}
.background_lake_with_floating_lanterns {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px 0px;
width: 141px;
height: 147px;
}
.background_lighthouse_shore {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -148px;
width: 141px;
height: 147px;
}
.background_lilypad {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -296px;
width: 141px;
height: 147px;
}
.background_magic_beanstalk {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -444px;
width: 141px;
height: 147px;
}
.background_magical_candles {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -592px;
width: 141px;
height: 147px;
}
.background_magical_museum {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -740px;
width: 141px;
height: 147px;
}
.background_marble_temple {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -740px;
width: 141px;
height: 147px;
}
.background_market {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -740px;
width: 141px;
height: 147px;
}
.background_meandering_cave {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -740px;
width: 141px;
height: 147px;
}
.background_medieval_kitchen {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -740px;
width: 141px;
height: 147px;
}
.background_meteor_shower {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -740px;
width: 141px;
height: 147px;
}
.background_midnight_castle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -740px;
width: 141px;
height: 147px;
}
.background_midnight_clouds {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px 0px;
width: 141px;
height: 147px;
}
.background_midnight_lake {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -148px;
width: 141px;
height: 147px;
}
.background_mist_shrouded_mountain {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -296px;
width: 141px;
height: 147px;
}
.background_mistiflying_circus {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -444px;
width: 141px;
height: 147px;
}
.background_monster_makers_workshop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -592px;
width: 141px;
height: 147px;
}
.background_mountain_lake {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -740px;
width: 141px;
height: 147px;
}
.background_mountain_pyramid {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -888px;
width: 141px;
height: 147px;
}
.background_mystical_observatory {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -888px;
width: 141px;
height: 147px;
}
.background_night_dunes {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -888px;
width: 141px;
height: 147px;
}
.background_ocean_sunrise {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -888px;
width: 141px;
height: 147px;
}
.background_old_fashioned_bakery {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -888px;
width: 141px;
height: 147px;
}
.background_on_tree_branch {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -888px;
width: 141px;
height: 147px;
}
.background_open_waters {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -888px;
width: 141px;
height: 147px;
}
.background_orange_grove {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -888px;
width: 141px;
height: 147px;
}
.background_orchard {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px 0px;
width: 141px;
height: 147px;
}
.background_pagodas {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -148px;
width: 141px;
height: 147px;
}
.background_palm_tree_with_fairy_lights {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -296px;
width: 141px;
height: 147px;
}
.background_park_with_statue {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -444px;
width: 141px;
height: 147px;
}
.background_pirate_flag {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -592px;
width: 141px;
height: 147px;
}
.background_pixelists_workshop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -740px;
width: 141px;
height: 147px;
}
.background_potion_shop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -888px;
width: 141px;
height: 147px;
}
.background_productivity_plaza {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -1036px;
width: 141px;
height: 147px;
}
.background_pumpkin_carriage {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -1036px;
width: 141px;
height: 147px;
}
.background_pumpkin_patch {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -1036px;
width: 141px;
height: 147px;
}
.background_purple {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -1036px;
width: 141px;
height: 147px;
}
.background_pyramids {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -1036px;
width: 141px;
height: 147px;
}
.background_raging_river {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -1036px;
width: 141px;
height: 147px;
}
.background_rainbow_meadow {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -1036px;
width: 141px;
height: 147px;
}
.background_rainbows_end {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -1036px;
width: 141px;
height: 147px;
}
.background_rainforest {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -1036px;
width: 141px;
height: 147px;
}
.background_rainy_barnyard {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px 0px;
width: 141px;
height: 147px;
}
.background_rainy_city {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -148px;
width: 141px;
height: 147px;
}
.background_red {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -296px;
width: 141px;
height: 147px;
}
.background_relaxation_river {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -444px;
width: 141px;
height: 147px;
}
.background_resting_in_the_inn {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -592px;
width: 141px;
height: 147px;
}
.background_river_of_lava {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -740px;
width: 141px;
height: 147px;
}
.background_rolling_hills {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -888px;
width: 141px;
height: 147px;
}
.background_rope_bridge {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -1036px;
width: 141px;
height: 147px;
}
.background_rose_garden {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -1184px;
width: 141px;
height: 147px;
}
.background_rowboat {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -1184px;
width: 141px;
height: 147px;
}
.background_salt_lake {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -1184px;
width: 141px;
height: 147px;
}
.background_sandcastle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -1184px;
width: 141px;
height: 147px;
}
.background_school_of_fish {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -1184px;
width: 141px;
height: 147px;
}
.background_scribes_workshop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -1184px;
width: 141px;
height: 147px;
}
.background_seafarer_ship {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -1184px;
width: 141px;
height: 147px;
}
.background_seaside_cliffs {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -1184px;
width: 141px;
height: 147px;
}
.background_shimmering_ice_prism {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -1184px;
width: 141px;
height: 147px;
}
.background_shimmery_bubbles {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -1184px;
width: 141px;
height: 147px;
}
.background_slimy_swamp {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px 0px;
width: 141px;
height: 147px;
}
.background_snowglobe {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -148px;
width: 141px;
height: 147px;
}
.background_snowman_army {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -296px;
width: 141px;
height: 147px;
}
.background_snowy_day_fireplace {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -444px;
width: 141px;
height: 147px;
}
.background_snowy_farm {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -592px;
width: 141px;
height: 147px;
}
.background_snowy_pines {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -740px;
width: 141px;
height: 147px;
}
.background_snowy_sunrise {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -888px;
width: 141px;
height: 147px;
}
.background_south_pole {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -1036px;
width: 141px;
height: 147px;
}
.background_sparkling_snowflake {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -1184px;
width: 141px;
height: 147px;
}
.background_spider_web {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -1332px;
width: 141px;
height: 147px;
}
.background_spiral_staircase {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -1332px;
width: 141px;
height: 147px;
}
.background_splash_in_a_puddle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -1332px;
width: 141px;
height: 147px;
}
.background_spooky_hotel {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -1332px;
width: 141px;
height: 147px;
}
.background_spooky_scarecrow_field {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -1332px;
width: 141px;
height: 147px;
}
.background_spring_rain {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -1332px;
width: 141px;
height: 147px;
}
.background_spring_thaw {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -1332px;
width: 141px;
height: 147px;
}
.background_stable {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -1332px;
width: 141px;
height: 147px;
}
.background_stained_glass {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -1332px;
width: 141px;
height: 147px;
}
.background_starry_skies {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -1332px;
width: 141px;
height: 147px;
}
.background_starry_winter_night {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -1332px;
width: 141px;
height: 147px;
}
.background_stoikalm_volcanoes {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px 0px;
width: 141px;
height: 147px;
}
.background_stone_circle {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -148px;
width: 141px;
height: 147px;
}
.background_stone_tower {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -296px;
width: 141px;
height: 147px;
}
.background_stormy_rooftops {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -444px;
width: 141px;
height: 147px;
}
.background_stormy_ship {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -592px;
width: 141px;
height: 147px;
}
.background_strange_sewers {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -740px;
width: 141px;
height: 147px;
}
.background_strawberry_patch {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -888px;
width: 141px;
height: 147px;
}
.background_succulent_garden {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -1036px;
width: 141px;
height: 147px;
}
.background_summer_fireworks {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -1184px;
width: 141px;
height: 147px;
}
.background_sunken_ship {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -1332px;
width: 141px;
height: 147px;
}
.background_sunset_meadow {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: 0px -1480px;
width: 141px;
height: 147px;
}
.background_sunset_oasis {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -142px -1480px;
width: 141px;
height: 147px;
}
.background_sunset_savannah {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -284px -1480px;
width: 141px;
height: 147px;
}
.background_swarming_darkness {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -426px -1480px;
width: 141px;
height: 147px;
}
.background_swimming_among_jellyfish {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -568px -1480px;
width: 141px;
height: 147px;
}
.background_tar_pits {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -710px -1480px;
width: 141px;
height: 147px;
}
.background_tavern {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -852px -1480px;
width: 141px;
height: 147px;
}
.background_tea_party {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -994px -1480px;
width: 141px;
height: 147px;
}
.background_terraced_rice_field {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1136px -1480px;
width: 141px;
height: 147px;
}
.background_throne_room {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1278px -1480px;
width: 141px;
height: 147px;
}
.background_thunderstorm {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1420px -1480px;
width: 141px;
height: 147px;
}
.background_tide_pool {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1562px -1480px;
width: 141px;
height: 147px;
}
.background_tornado {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1704px 0px;
width: 141px;
height: 147px;
}
.background_toymakers_workshop {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1704px -148px;
width: 141px;
height: 147px;
}
.background_training_grounds {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1704px -296px;
width: 141px;
height: 147px;
}
.background_treasure_room {
background-image: url('~@/assets/images/sprites/spritesmith-main-1.png');
background-position: -1704px -444px;
width: 141px;
height: 147px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,408 +0,0 @@
.npc_matt {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1150px -1519px;
width: 195px;
height: 138px;
}
.npc_matt_habitoween {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1355px -1332px;
width: 195px;
height: 138px;
}
.npc_matt_nye {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1551px -1332px;
width: 195px;
height: 138px;
}
.npc_matt_spring {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -366px -1519px;
width: 195px;
height: 138px;
}
.npc_matt_summer {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -562px -1519px;
width: 195px;
height: 138px;
}
.npc_matt_thanksgiving {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -758px -1519px;
width: 195px;
height: 138px;
}
.npc_matt_winter {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -954px -1519px;
width: 195px;
height: 138px;
}
.quest_alligator {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -1079px;
width: 201px;
height: 213px;
}
.quest_amber {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px 0px;
width: 219px;
height: 219px;
}
.quest_armadillo {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px 0px;
width: 219px;
height: 219px;
}
.quest_atom1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -645px -1332px;
width: 250px;
height: 150px;
}
.quest_atom2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1147px -1332px;
width: 207px;
height: 138px;
}
.quest_atom3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -211px -1332px;
width: 216px;
height: 180px;
}
.quest_axolotl {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -232px;
width: 219px;
height: 219px;
}
.quest_badger {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -232px;
width: 219px;
height: 219px;
}
.quest_basilist {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -1733px;
width: 189px;
height: 141px;
}
.quest_beetle {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -662px -1112px;
width: 204px;
height: 201px;
}
.quest_blackPearl {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px 0px;
width: 216px;
height: 216px;
}
.quest_bronze {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -232px;
width: 219px;
height: 219px;
}
.quest_bunny {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -1332px;
width: 210px;
height: 186px;
}
.quest_butterfly {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px 0px;
width: 219px;
height: 219px;
}
.quest_cheetah {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -220px;
width: 219px;
height: 219px;
}
.quest_cow {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -1519px;
width: 174px;
height: 213px;
}
.quest_dilatory {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -452px;
width: 219px;
height: 219px;
}
.quest_dilatoryDistress1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -868px;
width: 210px;
height: 210px;
}
.quest_dilatoryDistress2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px -208px;
width: 150px;
height: 150px;
}
.quest_dilatoryDistress3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -452px;
width: 219px;
height: 219px;
}
.quest_dilatory_derby {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -452px;
width: 219px;
height: 219px;
}
.quest_dolphin {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -452px;
width: 219px;
height: 219px;
}
.quest_dustbunnies {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px 0px;
width: 219px;
height: 219px;
}
.quest_egg {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px 0px;
width: 165px;
height: 207px;
}
.quest_evilsanta {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px -510px;
width: 118px;
height: 131px;
}
.quest_evilsanta2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -220px;
width: 219px;
height: 219px;
}
.quest_falcon {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -440px;
width: 219px;
height: 219px;
}
.quest_ferret {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -672px;
width: 219px;
height: 219px;
}
.quest_fluorite {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -672px;
width: 219px;
height: 219px;
}
.quest_frog {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -1112px;
width: 221px;
height: 213px;
}
.quest_ghost_stag {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -672px;
width: 219px;
height: 219px;
}
.quest_goldenknight1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -672px;
width: 219px;
height: 219px;
}
.quest_goldenknight2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -896px -1332px;
width: 250px;
height: 150px;
}
.quest_goldenknight3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px 0px;
width: 219px;
height: 231px;
}
.quest_gryphon {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1310px -1112px;
width: 216px;
height: 177px;
}
.quest_guineapig {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -672px;
width: 219px;
height: 219px;
}
.quest_harpy {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px 0px;
width: 219px;
height: 219px;
}
.quest_hedgehog {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -867px -1112px;
width: 219px;
height: 186px;
}
.quest_hippo {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -220px;
width: 219px;
height: 219px;
}
.quest_horse {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -440px;
width: 219px;
height: 219px;
}
.quest_kangaroo {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -660px;
width: 219px;
height: 219px;
}
.quest_kraken {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -428px -1332px;
width: 216px;
height: 177px;
}
.quest_lostMasterclasser1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -892px;
width: 219px;
height: 219px;
}
.quest_lostMasterclasser2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -892px;
width: 219px;
height: 219px;
}
.quest_lostMasterclasser3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -440px -892px;
width: 219px;
height: 219px;
}
.quest_mayhemMistiflying1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1757px -359px;
width: 150px;
height: 150px;
}
.quest_mayhemMistiflying2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -660px -892px;
width: 219px;
height: 219px;
}
.quest_mayhemMistiflying3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -880px -892px;
width: 219px;
height: 219px;
}
.quest_monkey {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1100px -892px;
width: 219px;
height: 219px;
}
.quest_moon1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -217px;
width: 216px;
height: 216px;
}
.quest_moon2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px 0px;
width: 219px;
height: 219px;
}
.quest_moon3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px -220px;
width: 219px;
height: 219px;
}
.quest_moonstone1 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px -440px;
width: 219px;
height: 219px;
}
.quest_moonstone2 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px -660px;
width: 219px;
height: 219px;
}
.quest_moonstone3 {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1320px -880px;
width: 219px;
height: 219px;
}
.quest_nudibranch {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -434px;
width: 216px;
height: 216px;
}
.quest_octopus {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1087px -1112px;
width: 222px;
height: 177px;
}
.quest_onyx {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: 0px -1112px;
width: 219px;
height: 219px;
}
.quest_owl {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -220px -1112px;
width: 219px;
height: 219px;
}
.quest_peacock {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -1540px -651px;
width: 216px;
height: 216px;
}
.quest_penguin {
background-image: url('~@/assets/images/sprites/spritesmith-main-15.png');
background-position: -175px -1519px;
width: 190px;
height: 183px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

+1 -3
View File
@@ -1,5 +1,3 @@
@import url("../css/sprites.css");
@import url("../css/sprites/spritesmith-main.css");
@for $i from 0 through 31 {
@import url("../css/sprites/spritesmith-main-#{$i}.css");
}
+1 -1
View File
@@ -224,7 +224,7 @@
</div>
<div class="row">
<div class="col-12 col-md-5 text-center text-md-left">
© 2021 Habitica. All rights reserved.
© 2022 Habitica. All rights reserved.
<div
v-if="!IS_PRODUCTION && isUserLoaded"
class="debug float-left"
@@ -26,7 +26,7 @@
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
<customize-options
:items="set.options"
:current-value="user.preferences.skin"
:current-value="user.preferences.hair.color"
:full-set="!hideSet(set) && !userOwnsSet('hair', set.keys, 'color')"
@unlock="unlock(`hair.color.${set.keys.join(',hair.color.')}`)"
/>

Some files were not shown because too many files have changed in this diff Show More