Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a317c269e | |||
| 618cdafd10 | |||
| e7b37d0378 | |||
| 765e08f999 | |||
| 598bc29647 | |||
| 39ccddfb1c | |||
| 108214a217 | |||
| 271f40e355 | |||
| e801547580 | |||
| fc11941186 | |||
| 882fad3113 | |||
| 6168492711 | |||
| 2aade9aaa6 | |||
| 4789946c4e | |||
| a69d8877c9 | |||
| 7cc0c3bc57 | |||
| fb78495a1b | |||
| 22def5111f | |||
| 6e91d51def | |||
| f3b8a4e931 | |||
| 69afa52beb | |||
| f09a39d27c | |||
| 2e71963fbf | |||
| f740a92fb7 | |||
| 21e7ddea16 | |||
| 923d90cf22 | |||
| b386a1917d | |||
| 4a5427b2b2 | |||
| 04554c5309 | |||
| 5ef88b5c56 | |||
| 1f2397b81a | |||
| 892c4934d5 | |||
| 60d5aaaaa6 | |||
| f506b840ed | |||
| f357750d88 | |||
| a2dbe68338 | |||
| 491d2cfab1 | |||
| fa91abb739 | |||
| 6b46d04537 | |||
| b90457c04f | |||
| 379d98a91e | |||
| 07352480cd | |||
| a6ff8e095a | |||
| 1fb44bbe73 | |||
| 5323849f90 | |||
| 034327f647 | |||
| de9aac0988 | |||
| f55d836398 | |||
| 287014518d | |||
| b46e2da61b | |||
| ef47d6cf0b | |||
| 1f5d66cd58 | |||
| a88602a21f | |||
| ffd2b4b76f | |||
| c50ed843fb | |||
| 760c05df5d | |||
| 26d070f2c3 | |||
| 850ae5114f | |||
| bc9577439e | |||
| 10cd596f0b | |||
| d180062ad2 | |||
| bfacf4b36e | |||
| 2912f31dec | |||
| c47b287a89 | |||
| 3aa626d2ae | |||
| 647ee2a073 | |||
| 2080c3f7b8 | |||
| 6f65c72921 | |||
| 22bbdd6a28 | |||
| 1a3d6f6520 | |||
| aa1e78ac94 | |||
| 858caa4582 | |||
| 28193f86fb | |||
| 877fe48225 | |||
| e0f6f79c5b | |||
| f62254d68e | |||
| d054e6fc16 | |||
| 7231f699c1 | |||
| 1dae0793fd | |||
| f18fbe86b6 | |||
| 61a61724ca | |||
| 93cf30eb18 | |||
| cff08adcd0 | |||
| 4da2ed4a1f | |||
| 11c5b26c59 | |||
| ac85bb2e2d | |||
| 74dfb2710f | |||
| 8dbd3c3db1 | |||
| 74b3b348ff | |||
| 3386d61fde | |||
| 19da14531c | |||
| 254dd80f24 | |||
| 0bc3f16b4b | |||
| 5184973bd5 | |||
| b6accca5ca | |||
| fec68e6211 | |||
| fc63c906dd | |||
| 3333f8f0f5 | |||
| 89a3ac3dde | |||
| 16551ec83f | |||
| 2645bf6023 | |||
| f5f4974a73 | |||
| 162e337d14 | |||
| 21a7d36b7b | |||
| f2506c3231 | |||
| d47641e25a | |||
| fb8479ad1e | |||
| 3810cf3ef3 | |||
| d05da3722c | |||
| b8a3440ef2 | |||
| 44d63032d8 | |||
| 9d7da91ec6 | |||
| 8b3267458b | |||
| bccfaab350 | |||
| 753f12979e |
@@ -3,10 +3,13 @@ FROM node:20
|
||||
# Install global packages
|
||||
RUN npm install -g gulp-cli mocha
|
||||
|
||||
# Copy package.json and package-lock.json into image, then install
|
||||
# dependencies.
|
||||
# Copy package.json and package-lock.json into image
|
||||
WORKDIR /usr/src/habitica
|
||||
COPY ["package.json", "package-lock.json", "./"]
|
||||
# Copy the remaining source files in.
|
||||
COPY . /usr/src/habitica
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
RUN npm run postinstall
|
||||
RUN npm run client:build
|
||||
RUN gulp build:prod
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
Habitica  [](https://codeclimate.com/github/HabitRPG/habitrpg) [](https://www.bountysource.com/trackers/68393-habitrpg?utm_source=68393&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
||||
Habitica 
|
||||
===============
|
||||
|
||||
[Habitica](https://habitica.com) is an open-source habit-building program that treats your life like a role-playing game. Level up as you succeed, lose HP as you fail, and earn money to buy weapons and armor.
|
||||
[Habitica](https://habitica.com) is an open-source habit-building program that treats your life like a role-playing game. Level up as you succeed, lose HP as you fail, and earn Gold to buy weapons and armor!
|
||||
|
||||
**We need more programmers!** Your assistance will be greatly appreciated. The wiki pages below and the additional pages they link to will tell you how to get started on contributing code and where you can go to seek further help or ask questions:
|
||||
**Want to contribute code to Habitica?** We're always looking for assistance on any issues in our repo with the "Help Wanted" label. The wiki pages below and the additional linked pages will tell you how to start contributing code and where you can seek further help or ask questions:
|
||||
* [Guidance for Blacksmiths](https://habitica.fandom.com/wiki/Guidance_for_Blacksmiths) - an introduction to the technologies used and how the software is organized.
|
||||
* [Setting up Habitica Locally](https://habitica.fandom.com/wiki/Setting_up_Habitica_Locally) - how to set up a local install of Habitica for development and testing on various platforms.
|
||||
* [Setting up Habitica Locally](https://github.com/HabitRPG/habitica/wiki/Setting-Up-Habitica-for-Local-Development) - how to set up a local install of Habitica for development and testing.
|
||||
|
||||
**Interested in contributing to Habitica’s mobile apps?** Visit the links below for our mobile repositories.
|
||||
* **Android:** https://github.com/HabitRPG/habitica-android
|
||||
* **iOS:** https://github.com/HabitRPG/habitica-ios
|
||||
|
||||
Habitica's code is licensed as described at https://github.com/HabitRPG/habitica/blob/develop/LICENSE
|
||||
|
||||
**Found a bug?** Please report it to [admin email](mailto:admin@habitica.com) rather than creating an issue (an admin will advise you if a new issue is necessary; usually it is not).
|
||||
**Found a bug?** Please report it to [admin email](mailto:admin@habitica.com) rather than create an issue (an admin will advise you if a new issue is necessary; usually it is not).
|
||||
|
||||
**Have any questions about Habitica or its community?** See the links in the [habitica.com](https://habitica.com) website's Help menu or drop in to [Guilds > Tavern Chat](https://habitica.com/groups/tavern) to ask questions or chat socially!
|
||||
**Creating a third-party tool?** Please review our [API Usage Guidelines](https://github.com/HabitRPG/habitica/wiki/API-Usage-Guidelines) to ensure that your tool is compliant and maintains the best experience for Habitica players.
|
||||
|
||||
**Have any questions about Habitica or contributing?** See the links in the [Habitica](https://habitica.com) website's Help menu. There’s FAQ’s, guides, and the option to reach out to us with any further questions!
|
||||
|
||||
@@ -42,10 +42,41 @@ function cssVarMap (sprite) {
|
||||
}
|
||||
}
|
||||
|
||||
function createSpritesStream (name, src) {
|
||||
function filterFile (file) {
|
||||
if (file.relative.indexOf('Mount_Icon_') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.path.indexOf('shop/') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.path.indexOf('stable/eggs') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.path.indexOf('stable/food') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.path.indexOf('stable/potions') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.relative.indexOf('shop_') === 0) {
|
||||
return false;
|
||||
}
|
||||
if (file.relative.indexOf('icon_background') === 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function createSpritesStream (name, src) {
|
||||
const stream = mergeStream();
|
||||
// need to import this way bc of weird dependency things
|
||||
// eslint-disable-next-line global-require
|
||||
const filter = require('gulp-filter');
|
||||
|
||||
const f = filter(filterFile);
|
||||
|
||||
const spriteData = gulp.src(src)
|
||||
.pipe(f)
|
||||
.pipe(spritesmith({
|
||||
imgName: `spritesmith-${name}.png`,
|
||||
cssName: `spritesmith-${name}.css`,
|
||||
@@ -63,7 +94,7 @@ function createSpritesStream (name, src) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
gulp.task('sprites:main', () => {
|
||||
gulp.task('sprites:main', async () => {
|
||||
const mainSrc = sync('habitica-images/**/*.png');
|
||||
return createSpritesStream('main', mainSrc);
|
||||
});
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20230731_naming_day';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20240731_naming_day';
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
let set;
|
||||
let push;
|
||||
@@ -115,16 +113,16 @@ async function updateUser (user) {
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
if (push) {
|
||||
return await user.updateOne({ $set: set, $inc: inc, $push: push }).exec();
|
||||
} else {
|
||||
return await user.updateOne({ $set: set, $inc: inc }).exec();
|
||||
return user.updateOne({ $set: set, $inc: inc, $push: push }).exec();
|
||||
}
|
||||
|
||||
return user.updateOne({ $set: set, $inc: inc }).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
let query = {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2023-07-01') },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2024-07-01') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
@@ -136,7 +134,7 @@ export default async function processUsers () {
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.exec();
|
||||
|
||||
@@ -152,4 +150,4 @@ export default async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"version": "5.25.3",
|
||||
"version": "5.27.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "habitica",
|
||||
"version": "5.25.3",
|
||||
"version": "5.27.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
@@ -40,6 +40,7 @@
|
||||
"got": "^11.8.6",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-babel": "^8.0.0",
|
||||
"gulp-filter": "^7.0.0",
|
||||
"gulp-imagemin": "^7.1.0",
|
||||
"gulp-nodemon": "^2.5.0",
|
||||
"gulp.spritesmith": "^6.13.0",
|
||||
@@ -4360,6 +4361,14 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/array-differ": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
|
||||
"integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/array-each": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
|
||||
@@ -9721,9 +9730,9 @@
|
||||
"integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w=="
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.4.tgz",
|
||||
"integrity": "sha512-utnwm92SyozgA3hhH2I8qldf2lBqm6qHOICawRNRFu1qMe3+oqr+GcXjGqTmXTMGE5T4eC03kr/rlh5C1IRdZA==",
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz",
|
||||
"integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -11493,6 +11502,31 @@
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gulp-filter": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gulp-filter/-/gulp-filter-7.0.0.tgz",
|
||||
"integrity": "sha512-ZGWtJo0j1mHfP77tVuhyqem4MRA5NfNRjoVe6VAkLGeQQ/QGo2VsFwp7zfPTGDsd1rwzBmoDHhxpE6f5B3Zuaw==",
|
||||
"dependencies": {
|
||||
"multimatch": "^5.0.0",
|
||||
"plugin-error": "^1.0.1",
|
||||
"streamfilter": "^3.0.0",
|
||||
"to-absolute-glob": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"gulp": ">=4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"gulp": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/gulp-imagemin": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/gulp-imagemin/-/gulp-imagemin-7.1.0.tgz",
|
||||
@@ -15043,6 +15077,29 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/multimatch": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz",
|
||||
"integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==",
|
||||
"dependencies": {
|
||||
"@types/minimatch": "^3.0.3",
|
||||
"array-differ": "^3.0.0",
|
||||
"array-union": "^2.1.0",
|
||||
"arrify": "^2.0.1",
|
||||
"minimatch": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/multimatch/node_modules/@types/minimatch": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
|
||||
"integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="
|
||||
},
|
||||
"node_modules/mute-stdout": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
|
||||
@@ -19468,6 +19525,17 @@
|
||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
|
||||
"integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="
|
||||
},
|
||||
"node_modules/streamfilter": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/streamfilter/-/streamfilter-3.0.0.tgz",
|
||||
"integrity": "sha512-kvKNfXCmUyC8lAXSSHCIXBUlo/lhsLcCU/OmzACZYpRUdtKIH68xYhm/+HI15jFJYtNJGYtCgn2wmIiExY1VwA==",
|
||||
"dependencies": {
|
||||
"readable-stream": "^3.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "5.25.3",
|
||||
"version": "5.27.0",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
@@ -35,6 +35,7 @@
|
||||
"got": "^11.8.6",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-babel": "^8.0.0",
|
||||
"gulp-filter": "^7.0.0",
|
||||
"gulp-imagemin": "^7.1.0",
|
||||
"gulp-nodemon": "^2.5.0",
|
||||
"gulp.spritesmith": "^6.13.0",
|
||||
@@ -107,7 +108,8 @@
|
||||
"debug": "gulp nodemon --inspect",
|
||||
"mongo:dev": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
|
||||
"apidoc": "gulp apidoc"
|
||||
"apidoc": "gulp apidoc",
|
||||
"heroku-postbuild": "npm run client:build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.4.0",
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('contentLib', () => {
|
||||
beforeEach(() => {
|
||||
resSpy = generateRes();
|
||||
if (fs.existsSync(contentLib.CONTENT_CACHE_PATH)) {
|
||||
fs.rmdirSync(contentLib.CONTENT_CACHE_PATH, { recursive: true });
|
||||
fs.rmSync(contentLib.CONTENT_CACHE_PATH, { recursive: true });
|
||||
}
|
||||
fs.mkdirSync(contentLib.CONTENT_CACHE_PATH);
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
createAndPopulateGroup,
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
import { model as Group } from '../../../../../website/server/models/group';
|
||||
|
||||
describe('GET /groups/:groupId/chat', () => {
|
||||
let user;
|
||||
@@ -37,4 +38,34 @@ describe('GET /groups/:groupId/chat', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('public Guild', () => {
|
||||
let group;
|
||||
before(async () => {
|
||||
({ group } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'test group',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
upgradeToGroupPlan: true,
|
||||
chat: [
|
||||
'Hello',
|
||||
'Welcome to the Guild',
|
||||
],
|
||||
}));
|
||||
|
||||
// Creation API is shut down, we need to simulate an extant public group
|
||||
await Group.updateOne({ _id: group._id }, { $set: { privacy: 'public' }, $unset: { 'purchased.plan': 1 } }).exec();
|
||||
});
|
||||
|
||||
it('returns error if user attempts to fetch a sunset Guild', async () => {
|
||||
await expect(user.get(`/groups/${group._id}/chat`)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('featureRetired'),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
createAndPopulateGroup,
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
import { model as Group } from '../../../../../website/server/models/group';
|
||||
|
||||
describe('POST /chat/:chatId/like', () => {
|
||||
let user;
|
||||
@@ -111,4 +112,18 @@ describe('POST /chat/:chatId/like', () => {
|
||||
message: t('groupNotFound'),
|
||||
});
|
||||
});
|
||||
|
||||
it('does not like a message that belongs to a sunset public group', async () => {
|
||||
const message = await anotherUser.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
||||
|
||||
// Creation API is shut down, we need to simulate an extant public group
|
||||
await Group.updateOne({ _id: groupWithChat._id }, { $set: { privacy: 'public' }, $unset: { 'purchased.plan': 1 } }).exec();
|
||||
|
||||
await expect(user.post(`/groups/${groupWithChat._id}/chat/${message.message.id}/like`))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('featureRetired'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,7 +123,7 @@ describe('GET /world-state', () => {
|
||||
|
||||
const res = await requester().get('/world-state');
|
||||
|
||||
expect(res.npcImageSuffix).to.equal('winter');
|
||||
expect(res.npcImageSuffix).to.equal('fall');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -341,6 +341,16 @@ describe('shops', () => {
|
||||
const backgrounds = shopCategories.find(cat => cat.identifier === 'backgrounds').items;
|
||||
expect(backgrounds.length).to.be.greaterThan(0);
|
||||
});
|
||||
|
||||
it('does not add an end date to steampunk gear', () => {
|
||||
const categories = shopCategories.filter(cat => cat.identifier.startsWith('30'));
|
||||
categories.forEach(category => {
|
||||
expect(category.end).to.not.exist;
|
||||
category.items.forEach(item => {
|
||||
expect(item.end).to.not.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('customizationShop', () => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import armoireSet from '../../../website/common/script/content/gear/sets/armoire
|
||||
describe('armoireSet items', () => {
|
||||
it('checks if canOwn has the same id', () => {
|
||||
Object.keys(armoireSet).forEach(type => {
|
||||
if (type === 'all') return;
|
||||
Object.keys(armoireSet[type]).forEach(itemKey => {
|
||||
const ownedKey = `${type}_armoire_${itemKey}`;
|
||||
expect(armoireSet[type][itemKey].canOwn({
|
||||
|
||||
@@ -233,6 +233,17 @@ describe('shared.ops.purchase', () => {
|
||||
expect(user.items.hatchingPotions[key]).to.eql(1);
|
||||
});
|
||||
|
||||
it('purchases event hatching potion', async () => {
|
||||
clock.restore();
|
||||
clock = sandbox.useFakeTimers(moment('2022-04-10').valueOf());
|
||||
const type = 'hatchingPotions';
|
||||
const key = 'Veggie';
|
||||
|
||||
await purchase(user, { params: { type, key } });
|
||||
|
||||
expect(user.items.hatchingPotions[key]).to.eql(1);
|
||||
});
|
||||
|
||||
it('purchases hatching potion if user completed quest', async () => {
|
||||
const type = 'hatchingPotions';
|
||||
const key = 'Bronze';
|
||||
|
||||
@@ -3,38 +3,26 @@ import forEach from 'lodash/forEach';
|
||||
import {
|
||||
expectValidTranslationString,
|
||||
} from '../helpers/content.helper';
|
||||
|
||||
function makeArmoireIitemList () {
|
||||
const armoire = require('../../website/common/script/content/gear/sets/armoire').default;
|
||||
const items = [];
|
||||
items.push(...Object.values(armoire.armor));
|
||||
items.push(...Object.values(armoire.body));
|
||||
items.push(...Object.values(armoire.eyewear));
|
||||
items.push(...Object.values(armoire.head));
|
||||
items.push(...Object.values(armoire.headAccessory));
|
||||
items.push(...Object.values(armoire.shield));
|
||||
items.push(...Object.values(armoire.weapon));
|
||||
return items;
|
||||
}
|
||||
import armoire from '../../website/common/script/content/gear/sets/armoire';
|
||||
|
||||
describe('armoire', () => {
|
||||
let clock;
|
||||
beforeEach(() => {
|
||||
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
|
||||
});
|
||||
afterEach(() => {
|
||||
clock.restore();
|
||||
if (clock) {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('does not return unreleased gear', async () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-01-02'));
|
||||
const items = makeArmoireIitemList();
|
||||
const items = armoire.all;
|
||||
expect(items.length).to.equal(377);
|
||||
expect(items.filter(item => item.set === 'pottersSet' || item.set === 'optimistSet' || item.set === 'schoolUniform')).to.be.an('array').that.is.empty;
|
||||
});
|
||||
|
||||
it('released gear has all required properties', async () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-05-08'));
|
||||
const items = makeArmoireIitemList();
|
||||
const items = armoire.all;
|
||||
expect(items.length).to.equal(396);
|
||||
forEach(items, item => {
|
||||
if (item.set !== undefined) {
|
||||
@@ -48,29 +36,30 @@ describe('armoire', () => {
|
||||
|
||||
it('releases gear when appropriate', async () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-01-01T00:00:00.000Z'));
|
||||
const items = makeArmoireIitemList();
|
||||
const items = armoire.all;
|
||||
expect(items.length).to.equal(377);
|
||||
clock.restore();
|
||||
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
|
||||
clock = sinon.useFakeTimers(new Date('2024-01-08'));
|
||||
const januaryItems = makeArmoireIitemList();
|
||||
const januaryItems = armoire.all;
|
||||
expect(januaryItems.length).to.equal(381);
|
||||
clock.restore();
|
||||
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
|
||||
clock = sinon.useFakeTimers(new Date('2024-02-07'));
|
||||
const januaryItems2 = makeArmoireIitemList();
|
||||
const januaryItems2 = armoire.all;
|
||||
expect(januaryItems2.length).to.equal(381);
|
||||
clock.restore();
|
||||
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
|
||||
clock = sinon.useFakeTimers(new Date('2024-02-07T16:00:00.000Z'));
|
||||
const febuaryItems = makeArmoireIitemList();
|
||||
clock = sinon.useFakeTimers(new Date('2024-02-07T09:00:00.000Z'));
|
||||
const febuaryItems = armoire.all;
|
||||
expect(febuaryItems.length).to.equal(384);
|
||||
});
|
||||
|
||||
it('sets have at least 2 items', () => {
|
||||
const armoire = makeArmoireIitemList();
|
||||
const setMap = {};
|
||||
forEach(armoire, item => {
|
||||
forEach(armoire.all, item => {
|
||||
// Gotta have one outlier
|
||||
if (!item.set || item.set.startsWith('armoire-')) return;
|
||||
if (setMap[item.set] === undefined) {
|
||||
setMap[item.set] = 0;
|
||||
}
|
||||
|
||||
@@ -5,29 +5,51 @@ import {
|
||||
expectValidTranslationString,
|
||||
} from '../helpers/content.helper';
|
||||
|
||||
import * as eggs from '../../website/common/script/content/eggs';
|
||||
import eggs from '../../website/common/script/content/eggs';
|
||||
|
||||
describe('eggs', () => {
|
||||
describe('all', () => {
|
||||
it('is a combination of drop and quest eggs', () => {
|
||||
const dropNumber = Object.keys(eggs.drops).length;
|
||||
const questNumber = Object.keys(eggs.quests).length;
|
||||
const allNumber = Object.keys(eggs.all).length;
|
||||
let clock;
|
||||
|
||||
expect(allNumber).to.be.greaterThan(0);
|
||||
expect(allNumber).to.equal(dropNumber + questNumber);
|
||||
});
|
||||
afterEach(() => {
|
||||
if (clock) {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('contains basic information about each egg', () => {
|
||||
each(eggs.all, (egg, key) => {
|
||||
expectValidTranslationString(egg.text);
|
||||
expectValidTranslationString(egg.adjective);
|
||||
expectValidTranslationString(egg.mountText);
|
||||
expectValidTranslationString(egg.notes);
|
||||
expect(egg.canBuy).to.be.a('function');
|
||||
expect(egg.value).to.be.a('number');
|
||||
expect(egg.key).to.equal(key);
|
||||
const eggTypes = [
|
||||
'drops',
|
||||
'quests',
|
||||
];
|
||||
|
||||
eggTypes.forEach(eggType => {
|
||||
describe(eggType, () => {
|
||||
it('contains basic information about each egg', () => {
|
||||
each(eggs[eggType], (egg, key) => {
|
||||
expectValidTranslationString(egg.text);
|
||||
expectValidTranslationString(egg.adjective);
|
||||
expectValidTranslationString(egg.mountText);
|
||||
expectValidTranslationString(egg.notes);
|
||||
expect(egg.canBuy).to.be.a('function');
|
||||
expect(egg.value).to.be.a('number');
|
||||
expect(egg.key).to.equal(key);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('does not contain unreleased eggs', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-05-20'));
|
||||
const questEggs = eggs.quests;
|
||||
expect(questEggs.Giraffe).to.not.exist;
|
||||
});
|
||||
|
||||
it('Releases eggs when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-05-20'));
|
||||
const mayEggs = eggs.quests;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const juneEggs = eggs.quests;
|
||||
expect(juneEggs.Giraffe).to.exist;
|
||||
expect(Object.keys(mayEggs).length).to.equal(Object.keys(juneEggs).length - 1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -68,6 +68,16 @@ describe('Gear', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('only assigns mage weapons twoHanded', () => {
|
||||
each([allGear.armor.special, allGear.head.special, allGear.shield.special], gearType => {
|
||||
each(gearType, gear => {
|
||||
if (gear.specialClass === 'wizard') {
|
||||
expect(gear.twoHanded, gear.key).to.not.eql(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('backer gear', () => {
|
||||
let user;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
expectValidTranslationString,
|
||||
} from '../helpers/content.helper';
|
||||
|
||||
import { all } from '../../website/common/script/content/hatching-potions';
|
||||
import hatchingPotions from '../../website/common/script/content/hatching-potions';
|
||||
|
||||
describe('hatchingPotions', () => {
|
||||
let clock;
|
||||
@@ -25,7 +25,7 @@ describe('hatchingPotions', () => {
|
||||
potionTypes.forEach(potionType => {
|
||||
describe(potionType, () => {
|
||||
it('contains basic information about each potion', () => {
|
||||
each(all, (potion, key) => {
|
||||
each(hatchingPotions.all, (potion, key) => {
|
||||
expectValidTranslationString(potion.text);
|
||||
expectValidTranslationString(potion.notes);
|
||||
expect(potion.canBuy).to.be.a('function');
|
||||
@@ -35,4 +35,20 @@ describe('hatchingPotions', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('does not contain unreleased potions', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-05-20'));
|
||||
const premiumPotions = hatchingPotions.premium;
|
||||
expect(premiumPotions.Koi).to.not.exist;
|
||||
});
|
||||
|
||||
it('Releases potions when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-05-20'));
|
||||
const mayPotions = hatchingPotions.premium;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const junePotions = hatchingPotions.premium;
|
||||
expect(junePotions.Koi).to.exist;
|
||||
expect(Object.keys(mayPotions).length).to.equal(Object.keys(junePotions).length - 1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import content from '../../website/common/script/content';
|
||||
|
||||
describe('content index', () => {
|
||||
let clock;
|
||||
|
||||
afterEach(() => {
|
||||
if (clock) {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('Releases eggs when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const mayEggs = content.eggs;
|
||||
expect(mayEggs.Chameleon).to.not.exist;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-07-20'));
|
||||
const juneEggs = content.eggs;
|
||||
expect(juneEggs.Chameleon).to.exist;
|
||||
expect(Object.keys(mayEggs).length, '').to.equal(Object.keys(juneEggs).length - 1);
|
||||
});
|
||||
|
||||
it('Releases hatching potions when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-05-20'));
|
||||
const mayHatchingPotions = content.hatchingPotions;
|
||||
expect(mayHatchingPotions.Koi).to.not.exist;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const juneHatchingPotions = content.hatchingPotions;
|
||||
expect(juneHatchingPotions.Koi).to.exist;
|
||||
expect(Object.keys(mayHatchingPotions).length, '').to.equal(Object.keys(juneHatchingPotions).length - 1);
|
||||
});
|
||||
|
||||
it('Releases armoire gear when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const juneGear = content.gear.flat;
|
||||
expect(juneGear.armor_armoire_corsairsCoatAndCape).to.not.exist;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-07-10'));
|
||||
const julyGear = content.gear.flat;
|
||||
expect(julyGear.armor_armoire_corsairsCoatAndCape).to.exist;
|
||||
expect(Object.keys(juneGear).length, '').to.equal(Object.keys(julyGear).length - 3);
|
||||
});
|
||||
|
||||
it('Releases pets gear when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const junePets = content.petInfo;
|
||||
expect(junePets['Chameleon-Base']).to.not.exist;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-07-20'));
|
||||
const julyPets = content.petInfo;
|
||||
expect(julyPets['Chameleon-Base']).to.exist;
|
||||
expect(Object.keys(junePets).length, '').to.equal(Object.keys(julyPets).length - 10);
|
||||
});
|
||||
|
||||
it('Releases mounts gear when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const juneMounts = content.mountInfo;
|
||||
expect(juneMounts['Chameleon-Base']).to.not.exist;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-07-20'));
|
||||
const julyMounts = content.mountInfo;
|
||||
expect(julyMounts['Chameleon-Base']).to.exist;
|
||||
expect(Object.keys(juneMounts).length, '').to.equal(Object.keys(julyMounts).length - 10);
|
||||
});
|
||||
|
||||
it('marks regular food as buyable and droppable without any events', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const { food } = content;
|
||||
Object.keys(food).forEach(key => {
|
||||
if (key === 'Saddle') {
|
||||
expect(food[key].canBuy(), `${key} canBuy`).to.be.true;
|
||||
expect(food[key].canDrop, `${key} canDrop`).to.be.false;
|
||||
return;
|
||||
}
|
||||
let expected = true;
|
||||
if (key.startsWith('Cake_')) {
|
||||
expected = false;
|
||||
} else if (key.startsWith('Candy_')) {
|
||||
expected = false;
|
||||
} else if (key.startsWith('Pie_')) {
|
||||
expected = false;
|
||||
}
|
||||
expect(food[key].canBuy(), `${key} canBuy`).to.equal(expected);
|
||||
expect(food[key].canDrop, `${key} canDrop`).to.equal(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('marks candy as buyable and droppable during habitoween', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-10-31'));
|
||||
const { food } = content;
|
||||
Object.keys(food).forEach(key => {
|
||||
if (key === 'Saddle') {
|
||||
expect(food[key].canBuy(), `${key} canBuy`).to.be.true;
|
||||
expect(food[key].canDrop, `${key} canDrop`).to.be.false;
|
||||
return;
|
||||
}
|
||||
let expected = false;
|
||||
if (key.startsWith('Cake_')) {
|
||||
expected = false;
|
||||
} else if (key.startsWith('Candy_')) {
|
||||
expected = true;
|
||||
} else if (key.startsWith('Pie_')) {
|
||||
expected = false;
|
||||
}
|
||||
expect(food[key].canBuy(), `${key} canBuy`).to.equal(expected);
|
||||
expect(food[key].canDrop, `${key} canDrop`).to.equal(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('marks cake as buyable and droppable during birthday', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-01-31'));
|
||||
const { food } = content;
|
||||
Object.keys(food).forEach(key => {
|
||||
if (key === 'Saddle') {
|
||||
expect(food[key].canBuy(), `${key} canBuy`).to.be.true;
|
||||
expect(food[key].canDrop, `${key} canDrop`).to.be.false;
|
||||
return;
|
||||
}
|
||||
let expected = false;
|
||||
if (key.startsWith('Cake_')) {
|
||||
expected = true;
|
||||
} else if (key.startsWith('Candy_')) {
|
||||
expected = false;
|
||||
} else if (key.startsWith('Pie_')) {
|
||||
expected = false;
|
||||
}
|
||||
expect(food[key].canBuy(), `${key} canBuy`).to.equal(expected);
|
||||
expect(food[key].canDrop, `${key} canDrop`).to.equal(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('marks pie as buyable and droppable during pi day', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-03-14'));
|
||||
const { food } = content;
|
||||
Object.keys(food).forEach(key => {
|
||||
if (key === 'Saddle') {
|
||||
expect(food[key].canBuy(), `${key} canBuy`).to.be.true;
|
||||
expect(food[key].canDrop, `${key} canDrop`).to.be.false;
|
||||
return;
|
||||
}
|
||||
let expected = false;
|
||||
if (key.startsWith('Cake_')) {
|
||||
expected = false;
|
||||
} else if (key.startsWith('Candy_')) {
|
||||
expected = false;
|
||||
} else if (key.startsWith('Pie_')) {
|
||||
expected = true;
|
||||
}
|
||||
expect(food[key].canBuy(), `${key} canBuy`).to.equal(expected);
|
||||
expect(food[key].canDrop, `${key} canDrop`).to.equal(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
import find from 'lodash/find';
|
||||
import maxBy from 'lodash/maxBy';
|
||||
import {
|
||||
ARMOIRE_RELEASE_DATES,
|
||||
EGGS_RELEASE_DATES,
|
||||
HATCHING_POTIONS_RELEASE_DATES,
|
||||
} from '../../website/common/script/content/constants/releaseDates';
|
||||
import armoire from '../../website/common/script/content/gear/sets/armoire';
|
||||
import eggs from '../../website/common/script/content/eggs';
|
||||
import hatchingPotions from '../../website/common/script/content/hatching-potions';
|
||||
|
||||
describe('releaseDates', () => {
|
||||
let clock;
|
||||
|
||||
afterEach(() => {
|
||||
if (clock) {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
describe('armoire', () => {
|
||||
it('should only contain valid armoire names', () => {
|
||||
const lastReleaseDate = maxBy(Object.values(ARMOIRE_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-20`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-20`));
|
||||
Object.keys(ARMOIRE_RELEASE_DATES).forEach(key => {
|
||||
expect(find(armoire.all, { set: key }), `${key} is not a valid armoire set`).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
it('should contain a valid year and month', () => {
|
||||
Object.keys(ARMOIRE_RELEASE_DATES).forEach(key => {
|
||||
const date = ARMOIRE_RELEASE_DATES[key];
|
||||
expect(date.year, `${key} year is not a valid year`).to.be.a('number');
|
||||
expect(date.year).to.be.at.least(2023);
|
||||
expect(date.month, `${key} month is not a valid month`).to.be.a('number');
|
||||
expect(date.month).to.be.within(1, 12);
|
||||
expect(date.day).to.not.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('eggs', () => {
|
||||
it('should only contain valid egg names', () => {
|
||||
const lastReleaseDate = maxBy(Object.values(EGGS_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-${value.day}`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-${lastReleaseDate.day}`));
|
||||
Object.keys(EGGS_RELEASE_DATES).forEach(key => {
|
||||
expect(eggs.all[key], `${key} is not a valid egg name`).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
it('should contain a valid year, month and date', () => {
|
||||
Object.keys(EGGS_RELEASE_DATES).forEach(key => {
|
||||
const date = EGGS_RELEASE_DATES[key];
|
||||
expect(date.year, `${key} year is not a valid year`).to.be.a('number');
|
||||
expect(date.year).to.be.at.least(2024);
|
||||
expect(date.month, `${key} month is not a valid month`).to.be.a('number');
|
||||
expect(date.month).to.be.within(1, 12);
|
||||
expect(date.day, `${key} day is not a valid day`).to.be.a('number');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hatchingPotions', () => {
|
||||
it('should only contain valid potion names', () => {
|
||||
const lastReleaseDate = maxBy(Object.values(HATCHING_POTIONS_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-${value.day}`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-${lastReleaseDate.day}`));
|
||||
Object.keys(HATCHING_POTIONS_RELEASE_DATES).forEach(key => {
|
||||
expect(hatchingPotions.all[key], `${key} is not a valid potion name`).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
it('should contain a valid year, month and date', () => {
|
||||
Object.keys(HATCHING_POTIONS_RELEASE_DATES).forEach(key => {
|
||||
const date = HATCHING_POTIONS_RELEASE_DATES[key];
|
||||
expect(date.year, `${key} year is not a valid year`).to.be.a('number');
|
||||
expect(date.year).to.be.at.least(2024);
|
||||
expect(date.month, `${key} month is not a valid month`).to.be.a('number');
|
||||
expect(date.month).to.be.within(1, 12);
|
||||
expect(date.day, `${key} day is not a valid day`).to.be.a('number');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import QUEST_PETS from '../../website/common/script/content/quests/pets';
|
||||
import QUEST_HATCHINGPOTIONS from '../../website/common/script/content/quests/potions';
|
||||
import QUEST_BUNDLES from '../../website/common/script/content/bundles';
|
||||
import { premium } from '../../website/common/script/content/hatching-potions';
|
||||
import potions from '../../website/common/script/content/hatching-potions';
|
||||
import SPELLS from '../../website/common/script/content/spells';
|
||||
import QUEST_SEASONAL from '../../website/common/script/content/quests/seasonal';
|
||||
|
||||
@@ -123,12 +123,18 @@ describe('Content Schedule', () => {
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2024-06-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('sets the end date for a winter gala', () => {
|
||||
const date = new Date('2024-12-22');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('contains content for repeating events', () => {
|
||||
const date = new Date('2024-04-15');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.premiumHatchingPotions).to.exist;
|
||||
expect(matchers.premiumHatchingPotions.items.length).to.equal(4);
|
||||
expect(matchers.premiumHatchingPotions.items.indexOf('Garden')).to.not.equal(-1);
|
||||
expect(matchers.premiumHatchingPotions.items.length).to.equal(5);
|
||||
expect(matchers.premiumHatchingPotions.items.indexOf('Veggie')).to.not.equal(-1);
|
||||
expect(matchers.premiumHatchingPotions.items.indexOf('Porcelain')).to.not.equal(-1);
|
||||
});
|
||||
|
||||
@@ -167,7 +173,7 @@ describe('Content Schedule', () => {
|
||||
});
|
||||
|
||||
it('premium hatching potions', () => {
|
||||
const potionKeys = Object.keys(premium);
|
||||
const potionKeys = Object.keys(potions.premium);
|
||||
Object.keys(MONTHLY_SCHEDULE).forEach(key => {
|
||||
const monthlyPotions = MONTHLY_SCHEDULE[key][21].find(item => item.type === 'premiumHatchingPotions');
|
||||
for (const potion of monthlyPotions.items) {
|
||||
@@ -245,27 +251,33 @@ describe('Content Schedule', () => {
|
||||
it('allows sets matching the month', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202307')).to.be.true;
|
||||
expect(matcher.match('202207')).to.be.true;
|
||||
expect(matcher.match('202307'), '202307').to.be.true;
|
||||
expect(matcher.match('202207'), '202207').to.be.true;
|
||||
});
|
||||
|
||||
it('disallows sets not matching the month', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202306')).to.be.false;
|
||||
expect(matcher.match('202402')).to.be.false;
|
||||
expect(matcher.match('202306'), '202306').to.be.false;
|
||||
expect(matcher.match('202402'), '202402').to.be.false;
|
||||
});
|
||||
|
||||
it('disallows sets from current month', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202407')).to.be.false;
|
||||
expect(matcher.match('202407'), '202407').to.be.false;
|
||||
});
|
||||
|
||||
it('disallows sets from the future', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
|
||||
expect(matcher.match('202507')).to.be.false;
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202507'), '202507').to.be.false;
|
||||
});
|
||||
|
||||
it('matches sets released in the earlier half of the year', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202401'), '202401').to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,12 +6,21 @@ import {
|
||||
} from '../helpers/content.helper';
|
||||
import t from '../../website/common/script/content/translation';
|
||||
|
||||
import * as stable from '../../website/common/script/content/stable';
|
||||
import * as eggs from '../../website/common/script/content/eggs';
|
||||
import * as potions from '../../website/common/script/content/hatching-potions';
|
||||
import stable from '../../website/common/script/content/stable';
|
||||
import eggs from '../../website/common/script/content/eggs';
|
||||
import potions from '../../website/common/script/content/hatching-potions';
|
||||
|
||||
describe('stable', () => {
|
||||
describe('dropPets', () => {
|
||||
let clock;
|
||||
beforeEach(() => {
|
||||
clock = sinon.useFakeTimers(new Date('2020-05-20'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clock.restore();
|
||||
});
|
||||
|
||||
it('contains a pet for each drop potion * each drop egg', () => {
|
||||
const numberOfDropPotions = Object.keys(potions.drops).length;
|
||||
const numberOfDropEggs = Object.keys(eggs.drops).length;
|
||||
|
||||
@@ -27,8 +27,15 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="loading-screen">
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.62 28.86c-.32-.706-1.057-1.048-1.538-.706-.48.341-1.147.393-1.78.24-.633-.153-.753-1.604-.616-3.278.136-1.673.363-2.318.506-2.925.162-.61.877-.562.962-.084.086.479.582.479 1.307-.391.724-.87.617-3.409-.218-5.474-.836-2.065.326-1.865.664-1.66.337.205.544-.102.462-1.28-.082-1.178-1.166-2.098-2.039-2.663-.873-.564-1.936-1.186-1.911-2.697.025-1.511 2.08-1.464 2.358-1.439.279.025.815-.093.506-1.663-.31-1.57-1.43-1.869-2.133-1.826-.703.042-1.177.428-2.17.053-.995-.376-1.655-.23-2.58-.023-.926.206-2.138.776-3.646 1.183-.795.219-1.064.274-1.93.288-.532.008-.755.653-.043 1.444.563.643 1.839.814 2.606.707.494-.07.608.258.563.74a8.013 8.013 0 0 0-.01 1.795c.08.6.18 1.62-.103 2.286-.14.326-.545.677-.98.653-.565-.034-1.022-.7-1.414-1.49-.825-1.662-1.793-2.014-5.404-3.535-3.248-1.367-5.007-3.5-6.096-4.874-.969-1.217-1.939-.756-1.85.342.07.852.592 3.604 1.912 5.257 1.623 2.525 4.128 3.67 7.013 3.895.755.06 1.226.208 1.29.553.095.735-.622 1.244-1.959 1.09-1.336-.157-1.907.087-1.641.848.85 1.79 2.809 1.869 3.623 1.942.275.05 1.246 0 1.764.143.605.166.735 1.005-.14 1.459-1.558.76-2.237 1.391-3.025 2.83-.595 1.13-1.108 3.022-.574 5.745.513 2.648-3.337 2.733-5 2.357-.716-.151-1.47-1.512.287-2.65 1.421-.922 1.708-1.49 1.645-2.657-.074-1.36-.824-1.458-.822-2.64v-2.82a.435.435 0 0 0-.435-.435H7.698a.435.435 0 0 1-.435-.434v-1.7a.435.435 0 0 0-.435-.435H5.501a.435.435 0 0 1-.435-.435v-1.524a.435.435 0 0 0-.435-.435H3.015a.435.435 0 0 1-.435-.435v-1.603a.435.435 0 0 0-.435-.434H.435a.435.435 0 0 0-.435.434v1.705c0 .24.195.435.435.435h1.62c.24 0 .435.195.435.435v6.076c0 .241.195.435.435.435h1.71c.241 0 .436.196.436.435v1.988c0 .24.195.434.435.434h2.402c.734-.052.862.934.854 1.286-.016.803-.923 1.06-1.352 1.395-1.145.884-2.031 1.783-1.513 3.512l.013.036c.945 2.007 3.542 1.8 5.183 1.8h10.326c.584 0 1.184.135 1.046-.545-.136-.68-.425-1.61-1.265-1.61-.84 0-.703.467-1.524.228-.821-.238-.822-1.348.411-3.279 1.276-1.649 3.46-1.524 4.781-.358 1.32 1.166.93 3.191.653 4.354-.158.82.218 1.224.669 1.213h5.242c.806-.014.647-.556.185-1.614h.003z" fill="#fff"/>
|
||||
<svg width="80" height="80" viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M79.05 72.15c-.8-1.766-2.643-2.62-3.845-1.766-1.201.855-2.867.985-4.448.602-1.584-.385-1.885-4.01-1.543-8.195.342-4.184.909-5.795 1.267-7.314.404-1.524 2.191-1.404 2.405-.209.215 1.196 1.454 1.196 3.266-.979 1.811-2.175 1.543-8.52-.546-13.684-2.088-5.163.817-4.661 1.66-4.149.844.513 1.362-.255 1.156-3.2-.204-2.945-2.916-5.247-5.096-6.657-2.184-1.41-4.842-2.967-4.78-6.745.063-3.777 5.2-3.658 5.897-3.596.697.063 2.037-.233 1.264-4.157-.773-3.924-3.575-4.673-5.332-4.567-1.758.106-2.943 1.071-5.427.133-2.484-.938-4.136-.572-6.45-.057-2.313.515-5.343 1.94-9.112 2.959-1.989.545-2.661.683-4.828.718-1.33.02-1.885 1.633-.106 3.61 1.408 1.608 4.597 2.036 6.515 1.768 1.236-.174 1.521.645 1.407 1.85a20.023 20.023 0 0 0-.024 4.488c.198 1.5.45 4.051-.258 5.713-.35.817-1.361 1.693-2.449 1.633-1.413-.084-2.555-1.75-3.537-3.726-2.06-4.152-4.48-5.033-13.509-8.835-8.12-3.417-12.516-8.749-15.24-12.185-2.421-3.042-4.846-1.89-4.626.855.179 2.128 1.48 9.008 4.781 13.141 4.058 6.314 10.32 9.177 17.534 9.739 1.885.149 3.065.52 3.225 1.383.236 1.835-1.557 3.11-4.898 2.722-3.341-.39-4.768.22-4.103 2.121 2.123 4.477 7.021 4.672 9.058 4.857.686.122 3.114 0 4.41.355 1.51.418 1.836 2.514-.353 3.648-3.892 1.903-5.59 3.479-7.561 7.075-1.486 2.826-2.77 7.555-1.435 14.365 1.283 6.62-8.342 6.83-12.497 5.89-1.793-.377-3.675-3.778.716-6.625 3.553-2.305 4.269-3.724 4.111-6.642-.184-3.4-2.058-3.644-2.053-6.598v-7.05c0-.602-.488-1.088-1.087-1.088h-3.334a1.087 1.087 0 0 1-1.087-1.087v-4.25c0-.602-.488-1.087-1.088-1.087h-3.317a1.087 1.087 0 0 1-1.087-1.088v-3.81c0-.602-.489-1.087-1.088-1.087h-4.04a1.087 1.087 0 0 1-1.089-1.088V26.25c0-.602-.488-1.088-1.087-1.088H1.088C.485 25.161 0 25.65 0 26.25v4.26c0 .602.488 1.087 1.088 1.087h4.049c.602 0 1.087.489 1.087 1.088v15.192c0 .602.489 1.087 1.088 1.087h4.277c.602 0 1.088.489 1.088 1.088v4.968c0 .602.488 1.087 1.087 1.087h6.005c1.836-.13 2.156 2.335 2.137 3.214-.04 2.007-2.308 2.652-3.382 3.487-2.861 2.21-5.077 4.459-3.78 8.781l.032.09c2.362 5.017 8.855 4.499 12.956 4.499h25.817c1.459 0 2.959.339 2.614-1.362-.342-1.7-1.063-4.024-3.162-4.024-2.1 0-1.758 1.166-3.81.57-2.054-.597-2.057-3.371 1.027-8.198 3.19-4.122 8.652-3.81 11.952-.895 3.301 2.915 2.325 7.978 1.633 10.885-.396 2.048.545 3.06 1.67 3.032H78.58c2.015-.035 1.62-1.391.464-4.035h.008z"
|
||||
fill="#fff"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -23,16 +23,14 @@
|
||||
{{ $t('foundNewItems') }}
|
||||
</h2>
|
||||
<div class="d-flex justify-content-center">
|
||||
<div
|
||||
<Sprite
|
||||
class="item-box ml-auto mr-3"
|
||||
:class="eggClass"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
:image-name="eggClass"
|
||||
/>
|
||||
<Sprite
|
||||
class="item-box mr-auto"
|
||||
:class="potionClass"
|
||||
>
|
||||
</div>
|
||||
:image-name="potionClass"
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
v-once
|
||||
@@ -103,8 +101,12 @@
|
||||
|
||||
<script>
|
||||
import closeIcon from '@/assets/svg/close.svg';
|
||||
import Sprite from '@/components/ui/sprite.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
</div>
|
||||
<div class="inner-content">
|
||||
<div class="achievement-background d-flex align-items-center">
|
||||
<div
|
||||
<Sprite
|
||||
class="icon"
|
||||
:class="achievementClass"
|
||||
></div>
|
||||
:image-name="achievementClass"
|
||||
/>
|
||||
</div>
|
||||
<h4
|
||||
class="title"
|
||||
@@ -99,8 +99,12 @@
|
||||
import achievements from '@/../../common/script/content/achievements';
|
||||
import { mapState } from '@/libs/store';
|
||||
import svgClose from '@/assets/svg/close.svg';
|
||||
import Sprite from '@/components/ui/sprite.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
props: ['data'],
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<div
|
||||
v-for="option in items"
|
||||
:key="option.key"
|
||||
:id="option.imageName"
|
||||
class="outer-option-background"
|
||||
:class="{
|
||||
premium: Boolean(option.gem),
|
||||
@@ -14,18 +15,28 @@
|
||||
hide: option.hide }"
|
||||
@click="option.click(option)"
|
||||
>
|
||||
<b-popover
|
||||
:target="option.imageName"
|
||||
triggers="hover focus"
|
||||
placement="bottom"
|
||||
:prevent-overflow="false"
|
||||
>
|
||||
<strong> {{ option.text }} </strong>
|
||||
</b-popover>
|
||||
<div class="option">
|
||||
<div
|
||||
class="sprite customize-option"
|
||||
:class="option.class"
|
||||
>
|
||||
<Sprite
|
||||
v-if="!option.none"
|
||||
class="sprite"
|
||||
:prefix="option.isGear ? 'shop' : 'icon'"
|
||||
:imageName="option.imageName"
|
||||
:image-name="option.imageName"
|
||||
/>
|
||||
<div
|
||||
v-if="option.none"
|
||||
v-else
|
||||
class="redline-outer"
|
||||
>
|
||||
<div class="redline"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -35,8 +46,12 @@
|
||||
import gem from '@/assets/svg/gem.svg';
|
||||
import gold from '@/assets/svg/gold.svg';
|
||||
import { avatarEditorUtilities } from '../../mixins/avatarEditUtilities';
|
||||
import Sprite from '@/components/ui/sprite.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
mixins: [
|
||||
avatarEditorUtilities,
|
||||
],
|
||||
@@ -75,7 +90,7 @@ export default {
|
||||
cursor: pointer;
|
||||
|
||||
&.premium {
|
||||
height: 112px;
|
||||
height: 120px;
|
||||
width: 96px;
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
@@ -92,21 +107,9 @@ export default {
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
background-color: $white;
|
||||
|
||||
.sprite.customize-option.shirt {
|
||||
margin-left: -3px !important;
|
||||
// otherwise its overriden by the .outer-option-background:not(.none) { rules
|
||||
}
|
||||
|
||||
.sprite.customize-option.skin {
|
||||
margin-left: -8px !important;
|
||||
// otherwise its overriden by the .outer-option-background:not(.none) { rules
|
||||
}
|
||||
|
||||
.option {
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
padding-left: 6px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -132,14 +135,14 @@ export default {
|
||||
}
|
||||
|
||||
.redline-outer {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
height: 68px;
|
||||
width: 68px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
margin: 0 auto 0 0;
|
||||
|
||||
.redline {
|
||||
width: 60px;
|
||||
width: 68px;
|
||||
height: 4px;
|
||||
display: block;
|
||||
background: red;
|
||||
@@ -148,7 +151,6 @@ export default {
|
||||
top: 0;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 20px;
|
||||
margin-left: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,10 +166,9 @@ export default {
|
||||
}
|
||||
.option {
|
||||
vertical-align: bottom;
|
||||
height: 64px;
|
||||
width: 64px;
|
||||
height: 76px;
|
||||
width: 76px;
|
||||
|
||||
margin: 12px 8px;
|
||||
border: 4px solid transparent;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
@@ -182,44 +183,6 @@ export default {
|
||||
.sprite.customize-option {
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
|
||||
&.skin {
|
||||
margin-top: -4px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
&.chair {
|
||||
margin-left: -1px;
|
||||
margin-top: -1px;
|
||||
|
||||
&.button_chair_black {
|
||||
// different sprite margin?
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
&.handleless {
|
||||
margin-left: -5px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
}
|
||||
&.color, &.bangs, &.beard, &.flower, &.mustache {
|
||||
background-position-x: -6px;
|
||||
background-position-y: -12px;
|
||||
}
|
||||
|
||||
&.hair.base {
|
||||
background-position-x: -6px;
|
||||
background-position-y: -4px;
|
||||
}
|
||||
|
||||
&.headAccessory {
|
||||
margin-top: 0;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
&.headband {
|
||||
margin-top: -6px;
|
||||
margin-left: -27px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
|
||||
<script>
|
||||
import appearance from '@/../../common/script/content/appearance';
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import { subPageMixin } from '../../mixins/subPage';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
import { avatarEditorUtilities } from '../../mixins/avatarEditUtilities';
|
||||
@@ -82,9 +83,6 @@ import customizeBanner from './customize-banner';
|
||||
import customizeOptions from './customize-options';
|
||||
import subMenu from './sub-menu';
|
||||
|
||||
const freeShirtKeys = Object.keys(appearance.shirt).filter(k => appearance.shirt[k].price === 0);
|
||||
const specialShirtKeys = Object.keys(appearance.shirt).filter(k => appearance.shirt[k].price !== 0);
|
||||
|
||||
export default {
|
||||
components: {
|
||||
customizeBanner,
|
||||
@@ -106,17 +104,6 @@ export default {
|
||||
headAccessory: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
|
||||
},
|
||||
chairKeys: ['none', 'black', 'blue', 'green', 'pink', 'red', 'yellow', 'handleless_black', 'handleless_blue', 'handleless_green', 'handleless_pink', 'handleless_red', 'handleless_yellow'],
|
||||
specialShirtKeys,
|
||||
items: [
|
||||
{
|
||||
id: 'size',
|
||||
label: this.$t('size'),
|
||||
},
|
||||
{
|
||||
id: 'shirt',
|
||||
label: this.$t('shirt'),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -167,6 +154,7 @@ export default {
|
||||
];
|
||||
const noneOption = this.createGearItem(0, 'eyewear', 'base');
|
||||
noneOption.none = true;
|
||||
noneOption.text = this.$t('none');
|
||||
const options = [
|
||||
noneOption,
|
||||
];
|
||||
@@ -178,42 +166,36 @@ export default {
|
||||
option.active = this.user.preferences.costume
|
||||
? this.user.items.gear.costume.eyewear === newKey
|
||||
: this.user.items.gear.equipped.eyewear === newKey;
|
||||
option.class = `eyewear_special_${key}`;
|
||||
option.imageName = `eyewear_special_${key}`;
|
||||
option.isGear = true;
|
||||
option.click = () => {
|
||||
const type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
|
||||
return this.equip(newKey, type);
|
||||
};
|
||||
option.text = this.$t(`eyewearSpecial${upperFirst(key)}Text`);
|
||||
options.push(option);
|
||||
}
|
||||
|
||||
return options;
|
||||
},
|
||||
freeShirts () {
|
||||
return freeShirtKeys.map(s => this.mapKeysToFreeOption(s, 'shirt'));
|
||||
},
|
||||
specialShirts () {
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
const keys = this.specialShirtKeys;
|
||||
const options = keys.map(key => this.mapKeysToOption(key, 'shirt'));
|
||||
return options;
|
||||
},
|
||||
headbands () {
|
||||
const keys = ['blackHeadband', 'blueHeadband', 'greenHeadband', 'pinkHeadband', 'redHeadband', 'whiteHeadband', 'yellowHeadband'];
|
||||
const noneOption = this.createGearItem(0, 'headAccessory', 'base', 'headband');
|
||||
const noneOption = this.createGearItem(0, 'headAccessory', 'base');
|
||||
noneOption.none = true;
|
||||
noneOption.text = this.$t('none');
|
||||
const options = [
|
||||
noneOption,
|
||||
];
|
||||
|
||||
for (const key of keys) {
|
||||
const option = this.createGearItem(key, 'headAccessory', 'special', 'headband');
|
||||
const option = this.createGearItem(key, 'headAccessory', 'special');
|
||||
const newKey = `headAccessory_special_${key}`;
|
||||
option.click = () => {
|
||||
const type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
return this.equip(newKey, type);
|
||||
};
|
||||
|
||||
option.text = this.$t(`headAccessory${upperFirst(key)}Text`);
|
||||
options.push(option);
|
||||
}
|
||||
|
||||
@@ -227,8 +209,9 @@ export default {
|
||||
option.none = true;
|
||||
}
|
||||
option.active = this.user.preferences.chair === key;
|
||||
option.class = `button_chair_${key} chair ${key.includes('handleless_') ? 'handleless' : ''}`;
|
||||
option.imageName = `chair_${key}`;
|
||||
option.click = () => this.set({ 'preferences.chair': key });
|
||||
option.text = appearance.chair[key].text();
|
||||
return option;
|
||||
});
|
||||
return options;
|
||||
@@ -242,8 +225,11 @@ export default {
|
||||
option.none = true;
|
||||
}
|
||||
option.active = this.user.preferences.hair.flower === key;
|
||||
option.class = `icon_hair_flower_${key} flower`;
|
||||
if (key !== 0) {
|
||||
option.imageName = `hair_flower_${key}`;
|
||||
}
|
||||
option.click = () => this.set({ 'preferences.hair.flower': key });
|
||||
option.text = appearance.hair.flower[key].text();
|
||||
return option;
|
||||
});
|
||||
return options;
|
||||
@@ -271,6 +257,7 @@ export default {
|
||||
|
||||
const noneOption = this.createGearItem(0, category, 'base', category);
|
||||
noneOption.none = true;
|
||||
noneOption.text = this.$t('none');
|
||||
const options = [
|
||||
noneOption,
|
||||
];
|
||||
@@ -284,10 +271,15 @@ export default {
|
||||
option.active = this.user.preferences.costume
|
||||
? this.user.items.gear.costume[category] === newKey
|
||||
: this.user.items.gear.equipped[category] === newKey;
|
||||
option.class = `headAccessory_special_${option.key} ${category}`;
|
||||
|
||||
if (category === 'back') {
|
||||
option.class = `icon_back_special_${option.key} back`;
|
||||
option.text = this.$t(`back${upperFirst(key)}Text`);
|
||||
option.imageName = `back_special_${option.key}`;
|
||||
} else {
|
||||
option.text = this.$t(`headAccessory${upperFirst(key)}Text`);
|
||||
option.imageName = `headAccessory_special_${option.key}`;
|
||||
}
|
||||
option.isGear = true;
|
||||
option.click = () => {
|
||||
const type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
return this.equip(newKey, type);
|
||||
@@ -303,7 +295,7 @@ export default {
|
||||
|
||||
return keys.join(',');
|
||||
},
|
||||
createGearItem (key, gearType, subGearType, additionalClass) {
|
||||
createGearItem (key, gearType, subGearType) {
|
||||
const newKey = `${gearType}_${subGearType ? `${subGearType}_` : ''}${key}`;
|
||||
const option = {};
|
||||
option.key = key;
|
||||
@@ -311,6 +303,7 @@ export default {
|
||||
const currentlyEquippedValue = this.user.items.gear[visibleGearType][gearType];
|
||||
|
||||
option.active = currentlyEquippedValue === newKey;
|
||||
option.isGear = true;
|
||||
|
||||
if (key === 0) {
|
||||
// if key is the "none" option check if a property
|
||||
@@ -318,7 +311,7 @@ export default {
|
||||
option.active = option.active || !currentlyEquippedValue;
|
||||
}
|
||||
|
||||
option.class = `${newKey} ${additionalClass}`;
|
||||
option.imageName = `${newKey}`;
|
||||
option.click = () => {
|
||||
const type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
const currentlyEquipped = this.user.items.gear[type][gearType];
|
||||
|
||||
@@ -220,10 +220,10 @@
|
||||
:class="{selected: bg.key === user.preferences.background}"
|
||||
@click="unlock('background.' + bg.key)"
|
||||
>
|
||||
<div
|
||||
<Sprite
|
||||
class="background"
|
||||
:class="`icon_background_${bg.key}`"
|
||||
></div>
|
||||
:image-name="`icon_background_${bg.key}`"
|
||||
/>
|
||||
<b-popover
|
||||
:target="bg.key"
|
||||
triggers="hover focus"
|
||||
@@ -254,10 +254,10 @@
|
||||
:class="{selected: bg.key === user.preferences.background}"
|
||||
@click="unlock('background.' + bg.key)"
|
||||
>
|
||||
<div
|
||||
<Sprite
|
||||
class="background"
|
||||
:class="`icon_background_${bg.key}`"
|
||||
></div>
|
||||
:image-name="`icon_background_${bg.key}`"
|
||||
/>
|
||||
<b-popover
|
||||
:target="bg.key"
|
||||
triggers="hover focus"
|
||||
@@ -286,10 +286,10 @@
|
||||
:class="{selected: bg.key === user.preferences.background}"
|
||||
@click="unlock('background.' + bg.key)"
|
||||
>
|
||||
<div
|
||||
<Sprite
|
||||
class="background"
|
||||
:class="`icon_background_${bg.key}`"
|
||||
></div>
|
||||
:image-name="`icon_background_${bg.key}`"
|
||||
/>
|
||||
<b-popover
|
||||
:target="bg.key"
|
||||
triggers="hover focus"
|
||||
@@ -818,9 +818,10 @@
|
||||
|
||||
.background {
|
||||
border-radius: 4px;
|
||||
object-position: -4px -4px;
|
||||
object-fit: none;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background-position: -4px -4px;
|
||||
}
|
||||
|
||||
.deselect {
|
||||
@@ -1013,6 +1014,7 @@ import arrowRight from '@/assets/svg/arrow_right.svg';
|
||||
import arrowLeft from '@/assets/svg/arrow_left.svg';
|
||||
import svgClose from '@/assets/svg/close.svg';
|
||||
import { avatarEditorUtilities } from '../mixins/avatarEditUtilities';
|
||||
import Sprite from './ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -1024,6 +1026,7 @@ export default {
|
||||
hairSettings,
|
||||
skinSettings,
|
||||
usernameForm,
|
||||
Sprite,
|
||||
},
|
||||
mixins: [guide, notifications, avatarEditorUtilities],
|
||||
data () {
|
||||
|
||||
@@ -320,7 +320,7 @@
|
||||
<script>
|
||||
import each from 'lodash/each';
|
||||
import * as quests from '@/../../common/script/content/quests';
|
||||
import { mountInfo, petInfo } from '@/../../common/script/content/stable';
|
||||
import stable from '@/../../common/script/content/stable';
|
||||
import content from '@/../../common/script/content';
|
||||
import gear from '@/../../common/script/content/gear';
|
||||
import styleHelper from '@/mixins/styleHelper';
|
||||
@@ -330,6 +330,8 @@ import userLink from '../userLink';
|
||||
import PurchaseHistoryTable from '../ui/purchaseHistoryTable.vue';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
|
||||
const { mountInfo, petInfo } = stable;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
userLink,
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
class="brand"
|
||||
aria-label="Habitica"
|
||||
>
|
||||
<div
|
||||
<router-link to="/">
|
||||
<div
|
||||
class="logo svg-icon svg color gryphon"
|
||||
v-html="icons.melior"
|
||||
></div>
|
||||
></div>
|
||||
<div class="svg-icon"></div>
|
||||
</router-link>
|
||||
<div class="svg-icon"></div>
|
||||
</b-navbar-brand>
|
||||
<b-navbar-toggle
|
||||
@@ -294,7 +297,7 @@
|
||||
<div class="topbar-dropdown">
|
||||
<router-link
|
||||
v-if="user.permissions.fullAccess ||
|
||||
user.permissions.userSupport || user.permissions.newsPoster"
|
||||
user.permissions.userSupport"
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
:to="{name: 'adminPanel'}"
|
||||
>
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
<slot
|
||||
name="itemBadge"
|
||||
:item="item"
|
||||
></slot><span
|
||||
></slot><Sprite
|
||||
class="item-content"
|
||||
:class="itemContentClass"
|
||||
></span>
|
||||
:image-name="itemContentClass"
|
||||
/>
|
||||
</div><span
|
||||
v-if="label"
|
||||
class="item-label"
|
||||
@@ -46,8 +46,12 @@
|
||||
|
||||
<script>
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div
|
||||
ref="root"
|
||||
v-if="draggedItem"
|
||||
class="draggedItemInfo mouse"
|
||||
v-mousePosition="30"
|
||||
@mouseMoved="mouseMoved($event)">
|
||||
<Sprite
|
||||
class="dragging-icon"
|
||||
:image-name="imageName()"
|
||||
/>
|
||||
<div class="popover">
|
||||
<div
|
||||
class="popover-content"
|
||||
>
|
||||
{{ $t(popoverTextKey, { [translationKey]: itemText() }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.draggedItemInfo {
|
||||
position: absolute;
|
||||
left: -500px;
|
||||
|
||||
z-index: 1080;
|
||||
|
||||
&.mouse {
|
||||
position: fixed;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.dragging-icon {
|
||||
width: 68px;
|
||||
margin: 0 auto 8px;
|
||||
display: block;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.popover {
|
||||
position: static;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.popover-content {
|
||||
color: white;
|
||||
margin: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
import MouseMoveDirective from '@/directives/mouseposition.directive';
|
||||
|
||||
export default {
|
||||
name: 'ItemPopover',
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
directives: {
|
||||
mousePosition: MouseMoveDirective,
|
||||
},
|
||||
props: {
|
||||
draggedItem: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
popoverTextKey: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
translationKey: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
imageName () {
|
||||
if (this.draggedItem) {
|
||||
if (this.draggedItem.class) {
|
||||
return this.draggedItem.class;
|
||||
}
|
||||
if (this.draggedItem.target) {
|
||||
return `Pet_Food_${this.draggedItem.key}`;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
mouseMoved ($event) {
|
||||
if (this.$refs.root) {
|
||||
this.$refs.root.style.left = `${$event.x - 60}px`;
|
||||
this.$refs.root.style.top = `${$event.y + 10}px`;
|
||||
}
|
||||
},
|
||||
itemText () {
|
||||
if (this.draggedItem) {
|
||||
if (this.draggedItem.text) {
|
||||
if (typeof this.draggedItem.text === 'function') {
|
||||
return this.draggedItem.text();
|
||||
}
|
||||
return this.draggedItem.text;
|
||||
}
|
||||
return this.draggedItem.class;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
@@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
v-mousePosition="30"
|
||||
class="row"
|
||||
@mouseMoved="mouseMoved($event)"
|
||||
>
|
||||
<div class="standard-sidebar d-none d-sm-block">
|
||||
<filter-sidebar>
|
||||
@@ -99,7 +97,7 @@
|
||||
{{ context.item.text }}
|
||||
</h4>
|
||||
<div
|
||||
v-if="currentDraggingPotion == null"
|
||||
v-if="!currentDraggingPotion"
|
||||
class="popover-content-text"
|
||||
>
|
||||
{{ context.item.notes }}
|
||||
@@ -148,7 +146,7 @@
|
||||
<h4 class="popover-content-title">
|
||||
{{ context.item.text }}
|
||||
</h4>
|
||||
<div class="popover-content-text">
|
||||
<div class="popover-content-text" v-if="!currentDraggingEgg">
|
||||
{{ context.item.notes }}
|
||||
</div>
|
||||
</template>
|
||||
@@ -224,120 +222,24 @@
|
||||
</div>
|
||||
</div>
|
||||
<hatchedPetDialog />
|
||||
<div
|
||||
ref="draggingEggInfo"
|
||||
class="eggInfo"
|
||||
>
|
||||
<div v-if="currentDraggingEgg != null">
|
||||
<div
|
||||
class="potion-icon"
|
||||
:class="`Pet_Egg_${currentDraggingEgg.key}`"
|
||||
></div>
|
||||
<div class="popover">
|
||||
<div class="popover-content">
|
||||
{{ $t('dragThisEgg', {eggName: currentDraggingEgg.text }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="eggClickMode"
|
||||
ref="clickEggInfo"
|
||||
class="eggInfo mouse"
|
||||
>
|
||||
<div v-if="currentDraggingEgg != null">
|
||||
<div
|
||||
class="potion-icon"
|
||||
:class="`Pet_Egg_${currentDraggingEgg.key}`"
|
||||
></div>
|
||||
<div class="popover">
|
||||
<div
|
||||
class="popover-content"
|
||||
>
|
||||
{{ $t('clickOnPotionToHatch', {eggName: currentDraggingEgg.text }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref="draggingPotionInfo"
|
||||
class="hatchingPotionInfo"
|
||||
>
|
||||
<div v-if="currentDraggingPotion != null">
|
||||
<div
|
||||
class="potion-icon"
|
||||
:class="`Pet_HatchingPotion_${currentDraggingPotion.key}`"
|
||||
></div>
|
||||
<div class="popover">
|
||||
<div
|
||||
class="popover-content"
|
||||
>
|
||||
{{ $t('dragThisPotion', {potionName: currentDraggingPotion.text }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="potionClickMode"
|
||||
ref="clickPotionInfo"
|
||||
class="hatchingPotionInfo mouse"
|
||||
>
|
||||
<div v-if="currentDraggingPotion != null">
|
||||
<div
|
||||
class="potion-icon"
|
||||
:class="`Pet_HatchingPotion_${currentDraggingPotion.key}`"
|
||||
></div>
|
||||
<div class="popover">
|
||||
<div
|
||||
class="popover-content"
|
||||
>
|
||||
{{ $t('clickOnEggToHatch', {potionName: currentDraggingPotion.text }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ItemPopover
|
||||
:dragged-item="currentDraggingEgg"
|
||||
popoverTextKey="clickOnPotionToHatch"
|
||||
translationKey="eggName" />
|
||||
<ItemPopover
|
||||
:dragged-item="currentDraggingPotion"
|
||||
popoverTextKey="clickOnEggToHatch"
|
||||
translationKey="potionName" />
|
||||
<questDetailModal :group="user.party" />
|
||||
<cards-modal :card-options="cardOptions" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.eggInfo, .hatchingPotionInfo {
|
||||
position: absolute;
|
||||
left: -500px;
|
||||
|
||||
z-index: 1080;
|
||||
|
||||
&.mouse {
|
||||
position: fixed;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.potion-icon {
|
||||
margin: 0 auto 8px;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.popover {
|
||||
position: inherit;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.popover-content {
|
||||
color: white;
|
||||
margin: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import each from 'lodash/each';
|
||||
import throttle from 'lodash/throttle';
|
||||
import moment from 'moment';
|
||||
import ItemPopover from '@/components/inventory/itemPopover';
|
||||
import Item from '@/components/inventory/item';
|
||||
import ItemRows from '@/components/ui/itemRows';
|
||||
import CountBadge from '@/components/ui/countBadge';
|
||||
@@ -354,7 +256,6 @@ import { createAnimal } from '@/libs/createAnimal';
|
||||
|
||||
import notifications from '@/mixins/notifications';
|
||||
import DragDropDirective from '@/directives/dragdrop.directive';
|
||||
import MouseMoveDirective from '@/directives/mouseposition.directive';
|
||||
import FilterGroup from '@/components/ui/filterGroup';
|
||||
import Checkbox from '@/components/ui/checkbox';
|
||||
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
||||
@@ -375,8 +276,6 @@ const groups = [
|
||||
allowedItems,
|
||||
}));
|
||||
|
||||
let lastMouseMoveEvent = {};
|
||||
|
||||
export default {
|
||||
name: 'Items',
|
||||
components: {
|
||||
@@ -391,10 +290,10 @@ export default {
|
||||
cardsModal,
|
||||
QuestInfo,
|
||||
FilterSidebar,
|
||||
ItemPopover,
|
||||
},
|
||||
directives: {
|
||||
drag: DragDropDirective,
|
||||
mousePosition: MouseMoveDirective,
|
||||
},
|
||||
mixins: [notifications],
|
||||
data () {
|
||||
@@ -405,9 +304,7 @@ export default {
|
||||
sortBy: 'quantity', // or 'AZ'
|
||||
|
||||
currentDraggingEgg: null,
|
||||
eggClickMode: false,
|
||||
currentDraggingPotion: null,
|
||||
potionClickMode: false,
|
||||
cardOptions: {
|
||||
cardType: '',
|
||||
messageOptions: 0,
|
||||
@@ -567,22 +464,13 @@ export default {
|
||||
}
|
||||
|
||||
this.currentDraggingPotion = null;
|
||||
this.potionClickMode = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.currentDraggingEgg === null || this.currentDraggingEgg !== egg) {
|
||||
this.currentDraggingEgg = egg;
|
||||
this.eggClickMode = true;
|
||||
|
||||
// Wait for the div.eggInfo.mouse node to be added to the DOM before
|
||||
// changing its position.
|
||||
this.$nextTick(() => {
|
||||
this.mouseMoved(lastMouseMoveEvent);
|
||||
});
|
||||
} else {
|
||||
this.currentDraggingEgg = null;
|
||||
this.eggClickMode = false;
|
||||
}
|
||||
},
|
||||
onPotionClicked ($event, potion) {
|
||||
@@ -592,21 +480,12 @@ export default {
|
||||
}
|
||||
|
||||
this.currentDraggingEgg = null;
|
||||
this.eggClickMode = false;
|
||||
return;
|
||||
}
|
||||
if (this.currentDraggingPotion === null || this.currentDraggingPotion !== potion) {
|
||||
this.currentDraggingPotion = potion;
|
||||
this.potionClickMode = true;
|
||||
|
||||
// Wait for the div.hatchingPotionInfo.mouse node to be added to the
|
||||
// DOM before changing its position.
|
||||
this.$nextTick(() => {
|
||||
this.mouseMoved(lastMouseMoveEvent);
|
||||
});
|
||||
} else {
|
||||
this.currentDraggingPotion = null;
|
||||
this.potionClickMode = false;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -640,23 +519,6 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
mouseMoved ($event) {
|
||||
// Keep track of the last mouse position even in click mode so that we
|
||||
// know where to position the dragged potion/egg info on item click.
|
||||
lastMouseMoveEvent = $event;
|
||||
|
||||
// Update the potion/egg popover if we are already dragging it.
|
||||
if (this.potionClickMode) {
|
||||
// dragging potioninfo is 180px wide (90 would be centered)
|
||||
this.$refs.clickPotionInfo.style.left = `${$event.x - 60}px`;
|
||||
this.$refs.clickPotionInfo.style.top = `${$event.y + 10}px`;
|
||||
} else if (this.eggClickMode) {
|
||||
// dragging eggInfo is 180px wide (90 would be centered)
|
||||
this.$refs.clickEggInfo.style.left = `${$event.x - 60}px`;
|
||||
this.$refs.clickEggInfo.style.top = `${$event.y + 10}px`;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
:show="true"
|
||||
:count="itemCount"
|
||||
/>
|
||||
<span
|
||||
<Sprite
|
||||
v-drag.food="item.key"
|
||||
class="item-content"
|
||||
:class="`Pet_Food_${item.key}`"
|
||||
:image-name="`Pet_Food_${item.key}`"
|
||||
@itemDragEnd="dragend($event)"
|
||||
@itemDragStart="dragstart($event)"
|
||||
></span>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<b-popover
|
||||
@@ -41,12 +41,14 @@
|
||||
<script>
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import DragDropDirective from '@/directives/dragdrop.directive';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
import CountBadge from '@/components/ui/countBadge';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CountBadge,
|
||||
Sprite,
|
||||
},
|
||||
directives: {
|
||||
drag: DragDropDirective,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
<div class="inner-content">
|
||||
<div class="pet-background d-flex align-items-center">
|
||||
<div :class="pet.class"></div>
|
||||
<Sprite :image-name="pet.imageName" />
|
||||
</div>
|
||||
<h4 class="title">
|
||||
{{ pet.name }}
|
||||
@@ -76,10 +76,11 @@
|
||||
height: 112px;
|
||||
border-radius: 4px;
|
||||
background-color: $gray-700;
|
||||
}
|
||||
|
||||
.Pet {
|
||||
margin: auto;
|
||||
img {
|
||||
transform: scale(1.5);
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
@@ -103,8 +104,12 @@
|
||||
<script>
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
import svgClose from '@/assets/svg/close.svg';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
>
|
||||
<div class="potionEggGroup">
|
||||
<div class="potionEggBackground">
|
||||
<div :class="`Pet_HatchingPotion_${hatchablePet.potionKey}`"></div>
|
||||
<Sprite :image-name="`Pet_HatchingPotion_${hatchablePet.potionKey}`" />
|
||||
</div>
|
||||
<div class="potionEggBackground">
|
||||
<div :class="`Pet_Egg_${hatchablePet.eggKey}`"></div>
|
||||
<Sprite :image-name="`Pet_Egg_${hatchablePet.eggKey}`" />
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="title">
|
||||
@@ -105,7 +105,7 @@
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
div {
|
||||
img {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
@@ -116,8 +116,12 @@
|
||||
import svgClose from '@/assets/svg/close.svg';
|
||||
|
||||
import petMixin from '@/mixins/petMixin';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
mixins: [petMixin],
|
||||
props: ['hatchablePet'],
|
||||
data () {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
v-mousePosition="30"
|
||||
class="row stable"
|
||||
@mouseMoved="mouseMoved($event)"
|
||||
>
|
||||
<div class="standard-sidebar d-none d-sm-block">
|
||||
<filter-sidebar>
|
||||
@@ -265,43 +263,10 @@
|
||||
</inventoryDrawer>
|
||||
</div>
|
||||
<hatchedPetDialog :hide-text="true" />
|
||||
<div
|
||||
ref="dragginFoodInfo"
|
||||
class="foodInfo"
|
||||
>
|
||||
<div v-if="currentDraggingFood != null">
|
||||
<div
|
||||
class="food-icon"
|
||||
:class="`Pet_Food_${currentDraggingFood.key}`"
|
||||
></div>
|
||||
<div class="popover">
|
||||
<div
|
||||
class="popover-content"
|
||||
>
|
||||
{{ $t('dragThisFood', {foodName: currentDraggingFood.text() }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="foodClickMode"
|
||||
ref="clickFoodInfo"
|
||||
class="foodInfo mouse"
|
||||
>
|
||||
<div v-if="currentDraggingFood != null">
|
||||
<div
|
||||
class="food-icon"
|
||||
:class="`Pet_Food_${currentDraggingFood.key}`"
|
||||
></div>
|
||||
<div class="popover">
|
||||
<div
|
||||
class="popover-content"
|
||||
>
|
||||
{{ $t('clickOnPetToFeed', {foodName: currentDraggingFood.text() }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ItemPopover
|
||||
:dragged-item="currentDraggingFood"
|
||||
popoverTextKey="clickOnPetToFeed"
|
||||
translationKey="foodName" />
|
||||
<mount-raised-modal />
|
||||
<welcome-modal />
|
||||
<hatching-modal :hatchable-pet.sync="hatchablePet" />
|
||||
@@ -364,34 +329,6 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.foodInfo {
|
||||
position: absolute;
|
||||
left: -500px;
|
||||
|
||||
z-index: 1080;
|
||||
|
||||
&.mouse {
|
||||
position: fixed;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.food-icon {
|
||||
margin: 0 auto 8px;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.popover {
|
||||
position: inherit;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.popover-content {
|
||||
color: white;
|
||||
margin: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.hatchablePopover {
|
||||
width: 180px;
|
||||
|
||||
@@ -428,6 +365,7 @@ import _throttle from 'lodash/throttle';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import ItemPopover from '@/components/inventory/itemPopover';
|
||||
import PetItem from './petItem';
|
||||
import MountItem from './mountItem.vue';
|
||||
import FoodItem from './foodItem';
|
||||
@@ -440,7 +378,6 @@ import InventoryDrawer from '@/components/shared/inventoryDrawer';
|
||||
|
||||
import ResizeDirective from '@/directives/resize.directive';
|
||||
import DragDropDirective from '@/directives/dragdrop.directive';
|
||||
import MouseMoveDirective from '@/directives/mouseposition.directive';
|
||||
|
||||
import { createAnimal } from '@/libs/createAnimal';
|
||||
|
||||
@@ -482,11 +419,11 @@ export default {
|
||||
WelcomeModal,
|
||||
HatchingModal,
|
||||
InventoryDrawer,
|
||||
ItemPopover,
|
||||
},
|
||||
directives: {
|
||||
resize: ResizeDirective,
|
||||
drag: DragDropDirective,
|
||||
mousePosition: MouseMoveDirective,
|
||||
},
|
||||
mixins: [notifications, openedItemRowsMixin, petMixin, seasonalNPC],
|
||||
data () {
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
name="itemBadge"
|
||||
:item="item"
|
||||
></slot>
|
||||
<span
|
||||
<Sprite
|
||||
class="item-content"
|
||||
:class="itemClass()"
|
||||
></span>
|
||||
:image-name="imageName()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<b-popover
|
||||
@@ -37,8 +38,12 @@
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { mapState } from '@/libs/store';
|
||||
import { isOwned } from '../../../libs/createAnimal';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
@@ -70,7 +75,10 @@ export default {
|
||||
return isOwned('mount', this.item, this.userItems);
|
||||
},
|
||||
itemClass () {
|
||||
return this.isOwned() ? `Mount_Icon_${this.item.key}` : 'PixelPaw GreyedOut';
|
||||
return this.isOwned() ? '' : 'GreyedOut';
|
||||
},
|
||||
imageName () {
|
||||
return this.isOwned() ? `stable_Mount_Icon_${this.item.key}` : 'PixelPaw';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
</div>
|
||||
<div class="inner-content">
|
||||
<div class="pet-background">
|
||||
<div
|
||||
<Sprite
|
||||
class="mount"
|
||||
:class="`Mount_Icon_${mount.key}`"
|
||||
></div>
|
||||
:image-name="`Mount_Icon_${mount.key}`"
|
||||
/>
|
||||
</div>
|
||||
<h4 class="title">
|
||||
{{ mount.text() }}
|
||||
@@ -80,10 +80,14 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mountInfo } from '@/../../common/script/content/stable';
|
||||
import stable from '@/../../common/script/content/stable';
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
@@ -105,7 +109,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
openDialog (mountKey) {
|
||||
this.mount = mountInfo[mountKey];
|
||||
this.mount = stable.mountInfo[mountKey];
|
||||
this.$root.$emit('bv::show::modal', 'mount-raised-modal');
|
||||
},
|
||||
close () {
|
||||
|
||||
@@ -13,19 +13,23 @@
|
||||
name="itemBadge"
|
||||
:item="item"
|
||||
></slot><span
|
||||
v-if="mountOwned() && isHatchable() && !item.isSpecial()"
|
||||
v-if="isHatchable() && !item.isSpecial()"
|
||||
class="item-content hatchAgain"
|
||||
><span
|
||||
><Sprite
|
||||
class="egg"
|
||||
:class="eggClass"
|
||||
></span><span
|
||||
:image-name="eggClass"
|
||||
/><Sprite
|
||||
class="potion"
|
||||
:class="potionClass"
|
||||
></span></span><span
|
||||
v-else
|
||||
:image-name="potionClass"
|
||||
/>
|
||||
</span>
|
||||
<Sprite
|
||||
v-else
|
||||
class="item-content"
|
||||
:class="getPetItemClass()"
|
||||
></span><span
|
||||
:class="itemClass()"
|
||||
:image-name="imageName()"
|
||||
/>
|
||||
<span
|
||||
v-if="isAllowedToFeed() && progress() > 0"
|
||||
class="pet-progress-background"
|
||||
><div
|
||||
@@ -52,9 +56,9 @@
|
||||
v-html="$t('haveHatchablePet', { potion: item.potionName, egg: item.eggName })"
|
||||
></div><div class="potionEggGroup">
|
||||
<div class="potionEggBackground">
|
||||
<div :class="potionClass"></div>
|
||||
<Sprite :image-name="potionClass" />
|
||||
</div><div class="potionEggBackground">
|
||||
<div :class="eggClass"></div>
|
||||
<Sprite :image-name="eggClass" />
|
||||
</div>
|
||||
</div>
|
||||
</div><div v-else>
|
||||
@@ -118,8 +122,12 @@ import foolPet from '@/mixins/foolPet';
|
||||
import {
|
||||
isAllowedToFeed, isHatchable, isOwned, isSpecial,
|
||||
} from '../../../libs/createAnimal';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
mixins: [foolPet],
|
||||
props: {
|
||||
item: {
|
||||
@@ -168,22 +176,28 @@ export default {
|
||||
isAllowedToFeed () {
|
||||
return isAllowedToFeed(this.item, this.userItems);
|
||||
},
|
||||
getPetItemClass () {
|
||||
itemClass () {
|
||||
if (this.isOwned() || this.isHatchable()) {
|
||||
return '';
|
||||
}
|
||||
return 'GreyedOut';
|
||||
},
|
||||
imageName () {
|
||||
if (this.isOwned() && some(
|
||||
this.currentEventList,
|
||||
event => moment().isBetween(event.start, event.end) && event.aprilFools && event.aprilFools === 'Fungi',
|
||||
)) {
|
||||
if (this.isSpecial()) return `Pet ${this.foolPet(this.item.key)}`;
|
||||
if (this.isSpecial()) return `stable_${this.foolPet(this.item.key)}`;
|
||||
const petString = `${this.item.eggKey}-${this.item.key}`;
|
||||
return `Pet ${this.foolPet(petString)}`;
|
||||
return `stable_${this.foolPet(petString)}`;
|
||||
}
|
||||
|
||||
if (this.isOwned() || (this.mountOwned() && this.isHatchable())) {
|
||||
return `Pet Pet-${this.item.key} ${this.item.eggKey}`;
|
||||
return `stable_Pet-${this.item.key}`;
|
||||
}
|
||||
|
||||
if (!this.isOwned() && this.isSpecial()) {
|
||||
return 'GreyedOut PixelPaw';
|
||||
return 'PixelPaw';
|
||||
}
|
||||
|
||||
if (this.isHatchable()) {
|
||||
@@ -191,11 +205,11 @@ export default {
|
||||
}
|
||||
|
||||
if (this.mountOwned()) {
|
||||
return `GreyedOut Pet Pet-${this.item.key} ${this.item.eggKey}`;
|
||||
return `stable_Pet-${this.item.key}`;
|
||||
}
|
||||
|
||||
// Can't hatch
|
||||
return 'GreyedOut PixelPaw';
|
||||
return 'PixelPaw';
|
||||
},
|
||||
progress () {
|
||||
return this.userItems.pets[this.item.key];
|
||||
|
||||
@@ -56,11 +56,11 @@
|
||||
class="list-group-item"
|
||||
ng-init="inv.gear[item.key] = user.items.gear.owned[item.key]"
|
||||
>
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'shop_' + item.key"
|
||||
:imageName="'shop_' + item.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
/>
|
||||
{{ item.text() }}
|
||||
<div class="clearfix">
|
||||
<label class="radio-inline">
|
||||
@@ -330,9 +330,9 @@
|
||||
class="list-group-item"
|
||||
ng-init="inv.mounts[mount] = user.items.mounts[mount]"
|
||||
>
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'Mount_Icon_' + mount"
|
||||
:imageName="mount.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
{{ mount }}
|
||||
@@ -363,9 +363,9 @@
|
||||
class="list-group-item"
|
||||
ng-init="inv.mounts[mount] = user.items.mounts[mount]"
|
||||
>
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'Mount_Icon_' + mount"
|
||||
:imageName="mount.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
{{ mount }}
|
||||
@@ -396,9 +396,9 @@
|
||||
class="list-group-item"
|
||||
ng-init="inv.mounts[mount] = user.items.mounts[mount]"
|
||||
>
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'Mount_Icon_' + mount"
|
||||
:imageName="mount.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
{{ mount }}
|
||||
@@ -429,9 +429,9 @@
|
||||
class="list-group-item"
|
||||
ng-init="inv.mounts[mount] = user.items.mounts[mount]"
|
||||
>
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'Mount_Icon_' + mount"
|
||||
:imageName="mount.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
{{ mount }}
|
||||
@@ -503,11 +503,11 @@
|
||||
ng-init="inv.hatchingPotions[item.key] = user.items.hatchingPotions[item.key]"
|
||||
>
|
||||
<div class="form-inline clearfix">
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'Pet_HatchingPotion_' + item.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
/>
|
||||
<p>{{ item.text() }}</p>
|
||||
<input
|
||||
class="form-control"
|
||||
@@ -565,11 +565,11 @@
|
||||
ng-init="inv.eggs[item.key] = user.items.eggs[item.key]"
|
||||
>
|
||||
<div class="form-inline clearfix">
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'Pet_Egg_' + item.key"
|
||||
:image-name="'Pet_Egg_' + item.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
/>
|
||||
<p>{{ item.text() }}</p>
|
||||
<input
|
||||
class="form-control"
|
||||
@@ -627,11 +627,11 @@
|
||||
ng-init="inv.food[item.key] = user.items.food[item.key]"
|
||||
>
|
||||
<div class="form-inline clearfix">
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'Pet_Food_' + item.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
/>
|
||||
<p>{{ item.text() }}</p>
|
||||
<input
|
||||
class="form-control"
|
||||
@@ -690,11 +690,11 @@
|
||||
ng-if="item.category !== 'world'"
|
||||
>
|
||||
<div class="form-inline clearfix">
|
||||
<div
|
||||
<Sprite
|
||||
class="pull-left"
|
||||
:class="'inventory_quest_scroll_' + item.key"
|
||||
style="margin-right: 10px"
|
||||
></div>
|
||||
/>
|
||||
<p>{{ item.text() }}</p>
|
||||
<input
|
||||
class="form-control"
|
||||
@@ -730,9 +730,13 @@
|
||||
import axios from 'axios';
|
||||
|
||||
import Content from '@/../../common/script/content';
|
||||
import Sprite from '@/components/ui/sprite.vue';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
data () {
|
||||
const showInv = {};
|
||||
const inv = {
|
||||
|
||||
@@ -107,7 +107,7 @@ export default {
|
||||
if (lastPublishedPost) this.posts.push(lastPublishedPost);
|
||||
|
||||
// If the user is authorized, show any draft
|
||||
if (this.user && this.user.contributor.newsPoster) {
|
||||
if (this.user && (this.user.permissions.news || this.user.permissions.fullAccess)) {
|
||||
this.posts.unshift(
|
||||
...postsFromServer
|
||||
.filter(p => !p.published || moment().isBefore(p.publishDate)),
|
||||
|
||||
@@ -46,10 +46,10 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<div
|
||||
:class="currentMysterySet"
|
||||
<Sprite
|
||||
:image-name="currentMysterySet"
|
||||
class="mt-n1"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<h3> {{ $t('monthlyMysteryItems') }} </h3>
|
||||
@@ -628,6 +628,7 @@ import paymentsMixin from '../../mixins/payments';
|
||||
import notificationsMixin from '../../mixins/notifications';
|
||||
|
||||
import subscriptionOptions from './subscriptionOptions.vue';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
import amazonPayLogo from '@/assets/svg/amazonpay.svg';
|
||||
import applePayLogo from '@/assets/svg/apple-pay-logo.svg';
|
||||
@@ -648,6 +649,7 @@ import subscriberHourglasses from '@/assets/svg/subscriber-hourglasses.svg';
|
||||
export default {
|
||||
components: {
|
||||
subscriptionOptions,
|
||||
Sprite,
|
||||
},
|
||||
mixins: [paymentsMixin, notificationsMixin],
|
||||
data () {
|
||||
|
||||
@@ -586,8 +586,8 @@ import reduce from 'lodash/reduce';
|
||||
import moment from 'moment';
|
||||
|
||||
import planGemLimits from '@/../../common/script/libs/planGemLimits';
|
||||
import { drops as dropEggs } from '@/../../common/script/content/eggs';
|
||||
import { drops as dropPotions } from '@/../../common/script/content/hatching-potions';
|
||||
import eggs from '@/../../common/script/content/eggs';
|
||||
import hatchingPotions from '@/../../common/script/content/hatching-potions';
|
||||
import { avatarEditorUtilities } from '@/mixins/avatarEditUtilities';
|
||||
import numberInvalid from '@/mixins/numberInvalid';
|
||||
import spellsMixin from '@/mixins/spells';
|
||||
@@ -617,6 +617,9 @@ import EquipmentAttributesGrid from '../inventory/equipment/attributesGrid.vue';
|
||||
import Item from '@/components/inventory/item';
|
||||
import Avatar from '@/components/avatar';
|
||||
|
||||
const dropEggs = eggs.drops;
|
||||
const dropPotions = hatchingPotions.drops;
|
||||
|
||||
const dropEggKeys = keys(dropEggs);
|
||||
|
||||
const amountOfDropEggs = size(dropEggs);
|
||||
@@ -712,6 +715,12 @@ export default {
|
||||
if (this.item.notes instanceof Function) {
|
||||
return this.item.notes();
|
||||
}
|
||||
if (this.item.items) {
|
||||
if (this.item.items[0].notes instanceof Function) {
|
||||
return this.item.items[0].notes();
|
||||
}
|
||||
return this.item.items[0].notes;
|
||||
}
|
||||
return this.item.notes;
|
||||
},
|
||||
gemsLeft () {
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import find from 'lodash/find';
|
||||
import shops from '@/../../common/script/libs/shops';
|
||||
import throttle from 'lodash/throttle';
|
||||
import { mapState } from '@/libs/store';
|
||||
@@ -145,9 +146,16 @@ export default {
|
||||
return Object.values(this.viewOptions).some(g => g.selected);
|
||||
},
|
||||
imageURLs () {
|
||||
const currentEvent = find(this.currentEventList, event => Boolean(event.season));
|
||||
if (!currentEvent) {
|
||||
return {
|
||||
background: 'url(/static/npc/normal/customizations_background.png)',
|
||||
npc: 'url(/static/npc/normal/customizations_npc.png)',
|
||||
};
|
||||
}
|
||||
return {
|
||||
background: 'url(/static/npc/normal/customizations_background.png)',
|
||||
npc: 'url(/static/npc/normal/customizations_npc.png)',
|
||||
background: `url(/static/npc/${currentEvent.season}/customizations_background.png)`,
|
||||
npc: `url(/static/npc/${currentEvent.season}/customizations_npc.png)`,
|
||||
};
|
||||
},
|
||||
categories () {
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
:emptyItem="emptyItem"
|
||||
></slot>
|
||||
<div class="image">
|
||||
<div
|
||||
<Sprite
|
||||
v-once
|
||||
:class="item.class"
|
||||
></div>
|
||||
:image-name="item.class"
|
||||
/>
|
||||
<slot
|
||||
name="itemImage"
|
||||
:item="item"
|
||||
@@ -157,9 +157,11 @@
|
||||
|
||||
<script>
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
|
||||
@@ -38,26 +38,6 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.key_to_pets {
|
||||
background-image: url('~@/assets/images/keys/key-to-the-pet-kennels.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
|
||||
.key_to_mounts {
|
||||
background-image: url('~@/assets/images/keys/key-to-the-mount-kennels.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
|
||||
.key_to_both {
|
||||
background-image: url('~@/assets/images/keys/keys-to-the-kennels.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { beastCount, mountMasterProgress } from '@/../../common/script/count';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
:item="item"
|
||||
:abbreviated="true"
|
||||
/>
|
||||
<div
|
||||
v-if="item.addlNotes"
|
||||
class="mx-4 mb-3"
|
||||
>
|
||||
{{ item.addlNotes }}
|
||||
</div>
|
||||
<quest-rewards :quest="item" />
|
||||
<div
|
||||
v-if="!item.locked"
|
||||
@@ -52,12 +58,6 @@
|
||||
<div class="how-many-to-buy">
|
||||
<strong>{{ $t('howManyToBuy') }}</strong>
|
||||
</div>
|
||||
<div
|
||||
v-if="item.addlNotes"
|
||||
class="mb-3"
|
||||
>
|
||||
{{ item.addlNotes }}
|
||||
</div>
|
||||
<div>
|
||||
<number-increment
|
||||
@updateQuantity="selectedAmountToBuy = $event"
|
||||
@@ -82,7 +82,7 @@
|
||||
v-if="priceType === 'gems'
|
||||
&& !enoughCurrency(priceType, item.value * selectedAmountToBuy)
|
||||
&& !item.locked"
|
||||
class="btn btn-primary"
|
||||
class="btn btn-primary mb-3"
|
||||
@click="purchaseGems()"
|
||||
>
|
||||
{{ $t('purchaseGems') }}
|
||||
@@ -177,7 +177,6 @@
|
||||
|
||||
.inner-content {
|
||||
margin: 33px auto auto;
|
||||
padding: 0px 24px;
|
||||
}
|
||||
|
||||
.item-notes {
|
||||
@@ -233,8 +232,6 @@
|
||||
}
|
||||
|
||||
.purchase-amount {
|
||||
margin-top: 24px;
|
||||
|
||||
.how-many-to-buy {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@@ -501,38 +498,6 @@ export default {
|
||||
hideDialog () {
|
||||
this.$root.$emit('bv::hide::modal', 'buy-quest-modal');
|
||||
},
|
||||
getDropIcon (drop) {
|
||||
switch (drop.type) {
|
||||
case 'gear':
|
||||
return `shop_${drop.key}`;
|
||||
case 'hatchingPotions':
|
||||
return `Pet_HatchingPotion_${drop.key}`;
|
||||
case 'food':
|
||||
return `Pet_Food_${drop.key}`;
|
||||
case 'eggs':
|
||||
return `Pet_Egg_${drop.key}`;
|
||||
case 'quests':
|
||||
return `inventory_quest_scroll_${drop.key}`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
getDropName (drop) {
|
||||
switch (drop.type) {
|
||||
case 'gear':
|
||||
return this.content.gear.flat[drop.key].text();
|
||||
case 'quests':
|
||||
return this.content.quests[drop.key].text();
|
||||
case 'hatchingPotions':
|
||||
return this.$t('namedHatchingPotion', { type: this.content.hatchingPotions[drop.key].text() });
|
||||
case 'food':
|
||||
return this.content.food[drop.key].text();
|
||||
case 'eggs':
|
||||
return this.content.eggs[drop.key].text();
|
||||
default:
|
||||
return `Unknown type: ${drop.type}`;
|
||||
}
|
||||
},
|
||||
purchaseGems () {
|
||||
this.$root.$emit('bv::show::modal', 'buy-gems');
|
||||
},
|
||||
|
||||
@@ -19,9 +19,9 @@ export const QuestHelperMixin = {
|
||||
case 'quests':
|
||||
return `inventory_quest_scroll_${drop.key}`;
|
||||
case 'mounts':
|
||||
return `rewards_mount Mount_Icon_${drop.key}`;
|
||||
return `Mount_Icon_${drop.key}`;
|
||||
case 'pets':
|
||||
return `rewards_pet Pet-${drop.key}`;
|
||||
return `stable_Pet-${drop.key}`;
|
||||
default:
|
||||
return `shop_${drop.key}`;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="quest-content">
|
||||
<div
|
||||
class="quest-image"
|
||||
:class="'quest_' + item.key"
|
||||
:class="item.purchaseType === 'bundles' ? `quest_bundle_${item.key}` : `quest_${item.key}`"
|
||||
></div>
|
||||
<h3 class="text-center">
|
||||
{{ itemText }}
|
||||
@@ -17,7 +17,7 @@
|
||||
<user-label :user="leader" />
|
||||
</div>
|
||||
<div
|
||||
class="text"
|
||||
class="mx-4"
|
||||
v-html="itemNotes"
|
||||
></div>
|
||||
<questInfo
|
||||
@@ -42,12 +42,6 @@
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.text {
|
||||
margin: 16px 16px;
|
||||
overflow-y: auto;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.leader-label {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="row"
|
||||
class="row mt-3"
|
||||
>
|
||||
<div
|
||||
v-if="quest.collect"
|
||||
@@ -25,7 +25,10 @@
|
||||
<dt>{{ $t('bossHP') + ':' }}</dt>
|
||||
<dd>{{ quest.boss.hp }}</dd>
|
||||
</div>
|
||||
<div class="table-row">
|
||||
<div
|
||||
class="table-row"
|
||||
v-if="quest.purchaseType !== 'bundles'"
|
||||
>
|
||||
<dt>{{ $t('difficulty') + ':' }}</dt>
|
||||
<dd>
|
||||
<div
|
||||
@@ -39,7 +42,6 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="quest.end && !abbreviated"
|
||||
class="m-auto"
|
||||
>
|
||||
{{ limitedString }}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="quest.drop"
|
||||
class="quest-rewards"
|
||||
class="quest-rewards mb-3"
|
||||
>
|
||||
<div
|
||||
class="header d-flex align-items-center"
|
||||
@@ -39,7 +39,7 @@
|
||||
label-class="purple"
|
||||
>
|
||||
<div slot="itemImage">
|
||||
<div :class="getDropIcon(drop)"></div>
|
||||
<Sprite :image-name="getDropIcon(drop)" />
|
||||
</div>
|
||||
<div slot="popoverContent">
|
||||
<quest-popover :item="drop" />
|
||||
@@ -92,7 +92,7 @@
|
||||
:count="drop.amount"
|
||||
/>
|
||||
<div slot="itemImage">
|
||||
<div :class="getDropIcon(drop)"></div>
|
||||
<Sprite :image-name="getDropIcon(drop)" />
|
||||
</div>
|
||||
<div slot="popoverContent">
|
||||
<equipmentAttributesPopover
|
||||
@@ -133,6 +133,7 @@ import { QuestHelperMixin } from './quest-helper.mixin';
|
||||
import EquipmentAttributesPopover from '@/components/inventory/equipment/attributesPopover';
|
||||
import QuestPopover from './questPopover';
|
||||
import CountBadge from '../../ui/countBadge';
|
||||
import Sprite from '../../ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -141,6 +142,7 @@ export default {
|
||||
ItemWithLabel,
|
||||
SectionButton,
|
||||
EquipmentAttributesPopover,
|
||||
Sprite,
|
||||
},
|
||||
mixins: [QuestHelperMixin],
|
||||
props: ['quest'],
|
||||
|
||||
@@ -480,7 +480,7 @@ export default {
|
||||
});
|
||||
|
||||
await this.triggerGetWorldState();
|
||||
this.currentEvent = _find(this.currentEventList, event => Boolean(['winter', 'spring', 'summer', 'fall'].includes(event.season)));
|
||||
this.currentEvent = _find(this.currentEventList, event => Boolean(event.season));
|
||||
this.imageURLs.background = `url(/static/npc/${this.currentEvent.season}/seasonal_shop_opened_background.png)`;
|
||||
this.imageURLs.npc = `url(/static/npc/${this.currentEvent.season}/seasonal_shop_opened_npc.png)`;
|
||||
},
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
class="suggestedDot"
|
||||
></span>
|
||||
<div class="image">
|
||||
<div
|
||||
<Sprite
|
||||
v-once
|
||||
:class="item.class"
|
||||
></div>
|
||||
:image-name="item.class"
|
||||
/>
|
||||
<slot
|
||||
name="itemImage"
|
||||
:item="item"
|
||||
@@ -281,11 +281,13 @@ import svgClock from '@/assets/svg/clock.svg';
|
||||
import EquipmentAttributesPopover from '@/components/inventory/equipment/attributesPopover';
|
||||
|
||||
import QuestInfo from './quests/questInfo.vue';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EquipmentAttributesPopover,
|
||||
QuestInfo,
|
||||
Sprite,
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
v-if="notification.type === 'drop'"
|
||||
class="icon-item"
|
||||
>
|
||||
<div
|
||||
:class="notification.icon"
|
||||
<Sprite
|
||||
:image-name="notification.icon"
|
||||
class="icon-negative-margin"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -231,9 +231,13 @@ import star from '@/assets/svg/star.svg';
|
||||
import mana from '@/assets/svg/mana.svg';
|
||||
import sword from '@/assets/svg/sword.svg';
|
||||
import CloseIcon from '../shared/closeIcon';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: { CloseIcon },
|
||||
components: {
|
||||
CloseIcon,
|
||||
Sprite,
|
||||
},
|
||||
props: ['notification', 'visibleAmount'],
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
<div class="spell">
|
||||
<div class="spell-border">
|
||||
<div class="mana">
|
||||
<div
|
||||
class="img"
|
||||
:class="`shop_${spell.key} shop-sprite item-img`"
|
||||
></div>
|
||||
<Sprite
|
||||
class="img"
|
||||
:imageName="`shop_${spell.key}`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="details">
|
||||
@@ -75,10 +75,9 @@
|
||||
class="spell"
|
||||
>
|
||||
<div class="details">
|
||||
<div
|
||||
class="img"
|
||||
:class="`shop_${skill.key} shop-sprite item-img`"
|
||||
></div>
|
||||
<Sprite
|
||||
:imageName="`shop_${skill.key}`"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="user.stats.lvl < skill.lvl"
|
||||
@@ -401,10 +400,12 @@ import {
|
||||
setLocalSetting,
|
||||
getLocalSetting,
|
||||
} from '@/libs/userlocalManager';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Drawer,
|
||||
Sprite,
|
||||
},
|
||||
directives: {
|
||||
mousePosition: MouseMoveDirective,
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<img
|
||||
class="pixel-art"
|
||||
v-if="imageName && imageName !== ''"
|
||||
:src="imageUrl()"
|
||||
>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.pixel-art {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import GIF_SPRITES from '@/../../common/script/content/constants/gifSprites';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
imageName: {
|
||||
type: String,
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getFileType (name) {
|
||||
if (GIF_SPRITES.includes(name)) {
|
||||
return 'gif';
|
||||
}
|
||||
return 'png';
|
||||
},
|
||||
imageUrl () {
|
||||
if (!this.imageName) {
|
||||
return '';
|
||||
}
|
||||
let name = this.imageName;
|
||||
if (name.indexOf(' ') !== -1) {
|
||||
const components = name.split(' ');
|
||||
name = components[components.length - 1];
|
||||
}
|
||||
if (this.prefix) {
|
||||
name = `${this.prefix}_${name}`;
|
||||
}
|
||||
return `https://habitica-assets.s3.amazonaws.com/mobileApp/images/${name}.${this.getFileType(name)}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -18,9 +18,9 @@
|
||||
v-if="label !== 'skip'"
|
||||
:id="key"
|
||||
class="gear box"
|
||||
:class="{white: equippedItems[key] && equippedItems[key].indexOf('base_0') === -1}"
|
||||
:class="{white: isUsed(equippedItems, key)}"
|
||||
>
|
||||
<div :class="`shop_${equippedItems[key]}`"></div>
|
||||
<Sprite v-if="isUsed(equippedItems, key)" :image-name="`shop_${equippedItems[key]}`"/>
|
||||
</div>
|
||||
<b-popover
|
||||
v-if="label !== 'skip'
|
||||
@@ -64,9 +64,9 @@
|
||||
v-if="label !== 'skip'"
|
||||
:id="key + 'C'"
|
||||
class="gear box"
|
||||
:class="{white: costumeItems[key] && costumeItems[key].indexOf('base_0') === -1}"
|
||||
:class="{white: isUsed(costumeItems, key)}"
|
||||
>
|
||||
<div :class="`shop_${costumeItems[key]}`"></div>
|
||||
<Sprite v-if="isUsed(costumeItems, key)" :image-name="`shop_${costumeItems[key]}`"/>
|
||||
</div>
|
||||
<!-- Show background on 8th tile rather than a piece of equipment.-->
|
||||
<div
|
||||
@@ -75,7 +75,7 @@
|
||||
:class="{white: user.preferences.background}"
|
||||
style="overflow:hidden"
|
||||
>
|
||||
<div :class="'icon_background_' + user.preferences.background"></div>
|
||||
<Sprite :image-name="'icon_background_' + user.preferences.background" />
|
||||
</div>
|
||||
<b-popover
|
||||
v-if="label !== 'skip'
|
||||
@@ -124,10 +124,10 @@
|
||||
class="box"
|
||||
:class="{white: user.items.currentPet}"
|
||||
>
|
||||
<div
|
||||
class="Pet"
|
||||
:class="`Pet-${user.items.currentPet}`"
|
||||
></div>
|
||||
<Sprite
|
||||
:image-name="user.items.currentPet ?
|
||||
`stable_Pet-${user.items.currentPet}` : ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pet-mount-well-text">
|
||||
@@ -156,10 +156,10 @@
|
||||
class="box"
|
||||
:class="{white: user.items.currentMount}"
|
||||
>
|
||||
<div
|
||||
class="mount"
|
||||
:class="`Mount_Icon_${user.items.currentMount}`"
|
||||
></div>
|
||||
<Sprite
|
||||
:image-name="user.items.currentMount ?
|
||||
`stable_Mount_Icon_${user.items.currentMount}` : ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pet-mount-well-text">
|
||||
@@ -330,6 +330,7 @@ import statsComputed from '@/../../common/script/libs/statsComputed';
|
||||
import { mapState } from '@/libs/store';
|
||||
import attributesGrid from '@/components/inventory/equipment/attributesGrid';
|
||||
import toggleSwitch from '@/components/ui/toggleSwitch';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
const DROP_ANIMALS = keys(Content.pets);
|
||||
const TOTAL_NUMBER_OF_DROP_ANIMALS = DROP_ANIMALS.length;
|
||||
@@ -337,6 +338,7 @@ export default {
|
||||
components: {
|
||||
toggleSwitch,
|
||||
attributesGrid,
|
||||
Sprite,
|
||||
},
|
||||
props: ['user', 'showAllocation'],
|
||||
data () {
|
||||
@@ -417,6 +419,9 @@ export default {
|
||||
|
||||
},
|
||||
methods: {
|
||||
isUsed (items, key) {
|
||||
return items[key] && items[key].indexOf('base_0') === -1;
|
||||
},
|
||||
getGearTitle (key) {
|
||||
return this.flatGear[key].text();
|
||||
},
|
||||
|
||||
@@ -37,6 +37,7 @@ export function createAnimal (egg, potion, type, _content, userItems) {
|
||||
return {
|
||||
key: animalKey,
|
||||
class: type === 'pet' ? `Pet Pet-${animalKey}` : `Mount_Icon_${animalKey}`,
|
||||
imageName: type === 'pet' ? `stable_Pet-${animalKey}` : `stable_Mount_Icon_${animalKey}`,
|
||||
eggKey: egg.key,
|
||||
eggName: getText(egg.text),
|
||||
potionKey: potion.key,
|
||||
|
||||
@@ -5,6 +5,7 @@ import unlock from '@/../../common/script/ops/unlock';
|
||||
import buy from '@/../../common/script/ops/buy/buy';
|
||||
|
||||
import appearanceSets from '@/../../common/script/content/appearance/sets';
|
||||
import appearances from '@/../../common/script/content/appearance';
|
||||
import { getScheduleMatchingGroup } from '@/../../common/script/content/constants/schedule';
|
||||
|
||||
import { userStateMixin } from './userState';
|
||||
@@ -31,8 +32,11 @@ export const avatarEditorUtilities = { // eslint-disable-line import/prefer-defa
|
||||
option.key = key;
|
||||
option.pathKey = pathKey;
|
||||
option.active = userPreference === key;
|
||||
option.class = this.createClass(type, subType, key);
|
||||
option.imageName = this.createImageName(type, subType, key);
|
||||
option.click = optionParam => (option.gemLocked ? this.unlock(`${optionParam.pathKey}.${key}`) : this.set({ [`preferences.${optionParam.pathKey}`]: optionParam.key }));
|
||||
option.text = subType ? appearances[type][subType][key].text()
|
||||
: appearances[type][key].text();
|
||||
|
||||
return option;
|
||||
},
|
||||
mapKeysToOption (key, type, subType, set) {
|
||||
@@ -56,8 +60,8 @@ export const avatarEditorUtilities = { // eslint-disable-line import/prefer-defa
|
||||
|
||||
return option;
|
||||
},
|
||||
createClass (type, subType, key) {
|
||||
let str = `${type} ${subType} `;
|
||||
createImageName (type, subType, key) {
|
||||
let str = '';
|
||||
|
||||
switch (type) {
|
||||
case 'shirt': {
|
||||
@@ -70,14 +74,14 @@ export const avatarEditorUtilities = { // eslint-disable-line import/prefer-defa
|
||||
}
|
||||
case 'hair': {
|
||||
if (subType === 'color') {
|
||||
str += `icon_hair_bangs_${this.user.preferences.hair.bangs || 1}_${key}`;
|
||||
str += `color_hair_bangs_${this.user.preferences.hair.bangs || 1}_${key}`;
|
||||
} else {
|
||||
str += `icon_hair_${subType}_${key}_${this.user.preferences.hair.color}`;
|
||||
str += `hair_${subType}_${key}_${this.user.preferences.hair.color}`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'skin': {
|
||||
str += `skin skin_${key}`;
|
||||
str += `skin_${key}`;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
@@ -189,7 +189,6 @@ const router = new VueRouter({
|
||||
meta: {
|
||||
privilegeNeeded: [ // any one of these is enough to give access
|
||||
'userSupport',
|
||||
'newsPoster',
|
||||
],
|
||||
},
|
||||
children: [
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
"paymentSubBillingWithMethod": "Tvé předplatné <strong>$<%= amount %> bude účtováno </strong> každé/CZ <strong><%= months %> měsíce/ů </strong> skrze <strong><%= paymentMethod %></strong>.",
|
||||
"invalidUnlockSet": "Tento set předmětů je prošlý a nemůže být odemčen.",
|
||||
"amountExp": "<%= amount %> Zk",
|
||||
"limitedAvailabilityDays": "K získání na <%= dny %>d <%= hodin%>h <%= minut %>m",
|
||||
"limitedAvailabilityDays": "K získání na <%= day %>d <%= hours%>h <%= minutes %>m",
|
||||
"nGemsGift": "<%= nGems %> Drahokamy (Dárek)",
|
||||
"nMonthsSubscriptionGift": "<%= nMonths %> Měsíční odběr (Dárek)",
|
||||
"nGems": "<%= nGems %> Drahokamy",
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
"backgroundStormyRooftopsNotes": "Schleiche über stürmische Hausdächer.",
|
||||
"backgroundWindyAutumnText": "Windiger Herbst",
|
||||
"backgroundWindyAutumnNotes": "Jage Laub an einem windigen Herbsttag.",
|
||||
"incentiveBackgrounds": "Einfaches Hintergründe-Set",
|
||||
"incentiveBackgrounds": "Standard Hintergründe",
|
||||
"backgroundVioletText": "Violett",
|
||||
"backgroundVioletNotes": "Ein vital-violetter Hintergrund.",
|
||||
"backgroundBlueText": "Blau",
|
||||
@@ -871,5 +871,12 @@
|
||||
"backgroundPottersStudioText": "Töpfer Atelier",
|
||||
"backgroundPottersStudioNotes": "Erschaffe Kunst im Töpfer Atelier.",
|
||||
"backgrounds052024": "SET 120: Veröffentlicht im Mai 2024",
|
||||
"backgroundDragonsBackNotes": "Segle durch den Himmel auf einem Drachenrücken."
|
||||
"backgroundDragonsBackNotes": "Segle durch den Himmel auf einem Drachenrücken.",
|
||||
"backgrounds062024": "SET 121: Veröffentlicht im Juni 2024",
|
||||
"backgroundShellGateText": "Muscheltor",
|
||||
"backgroundShellGateNotes": "Spaziere durch das korallenverzierte Muscheltor.",
|
||||
"backgrounds072024": "SET 122: Veröffentlicht im Juli 2024",
|
||||
"backgroundRiverBottomText": "Flussgrund",
|
||||
"backgroundRiverBottomNotes": "Erkunde den Grund eines Flusses.",
|
||||
"monthlyBackgrounds": "Hintergrund des Monats"
|
||||
}
|
||||
|
||||
@@ -189,5 +189,10 @@
|
||||
"notEnoughGold": "Nicht genügend Gold.",
|
||||
"chatCastSpellPartyTimes": "<%= username %> verwendet <%= spell %> <%= times %> Male für Deine Party <%= times %>.",
|
||||
"chatCastSpellUserTimes": "<%= username %> spricht <%= times %> mal <%= spell %> auf <%= target %>.",
|
||||
"nextReward": "Nächste Anmelde-Belohnung"
|
||||
"nextReward": "Nächste Anmelde-Belohnung",
|
||||
"skins": "Hautfarben",
|
||||
"titleHaircolor": "Haarfarben",
|
||||
"titleFacialHair": "Bärte",
|
||||
"titleHairbase": "Frisuren",
|
||||
"customizations": "Individualisierungen"
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
"commGuideHeadingInteractions": "Interaktionen in Habitica",
|
||||
"commGuidePara015": "Habitica hat verschiedene Orte wo du mit anderen Spielern in Kontakt kommen kannst. Darunter sind die Chats (Privatnachrichten oder Party Chats) und außerdem die Möglichkeit nach Parties und Herausforderungen zu suchen.",
|
||||
"commGuidePara016": "Wenn Du dich durch die sozialen Aspekte von Habitica bewegst, gibt es ein paar allgemeine Regeln, damit jeder sicher und glücklich ist.",
|
||||
"commGuideList02A": "<strong>Respektiert einander</strong>. Sei höflich, freundlich und hilfsbereit. Vergiss nicht: Habiticaner kommen aus den verschiedensten Hintergründen und haben sehr unterschiedliche Erfahrungen gemacht. Das macht Habitica so eigenartig! Es ist wichtig, dass man beim Aufbauen einer Community seine Unterschiede und Ähnlichkeiten respektieren, aber natürlich auch feiern kann.",
|
||||
"commGuideList02A": "<strong>Respektiert einander</strong>. Sei höflich, freundlich und hilfsbereit. Vergiss nicht: Habiticaner kommen aus den verschiedensten Hintergründen und haben sehr unterschiedliche Erfahrungen gemacht.",
|
||||
"commGuideList02B": "<strong>Halte Dich an die <a href='/static/terms' target='_blank'>allgemeinen Geschäftsbedingungen</a></strong>, sowohl in öffentlichen als auch in privaten Bereichen.",
|
||||
"commGuideList02C": "<strong>Poste keine Bilder oder Texte, die Gewalt darstellen, andere einschüchtern, oder eindeutig/indirekt sexuell sind, die Diskriminierung, Fanatismus, Rassismus, Sexismus, Hass, Belästigungen oder Hetze gegen jedwede Individuen oder Gruppen beinhalten.</strong> Auch nicht als Scherz oder Meme. Das bezieht sowohl Sprüche als auch Stellungnahmen mit ein. Nicht jeder hat den gleichen Humor, etwas, was Du als Witz wahrnimmst, kann für jemand anderen verletzend sein.",
|
||||
"commGuideList02D": "<strong>Halte die Diskussionen für alle Altersgruppen angemessen</strong>. Das heißt, Erwachsenenthemen in öffentlichen Bereichen zu vermeiden. Viele junge Habiticaner und Menschen mit verschiedenen Hintergründen nutzen diese Seite. Wir wollen unsere Gemeinschaft so angenehm und inklusiv wie möglich gestalten.",
|
||||
"commGuideList02D": "<strong>Sei dir bewusst, dass Habiticaner Menschen unterschiedlichen Alters und mit verschiedenen Hintergründen sind.</strong> Wettbewerbe und Spielerprofile sollten den Jugendschutz beachten, sowie Schimpfwörter, Streitigkeiten und Konflikte vermeiden.",
|
||||
"commGuideList02E": "<strong>Vermeide vulgäre Ausdrücke. Dazu gehören auch mildere, religiöse Ausdrücke, die anderswo möglicherweise akzeptiert werden, oder verschleierte Schimpfwörter</strong>. Unter uns sind Menschen aus allen religiösen und kulturellen Hintergründen und wir wollen, dass sich alle im öffentlichen Raum wohl fühlen. <strong>Wenn Dir ein Moderator oder Mitarbeiter mitteilt, dass ein bestimmter Ausdruck in Habitica nicht erlaubt ist, selbst wenn er Dir vielleicht nicht problematisch vorkommt, ist diese Entscheidung endgültig</strong>. Zusätzlich werden verbale Angriffe jeder Art strenge Konsequenzen haben, da sie auch unsere Nutzungsbedingungen verletzen.",
|
||||
"commGuideList02F": "Vermeide längere Diskussionen über spaltende Themen in der Taverne und wenn sie außerhalb des Themenbereichs liegen. Wenn jemand etwas sagt, das zwar von den Richtlinien her erlaubt ist, das Dich aber verletzt, dann ist es in Ordnung, diese Person höflich darauf hinzuweisen. Wenn Dir eine Person sagt, dass ihr Dein Verhalten unangenehm ist, nimm Dir Zeit, darüber zu reflektieren, anstatt im Zorn zu antworten. Aber wenn Du das Gefühl hast, dass ein Gespräch hitzig, übermäßig emotional, oder verletzend wird, dann <strong>lass dich nicht darauf ein. Melde stattdessen die Beiträge, um uns darüber in Kenntnis zu setzen.</strong> Moderatoren werden so schnell wie möglich antworten. Du kannst auch eine E-Mail an <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a> senden und gegebenenfalls Screenshots anhängen.",
|
||||
"commGuideList02G": "<strong>Erfülle alle Mitarbeitenden-Anfragen sofort</strong>. Diese könnten Folgendes beinhalten, ist aber nicht darauf beschränkt: Dich aufzufordern, deine Beiträge in einem bestimmten Bereich zu begrenzen, dein Profil zu bearbeiten, um ungeeignete Inhalte zu entfernen, dich zu bitten, deine Diskussion in einen geeigneteren Bereich zu verschieben, etc. Diskutiere nicht mit Mitarbeitenden. Solltest du mit einer Entscheidung unzufrieden sein, oder anderes Feedback zur Mitarbeitenden haben, sende eine E-mail an <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a> um unseren Community Manager zu kontaktieren.",
|
||||
"commGuideList02G": "<strong>Erfülle alle Mitarbeitenden-Anfragen sofort</strong>. Diese könnten Folgendes beinhalten, ist aber nicht darauf beschränkt: Dich aufzufordern, deine Beiträge in einem bestimmten Bereich zu begrenzen, dein Profil zu bearbeiten, um ungeeignete Inhalte zu entfernen, etc. Diskutiere nicht mit Mitarbeitenden. Solltest du mit einer Entscheidung unzufrieden sein, oder anderes Feedback zur Mitarbeitenden haben, sende eine E-mail an <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a>, um unseren Community Manager zu kontaktieren.",
|
||||
"commGuideList02J": "<strong>Poste keinen Spam</strong>. Spamming kann Folgendes beinhalten, ist aber nicht beschränkt auf: das Posten desselben Kommentars oder derselben Frage an mehreren Stellen, <strong>das Posten von Links ohne Erklärung oder Kontext</strong>, das Posten unsinniger Nachrichten, das Posten mehrerer Werbebotschaften für eine Gilde, Party, oder Herausforderung, oder das Posten vieler Nachrichten hintereinander. Wenn Du irgendeinen Nutzen daraus ziehst, wenn jemand auf einen Link klickt, musst Du das im Text Deiner Nachricht offenlegen, sonst wird sie auch als Spam betrachtet. Mods können gegebenenfalls nach ihrem Ermessen entscheiden, was Spam ausmacht.",
|
||||
"commGuideList02K": "<strong>Bitte vermeide große Überschriften in öffentlichen Chats, vor allem in der Taverne.</strong> Ähnlich wie bei GROSSBUCHSTABEN liest sich der Text, als ob Du schreien würdest, und beeinträchtigt die gemütliche Atmosphäre.",
|
||||
"commGuideList02L": "<strong>Wir raten Dir dringend davon ab, persönliche Informationen - besonders solche, mit denen Du identifiziert werden könntest - in öffentlichen Chats zu teilen.</strong> Zu den identifizierenden Informationen gehören unter anderem: Deine Adresse, Deine E-Mail-Adresse und Dein API-Token/Passwort. Dies dient nur Deiner Sicherheit! Mitarbeiter oder Moderatoren werden solche Beiträge nach eigenem Ermessen entfernen. Wenn Du nach persönlichen Informationen in einer privaten Gilde, Party oder per PN gefragt wirst, empfehlen wir dringend, dass Du höflich ablehnst und Mitarbeiter und Moderatoren informierst, indem Du entweder 1) den Beitrag über das Fähnchen meldest, oder 2) eine E-Mail an <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a> schreibst und Screenshots anhängst.",
|
||||
@@ -130,7 +130,7 @@
|
||||
"commGuideList02M": "Frage nicht nach oder bettle nicht um Edelsteine, Abonnements oder die Mitgliedschaft in Gruppenplänen. Wenn Du ungewollte Nachrichten erhältst, in denen man Dich um bezahlte Artikel fragt, melde sie bitte. Wiederholte Betteleien nach Edelsteinen oder Abonnements, vor allem nachdem bereits eine Warnung ausgesprochen wurde, können zu einer Kontosperre führen.",
|
||||
"commGuideList09D": "Entfernung oder Herabstufung des Mitwirkenden-Ranges",
|
||||
"commGuideList05H": "Schwerwiegende oder wiederholte Versuche, andere Spielende zu betrügen oder zu bedrängen, um an Gegenstände zu kommen, die echtes Geld kosten",
|
||||
"commGuideList02N": "<strong>Markiere und melde Nachrichten, in denen diese Richtlinien oder die Nutzungsbedingungen nicht eingehalten werden.</strong> Wir werden uns so schnell wie möglich darum kümmern. Alternativ kannst du Mitarbeiter:innen über <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a> benachrichtigen, doch die Markierung ist der schnellste Weg, um Hilfe zu erhalten.",
|
||||
"commGuideList02N": "<strong>Melde Nachrichten, in denen diese Richtlinien oder die Nutzungsbedingungen nicht eingehalten werden.</strong> Melde eine Nachricht direkt oder informiere Mitarbeiter:innen über <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a>, um Verstöße in Profilen oder Wettbewerben zu melden. Wir werden uns schnellstmöglich darum kümmern. Kontaktiere uns in deiner Muttersprache, wenn dir das leichter fällt. Es kann sein, dass wir Google Translate nutzen müssen, aber wir wollen, dass du dich sicher fühlst, uns zu kontaktieren, falls bei dir ein Problem auftreten sollte.",
|
||||
"commGuideList02H": "<strong>Alle Anzeigenamen und @Benutzernamen müssen den Service-Bedingungen entsprechen</strong>. Um deinen Anzeigenamen und/oder @Benutzernamen zu ändern: wähle in der mobilen App Menü > Einstellungen > Account. Auf der Webseite navigierst du über das Benutzer-Icon in der oberen Navigationsleiste.",
|
||||
"commGuideList02I": "<strong>Namen von Herausforderungen sollten für alle Bereiche angemessen sein, weil sie im öffentlichen Profil der Gewinner erscheinen</strong>. Behalte das in Erinnerung beim Erstellen von Herausforderungen, weil wir gezwungen sein könnten, den Eintrag in ihrem Profil zu ändern, falls es eine Meldung gibt.",
|
||||
"commGuideList02P": "<strong>Wir raten davon ab, unaufgefordert private Nachrichten zu verschicken</strong>. Wenn du ungewollt eine Nachricht empfängst, die dir unangenehm ist, oder die gegen diese Richtlinien oder die Nutzungsbedingungen verstößt, sperre bitte den Absender und melde sie, um den Mitarbeiterstab darauf aufmerksam zu machen.",
|
||||
|
||||
@@ -376,5 +376,12 @@
|
||||
"hatchingPotionRoseGold": "Rotgold",
|
||||
"hatchingPotionPinkMarble": "Pink Marmor",
|
||||
"hatchingPotionTeaShop": "Teeladen",
|
||||
"hatchingPotionFungi": "Fungus"
|
||||
"hatchingPotionFungi": "Fungus",
|
||||
"questEggGiraffeMountText": "Giraffe",
|
||||
"questEggChameleonText": "Chamäleon",
|
||||
"questEggChameleonMountText": "Chamäleon",
|
||||
"hatchingPotionKoi": "Koi",
|
||||
"questEggGiraffeText": "Giraffe",
|
||||
"questEggGiraffeAdjective": "eine riesengroße",
|
||||
"questEggChameleonAdjective": "ein chaotisches"
|
||||
}
|
||||
|
||||
@@ -2885,5 +2885,45 @@
|
||||
"armorSpecialSummer2023MageNotes": "Fühl dich beschützt und bequem in diesen fließenden Roben, perfekt koloriert für Unterwasser-Abenteuer. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"armorSpecialSummer2023HealerNotes": "Halte an deinen Zielen und Überzeugungen fest, in diesem eleganten grünen Kleid. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"armorSpecialFall2023RogueText": "Verfluchter Hexenkessel",
|
||||
"armorSpecialFall2023RogueNotes": "Du wurdest mit dem Versprechen einer schönen, heissen Trinkerei gelockt... der Spaß geht auf deine Kosten! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Herbstausrüstung."
|
||||
"armorSpecialFall2023RogueNotes": "Du wurdest mit dem Versprechen einer schönen, heissen Trinkerei gelockt... der Spaß geht auf deine Kosten! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"armorSpecialFall2023WarriorText": "Videorekorder Rüstung",
|
||||
"armorSpecialFall2023WarriorNotes": "Spielt sie DVDs ab? VHS?? Was für Kabel benötigt dieses Ding, um es mit dem TV zu verbinden?! Wie sich herausstellt, ist dies der beängstigendste Aspekt an der Sache. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Sommerausrüstung.",
|
||||
"gearItemsCompleted": "Du besitzt alle <%= klass %> Ausrüstungsteile! Neue Ausrüstung wird während den saisonalen Galas veröffentlicht.",
|
||||
"moreArmoireGearAvailable": "Bis dahin kannst du <%= armoireCount %> Ausrüstungsteile im Verzauberten Schrank finden!",
|
||||
"moreArmoireGearComing": "Der Verzauberte Schrank bekommt jeden Monat neuen Vorrat!",
|
||||
"weaponSpecialSummer2024RogueText": "Nacktkiemerschnecke Dreizack",
|
||||
"weaponSpecialSummer2024RogueNotes": "Wende die scharfen Stacheln anderer gegen sie selbst! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2024 Sommerausrüstung.",
|
||||
"weaponSpecialSummer2024WarriorText": "Walhai-Zahn Schneider",
|
||||
"weaponSpecialSummer2024WarriorNotes": "Einige ausgefallene Haizähne verwandeln dies in eine Waffe, die aus jeder Richtung Schaden verursachen kann. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2024 Sommerausrüstung.",
|
||||
"weaponSpecialSummer2024HealerText": "Meeresschnecken Stab",
|
||||
"weaponSpecialSummer2024MageText": "Seeanemonen Zauberstab",
|
||||
"weaponSpecialSummer2024MageNotes": "Diese grandiosen Tentakel können Magie gleichzeitig abhalten, ablenken und steuern. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2024 Sommerausrüstung.",
|
||||
"weaponSpecialSummer2024HealerNotes": "Du wirst erstaunt sein zu entdecken, wie hart die Muschel am Ende des Stabs ist. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024 Sommerausrüstung.",
|
||||
"weaponArmoireCorsairsBladeNotes": "Ob du sie zum Plündern oder zum Schutz trägst - du kannst froh sein, daß du diese grimmige Klinge mit dir zur See gebracht hast. Achte nur darauf, daß sie sicher verstaut ist, wenn nicht in Benutzung. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Korsaren Set (Gegenstand 3 von 3)",
|
||||
"weaponArmoireCorsairsBladeText": "Korsarenklinge",
|
||||
"armorSpecialFall2023MageText": "Scharlachrote Hexenmeister Robe",
|
||||
"armorSpecialFall2023MageNotes": "Mit scharlachrotem Garn und goldenen Akzenten ist dieses Outfit ein Wunder für die Sinne. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"weaponArmoireRollingPinText": "Wellholz",
|
||||
"weaponArmoireRollingPinNotes": "Rolle deinen Teig zwischendrin so dünn wie du möchtest, während du schlechte Gewohnheiten auf den Kopf haust, sobald sie um dich herum aufploppen, wie bei einem gewissen Nagetier-Kloppen Spiel. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Küchenwerkzeugset 2 (Gegenstand 2 von 2).",
|
||||
"armorSpecialFall2023HealerText": "Sumpfkreatur-Body",
|
||||
"armorSpecialFall2023HealerNotes": "Mit Moos, Fels, Holz und Sumpfwasser reingemischt, ist dieses Outfit manchmal tough und manchmal schwammig (aber immer einschüchternd). Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023 Herbstausrüstung.",
|
||||
"armorSpecialWinter2024RogueText": "Verschneite Eulen Roben",
|
||||
"armorSpecialWinter2024RogueNotes": "Wuuuuu wer wirst du sein, wenn du diese Roben trägst? In Federn und Flaum gehüllt, wirst du sowohl warm als auch getarnt sein! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023-2024 Winterausrüstung.",
|
||||
"armorSpecialWinter2024WarriorNotes": "Es stellt sich heraus, daß Schokolade, Pfefferminz und Zuckerguß stabilere Materialien sind, als man denkt. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023-2024 Winterausrüstung.",
|
||||
"armorSpecialWinter2024WarriorText": "Pfefferminz Plätzchen Rüstung",
|
||||
"armorSpecialWinter2024MageNotes": "Sowohl praktisch als auch hübsch, werden diese Roben dich angenehm warm halten, während du deine magischen Fähigkeiten draußen in der Kälte ausübst. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023-2024 Winterausrüstung.",
|
||||
"armorSpecialWinter2024MageText": "Narwal Zauberer Roben",
|
||||
"armorSpecialWinter2024HealerText": "Gefrorene Rüstung",
|
||||
"armorSpecialWinter2024HealerNotes": "Dieser glitzernde Block aus magischem Eis ist zumindest schützend, während du deine Flucht ausknobelst. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2023-2024 Winterausrüstung.",
|
||||
"armorSpecialSpring2024RogueNotes": "Diese rustikale Robe verbirgt dich, sogar wenn die Jahreszeiten rings um dich herum wechseln. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2024 Frühlingsausrüstung.",
|
||||
"armorSpecialSpring2024RogueText": "Schmelzende Schnee Robe",
|
||||
"armorSpecialSpring2024WarriorText": "Fluorit Rüstung",
|
||||
"armorSpecialSpring2024WarriorNotes": "Diese stabilisierende Steinrüstung wird helfen, dich zu erden, während du alles blendest, dem du entgegentrittst. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024 Frühlingsausrüstung.",
|
||||
"armorSpecialSpring2024MageText": "Hibiskus Roben",
|
||||
"armorSpecialSpring2024MageNotes": "Diese hübschen Blüten werden dir helfen, stilvoll mit deinen Kräften zu posieren. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024 Frühlingsausrüstung.",
|
||||
"headSpecialSpring2024HealerText": "Blaukehlchen Helm",
|
||||
"armorSpecialSpring2024HealerNotes": "Diese fabelhaften Federn werden helfen, deinen glücklichsten Träumen Flügel zu verleihen. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024 Frühlingsausrüstung.",
|
||||
"armorSpecialSummer2024RogueText": "Nacktkiemerschnecken-Schwanz",
|
||||
"armorSpecialSummer2024RogueNotes": "Du magst vielleicht eine Seeschnecke ohne Schneckenhaus sein, aber du bist eine Seeschnecke mit See-Schwingen! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2024 Sommerausrüstung.",
|
||||
"armorSpecialSpring2024HealerText": "Blaukehlchen Anzug"
|
||||
}
|
||||
|
||||
@@ -238,5 +238,6 @@
|
||||
"viewAdminPanel": "Admin Panel anzeigen",
|
||||
"mutePlayer": "Stumm",
|
||||
"skipExternalLinkModal": "Halte STRG (Windows) oder Command (Mac) beim Anklicken eines Links, um dieses Modal zu überspringen.",
|
||||
"shadowMute": "Unsichtbare Stummschaltung"
|
||||
"shadowMute": "Unsichtbare Stummschaltung",
|
||||
"titleCustomizations": "Individualisierungen"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"tavern": "Tavernen-Chat",
|
||||
"tavernChat": "Tavernen-Chat",
|
||||
"innCheckOutBanner": "Du bist derzeit im Gasthaus eingecheckt. Deine Tagesaufgaben können Dir nicht schaden und Du erzielst keinen Fortschritt bei Deinen Quests.",
|
||||
"innCheckOutBannerShort": "Du bist im Gasthaus eingecheckt.",
|
||||
"innCheckOutBanner": "Du hast derzeit Schaden pausiert. Deine Tagesaufgaben können Dir nicht schaden und Du erzielst keinen Fortschritt bei Deinen Quests.",
|
||||
"innCheckOutBannerShort": "Du hast Schaden derzeit pausiert.",
|
||||
"resumeDamage": "Schaden fortsetzen",
|
||||
"helpfulLinks": "Weiterführende Links",
|
||||
"communityGuidelinesLink": "Community-Richtlinien",
|
||||
@@ -20,7 +20,7 @@
|
||||
"dataTool": "Werkzeug zur Datenanzeige",
|
||||
"resources": "Ressourcen",
|
||||
"communityGuidelines": "Community-Richtlinien",
|
||||
"bannedWordUsed": "Hoppla! Es sieht so aus, als würde dieser Beitrag ein Schimpfwort enthalten, oder sich auf Suchtstoffe oder nicht-jugendfreie Themen beziehen (<%= swearWordsUsed %>). Habitica achtet darauf, unsere Chats frei von diesen Dingen zu halten. Du kannst Deine Nachricht gerne überarbeiten und sie wieder posten! Die betroffenen Wörter musst Du allerdings löschen, nicht einfach zensieren.",
|
||||
"bannedWordUsed": "Hoppla! Es sieht so aus, als würde dieser Beitrag ein Schimpfwort enthalten, oder sich auf Suchtstoffe oder nicht-jugendfreie Themen beziehen (<%= swearWordsUsed %>). Habitica achtet darauf, unsere Chats frei von diesen Dingen zu halten. Du kannst Deine Nachricht gerne überarbeiten und sie wieder posten! Die betroffenen Wörter musst Du allerdings löschen, nicht einfach nur zensieren.",
|
||||
"bannedSlurUsed": "Dein Beitrag enthielt unangebrachte Inhalte, daher wurden Dir Deine Chat-Privilegien entzogen.",
|
||||
"party": "Party",
|
||||
"usernameCopied": "Benutzername in die Zwischenablage kopiert.",
|
||||
@@ -30,8 +30,8 @@
|
||||
"invite": "Einladen",
|
||||
"leave": "Verlassen",
|
||||
"invitedToParty": "Du wurdest in die Party <span class=\"notification-bold\"><%- party %></span> eingeladen",
|
||||
"invitedToPrivateGuild": "Du wurdest eingeladen, der privaten Gilde <span class=\"notification-bold\"><%- guild %></span> beizutreten",
|
||||
"invitedToPublicGuild": "Du wurdest eingeladen, der Gilde <span class=\"notification-bold-blue\"><%- guild %></span> beizutreten",
|
||||
"invitedToPrivateGuild": "Du wurdest eingeladen, der privaten Gruppe<span class=\"notification-bold\"><%- guild %></span> beizutreten",
|
||||
"invitedToPublicGuild": "Du wurdest eingeladen, der Gruppe<span class=\"notification-bold-blue\"><%- guild %></span> beizutreten",
|
||||
"invitationAcceptedHeader": "Deine Einladung wurde angenommen",
|
||||
"invitationAcceptedBody": "<%= username %> hat Deine Einladung zu <%= groupName %> angenommen!",
|
||||
"systemMessage": "Systemmeldung",
|
||||
@@ -57,7 +57,7 @@
|
||||
"createGuild2": "Erstellen",
|
||||
"guild": "Gilde",
|
||||
"guilds": "Gilden",
|
||||
"sureKick": "Willst Du dieses Mitglied wirklich aus der Party/Gilde entfernen?",
|
||||
"sureKick": "Willst Du dieses Mitglied wirklich aus der Party oder Gruppe entfernen?",
|
||||
"optionalMessage": "Optionale Nachricht",
|
||||
"yesRemove": "Ja, entferne sie",
|
||||
"sortBackground": "Nach Hintergrund sortieren",
|
||||
@@ -85,9 +85,9 @@
|
||||
"PMDisabledOptPopoverText": "Private Nachrichten sind deaktiviert. Aktiviere diese Option, damit andere User Dich über Dein Profil erreichen können.",
|
||||
"PMDisabledCaptionTitle": "Private Nachrichten sind deaktiviert",
|
||||
"PMDisabledCaptionText": "Du kannst weiterhin Nachrichten versenden, aber Dir können keine zugeschickt werden.",
|
||||
"block": "Sperren",
|
||||
"unblock": "Entsperren",
|
||||
"blockWarning": "Sperre - Dies hat keine Auswirkung, wenn der Spieler jetzt Moderator ist oder in Zukunft Moderator wird.",
|
||||
"block": "Spieler sperren",
|
||||
"unblock": "Spieler entsperren",
|
||||
"blockWarning": "Dies hat keine Auswirkung, wenn der Spieler ein Administrator ist.",
|
||||
"inbox": "Postfach",
|
||||
"messageRequired": "Eine Nachricht wird benötigt.",
|
||||
"toUserIDRequired": "Eine Benutzer-ID wird benötigt",
|
||||
@@ -98,10 +98,10 @@
|
||||
"badAmountOfGemsToSend": "Die Menge muss zwischen 1 und Deiner aktuellen Edelsteinanzahl liegen.",
|
||||
"report": "Melden",
|
||||
"abuseFlagModalHeading": "Melde einen Verstoß",
|
||||
"abuseFlagModalBody": "Möchtest Du diesen Beitrag wirklich melden? Du solltest <strong>ausschließlich</strong> Beiträge melden, die unsere <%= firstLinkStart %>Community-Richtlinien<%= linkEnd %> und/oder unsere <%= secondLinkStart %>Nutzungsbedingungen<%= linkEnd %> verletzen. Das ungerechtfertigte Melden von Beiträgen stellt eine Verletzung der Community-Richtlinien dar und kann geahndet werden.",
|
||||
"abuseFlagModalBody": "Du solltest <strong>ausschließlich</strong> Beiträge melden, die unsere <%= firstLinkStart %>Community-Richtlinien<%= linkEnd %> und/oder unsere <%= secondLinkStart %>Nutzungsbedingungen<%= linkEnd %> verletzen. Das ungerechtfertigte Melden von Beiträgen stellt eine Verletzung der Community-Richtlinien dar.",
|
||||
"abuseReported": "Danke, dass Du diesen Verstoß gemeldet hast. Die Moderatoren wurden benachrichtigt.",
|
||||
"whyReportingPost": "Wieso meldest Du diesen Post?",
|
||||
"whyReportingPostPlaceholder": "Bitte hilf unseren Moderatoren und gib einen Grund an, warum Du diesen Beitrag als Verstoß gemeldet hast, z.B. Spam, Fluchen, Religiöse Schwüre, Intoleranz, Beleidigungen, Nicht jugendfreie Themen, Gewalt.",
|
||||
"whyReportingPostPlaceholder": "Grund für die Beschwerde",
|
||||
"optional": "Optional",
|
||||
"needsTextPlaceholder": "Gib Deine Nachricht hier ein.",
|
||||
"copyMessageAsToDo": "Nachricht als To-Do übernehmen",
|
||||
@@ -126,7 +126,7 @@
|
||||
"sendGiftMessagePlaceholder": "Füge eine Geschenknachricht hinzu",
|
||||
"sendGiftSubscription": "<%= months %> Monat(e): $<%= price %> USD",
|
||||
"gemGiftsAreOptional": "Bitte nimm zur Kenntnis, dass Habitica niemals von Dir verlangen wird, anderen Spielern Edelsteine zu schenken. Bei anderen Spielern um Edelsteine zu betteln ist ein <strong>Verstoss gegen die Community-Richtlinien</strong>, und jedes Vorkommnis sollte bei <%= hrefTechAssistanceEmail %> gemeldet werden.",
|
||||
"battleWithFriends": "Besiege mit Freunden Monster",
|
||||
"battleWithFriends": "Spiele Habitica zusammen mit anderen",
|
||||
"startAParty": "Erstelle eine Party",
|
||||
"partyUpName": "Party!",
|
||||
"partyOnName": "Riesenparty!",
|
||||
@@ -221,42 +221,42 @@
|
||||
"badAmountOfGemsToPurchase": "Die Anzahl muss mindestens 1 sein.",
|
||||
"groupPolicyCannotGetGems": "Die Regeln einer Gruppe in der Du Mitglied bist verhindern, dass die Gruppenmitglieder Edelsteine erhalten.",
|
||||
"viewParty": "Party ansehen",
|
||||
"newGuildPlaceholder": "Gib den Namen Deiner Gilde ein.",
|
||||
"guildBank": "Gildenbankkonto",
|
||||
"chatPlaceholder": "Füge die Botschaft an Gildenmitglieder hier ein",
|
||||
"newGuildPlaceholder": "Gib den Namen deiner Gruppe ein.",
|
||||
"guildBank": "Bankkonto",
|
||||
"chatPlaceholder": "Füge die Botschaft an Gruppenmitglieder hier ein",
|
||||
"partyChatPlaceholder": "Füge die Botschaft an Partymitglieder hier ein",
|
||||
"fetchRecentMessages": "Neue Nachrichten abrufen",
|
||||
"like": "Like",
|
||||
"liked": "Liked",
|
||||
"inviteToGuild": "In Gilde einladen",
|
||||
"inviteToGuild": "In Gruppe einladen",
|
||||
"inviteToParty": "In die Party einladen",
|
||||
"inviteEmailUsername": "Via E-Mail oder Benutzernamen einladen",
|
||||
"inviteEmailUsernameInfo": "Einladung von Benutzern über eine gültige E-Mailadresse oder Benutzernamen. Wenn eine E-Mail noch nicht registriert ist, werden wir sie einladen, beizutreten.",
|
||||
"emailOrUsernameInvite": "E-Mailadresse oder Benutzername",
|
||||
"messageGuildLeader": "Gildenleiter benachrichtigen",
|
||||
"messageGuildLeader": "Gruppenleiter benachrichtigen",
|
||||
"donateGems": "Edelsteine spenden",
|
||||
"updateGuild": "Gilde aktualisieren",
|
||||
"updateGuild": "Gruppe aktualisieren",
|
||||
"viewMembers": "Mitglieder ansehen",
|
||||
"memberCount": "Anzahl Mitglieder",
|
||||
"recentActivity": "Kürzliche Aktivitäten",
|
||||
"myGuilds": "Meine Gilden",
|
||||
"guildsDiscovery": "Gilden entdecken",
|
||||
"role": "Rolle",
|
||||
"guildLeader": "Gildenleiter",
|
||||
"guildLeader": "Gruppenleiter",
|
||||
"member": "Mitglied",
|
||||
"guildSize": "Gildengröße",
|
||||
"guildSize": "Gruppengröße",
|
||||
"goldTier": "Gold",
|
||||
"silverTier": "Silber",
|
||||
"bronzeTier": "Bronze",
|
||||
"privacySettings": "Datenschutzeinstellungen",
|
||||
"onlyLeaderCreatesChallenges": "Nur der Leiter kann Herausforderungen erstellen",
|
||||
"onlyLeaderCreatesChallengesDetail": "Wenn diese Option ausgewählt ist, können gewöhnliche Gruppenmitglieder keine Herausforderungen für die Gruppe erstellen.",
|
||||
"privateGuild": "Private Gilde",
|
||||
"privateGuild": "Private Gruppe",
|
||||
"charactersRemaining": "<%= characters %> Zeichen übrig",
|
||||
"guildSummary": "Zusammenfassung",
|
||||
"guildSummaryPlaceholder": "Schreibe eine Kurzbeschreibung um Deine Gilde anderen Habiticanern bekannt zu machen. Was ist der Hauptzweck der Gilde und warum sollten Leute ihr beitreten? Verwende hilfreiche Schlüsselwörter in der Beschreibung, um die Suche für andere Habiticaner zu erleichtern!",
|
||||
"guildSummaryPlaceholder": "Schreibe eine Kurzbeschreibung über deine Gruppe.. Was ist der Hauptzweck der Gruppe und was werden die Gruppenmitglieder tun?",
|
||||
"groupDescription": "Beschreibung",
|
||||
"guildDescriptionPlaceholder": "Nutze diesen Abschnitt um alles, was Mitglieder der Gilde über Deine Gilde wissen sollten, ausführlicher darzustellen. Nützliche Tipps, hilfreiche Links und ermutigende Worte gehören hier hin!",
|
||||
"guildDescriptionPlaceholder": "Nutze diesen Abschnitt um alles, was Mitglieder über Deine Gruppe wissen sollten, ausführlicher darzustellen. Nützliche Tipps, hilfreiche Links und ermutigende Worte gehören hier hin!",
|
||||
"markdownFormattingHelp": "[Markdown Formatierungshilfe](https://habitica.fandom.com/wiki/Markdown_Cheat_Sheet)",
|
||||
"partyDescriptionPlaceholder": "Das ist unsere Partybeschreibung. Sie beschreibt, was wir in unserer Party so tun. Wenn Du mehr darüber wissen willst, was wir in unserer Party so machen, lies die Beschreibung. Party on!",
|
||||
"guildGemCostInfo": "Eine Edelstein-Gebühr fördert die Qualität der Gilden und wird der Gildenbank gutgeschrieben.",
|
||||
@@ -265,7 +265,7 @@
|
||||
"noGuildsParagraph2": "Klicke auf den \"Gilden entdecken\"-Reiter, um basierend auf Deinen Interessen empfohlene Gilden zu sehen, stöbere durch Habiticas öffentliche Gilden, oder erstelle Deine eigene Gilde.",
|
||||
"noGuildsMatchFilters": "Wir haben keine passenden Gilden gefunden.",
|
||||
"privateDescription": "Private Gilden werden nicht in Habiticas Gildenübersicht angezeigt. Neue Mitglieder können nur durch eine Einladung hinzugefügt werden.",
|
||||
"removeInvite": "Einladung entfernen",
|
||||
"removeInvite": "Einladung löschen",
|
||||
"removeMember": "Mitglied entfernen",
|
||||
"sendMessage": "Nachricht senden",
|
||||
"promoteToLeader": "Gruppenleitung übertragen",
|
||||
@@ -353,7 +353,7 @@
|
||||
"PMCanNotReply": "Du kannst auf diese Nachricht nicht antworten",
|
||||
"PMUnblockUserToSendMessages": "Entblocke diese Person, um wieder Nachrichten versenden und empfangen zu können.",
|
||||
"PMUserDoesNotReceiveMessages": "Diese Person empfängt keine privaten Nachrichten mehr",
|
||||
"newPartyPlaceholder": "Gib den Namen Deiner Party ein.",
|
||||
"newPartyPlaceholder": "Gib den Namen deiner Party ein.",
|
||||
"chooseTeamMember": "Wähle ein Teammitglied",
|
||||
"unassigned": "Nicht zugewiesen",
|
||||
"claimRewards": "Belohnung einfordern",
|
||||
@@ -362,7 +362,7 @@
|
||||
"managerNotes": "Manager-Notizen",
|
||||
"thisTaskApproved": "Dieser Aufgabe wurde zugestimmt",
|
||||
"onlyPrivateGuildsCanUpgrade": "Nur bei privaten Gilden kann ein Upgrade zu einem Gruppenplan durchgeführt werden.",
|
||||
"bannedWordsAllowedDetail": "Durch Auswahl dieser Option, wird das Verwenden verbotener Wörter in dieser Gilde zugelassen.",
|
||||
"bannedWordsAllowedDetail": "Durch Auswahl dieser Option, wird das Verwenden verbotener Wörter in dieser Gruppe zugelassen.",
|
||||
"bannedWordsAllowed": "Verbotene Wörter zulassen",
|
||||
"languageSettings": "Spracheinstellungen",
|
||||
"cannotRemoveQuestOwner": "Du kannst die Person, welche die aktive Quest besitzt, nicht entfernen. Breche erst die Quest ab.",
|
||||
@@ -372,11 +372,11 @@
|
||||
"blockYourself": "Du kannst Dich nicht selbst blockieren",
|
||||
"invitedToThisQuest": "Du wurdest zu dieser Quest eingeladen!",
|
||||
"messagePartyLeader": "Partyleitung benachrichtigen",
|
||||
"joinGuild": "Gilde beitreten",
|
||||
"joinGuild": "Gruppe beitreten",
|
||||
"joinParty": "Party beitreten",
|
||||
"editGuild": "Gilde bearbeiten",
|
||||
"editGuild": "Gruppe bearbeiten",
|
||||
"editParty": "Party bearbeiten",
|
||||
"leaveGuild": "Gilde verlassen",
|
||||
"leaveGuild": "Gruppe verlassen",
|
||||
"viewDetails": "Details ansehen",
|
||||
"upgradeToGroup": "Auf Gruppenplan upgraden",
|
||||
"sendGiftTotal": "Insgesamt:",
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
"winter2019PyrotechnicSet": "Pyrotechniker (Magier)",
|
||||
"winter2019WinterStarSet": "Winterstern (Heiler)",
|
||||
"winter2019PoinsettiaSet": "Weihnachtsstern (Schurke)",
|
||||
"winterPromoGiftHeader": "VERSCHENK EIN ABO, BEKOMME EINS UMSONST!",
|
||||
"winterPromoGiftHeader": "VERSCHENK EIN ABO, BEKOMME EINS UMSONST!",
|
||||
"winterPromoGiftDetails1": "Nur bis zum 6. Januar: wenn Du jemandem ein Abonnement schenkst, erhältst Du das gleiche Abonnement gratis für Dich!",
|
||||
"winterPromoGiftDetails2": "Bitte bedenke, dass das geschenkte Abonnement, falls Du oder Deine beschenkte Person bereits über ein sich wiederholendes Abonnement verfügen, erst dann startet, wenn das alte Abonnement gekündigt wird oder ausläuft. Herzlichen Dank für Deine Unterstützung! <3",
|
||||
"discountBundle": "Paket",
|
||||
@@ -144,22 +144,22 @@
|
||||
"summer2019WaterLilyMageSet": "Seerose (Magier)",
|
||||
"summer2019ConchHealerSet": "Trompetenschnecke (Heiler)",
|
||||
"summer2019HammerheadRogueSet": "Hammerkopf (Schurke)",
|
||||
"june2018": "Juni 2018",
|
||||
"june2018": "Juni 2018",
|
||||
"fall2019LichSet": "Lich (Heiler)",
|
||||
"september2018": "September 2018",
|
||||
"september2017": "September 2017",
|
||||
"fall2019RavenSet": "Rabe (Krieger)",
|
||||
"fall2019CyclopsSet": "Zyklop (Magier)",
|
||||
"fall2019OperaticSpecterSet": "Opernhaftes Gespenst (Schurke)",
|
||||
"winter2020LanternSet": "Laterne (Schurke)",
|
||||
"winter2020LanternSet": "Laterne (Schurke)",
|
||||
"winter2020WinterSpiceSet": "Wintergewürz (Heiler)",
|
||||
"winter2020CarolOfTheMageSet": "Weihnachtslied des Magiers (Magier)",
|
||||
"winter2020EvergreenSet": "Immergrün (Krieger)",
|
||||
"spring2020BeetleWarriorSet": "Nashornkäfer (Krieger)",
|
||||
"spring2020LapisLazuliRogueSet": "Lapislazuli (Schurke)",
|
||||
"spring2020BeetleWarriorSet": "Nashornkäfer (Krieger)",
|
||||
"spring2020LapisLazuliRogueSet": "Lapislazuli (Schurke)",
|
||||
"spring2020IrisHealerSet": "Iris (Heiler)",
|
||||
"spring2020PuddleMageSet": "Pfütze (Magier)",
|
||||
"summer2020CrocodileRogueSet": "Krokodil (Schurke)",
|
||||
"summer2020CrocodileRogueSet": "Krokodil (Schurke)",
|
||||
"summer2020SeaGlassHealerSet": "Meerglas (Heiler)",
|
||||
"summer2020OarfishMageSet": "Riemenfisch (Magier)",
|
||||
"summer2020RainbowTroutWarriorSet": "Regenbogenforelle (Krieger)",
|
||||
@@ -167,8 +167,8 @@
|
||||
"fall2020ThirdEyeMageSet": "Drittes Auge (Magier)",
|
||||
"fall2020DeathsHeadMothHealerSet": "Totenkopfschwärmer (Heiler)",
|
||||
"fall2020WraithWarriorSet": "Gespenst (Krieger)",
|
||||
"royalPurpleJackolantern": "Purpurne Kürbislaterne",
|
||||
"g1g1Limitations": "Dies ist eine zeitlich beschränkte Aktion, die am 16. Dezember um 13:00 Uhr (GMT) startet und am 6. Januar um 01:00 Nachts (GMT) endet. Dieses Angebot ist nur gültig, wenn Du einen anderen Habiticaner beschenkst. Wenn Du oder die beschenkte Person bereits ein Abo haben, wird dieses, sobald es abläuft oder gekündigt wird, um die Zeit des Geschenkes verlängert werden.",
|
||||
"royalPurpleJackolantern": "Purpurne Kürbislaterne",
|
||||
"g1g1Limitations": "Dies ist eine zeitlich beschränkte Aktion, die am 16. Dezember um 13:00 Uhr (GMT) startet und am 6. Januar um 01:00 Nachts (GMT) endet. Dieses Angebot ist nur gültig, wenn Du einen anderen Habiticaner beschenkst. Wenn Du oder die beschenkte Person bereits ein Abo haben, wird dieses, sobald es abläuft oder gekündigt wird, um die Zeit des Geschenkes verlängert werden.",
|
||||
"limitations": "Einschränkungen",
|
||||
"g1g1HowItWorks": "Gebe den Benutzernamen ein, welchem Du das Geschenk machen willst. Dann wähle die Länge des Abos, das Du verschenken möchtest und schließe den Vorgang ab. Dein Account wird automatisch mit dem selben Abo belohnt, das Du gerade verschenkt hast.",
|
||||
"howItWorks": "So funktioniert es",
|
||||
@@ -196,15 +196,15 @@
|
||||
"winter2022StockingWarriorSet": "Strumpf (Krieger)",
|
||||
"winter2022IceCrystalHealerSet": "Eiskristall (Heiler)",
|
||||
"winter2022PomegranateMageSet": "Granatapfel (Magier)",
|
||||
"spring2022MagpieRogueSet": "Elster (Schurke)",
|
||||
"spring2022MagpieRogueSet": "Elster (Schurke)",
|
||||
"spring2022RainstormWarriorSet": "Gewitterregen (Krieger)",
|
||||
"spring2022ForsythiaMageSet": "Forsythie (Magier)",
|
||||
"spring2022PeridotHealerSet": "Abendsmaragd (Heiler)",
|
||||
"summer2022WaterspoutWarriorSet": "Wasserspeier (Krieger)",
|
||||
"summer2022WaterspoutWarriorSet": "Wasserspeier (Krieger)",
|
||||
"summer2022AngelfishHealerSet": "Kaiserfisch (Heiler)",
|
||||
"summer2022CrabRogueSet": "Krabbe (Schurke)",
|
||||
"summer2022CrabRogueSet": "Krabbe (Schurke)",
|
||||
"summer2022MantaRayMageSet": "Mantarochen (Magier)",
|
||||
"fall2022KappaRogueSet": "Kappa (Schurke)",
|
||||
"fall2022KappaRogueSet": "Kappa (Schurke)",
|
||||
"fall2022OrcWarriorSet": "Ork (Krieger)",
|
||||
"fall2022HarpyMageSet": "Harpyie (Magier)",
|
||||
"fall2022WatcherHealerSet": "Beobachter (Heiler)",
|
||||
@@ -213,7 +213,7 @@
|
||||
"winter2023WalrusWarriorSet": "Walross (Krieger)",
|
||||
"winter2023FairyLightsMageSet": "Feenlichter (Magier)",
|
||||
"winter2023CardinalHealerSet": "Kardinal (Heiler)",
|
||||
"anniversaryLimitedDates": "30. Januar bis 8. Februar",
|
||||
"anniversaryLimitedDates": "30. Januar bis 8. Februar",
|
||||
"limitedEvent": "Limitiertes Event",
|
||||
"winter2023RibbonRogueSet": "Schleife (Schurke)",
|
||||
"spring2024MeltingSnowRogueSet": "Schmelzendes Schnee Set (Schurke)",
|
||||
@@ -261,5 +261,9 @@
|
||||
"fourForFreeText": "Um die Party am Laufen zu halten, verschenken wir Party Gewänder, 20 Edelsteine, und eine limitierte Geburtstags-Hintergrund Ausgabe und ein Gegenstände Set, das ein Cape, ein Schulterstück und eine Augenmaske enthält.",
|
||||
"partyRobes": "Party Gewänder",
|
||||
"twentyGems": "20 Edelsteine",
|
||||
"dayOne": "Tag 1"
|
||||
"dayOne": "Tag 1",
|
||||
"summer2024WhaleSharkWarriorSet": "Walhai Set (Krieger)",
|
||||
"summer2024SeaAnemoneMageSet": "Seeanemonen Set (Magier)",
|
||||
"summer2024SeaSnailHealerSet": "Meeresschnecken Set (Heiler)",
|
||||
"summer2024NudibranchRogueSet": "Nacktkiemerschnecken Set (Schurke)"
|
||||
}
|
||||
|
||||
@@ -135,5 +135,7 @@
|
||||
"helpSupportHabitica": "Hilf Habitica zu unterstützen",
|
||||
"groupsPaymentSubBilling": "Dein nächstes Rechnungsdatum ist <strong><%= renewalDate %></strong>.",
|
||||
"groupsPaymentAutoRenew": "Dieses Abonnement läuft automatisch weiter, bis es gekündigt wird. Du kannst es im Gruppen-Abrechnungs-Tab kündigen.",
|
||||
"sellItems": "Items verkaufen"
|
||||
"sellItems": "Items verkaufen",
|
||||
"customizationsShopText": "Willst du deinen Style ändern? Hier bist du richtig! Wir haben die frischesten Looks, passend zur Saison, auf Lager.",
|
||||
"notAvailable": "Dieser Gegenstand ist nicht verfügbar."
|
||||
}
|
||||
|
||||
@@ -115,5 +115,6 @@
|
||||
"notEnoughFood": "Du hast nicht genug Futter",
|
||||
"invalidAmount": "Ungültige Menge Futter, positiver Integer benötigt",
|
||||
"jubilantGryphatrice": "Jubelnder Greifatrice",
|
||||
"veteranDragon": "Veterandrache"
|
||||
"veteranDragon": "Veterandrache",
|
||||
"veteranCactus": "Veterankaktus"
|
||||
}
|
||||
|
||||
@@ -772,5 +772,11 @@
|
||||
"questFungiDropFungiPotion": "Pilz Schlüpfelixier",
|
||||
"questFungiUnlockText": "Schaltet den Kauf von Pilz Schlüpfelixieren auf dem Marktplatz frei.",
|
||||
"questFungiNotes": "Es war ein verregneter Frühling in Habitica und der Boden um die Ställe ist schwammig und feucht. Du bemerkst, dass einige Pilze entlang den hölzernen Stallwänden und Zäunen aufgetaucht sind. Nebel hängt in der Luft, der die Sonne nicht so richtig durchscheinen lässt, und es fühlt sich ein wenig entmutigend an.<br><br>Durch den Nebel siehst du die Umrisse des April-Scherzkekses, der nicht so hüpfig ist wie sonst.<br><br>\"Ich hatte gehofft, euch allen ein paar köstliche Magische Pilz Schlüpfelixiere zu bringen, so dass ihr eure Pilzfreunde für immer von meinem Ehrentag fernhalten könnt,\" sagt er mit einem bedenklich ernsten Gesichtsausdruck. \"Aber dieser kalte Nebel macht mir echt zu schaffen, er lässt mich zu müde und trübselig fühlen, um meine gewohnte Magie zu wirken.\"<br><br>\"Oh nein, tut mir leid, das zu hören,\" sagst du, und bemerkst deine eigene, zunehmend düstere Stimmung. \"Dieser Nebel macht den Tag wirklich bedrückend. Ich frage mich, woher er kommt...\"<br><br>Ein tiefes Grollen ertönt über die Felder, und du siehst einen Umriss aus dem Nebel erscheinen. Erschrocken siehst du eine riesengroß und unglücklich aussehende Pilzkreatur, von welcher der Nebel auszuströmen scheint.<br><br>\"Aha,\" sagt der Scherzkeks, \"ich denke, dieser pilzige Kerl könnte der Ursprung unserer Niedergeschlagenheit sein. Lasst uns schauen, ob wir ein bisschen Freude für unseren Freund hier und für uns selbst herbeirufen können.\"",
|
||||
"questFungiCompletion": "Du und der April-Scherzkeks schaut einander mit einem Ausdruck der Erleichterung an, als sich der Pilz in den Wald zurückzieht.<br><br>\"Ah,\" ruft der Scherzkeks aus, \"das war eine wahre myzelische Melancholie. Ich bin froh, daß wir seine Laune verbessern konnten, und unsere eigene auch! Ich spüre meine Energie zurückkehren. Komm mit mir, und wir bringen zusammen diese Pilz Elixiere auf die Beine.\""
|
||||
"questFungiCompletion": "Du und der April-Scherzkeks schaut einander mit einem Ausdruck der Erleichterung an, als sich der Pilz in den Wald zurückzieht.<br><br>\"Ah,\" ruft der Scherzkeks aus, \"das war eine wahre myzelische Melancholie. Ich bin froh, daß wir seine Laune verbessern konnten, und unsere eigene auch! Ich spüre meine Energie zurückkehren. Komm mit mir, und wir bringen zusammen diese Pilz Elixiere auf die Beine.\"",
|
||||
"QuestGiraffeUnlockText": "Schält Giraffe Ei zum Kauf im Marktplatz frei.",
|
||||
"questChameleonText": "Das chaotische Chamäleon",
|
||||
"questChameleonBoss": "Chaotisches Chamäleon",
|
||||
"questChameleonDropChameleonEgg": "Chamäleon (Ei)",
|
||||
"QuestChameleonUnlockText": "Schält Chamäleon Eier zum Kauf im Marktplatz frei",
|
||||
"questGiraffeDropGiraffeEgg": "Giraffe (Ei)"
|
||||
}
|
||||
|
||||
@@ -240,5 +240,6 @@
|
||||
"mysterySet202303": "Mähniges Hauptfigur Set",
|
||||
"mysterySet202403": "Glückliches Legenden Set",
|
||||
"mysterySet202405": "Vergoldetes Drachen Set",
|
||||
"mysterySet202406": "Phantom-Seeräuber Set"
|
||||
"mysterySet202406": "Phantom-Seeräuber Set",
|
||||
"mysterySet202407": "Liebenswertes Axolotl Set"
|
||||
}
|
||||
|
||||
@@ -983,6 +983,14 @@
|
||||
"backgroundShellGateText": "Shell Gate",
|
||||
"backgroundShellGateNotes": "March through the decorated coral of a Shell Gate.",
|
||||
|
||||
"backgrounds072024": "SET 122: Released July 2024",
|
||||
"backgroundRiverBottomText": "River Bottom",
|
||||
"backgroundRiverBottomNotes": "Explore a River Bottom.",
|
||||
|
||||
"backgrounds082024": "SET 123: Released August 2024",
|
||||
"backgroundSavannaText": "Hazy Grasslands",
|
||||
"backgroundSavannaNotes": "Hike through Hazy Grasslands.",
|
||||
|
||||
"timeTravelBackgrounds": "Steampunk Backgrounds",
|
||||
"backgroundAirshipText": "Airship",
|
||||
"backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.",
|
||||
|
||||
@@ -255,6 +255,14 @@
|
||||
"questEggGiraffeMountText": "Giraffe",
|
||||
"questEggGiraffeAdjective": "a towering",
|
||||
|
||||
"questEggChameleonText": "Chameleon",
|
||||
"questEggChameleonMountText": "Chameleon",
|
||||
"questEggChameleonAdjective": "a chaotic",
|
||||
|
||||
"questEggCrabText": "Crab",
|
||||
"questEggCrabMountText": "Crab",
|
||||
"questEggCrabAdjective": "a fiddling",
|
||||
|
||||
"eggNotes": "Find a hatching potion to pour on this egg, and it will hatch into <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
|
||||
"hatchingPotionBase": "Base",
|
||||
|
||||
@@ -3,25 +3,35 @@
|
||||
"2b43f6": "Blue",
|
||||
"6bd049": "Green",
|
||||
"800ed0": "Purple",
|
||||
"98461a": "Skin Tone 6",
|
||||
"915533": "Skin Tone 1",
|
||||
"98461a": "Skin Tone 6",
|
||||
"allCustomizationsOwned": "You own all of these items. You can try them on by <a href=''>customizing your avatar</a>.",
|
||||
"allEquipmentOwned": "You own all of these items. You can find them in your <a href='/inventory/equipment'>Equipment</a>. Be sure to check back later for next month's options!",
|
||||
"aurora": "Aurora",
|
||||
"bear": "Bear",
|
||||
"black": "Black",
|
||||
"blond": "Blond",
|
||||
"blue": "Blue",
|
||||
"blueEarrings": "Blue Earrings",
|
||||
"blueFlower": "Blue Flower",
|
||||
"blunt": "Blunt",
|
||||
"braid": "Braid",
|
||||
"broad": "Broad",
|
||||
"brown": "Brown",
|
||||
"c06534": "Skin Tone 5",
|
||||
"c3e1dc": "Cyan",
|
||||
"cactus": "Cactus",
|
||||
"candycane": "Candy Cane",
|
||||
"candycorn": "Candy Corn",
|
||||
"checkNextMonth": "Be sure to check back later for next month's options!",
|
||||
"checkNextSeason": "Be sure to check back later for next season's options!",
|
||||
"clownfish": "Clownfish",
|
||||
"convict": "Referee",
|
||||
"cross": "Cross",
|
||||
"curly": "Curly",
|
||||
"curlyLong": "Curly Long",
|
||||
"curlyShort": "Curly Short",
|
||||
"customizationsNPC": "Felicitus Fennec",
|
||||
"d7a9f7": "Lavender",
|
||||
"dapper": "Dapper",
|
||||
"ddc994": "Skin Tone 2",
|
||||
@@ -43,18 +53,31 @@
|
||||
"ghost": "Ghost",
|
||||
"ghostwhite": "Ghost White",
|
||||
"goatee": "Goatee",
|
||||
"goldEarringLeft": "Gold Earring Left",
|
||||
"goldEarringRight": "Gold Earring Right",
|
||||
"goldEarrings": "Gold Earrings",
|
||||
"green": "Green",
|
||||
"greenEarrings": "Green Earrings",
|
||||
"greenFlower": "Green Flower",
|
||||
"halloween": "Halloween",
|
||||
"handleless_black": "Black Handleless",
|
||||
"handleless_blue": "Blue Handleless",
|
||||
"handleless_green": "Green Handleless",
|
||||
"handleless_pink": "Pink Handleless",
|
||||
"handleless_red": "Red Handleless",
|
||||
"handleless_yellow": "Yellow Handleless",
|
||||
"highPonytailLeft": "High Ponytail Left",
|
||||
"highPonytailRight": "High Ponytail Right",
|
||||
"holly": "Holly",
|
||||
"hollygreen": "Holly Green",
|
||||
"hoopEarrings": "Hoop Earrings",
|
||||
"horizon": "Horizon",
|
||||
"largeMustache": "Large Mustache",
|
||||
"lava": "Lava",
|
||||
"leftBun": "Left Bun",
|
||||
"lion": "Lion",
|
||||
"longBeard": "Long Beard",
|
||||
"lookingForMore": "Looking for more?",
|
||||
"merblue": "Merblue",
|
||||
"mergold": "Mergold",
|
||||
"mergreen": "Mergreen",
|
||||
@@ -63,8 +86,10 @@
|
||||
"midnight": "Midnight",
|
||||
"mohawk": "Mohawk",
|
||||
"monster": "Monster",
|
||||
"noItemsOwned": "You don't own any of these items",
|
||||
"ocean": "Ocean",
|
||||
"ogre": "Ogre",
|
||||
"orangeFlower": "Orange Flower",
|
||||
"orchid": "Orchid",
|
||||
"panda": "Panda",
|
||||
"pastelBlue": "Pastel Blue",
|
||||
@@ -81,6 +106,9 @@
|
||||
"pgreen": "Special Pastel Green",
|
||||
"pgreen2": "Pastel Green",
|
||||
"pig": "Pig",
|
||||
"pink": "Pink",
|
||||
"pinkEarrings": "Pink Earrings",
|
||||
"pinkFlower": "Pink Flower",
|
||||
"polar": "Polar",
|
||||
"ponytail": "Ponytail",
|
||||
"porange": "Special Pastel Orange",
|
||||
@@ -92,11 +120,14 @@
|
||||
"pumpkin": "Pumpkin",
|
||||
"pumpkin2": "Jack O' Lantern",
|
||||
"purple": "Purple",
|
||||
"purpleEarrings": "Purple Earrings",
|
||||
"purpleFlower": "Purple Flower",
|
||||
"pyellow": "Special Pastel Yellow",
|
||||
"pyellow2": "Pastel Yellow",
|
||||
"rainbow": "Rainbow",
|
||||
"red": "Red",
|
||||
"redblue": "Red and Blue",
|
||||
"redEarrings": "Red Earrings",
|
||||
"reptile": "Reptile",
|
||||
"rightBun": "Right Bun",
|
||||
"sandnsea": "Sand 'n' Sea",
|
||||
@@ -105,8 +136,10 @@
|
||||
"shadow2": "Shade",
|
||||
"shark": "Shark",
|
||||
"shortBeard": "Short Beard",
|
||||
"sideswept": "Sideswept",
|
||||
"skeleton": "Skeleton",
|
||||
"skeleton2": "Bones",
|
||||
"slim": "Slim",
|
||||
"smallMustache": "Small Mustache",
|
||||
"snowy": "Snowy",
|
||||
"straightLong": "Straight Long",
|
||||
@@ -121,21 +154,17 @@
|
||||
"tropicalwater": "Tropical Water",
|
||||
"TRUred": "Crimson",
|
||||
"updo": "Updo",
|
||||
"visitCustomizationsShop": "Head over to the <a href='/shops/customizations'>Customizations Shop</a> to browse the many ways you can customize your avatar!",
|
||||
"wavyLong": "Wavy Long",
|
||||
"wavyShort": "Wavy Short",
|
||||
"white": "White",
|
||||
"whiteEarrings": "White Earrings",
|
||||
"winternight": "Winter Night",
|
||||
"winterstar": "Winter Star",
|
||||
"wispy": "Wispy",
|
||||
"wolf": "Wolf",
|
||||
"yellow": "Yellow",
|
||||
"yellowFlower": "Yellow Flower",
|
||||
"zombie": "Zombie",
|
||||
"zombie2": "Undead",
|
||||
"allCustomizationsOwned": "You own all of these items. You can try them on by <a href=''>customizing your avatar</a>.",
|
||||
"checkNextMonth": "Be sure to check back later for next month's options!",
|
||||
"checkNextSeason": "Be sure to check back later for next season's options!",
|
||||
"noItemsOwned": "You don't own any of these items",
|
||||
"visitCustomizationsShop": "Head over to the <a href='/shops/customizations'>Customizations Shop</a> to browse the many ways you can customize your avatar!",
|
||||
"lookingForMore": "Looking for more?",
|
||||
"allEquipmentOwned": "You own all of these items. You can find them in your <a href='/inventory/equipment'>Equipment</a>. Be sure to check back later for next month's options!",
|
||||
"customizationsNPC": "Felicitus Fennec"
|
||||
"zombie2": "Undead"
|
||||
}
|
||||
@@ -562,6 +562,8 @@
|
||||
"weaponMystery202403Notes": "Carrying the biggest sword around is surely a way to create your own luck! Confers no benefit. March 2024 Subscriber Item.",
|
||||
"weaponMystery202404Text": "Mycelial Magus Staff",
|
||||
"weaponMystery202404Notes": "This staff will bestow upon you an ancient wisdom as ageless as the rocks and trees. Confers no benefit. April 2024 Subscriber Item.",
|
||||
"weaponMystery202408Text": "Arcane Aegis",
|
||||
"weaponMystery202408Notes": "A magic bubble shield that protects you from enemy spells or helps you float in the air or water. Confers no benefit. August 2024 Subscriber Item.",
|
||||
|
||||
"weaponMystery301404Text": "Steampunk Cane",
|
||||
"weaponMystery301404Notes": "Excellent for taking a turn about town. March 3015 Subscriber Item. Confers no benefit.",
|
||||
@@ -770,6 +772,10 @@
|
||||
"weaponArmoirePottersWheelNotes": "Throw some clay on this wheel and make a bowl or a mug or a vase or a slightly different bowl. If you're lucky, a ghost might visit while you create! Increases Perception by <%= per %>. Enchanted Armoire: Potter Set (Item 4 of 4).",
|
||||
"weaponArmoireShadyBeachUmbrellaText": "Beach Umbrella",
|
||||
"weaponArmoireShadyBeachUmbrellaNotes": "The shade of this rainbow-colored umbrella conceals you briefly from the day star and any unwanted bothers. Increases Perception by <%= per %>. Enchanted Armoire: Beachside Set (Item 3 of 4).",
|
||||
"weaponArmoireCorsairsBladeText": "Corsair’s Blade",
|
||||
"weaponArmoireCorsairsBladeNotes": "Whether you wield it to plunder or to protect, you can be glad you brought this fierce blade to sea with you. Just be sure to stow it safely when not in use. Increases Strength by <%= str %>. Enchanted Armoire: Corsair Set (Item 3 of 3)",
|
||||
"weaponArmoireDragonKnightsLanceText": "Dragon Knight Lance",
|
||||
"weaponArmoireDragonKnightsLanceNotes": "This red and silver lance has unseated many opponents from their mounts. Increases Constitution by <%= con %>. Enchanted Armoire: Dragon Knight Set (Item 3 of 3)",
|
||||
|
||||
"armor": "armor",
|
||||
"armorCapitalized": "Armor",
|
||||
@@ -1400,6 +1406,8 @@
|
||||
"armorMystery202401Notes": "These robes appear as delicate as crystal snowflakes, but will keep you plenty warm as you work your wintry magic. Confers no benefit. January 2024 Subscriber Item.",
|
||||
"armorMystery202406Text": "Phantom Buccaneer’s Attire",
|
||||
"armorMystery202406Notes": "Haunt your enemies with style and flair! Confers no benefit. June 2024 Subscriber Item.",
|
||||
"armorMystery202407Text": "Amiable Axolotl Suit",
|
||||
"armorMystery202407Notes": "Glide through lakes and canals with your sweeping pink tail! Confers no benefit. July 2024 Subscriber Item.",
|
||||
|
||||
"armorMystery301404Text": "Steampunk Suit",
|
||||
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
|
||||
@@ -1616,6 +1624,10 @@
|
||||
"armorArmoireYellowStripedSwimsuitNotes": "What could be more delightful than battling sea monsters on the beach? Increases Constitution by <%= con %>. Enchanted Armoire: Beachside Set (Item 1 of 4).",
|
||||
"armorArmoireBlueStripedSwimsuitText": "Blue Striped Swimsuit",
|
||||
"armorArmoireBlueStripedSwimsuitNotes": "What could be more exciting than battling sea monsters on the beach? Increases Constitution by <%= con %>. Enchanted Armoire: Beachside Set (Item 2 of 4).",
|
||||
"armorArmoireCorsairsCoatAndCapeText": "Corsair’s Coat and Cape",
|
||||
"armorArmoireCorsairsCoatAndCapeNotes": "Whether you’re biding your time on the docks or watching for danger on the open seas, these will surely keep you feeling dry and looking dramatic. Just keep your balance on deck. Increases Constitution by <%= con %>. Enchanted Armoire: Corsair Set (Item 1 of 3)",
|
||||
"armorArmoireDragonKnightsArmorText": "Dragon Knight Armor",
|
||||
"armorArmoireDragonKnightsArmorNotes": "Channel the strength and power of a dragon with this armor made of silver and shed scales. Increases Strength by <%= str %>. Enchanted Armoire: Dragon Knight Set (Item 2 of 3)",
|
||||
|
||||
"headgear": "helm",
|
||||
"headgearCapitalized": "Headgear",
|
||||
@@ -2279,6 +2291,8 @@
|
||||
"headMystery202404Notes": "This hat will connect you with the earth and allow you to hear secret wishes from many creatures. Confers no benefit. April 2024 Subscriber Item.",
|
||||
"headMystery202406Text": "Phantom Buccaneer’s Hat",
|
||||
"headMystery202406Notes": "The ghostly feathers that adorn this hat glow faintly, like the waves of a spectral sea. Confers no benefit. June 2024 Subscriber Item.",
|
||||
"headMystery202407Text": "Amiable Axolotl Hood",
|
||||
"headMystery202407Notes": "These magical gills will let you breathe underwater! Confers no benefit. July 2024 Subscriber Item.",
|
||||
|
||||
"headMystery301404Text": "Fancy Top Hat",
|
||||
"headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.",
|
||||
@@ -2475,6 +2489,10 @@
|
||||
"headArmoireHattersTopHatNotes": "Our hats are off to you, and yours is on! What’s hidden in your hat is anybody’s guess (but we’re hoping it’s a bunny). Increases Perception by <%= per %>. Enchanted Armoire: Hatter Set (Item 1 of 4).",
|
||||
"headArmoirePottersBandanaText": "Bandana",
|
||||
"headArmoirePottersBandanaNotes": "Look the part and keep your hair out of your face while you work. It’s a win-win! Increases Intelligence by <%= int %>. Enchanted Armoire: Potter Set (Item 2 of 4).",
|
||||
"headArmoireCorsairsBandanaText": "Corsair’s Bandana",
|
||||
"headArmoireCorsairsBandanaNotes": "Whether you’re keeping your head covered in case a seagull flies overhead or making sure your foes never see you sweat, this bandana is essential. Just add a decorative bead for every adventure you complete. Increases Intelligence by <%= int %>. Enchanted Armoire: Corsair Set (Item 2 of 3)",
|
||||
"headArmoireDragonKnightsHelmText": "Dragon Knight Helm",
|
||||
"headArmoireDragonKnightsHelmNotes": "With the fiery features on this helmet, dragons might mistake you for one of their own. Increases Intelligence by <%= int %>. Enchanted Armoire: Dragon Knight Set (Item 1 of 3)",
|
||||
|
||||
"offhand": "off-hand item",
|
||||
"offHandCapitalized": "Off-Hand Item",
|
||||
@@ -2773,6 +2791,8 @@
|
||||
"shieldMystery202011Notes": "Harness the power of the autumn wind with this staff. Use for arcane magic or to make awesome leaf piles, the choice is yours! Confers no benefit. November 2020 Subscriber Item.",
|
||||
"shieldMystery202209Text": "Mound o' Magic Books",
|
||||
"shieldMystery202209Notes": "Building your sorcery knowledge takes a lot of reading, but you're sure to enjoy your education. Confers no benefit. September 2022 Subscriber Item.",
|
||||
"shieldMystery202408Text": "Arcane Sparkles",
|
||||
"shieldMystery202408Notes": "Magic lights will illuminate the inside of your bubble hideout, or anywhere else you need a little light! Confers no benefit. August 2024 Subscriber Item.",
|
||||
"shieldMystery301405Text": "Clock Shield",
|
||||
"shieldMystery301405Notes": "Time is on your side with this towering clock shield! Confers no benefit. June 3015 Subscriber Item.",
|
||||
"shieldMystery301704Text": "Fluttery Fan",
|
||||
|
||||
@@ -576,7 +576,7 @@
|
||||
"questMayhemMistiflying3DropWeapon": "Roguish Rainbow Message (Main-Hand Item)",
|
||||
|
||||
"featheredFriendsText": "Feathered Friends Quest Bundle",
|
||||
"featheredFriendsNotes": "Contains 'Help! Harpy!', 'The Night-Owl', and 'The Birds of Preycrastination'.",
|
||||
"featheredFriendsNotes": "Contains Quests to obtain Owl, Parrot, and Hawk Pet eggs: The Night-Owl, Help! Harpy!, and The Birds of Preycrastination.",
|
||||
|
||||
"questNudibranchText": "Infestation of the NowDo Nudibranchs",
|
||||
"questNudibranchNotes": "You finally get around to checking your To Do's on a lazy day in Habitica. Bright against your deepest red tasks are a gaggle of vibrant blue sea slugs. You are entranced! Their sapphire colors make your most intimidating tasks look as easy as your best Habits. In a feverish stupor you get to work, tackling one task after the other in a ceaseless frenzy...<br><br>The next thing you know, @LilithofAlfheim is pouring cold water over you. “The NowDo Nudibranchs have been stinging you all over! You need to take a break!”<br><br>Shocked, you see that your skin is as bright red as your To Do list was. \"Being productive is one thing,\" @beffymaroo says, \"but you've also got to take care of yourself. Hurry, let's get rid of them!\"",
|
||||
@@ -586,7 +586,7 @@
|
||||
"questNudibranchUnlockText": "Unlocks Nudibranch Eggs for purchase in the Market",
|
||||
|
||||
"splashyPalsText": "Splashy Pals Quest Bundle",
|
||||
"splashyPalsNotes": "Contains 'The Dilatory Derby', 'Guide the Turtle', and 'Wail of the Whale'.",
|
||||
"splashyPalsNotes": "Contains Quests to obtain Turtle, Whale, and Seahorse Pet eggs: Guide the Turtle, Wail of the Whale, and The Dilatory Derby.",
|
||||
|
||||
"questHippoText": "What a Hippo-Crite",
|
||||
"questHippoNotes": "You and @awesomekitty collapse into the shade of a palm tree, exhausted. The sun beats down over the Sloensteadi Savannah, scorching the ground below. It’s been a productive day so far, conquering your Dailies, and this oasis looks like a nice place to take a break and refresh. Stooping near the water to get a drink, you stumble back in shock as a massive hippopotamus rises. “Resting so soon? Don’t be so lazy, get back to work.” You try and protest that you’ve been working hard and need a break, but the hippo isn’t having any of it.<br><br>@khdarkwolf whispers to you, “Notice how it’s lounging around all day but has the nerve to call you lazy? It’s the Hippo-Crite!”<br><br>Your friend @jumorales nods. “Let’s show it what hard work looks like!”",
|
||||
@@ -596,10 +596,10 @@
|
||||
"questHippoUnlockText": "Unlocks Hippo Eggs for purchase in the Market",
|
||||
|
||||
"farmFriendsText": "Farm Friends Quest Bundle",
|
||||
"farmFriendsNotes": "Contains 'The Mootant Cow', 'Ride the Night-Mare', and 'The Thunder Ram'.",
|
||||
"farmFriendsNotes": "Contains Quests to obtain Horse, Sheep, and Cow Pet eggs: Ride the Night-Mare, The Thunder Ram, and The Mootant Cow.",
|
||||
|
||||
"witchyFamiliarsText": "Witchy Familiars Quest Bundle",
|
||||
"witchyFamiliarsNotes": "Contains 'The Rat King', 'The Icy Arachnid', and 'Swamp of the Clutter Frog'.",
|
||||
"witchyFamiliarsNotes": "Contains Quests to obtain Frog, Spider, and Rat Pet eggs: Swamp of the Clutter Frog, The Icy Arachnid, and The Rat King.",
|
||||
|
||||
"questGroupLostMasterclasser": "Mystery of the Masterclassers",
|
||||
"questUnlockLostMasterclasser": "To unlock this quest, complete the final quests of these quest chains: 'Dilatory Distress', 'Mayhem in Mistiflying', 'Stoïkalm Calamity', and 'Terror in the Taskwoods'.",
|
||||
@@ -650,7 +650,7 @@
|
||||
"questYarnUnlockText": "Unlocks Yarn Eggs for purchase in the Market",
|
||||
|
||||
"winterQuestsText": "Winter Quest Bundle",
|
||||
"winterQuestsNotes": "Contains 'Trapper Santa', 'Find the Cub', and 'The Fowl Frost'. Note that Trapper Santa and Find the Cub have stackable quest achievements but give a rare pet and mount that can only be obtained once each.",
|
||||
"winterQuestsNotes": "Contains Quests to obtain the Polar Bear Pet, the Polar Bear Mount, and Penguin Pet eggs: Find the Cub, Trapper Santa, and The Fowl Frost.",
|
||||
|
||||
"questPterodactylText": "The Pterror-dactyl",
|
||||
"questPterodactylNotes": "You're taking a stroll along the peaceful Stoïkalm Cliffs when an evil screech rends the air. You turn to find a hideous creature flying towards you and are overcome by a powerful terror. As you turn to flee, @Lilith of Alfheim grabs you. \"Don't panic! It's just a Pterror-dactyl.\"<br><br>@Procyon P nods. \"They nest nearby, but they're attracted to the scent of negative Habits and undone Dailies.\"<br><br>\"Don't worry,\" @Katy133 says. \"We just need to be extra productive to defeat it!\" You are filled with a renewed sense of purpose and turn to face your foe.",
|
||||
@@ -689,7 +689,7 @@
|
||||
"dysheartenerArtCredit": "Artwork by @AnnDeLune",
|
||||
|
||||
"hugabugText": "Hug a Bug Quest Bundle",
|
||||
"hugabugNotes": "Contains 'The CRITICAL BUG', 'The Snail of Drudgery Sludge', and 'Bye, Bye, Butterfry'.",
|
||||
"hugabugNotes": "Contains Quests to obtain Beetle, Caterpillar, and Snail Pet eggs: The CRITICAL BUG, Bye Bye Butterfry, and The Snail of Drudgery Sludge.",
|
||||
|
||||
"questSquirrelText": "The Sneaky Squirrel",
|
||||
"questSquirrelNotes": "You wake up and find you’ve overslept! Why didn’t your alarm go off? … How did an acorn get stuck in the ringer?<br><br>When you try to make breakfast, the toaster is stuffed with acorns. When you go to retrieve your mount, @Shtut is there, trying unsuccessfully to unlock their stable. They look into the keyhole. “Is that an acorn in there?”<br><br>@randomdaisy cries out, “Oh no! I knew my pet squirrels had gotten out, but I didn’t know they’d made such trouble! Can you help me round them up before they make any more of a mess?”<br><br>Following the trail of mischievously placed oak nuts, you track and catch the wayward sciurines, with @Cantras helping secure each one safely at home. But just when you think your task is almost complete, an acorn bounces off your helm! You look up to see a mighty beast of a squirrel, crouched in defense of a prodigious pile of seeds.<br><br>“Oh dear,” says @randomdaisy, softly. “She’s always been something of a resource guarder. We’ll have to proceed very carefully!” You circle up with your party, ready for trouble!",
|
||||
@@ -699,10 +699,10 @@
|
||||
"questSquirrelUnlockText": "Unlocks Squirrel Eggs for purchase in the Market",
|
||||
|
||||
"cuddleBuddiesText": "Cuddle Buddies Quest Bundle",
|
||||
"cuddleBuddiesNotes": "Contains 'The Killer Bunny', 'The Nefarious Ferret', and 'The Guinea Pig Gang'.",
|
||||
"cuddleBuddiesNotes": "Contains Quests to obtain Rabbit, Ferret, and Guinea Pig Pet eggs: The Killer Bunny, The Nefarious Ferret, and The Guinea Pig Gang.",
|
||||
|
||||
"aquaticAmigosText": "Aquatic Amigos Quest Bundle",
|
||||
"aquaticAmigosNotes": "Contains 'The Magical Axolotl', 'The Kraken of Inkomplete', and 'The Call of Octothulu'.",
|
||||
"aquaticAmigosNotes": "Contains Quests to obtain Cuttlefish, Octopus, and Axolotl Pet eggs: The Kraken of Inkomplete, The Call of Octothulu, and The Magical Axolotl.",
|
||||
|
||||
"questSeaSerpentText": "Danger in the Depths: Sea Serpent Strike!",
|
||||
"questSeaSerpentNotes": "Your streaks have you feeling lucky—it’s the perfect time for a trip to the seahorse racetrack. You board the submarine at Diligent Docks and settle in for the trip to Dilatory, but you’ve barely submerged when an impact rocks the sub, sending its occupants tumbling. “What’s going on?” @AriesFaries shouts.<br><br>You glance through a nearby porthole and are shocked by the wall of shimmering scales passing by it. “Sea serpent!” Captain @Witticaster calls through the intercom. “Brace yourselves, it’s coming ‘round again!” As you grip the arms of your seat, your unfinished tasks flash before your eyes. ‘Maybe if we work together and complete them,’ you think, ‘we can drive this monster away!’",
|
||||
@@ -719,7 +719,7 @@
|
||||
"questKangarooUnlockText": "Unlocks Kangaroo Eggs for purchase in the Market",
|
||||
|
||||
"forestFriendsText": "Forest Friends Quest Bundle",
|
||||
"forestFriendsNotes": "Contains 'The Spirit of Spring', 'The Hedgebeast', and 'The Tangle Tree'.",
|
||||
"forestFriendsNotes": "Contains Quests to obtain Treeling, Deer, and Hedgehog Pet eggs: The Tangle Tree, The Spirit of Spring, and The Hedgebeast.",
|
||||
|
||||
"questAlligatorText": "The Insta-Gator",
|
||||
"questAlligatorNotes": "“Crikey!” exclaims @gully. “An Insta-Gator in its natural habitat! Careful, it distracts its prey with things that seem urgent THIS INSTANT, and it feeds on the unchecked Dailies that result.” You fall silent to avoid attracting its attention, but to no avail. The Insta-Gator spots you and charges! Distracting voices rise up from Swamps of Stagnation, grabbing for your attention: “Read this post! See this photo! Pay attention to me THIS INSTANT!” You scramble to mount a counterattack, completing your Dailies and bolstering your good Habits to fight off the dreaded Insta-Gator.",
|
||||
@@ -729,10 +729,10 @@
|
||||
"questAlligatorUnlockText": "Unlocks Alligator Eggs for purchase in the Market",
|
||||
|
||||
"oddballsText": "Oddballs Quest Bundle",
|
||||
"oddballsNotes": "Contains 'The Jelly Regent', 'Escape the Cave Creature', and 'A Tangled Yarn'.",
|
||||
"oddballsNotes": "Contains Quests to obtain Slime, Yarn, and Rock Pet eggs: The Jelly Regent, A Tangled Yarn, and Escape the Cave Creature.",
|
||||
|
||||
"birdBuddiesText": "Bird Buddies Quest Bundle",
|
||||
"birdBuddiesNotes": "Contains 'The Fowl Frost', 'Rooster Rampage', and 'The Push-and-Pull Peacock'.",
|
||||
"birdBuddiesNotes": "Contains Quests to obtain Peacock, Penguin, and Rooster Pet eggs: The Push-and-Pull Peacock, The Fowl Frost, and Rooster Rampage.",
|
||||
|
||||
"questVelociraptorText": "The Veloci-Rapper",
|
||||
"questVelociraptorNotes": "You’re sharing honey cakes with @*~Seraphina~*, @Procyon P, and @Lilith of Alfheim by a lake in the Stoïkalm Steppes. Suddenly, a mournful voice interrupts your picnic.<br><br><em>My Habits took a hit, I missed my Dailies,<br>I’m losing it, sinking with doubt and maybes,<br>At the top of my game I used to be so fly,<br>But now I just let my Due Dates go by.</em><br><br>@*~Seraphina~* peers behind a stand of grass. “It’s the Veloci-Rapper. It seems... distraught?”<br><br>You pump a fist in determination. “There's only one thing to do. Rap battle time!”",
|
||||
@@ -742,7 +742,7 @@
|
||||
"questVelociraptorUnlockText": "Unlocks Velociraptor Eggs for purchase in the Market",
|
||||
|
||||
"mythicalMarvelsText": "Mythical Marvels Quest Bundle",
|
||||
"mythicalMarvelsNotes": "Contains 'Convincing the Unicorn Queen', 'The Fiery Gryphon', and 'Danger in the Depths: Sea Serpent Strike!'",
|
||||
"mythicalMarvelsNotes": "Contains Quests to obtain Unicorn, Gryphon, and Sea Serpent Pet eggs: Convincing the Unicorn Queen, The Fiery Gryphon, and Danger in the Depths: Sea Serpent Strike!",
|
||||
|
||||
"questBronzeText": "Brazen Beetle Battle",
|
||||
"questBronzeNotes": "On a refreshing break between tasks, you and some friends take a stroll through the forest trails of the Taskwoods. You come upon a large hollow log and a sparkle from inside catches your attention.<br><br>Why, it's a cache of Magic Hatching Potions! The shimmering bronze liquid swirls gently in the bottles, and @Hachiseiko reaches to pick one up to examine it.<br><br>“Halt!” hisses a voice from behind you. It's a gigantic beetle with a carapace of gleaming bronze, raising her clawed feet in a fighting stance. “Those are my potions, and if you wish to earn them, you must prove yourself in a gentlefolks' duel!”",
|
||||
@@ -777,10 +777,10 @@
|
||||
"questRobotUnlockText": "Unlocks purchasable Robot Eggs in the Market",
|
||||
|
||||
"rockingReptilesText": "Rocking Reptiles Quest Bundle",
|
||||
"rockingReptilesNotes": "Contains 'The Insta-Gator', 'The Serpent of Distraction', and 'The Veloci-Rapper'.",
|
||||
"rockingReptilesNotes": "Contains Quests to obtain Alligator, Velociraptor, and Snake Pet eggs: The Insta-Gator, The Veloci-Rapper, and The Serpent of Distraction.",
|
||||
|
||||
"delightfulDinosText": "Delightful Dinos Quest Bundle",
|
||||
"delightfulDinosNotes": "Contains 'The Pterror-dactyl', 'The Trampling Triceratops', and 'The Dinosaur Unearthed'.",
|
||||
"delightfulDinosNotes": "Contains Quests to obtain Triceratops, T-Rex, and Pterodactyl Pet eggs: The Trampling Triceratops, The Dinosaur Unearthed, and The Pterror-dactyl.",
|
||||
|
||||
"questAmberText": "The Amber Alliance",
|
||||
"questAmberNotes": "You’re sitting in the Tavern with @beffymaroo and @-Tyr- when @Vikte bursts through the door and excitedly tells you about the rumors of another type of Magic Hatching Potion hidden in the Taskwoods. Having completed your Dailies, the three of you immediately agree to help @Vikte on their search. After all, what’s the harm in a little adventure?<br><br>After walking through the Taskwoods for hours, you’re beginning to regret joining such a wild chase. You’re about to head home, when you hear a surprised yelp and turn to see a huge lizard with shiny amber scales coiled around a tree, clutching @Vikte in her claws. @beffymaroo reaches for her sword.<br><br>“Wait!” cries @-Tyr-. “It’s the Trerezin! She’s not dangerous, just dangerously clingy!”",
|
||||
@@ -809,7 +809,7 @@
|
||||
"questWaffleUnlockText": "Unlocks Confection Hatching Potions for purchase in the Market",
|
||||
|
||||
"jungleBuddiesText": "Jungle Buddies Quest Bundle",
|
||||
"jungleBuddiesNotes": "Contains 'Monstrous Mandrill and the Mischief Monkeys', 'The Somnolent Sloth', and 'The Tangle Tree'.",
|
||||
"jungleBuddiesNotes": "Contains Quests to obtain Monkey, Treeling, and Sloth Pet eggs: Monstrous Mandrill and the Mischief Monkeys, The Tangle Tree, and The Somnolent Sloth.",
|
||||
|
||||
"questFluoriteText": "A Bright Fluorite Fright",
|
||||
"questFluoriteNotes": "Unusual minerals are in high demand these days, so you and a few friends have trekked deep into the mines of the Meandering Mountains, in search of exciting ores. It’s a long and boring expedition, until @-Tyr- stumbles over a large rock, sitting right in the middle of the tunnel.<br><br>“This should help brighten things up,” says @nirbhao, before conjuring up an orb of light.<br><br>A warm brightness fills the tunnel, but something odd starts happening to that large rock. Feeding on the magical light, it begins to glow with fluorescent blues, greens and purples. Then it rears upright into a vaguely humanoid shape, complete with glowing red eyes fixed right on you! You jump into action with flashing spells and shining weapons.",
|
||||
@@ -835,7 +835,7 @@
|
||||
"questTurquoiseUnlockText": "Unlocks Turquoise Hatching Potions for purchase in the Market",
|
||||
|
||||
"sandySidekicksText": "Sandy Sidekicks Quest Bundle",
|
||||
"sandySidekicksNotes": "Contains 'The Indulgent Armadillo', 'The Serpent of Distraction', and 'The Icy Arachnid'.",
|
||||
"sandySidekicksNotes": "Contains Quests to obtain Spider, Armadillo, and Snake Pet eggs: The Icy Arachnid, The Indulgent Armadillo, and The Serpent of Distraction.",
|
||||
|
||||
"questBlackPearlText": "A Startling Starry Idea",
|
||||
"questBlackPearlNotes": "You’ve been feeling uninspired lately, so when @jjgame83 suggests a trip to Lively Lake, you jump at the chance for a change of scenery. As @QuartzFox lays out a picnic on the shore, you find something glinting in the shallows. A strange black pearl.<br><br>“I wish I had a new idea,” you sigh.<br><br>A chill washes over the shore. The lake turns to black ink. The stars rise as noon becomes midnight in a heartbeat.<br><br>“Those aren’t good signs,” says @PixelStormArt.<br><br>A towering mass of arms bursts from the lake in a spray of foam, and from its beak, it booms: “BEHOLD ASTEROIDEA, THE IDEA FROM BEYOND THE STARS!”<br><br>A tentacle slams down onto the picnic basket. Good idea or not, you leap into action.",
|
||||
@@ -887,15 +887,31 @@
|
||||
"questPinkMarbleRageDescription": "This bar fills when you don't complete your Dailies. When it is full, Cupido will take away some of your party's pending damage!",
|
||||
"questPinkMarbleRageEffect": "`Cupido uses Pink Punch!` That wasn't affectionate at all! Your partymates are taken aback. Pending damage reduced.",
|
||||
"questPinkMarbleDropPinkMarblePotion": "Pink Marble Hatching Potion",
|
||||
"QuestPinkMarbleUnlockText": "Unlocks Pink Marble Hatching Potions for purchase in the Market.",
|
||||
"questPinkMarbleUnlockText": "Unlocks Pink Marble Hatching Potions for purchase in the Market.",
|
||||
|
||||
"questGiraffeText": "The Gear-affe",
|
||||
"questGiraffeNotes": "You’re strolling across the tall grass of the Sloenstedi Savannah, enjoying a nice walk in nature as a break from your tasks. As you pass through the rolling landscape, you notice a collection of items in the distance. It’s a pile of musical instruments, art supplies, electronic equipment, and more! You venture near for a better look.<br><br>“Hey, what do you think you’re doing?” yells a voice from behind an acacia. A tall and imposing giraffe emerges, wearing a fancy pair of shades. a guitar, and a fancy camera around its long neck. “This is all my gear, be careful and don’t touch anything!”<br><br>You notice dust on many of the items. “Wow, you sure have a lot of hobbies!” you say. “Can you show me some art or play me a tune?”<br><br>The giraffe’s face falls as he looks at all his supplies. “I have so much of this stuff but don’t know where to begin! Why don't you give me some of your motivation so I can have the productive energy I need to finally get started!”",
|
||||
"questGiraffeCompletion": "After helping the Gear-Affe with some basic organization of his stash, you’re both feeling more energized and upbeat!<br><br>He grabs his guitar and a book of beginner exercises and strums a few notes. “It feels good to take a step in the right direction, even a small one. Thanks for helping me out! Take these, I hear you have a stash of pets and these fellas could be a nice addition!”",
|
||||
"questGiraffeBoss": "Gear-affe",
|
||||
"questGiraffeDropGiraffeEgg": "Giraffe (Egg)",
|
||||
"QuestGiraffeUnlockText": "Unlocks Giraffe Eggs for purchase in the Market.",
|
||||
"questPinkMarbleUnlockText": "Unlocks Pink Marble Hatching Potions for purchase in the Market.",
|
||||
"questGiraffeUnlockText": "Unlocks Giraffe Eggs for purchase in the Market.",
|
||||
|
||||
"questChameleonText": "The Chaotic Chameleon",
|
||||
"questChameleonNotes": "It’s a beautiful day in a warm, rainy corner of the Taskwoods. You’re on the hunt for new additions to your leaf collection when a branch in front of you changes color without warning! Then it moves!<br><br>Stumbling backwards, you realize this is not a branch at all, but a huge chameleon! Each part of his body keeps changing colors as his eyes dart in different directions.<br><br>“Are you all right?” you ask the chameleon.<br><br>“Ahhh, well,” he says, looking a little flustered. “I’ve been trying to blend in… but it’s so overwhelming… the colors keep coming and going! It’s hard to focus on just one....”<br><br>“Aha,” you say, “I think I can help. We’ll sharpen your focus with a little challenge! Get your colors ready!”<br><br>“You’re on!” replied the chameleon.",
|
||||
"questChameleonCompletion": "After a few lively turns the Chameleon went through every color of the rainbow, perfectly matching each color you requested.<br><br>“Wow,” he says, “working together and making it into a game really helped me concentrate! Please take these as a reward, you’re earned them! Teach these little guys how to change all the colors of the rainbow when they hatch.”",
|
||||
"questChameleonBoss": "Chaotic Chameleon",
|
||||
"questChameleonDropChameleonEgg": "Chameleon (Egg)",
|
||||
"questChameleonUnlockText": "Unlocks Chameleon Eggs for purchase in the Market",
|
||||
|
||||
"questCrabText": "The Fiddling Crab",
|
||||
"questCrabNotes": "It’s a warm sunny morning, and you’re enjoying a visit to the beach to catch up on some of the books on your summer reading list. You’re startled when you nearly step on a shiny crystal near a shallow hole in the sand.<br><br>“Ey, watch where you’re goin’! I’m makin’ a burrow here!” says a voice. A surprisingly large crab with a decorative shell runs out in front of your toes, snapping her claw as she speaks.<br><br>“Hm, is this a burrow?” you ask, looking at the shallow depression. There are shells and crystals arranged around it, but it’s not much in the way of a hiding place.<br><br>The crab stammers. \"Ey, this is a judgment free zone! I'm gettin' to it, I'm gettin' to it... I just got caught up on decorating. Sometimes a crab's gotta fiddle,\" she says, adjusting a shell.<br><br>\"Why don't you lend a claw and help if you've got some big ideas on what a burrow should look like?\"",
|
||||
"questCrabCompletion": "You and the crab figure out how to work together to get everything in just the right place, ending up with a fine sandy burrow. The crab happily nestles in.<br><br>\"Thank ya!\" she says, making herself comfy. \"Now this is a hole that's made just for me. I can finally enjoy all my perfectly placed decorations. Here, take these lil guys as a token of my appreciation. It's an offer you can't refuse!\"",
|
||||
"questCrabBoss": "Fiddling Crab",
|
||||
"questCrabRageTitle": "Distracting Fiddling",
|
||||
"questCrabRageDescription": "This bar fills when you don't complete your Dailies. When it's full, the Fiddling Crab will take away some of your party's MP!",
|
||||
"questCrabRageEffect": "The Fiddling Crab distracts you with decorating, slowing your work on digging and draining some of your magic. The party's MP is reduced!",
|
||||
"questCrabDropCrabEgg": "Crab (Egg)",
|
||||
"questCrabUnlockText": "Unlocks Crab Eggs for purchase in the Market.",
|
||||
|
||||
"questFungiText": "The Moody Mushroom",
|
||||
"questFungiNotes": "It’s been a rainy spring in Habitica and the ground around the stables is spongy and damp. You notice quite a few mushrooms have appeared along the wooden stable walls and fences. There’s a fog hanging about, not quite letting the sun peek through, and it’s a bit dispiriting.<br><br>Out of the mist you see the outline of the April Fool, not at all his usual bouncy self.<br><br>”I’d hoped to bring you all some delightful Fungi Magic Hatching Potions so that you can keep your mushroom friends from my special day forever,” he says, his expression alarmingly unsmiling. “But this cold fog is really getting to me, it’s making me feel too tired and dismal to work my usual magic.”<br><br>“Oh no, sorry to hear that,” you say, noticing your own increasingly somber mood. “This fog is really making the day gloomy. I wonder where it came from…”<br><br>A low rumble sounds across the fields, and you see an outline emerging from the mist. You’re alarmed to see a gigantic and unhappy looking mushroom creature, and the mist appears to be emanating from it.<br><br>“Aha,” says the Fool, “I think this fungal fellow may be the source of our blues. Let’s see if we can summon a little cheer for our friend here and ourselves.”",
|
||||
|
||||