Compare commits
1 Commits
v5.42.2
...
phillip/gu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b39d41ace6 |
@@ -80,7 +80,7 @@ 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 filter = require('gulp-filter').default;
|
||||
|
||||
const f = filter(filterFile);
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ export default async function processUsers () {
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1]._id,
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
15384
package-lock.json
generated
12
package.json
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "5.42.2",
|
||||
"version": "5.40.1",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
"@babel/preset-env": "^7.22.10",
|
||||
"@babel/register": "^7.22.15",
|
||||
"@google-analytics/data": "^4.12.1",
|
||||
"@google-cloud/trace-agent": "^7.1.2",
|
||||
"@parse/node-apn": "^5.2.3",
|
||||
"@slack/webhook": "^6.1.0",
|
||||
@@ -34,10 +35,9 @@
|
||||
"firebase-admin": "^12.1.1",
|
||||
"glob": "^8.1.0",
|
||||
"got": "^11.8.6",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp": "5.0.1",
|
||||
"gulp-babel": "^8.0.0",
|
||||
"gulp-filter": "^7.0.0",
|
||||
"gulp-imagemin": "^7.1.0",
|
||||
"gulp-filter": "^9.0.0",
|
||||
"gulp.spritesmith": "^6.13.0",
|
||||
"habitica-markdown": "^3.0.0",
|
||||
"helmet": "^4.6.0",
|
||||
@@ -105,8 +105,8 @@
|
||||
"start": "node --watch ./website/server/index.js",
|
||||
"start:simple": "node ./website/server/index.js",
|
||||
"debug": "node --watch --inspect ./website/server/index.js",
|
||||
"mongo:dev": "run-rs -v 7.0.23 -l ubuntu2214 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"mongo:test": "run-rs -v 7.0.23 -l ubuntu2214 --keep --dbpath mongodb-data-testing --number 1 --quiet",
|
||||
"mongo:dev": "run-rs -v 7.0.23 -l ubuntu2204 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"mongo:test": "run-rs -v 7.0.23 -l ubuntu2204 --keep --dbpath mongodb-data-testing --number 1 --quiet",
|
||||
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
|
||||
"apidoc": "gulp apidoc",
|
||||
"heroku-postbuild": ".heroku/report_deploy.sh"
|
||||
|
||||
@@ -150,7 +150,7 @@ describe('emails', () => {
|
||||
|
||||
sendTxn(mailingInfo, emailType);
|
||||
expect(got.post).to.be.called;
|
||||
expect(got.post).to.be.calledWith('http://example.com/job', sinon.match({
|
||||
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
|
||||
json: {
|
||||
data: {
|
||||
emailType: sinon.match.same(emailType),
|
||||
@@ -234,7 +234,7 @@ describe('emails', () => {
|
||||
|
||||
sendTxn(mailingInfo, emailType);
|
||||
expect(got.post).to.be.called;
|
||||
expect(got.post).to.be.calledWith('http://example.com/job', sinon.match({
|
||||
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
|
||||
json: {
|
||||
data: {
|
||||
emailType: sinon.match.same(emailType),
|
||||
@@ -254,7 +254,7 @@ describe('emails', () => {
|
||||
|
||||
sendTxn(mailingInfo, emailType, variables);
|
||||
expect(got.post).to.be.called;
|
||||
expect(got.post).to.be.calledWith('http://example.com/job', sinon.match({
|
||||
expect(got.post).to.be.calledWith('undefined/job', sinon.match({
|
||||
json: {
|
||||
data: {
|
||||
variables: sinon.match(value => value[0].name === 'BASE_URL', 'matches variables'),
|
||||
|
||||
@@ -47,12 +47,6 @@ describe('highlightMentions', () => {
|
||||
expect(result[0]).to.equal('[@user-dash](/profile/444): message [@user_underscore](/profile/555)');
|
||||
});
|
||||
|
||||
it('highlights users with case-insensitive matching', async () => {
|
||||
const text = '@USER: message @User2 @USER3';
|
||||
const result = await highlightMentions(text);
|
||||
expect(result[0]).to.equal('[@USER](/profile/111): message [@User2](/profile/222) [@USER3](/profile/333)');
|
||||
});
|
||||
|
||||
it('doesn\'t highlight nonexisting users', async () => {
|
||||
const text = '@nouser message';
|
||||
const result = await highlightMentions(text);
|
||||
|
||||
@@ -12,33 +12,11 @@ const { i18n } = common;
|
||||
describe('Apple Payments', () => {
|
||||
const subKey = 'basic_3mo';
|
||||
|
||||
let iapSetupStub;
|
||||
let iapValidateStub;
|
||||
let iapIsValidatedStub;
|
||||
let iapIsCanceledStub;
|
||||
let iapIsExpiredStub;
|
||||
let paymentBuySkuStub;
|
||||
let iapGetPurchaseDataStub;
|
||||
let validateGiftMessageStub;
|
||||
let paymentsCreateSubscritionStub;
|
||||
|
||||
beforeEach(() => {
|
||||
iapSetupStub = sinon.stub(iap, 'setup').resolves();
|
||||
iapValidateStub = sinon.stub(iap, 'validate').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.isExpired.restore();
|
||||
iap.isCanceled.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
});
|
||||
|
||||
describe('verifyPurchase', () => {
|
||||
let sku; let user; let token; let receipt; let
|
||||
headers;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let paymentBuySkuStub; let
|
||||
iapGetPurchaseDataStub; let validateGiftMessageStub;
|
||||
|
||||
beforeEach(() => {
|
||||
token = 'testToken';
|
||||
@@ -47,9 +25,13 @@ describe('Apple Payments', () => {
|
||||
receipt = `{"token": "${token}", "productId": "${sku}"}`;
|
||||
headers = {};
|
||||
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated').returns(true);
|
||||
iapIsCanceledStub = sinon.stub(iap, 'isCanceled').returns(false);
|
||||
iapIsExpiredStub = sinon.stub(iap, 'isExpired').returns(false);
|
||||
sinon.stub(iap, 'isExpired').returns(false);
|
||||
sinon.stub(iap, 'isCanceled').returns(false);
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
productId: 'com.habitrpg.ios.Habitica.21gems',
|
||||
@@ -60,6 +42,12 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.isExpired.restore();
|
||||
iap.isCanceled.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
payments.buySkuItem.restore();
|
||||
gems.validateGiftMessage.restore();
|
||||
});
|
||||
@@ -221,6 +209,9 @@ describe('Apple Payments', () => {
|
||||
describe('subscribe', () => {
|
||||
let sub; let sku; let user; let token; let receipt; let headers; let
|
||||
nextPaymentProcessing;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub;
|
||||
let paymentsCreateSubscritionStub; let
|
||||
iapGetPurchaseDataStub;
|
||||
|
||||
beforeEach(() => {
|
||||
sub = common.content.subscriptionBlocks[subKey];
|
||||
@@ -232,10 +223,12 @@ describe('Apple Payments', () => {
|
||||
nextPaymentProcessing = moment.utc().add({ days: 2 });
|
||||
user = new User();
|
||||
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
iapIsCanceledStub = sinon.stub(iap, 'isCanceled').returns(false);
|
||||
iapIsExpiredStub = sinon.stub(iap, 'isExpired').returns(false);
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
expirationDate: moment.utc().subtract({ day: 1 }).toDate(),
|
||||
@@ -257,6 +250,10 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
if (payments.createSubscription.restore) payments.createSubscription.restore();
|
||||
});
|
||||
|
||||
@@ -273,29 +270,6 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if no active subscription is found', async () => {
|
||||
iap.isCanceled.restore();
|
||||
iapIsCanceledStub = sinon.stub(iap, 'isCanceled')
|
||||
.returns(true);
|
||||
|
||||
iap.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
expirationDate: moment.utc().add({ day: -2 }).toDate(),
|
||||
purchaseDate: new Date(),
|
||||
productId: 'subscription1month',
|
||||
transactionId: token,
|
||||
originalTransactionId: token,
|
||||
}]);
|
||||
|
||||
await expect(applePayments.subscribe(user, receipt, headers, nextPaymentProcessing))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
message: applePayments.constants.RESPONSE_NO_ITEM_PURCHASED,
|
||||
});
|
||||
});
|
||||
|
||||
const subOptions = [
|
||||
{
|
||||
sku: 'subscription1month',
|
||||
@@ -600,7 +574,8 @@ describe('Apple Payments', () => {
|
||||
describe('cancelSubscribe ', () => {
|
||||
let user; let token; let receipt; let headers; let customerId; let
|
||||
expirationDate;
|
||||
let paymentCancelSubscriptionSpy;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let iapGetPurchaseDataStub; let
|
||||
paymentCancelSubscriptionSpy;
|
||||
|
||||
beforeEach(async () => {
|
||||
token = 'test-token';
|
||||
@@ -609,7 +584,8 @@ describe('Apple Payments', () => {
|
||||
customerId = 'test-customerId';
|
||||
expirationDate = moment.utc();
|
||||
|
||||
iapValidateStub.restore();
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({
|
||||
expirationDate,
|
||||
@@ -617,8 +593,8 @@ describe('Apple Payments', () => {
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{ expirationDate: expirationDate.toDate() }]);
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated').returns(true);
|
||||
iapIsCanceledStub = sinon.stub(iap, 'isCanceled').returns(false);
|
||||
iapIsExpiredStub = sinon.stub(iap, 'isExpired').returns(true);
|
||||
sinon.stub(iap, 'isCanceled').returns(false);
|
||||
sinon.stub(iap, 'isExpired').returns(true);
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
user.purchased.plan.paymentMethod = applePayments.constants.PAYMENT_METHOD_APPLE;
|
||||
@@ -630,7 +606,13 @@ describe('Apple Payments', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
paymentCancelSubscriptionSpy.restore();
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.isExpired.restore();
|
||||
iap.isCanceled.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
payments.cancelSubscription.restore();
|
||||
});
|
||||
|
||||
it('should throw an error if we are missing a subscription', async () => {
|
||||
@@ -713,8 +695,6 @@ describe('Apple Payments', () => {
|
||||
expect(iapIsValidatedStub).to.be.calledWith({
|
||||
expirationDate,
|
||||
});
|
||||
expect(iapIsCanceledStub).to.be.calledOnce;
|
||||
expect(iapIsExpiredStub).to.be.calledOnce;
|
||||
expect(iapGetPurchaseDataStub).to.be.calledOnce;
|
||||
|
||||
expect(paymentCancelSubscriptionSpy).to.be.calledOnce;
|
||||
|
||||
@@ -11,36 +11,12 @@ const { i18n } = common;
|
||||
|
||||
describe('Google Payments', () => {
|
||||
const subKey = 'basic_3mo';
|
||||
let iapSetupStub;
|
||||
let iapValidateStub;
|
||||
let iapIsValidatedStub;
|
||||
let paymentBuySkuStub;
|
||||
let validateGiftMessageStub;
|
||||
|
||||
beforeEach(() => {
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
sinon.stub(iap, 'isCanceled').returns(false);
|
||||
sinon.stub(iap, 'isExpired').returns(false);
|
||||
paymentBuySkuStub = sinon.stub(payments, 'buySkuItem').resolves({});
|
||||
validateGiftMessageStub = sinon.stub(gems, 'validateGiftMessage');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.isCanceled.restore();
|
||||
iap.isExpired.restore();
|
||||
payments.buySkuItem.restore();
|
||||
gems.validateGiftMessage.restore();
|
||||
});
|
||||
|
||||
describe('verifyPurchase', () => {
|
||||
let sku; let user; let token; let receipt; let signature; let
|
||||
headers;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let
|
||||
paymentBuySkuStub; let validateGiftMessageStub;
|
||||
|
||||
beforeEach(() => {
|
||||
sku = 'com.habitrpg.android.habitica.iap.21gems';
|
||||
@@ -49,7 +25,21 @@ describe('Google Payments', () => {
|
||||
signature = '';
|
||||
headers = {};
|
||||
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iap, 'validate').resolves({ productId: sku });
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
paymentBuySkuStub = sinon.stub(payments, 'buySkuItem').resolves({});
|
||||
validateGiftMessageStub = sinon.stub(gems, 'validateGiftMessage');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
payments.buySkuItem.restore();
|
||||
gems.validateGiftMessage.restore();
|
||||
});
|
||||
|
||||
it('should throw an error if receipt is invalid', async () => {
|
||||
@@ -170,7 +160,8 @@ describe('Google Payments', () => {
|
||||
describe('subscribe', () => {
|
||||
let sub; let sku; let user; let token; let receipt; let signature; let headers; let
|
||||
nextPaymentProcessing;
|
||||
let paymentsCreateSubscritionStub;
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let
|
||||
paymentsCreateSubscritionStub;
|
||||
|
||||
beforeEach(() => {
|
||||
sub = common.content.subscriptionBlocks[subKey];
|
||||
@@ -182,12 +173,19 @@ describe('Google Payments', () => {
|
||||
signature = '';
|
||||
nextPaymentProcessing = moment.utc().add({ days: 2 });
|
||||
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({});
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
paymentsCreateSubscritionStub = sinon.stub(payments, 'createSubscription').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
payments.createSubscription.restore();
|
||||
});
|
||||
|
||||
@@ -245,7 +243,7 @@ describe('Google Payments', () => {
|
||||
describe('cancelSubscribe ', () => {
|
||||
let user; let token; let receipt; let signature; let headers; let customerId; let
|
||||
expirationDate;
|
||||
let iapGetPurchaseDataStub; let
|
||||
let iapSetupStub; let iapValidateStub; let iapIsValidatedStub; let iapGetPurchaseDataStub; let
|
||||
paymentCancelSubscriptionSpy;
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -255,12 +253,17 @@ describe('Google Payments', () => {
|
||||
signature = '';
|
||||
customerId = 'test-customerId';
|
||||
expirationDate = moment.utc();
|
||||
|
||||
iapSetupStub = sinon.stub(iap, 'setup')
|
||||
.resolves();
|
||||
iapValidateStub = sinon.stub(iap, 'validate')
|
||||
.resolves({
|
||||
expirationDate,
|
||||
});
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{ expirationDate: expirationDate.toDate(), autoRenewing: false }]);
|
||||
iapIsValidatedStub = sinon.stub(iap, 'isValidated')
|
||||
.returns(true);
|
||||
|
||||
user = new User();
|
||||
user.profile.name = 'sender';
|
||||
@@ -273,6 +276,9 @@ describe('Google Payments', () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
iap.setup.restore();
|
||||
iap.validate.restore();
|
||||
iap.isValidated.restore();
|
||||
iap.getPurchaseData.restore();
|
||||
payments.cancelSubscription.restore();
|
||||
});
|
||||
@@ -302,8 +308,6 @@ describe('Google Payments', () => {
|
||||
});
|
||||
|
||||
it('should cancel a user subscription', async () => {
|
||||
iap.isCanceled.restore();
|
||||
iap.isCanceled = sinon.stub(iap, 'isCanceled').returns(true);
|
||||
await googlePayments.cancelSubscribe(user, headers);
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
@@ -328,20 +332,11 @@ describe('Google Payments', () => {
|
||||
});
|
||||
|
||||
it('should cancel a user subscription with multiple inactive subscriptions', async () => {
|
||||
iap.isCanceled.restore();
|
||||
iap.isCanceled = sinon.stub(iap, 'isCanceled').returns(true);
|
||||
const laterDate = moment.utc().add(7, 'days');
|
||||
iap.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{
|
||||
startTimeMillis: expirationDate.valueOf(),
|
||||
expirationDate,
|
||||
autoRenewing: false,
|
||||
}, {
|
||||
startTimeMillis: laterDate.valueOf(),
|
||||
expirationDate: laterDate,
|
||||
autoRenewing: false,
|
||||
},
|
||||
.returns([{ expirationDate, autoRenewing: false },
|
||||
{ expirationDate: laterDate, autoRenewing: false },
|
||||
]);
|
||||
await googlePayments.cancelSubscribe(user, headers);
|
||||
|
||||
@@ -370,12 +365,7 @@ describe('Google Payments', () => {
|
||||
iap.getPurchaseData.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iap, 'getPurchaseData')
|
||||
.returns([{ autoRenewing: true }]);
|
||||
await expect(googlePayments.cancelSubscribe(user, headers))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
message: googlePayments.constants.RESPONSE_STILL_VALID,
|
||||
});
|
||||
await googlePayments.cancelSubscribe(user, headers);
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
@@ -398,12 +388,8 @@ describe('Google Payments', () => {
|
||||
.returns([{ expirationDate, autoRenewing: false },
|
||||
{ autoRenewing: true },
|
||||
{ expirationDate, autoRenewing: false }]);
|
||||
await expect(googlePayments.cancelSubscribe(user, headers))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
message: googlePayments.constants.RESPONSE_STILL_VALID,
|
||||
});
|
||||
await googlePayments.cancelSubscribe(user, headers);
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledWith(iap.GOOGLE, {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import {
|
||||
SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
|
||||
} from '../../../../../website/server/models/group';
|
||||
import { MAX_MESSAGE_LENGTH, CHAT_FLAG_FROM_SHADOW_MUTE } from '../../../../../website/common/script/constants';
|
||||
import { MAX_MESSAGE_LENGTH } from '../../../../../website/common/script/constants';
|
||||
import * as email from '../../../../../website/server/libs/email';
|
||||
|
||||
describe('POST /chat', () => {
|
||||
@@ -80,20 +80,17 @@ describe('POST /chat', () => {
|
||||
member.updateOne({ 'flags.chatRevoked': false });
|
||||
});
|
||||
|
||||
it('errors when chat privileges are revoked when sending a message to a private guild', async () => {
|
||||
it('does not error when chat privileges are revoked when sending a message to a private guild', async () => {
|
||||
await member.updateOne({
|
||||
'flags.chatRevoked': true,
|
||||
});
|
||||
|
||||
await expect(member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage }))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('chatPrivilegesRevoked'),
|
||||
});
|
||||
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
});
|
||||
|
||||
it('errors when chat privileges are revoked when sending a message to a party', async () => {
|
||||
it('does not error when chat privileges are revoked when sending a message to a party', async () => {
|
||||
const { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Party',
|
||||
@@ -109,12 +106,9 @@ describe('POST /chat', () => {
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
});
|
||||
|
||||
await expect(privatePartyMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage }))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('chatPrivilegesRevoked'),
|
||||
});
|
||||
const message = await privatePartyMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -129,7 +123,7 @@ describe('POST /chat', () => {
|
||||
member.updateOne({ 'flags.chatShadowMuted': false });
|
||||
});
|
||||
|
||||
it('creates a chat with flagCount set when sending a message to a private guild', async () => {
|
||||
it('creates a chat with zero flagCount when sending a message to a private guild', async () => {
|
||||
await member.updateOne({
|
||||
'flags.chatShadowMuted': true,
|
||||
});
|
||||
@@ -137,10 +131,10 @@ describe('POST /chat', () => {
|
||||
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
expect(message.message.flagCount).to.eql(CHAT_FLAG_FROM_SHADOW_MUTE);
|
||||
expect(message.message.flagCount).to.eql(0);
|
||||
});
|
||||
|
||||
it('creates a chat with flagCount set when sending a message to a party', async () => {
|
||||
it('creates a chat with zero flagCount when sending a message to a party', async () => {
|
||||
const { group, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Party',
|
||||
@@ -159,7 +153,7 @@ describe('POST /chat', () => {
|
||||
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||
|
||||
expect(message.message.id).to.exist;
|
||||
expect(message.message.flagCount).to.eql(CHAT_FLAG_FROM_SHADOW_MUTE);
|
||||
expect(message.message.flagCount).to.eql(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -244,18 +238,6 @@ describe('POST /chat', () => {
|
||||
expect(groupMessages[0].id).to.exist;
|
||||
});
|
||||
|
||||
it('creates a chat with case-insensitive mentions', async () => {
|
||||
const originalUsername = member.auth.local.username;
|
||||
const uppercaseUsername = originalUsername.toUpperCase();
|
||||
const messageWithMentions = `hi @${uppercaseUsername}`;
|
||||
const newMessage = await user.post(`/groups/${groupWithChat._id}/chat`, { message: messageWithMentions });
|
||||
const groupMessages = await user.get(`/groups/${groupWithChat._id}/chat`);
|
||||
|
||||
expect(newMessage.message.id).to.exist;
|
||||
expect(newMessage.message.text).to.include(`[@${uppercaseUsername}](/profile/${member._id})`);
|
||||
expect(groupMessages[0].id).to.exist;
|
||||
});
|
||||
|
||||
it('creates a chat with a max length of 3000 chars', async () => {
|
||||
const veryLongMessage = `
|
||||
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789.
|
||||
|
||||
@@ -61,24 +61,6 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('fakes sending an invite if user is shadow muted', async () => {
|
||||
const inviterMuted = await inviter.updateOne({ 'flags.chatShadowMuted': true });
|
||||
const userToInvite = await generateUser();
|
||||
|
||||
const response = await inviterMuted.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [userToInvite.auth.local.lowerCaseUsername],
|
||||
});
|
||||
expect(response).to.be.an('Array');
|
||||
expect(response[0]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
|
||||
expect(response[0]._id).to.be.a('String');
|
||||
expect(response[0].id).to.eql(group._id);
|
||||
expect(response[0].name).to.eql(groupName);
|
||||
expect(response[0].inviter).to.eql(inviter._id);
|
||||
|
||||
await expect(userToInvite.get('/user'))
|
||||
.to.eventually.not.have.nested.property('invitations.parties[0].id', group._id);
|
||||
});
|
||||
|
||||
it('invites a user to a group by username', async () => {
|
||||
const userToInvite = await generateUser();
|
||||
|
||||
@@ -227,24 +209,6 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('fakes sending an invite if user is shadow muted', async () => {
|
||||
const inviterMuted = await inviter.updateOne({ 'flags.chatShadowMuted': true });
|
||||
const userToInvite = await generateUser();
|
||||
|
||||
const response = await inviterMuted.post(`/groups/${group._id}/invite`, {
|
||||
uuids: [userToInvite._id],
|
||||
});
|
||||
expect(response).to.be.an('Array');
|
||||
expect(response[0]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
|
||||
expect(response[0]._id).to.be.a('String');
|
||||
expect(response[0].id).to.eql(group._id);
|
||||
expect(response[0].name).to.eql(groupName);
|
||||
expect(response[0].inviter).to.eql(inviter._id);
|
||||
|
||||
await expect(userToInvite.get('/user'))
|
||||
.to.eventually.not.have.nested.property('invitations.parties[0].id', group._id);
|
||||
});
|
||||
|
||||
it('invites a user to a group by uuid', async () => {
|
||||
const userToInvite = await generateUser();
|
||||
|
||||
@@ -317,19 +281,6 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('fakes sending invite when inviter is shadow muted', async () => {
|
||||
const inviterMuted = await inviter.updateOne({ 'flags.chatShadowMuted': true });
|
||||
const res = await inviterMuted.post(`/groups/${group._id}/invite`, {
|
||||
emails: [testInvite],
|
||||
inviter: 'inviter name',
|
||||
});
|
||||
|
||||
const updatedUser = await inviterMuted.sync();
|
||||
|
||||
expect(res).to.exist;
|
||||
expect(updatedUser.invitesSent).to.eql(1);
|
||||
});
|
||||
|
||||
it('returns an error when invite is missing an email', async () => {
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
emails: [{ name: 'test' }],
|
||||
@@ -454,19 +405,6 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('fakes sending an invite if user is shadow muted', async () => {
|
||||
const inviterMuted = await inviter.updateOne({ 'flags.chatShadowMuted': true });
|
||||
const newUser = await generateUser();
|
||||
const invite = await inviterMuted.post(`/groups/${group._id}/invite`, {
|
||||
uuids: [newUser._id],
|
||||
emails: [{ name: 'test', email: 'test@habitica.com' }],
|
||||
});
|
||||
const invitedUser = await newUser.get('/user');
|
||||
|
||||
expect(invitedUser.invitations.parties[0]).to.not.exist;
|
||||
expect(invite).to.exist;
|
||||
});
|
||||
|
||||
it('invites users to a group by uuid and email', async () => {
|
||||
const newUser = await generateUser();
|
||||
const invite = await inviter.post(`/groups/${group._id}/invite`, {
|
||||
|
||||
@@ -43,7 +43,7 @@ describe('POST /members/send-private-message', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error when recipient has blocked the sender', async () => {
|
||||
it('returns error when to user has blocked the sender', async () => {
|
||||
const receiver = await generateUser({ 'inbox.blocks': [userToSendMessage._id] });
|
||||
|
||||
await expect(userToSendMessage.post('/members/send-private-message', {
|
||||
@@ -56,7 +56,7 @@ describe('POST /members/send-private-message', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error when sender has blocked recipient', async () => {
|
||||
it('returns error when sender has blocked to user', async () => {
|
||||
const receiver = await generateUser();
|
||||
const sender = await generateUser({ 'inbox.blocks': [receiver._id] });
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('POST /members/send-private-message', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error when recipient has opted out of messaging', async () => {
|
||||
it('returns error when to user has opted out of messaging', async () => {
|
||||
const receiver = await generateUser({ 'inbox.optOut': true });
|
||||
|
||||
await expect(userToSendMessage.post('/members/send-private-message', {
|
||||
@@ -174,7 +174,7 @@ describe('POST /members/send-private-message', () => {
|
||||
expect(notification.data.excerpt).to.equal(messageExcerpt);
|
||||
});
|
||||
|
||||
it('allows admin to send when recipient has blocked the admin', async () => {
|
||||
it('allows admin to send when sender has blocked the admin', async () => {
|
||||
userToSendMessage = await generateUser({
|
||||
'permissions.moderator': true,
|
||||
});
|
||||
@@ -202,7 +202,7 @@ describe('POST /members/send-private-message', () => {
|
||||
expect(sendersMessageInSendersInbox).to.exist;
|
||||
});
|
||||
|
||||
it('allows admin to send when recipient has opted out of messaging', async () => {
|
||||
it('allows admin to send when to user has opted out of messaging', async () => {
|
||||
userToSendMessage = await generateUser({
|
||||
'permissions.moderator': true,
|
||||
});
|
||||
@@ -229,58 +229,4 @@ describe('POST /members/send-private-message', () => {
|
||||
expect(sendersMessageInReceiversInbox).to.exist;
|
||||
expect(sendersMessageInSendersInbox).to.exist;
|
||||
});
|
||||
|
||||
describe('sender is shadow muted', () => {
|
||||
beforeEach(async () => {
|
||||
userToSendMessage = await generateUser({
|
||||
'flags.chatShadowMuted': true,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not save the message in the receiver inbox', async () => {
|
||||
const receiver = await generateUser();
|
||||
|
||||
const response = await userToSendMessage.post('/members/send-private-message', {
|
||||
message: messageToSend,
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
expect(response.message.uuid).to.equal(receiver._id);
|
||||
|
||||
const updatedReceiver = await receiver.get('/user');
|
||||
const updatedSender = await userToSendMessage.get('/user');
|
||||
|
||||
const sendersMessageInReceiversInbox = _.find(
|
||||
updatedReceiver.inbox.messages,
|
||||
message => message.uuid === userToSendMessage._id && message.text === messageToSend,
|
||||
);
|
||||
|
||||
const sendersMessageInSendersInbox = _.find(
|
||||
updatedSender.inbox.messages,
|
||||
message => message.uuid === receiver._id && message.text === messageToSend,
|
||||
);
|
||||
|
||||
expect(sendersMessageInReceiversInbox).to.not.exist;
|
||||
expect(sendersMessageInSendersInbox).to.exist;
|
||||
});
|
||||
|
||||
it('does not save the message message twice if recipient is sender', async () => {
|
||||
const response = await userToSendMessage.post('/members/send-private-message', {
|
||||
message: messageToSend,
|
||||
toUserId: userToSendMessage._id,
|
||||
});
|
||||
|
||||
expect(response.message.uuid).to.equal(userToSendMessage._id);
|
||||
|
||||
const updatedSender = await userToSendMessage.get('/user');
|
||||
|
||||
const sendersMessageInSendersInbox = _.find(
|
||||
updatedSender.inbox.messages,
|
||||
message => message.uuid === userToSendMessage._id && message.text === messageToSend,
|
||||
);
|
||||
|
||||
expect(sendersMessageInSendersInbox).to.exist;
|
||||
expect(Object.keys(updatedSender.inbox.messages).length).to.equal(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('POST /user/auth/local/login', () => {
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('accountSuspended', { communityManagerEmail: nconf.get('EMAILS_COMMUNITY_MANAGER_EMAIL'), userId: user._id, username: user.auth.local.username }),
|
||||
message: t('accountSuspended', { communityManagerEmail: nconf.get('EMAILS_COMMUNITY_MANAGER_EMAIL'), userId: user._id }),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
44
website/client/package-lock.json
generated
@@ -23,6 +23,7 @@
|
||||
"eslint-config-habitrpg": "6.2.0",
|
||||
"eslint-plugin-mocha": "5.3.0",
|
||||
"eslint-plugin-vue": "7.20.0",
|
||||
"ga-gtag": "^1.2.0",
|
||||
"habitica-markdown": "^3.0.0",
|
||||
"hellojs": "^1.20.0",
|
||||
"intro.js": "^7.2.0",
|
||||
@@ -37,7 +38,7 @@
|
||||
"timers-browserify": "^2.0.12",
|
||||
"uuid": "^9.0.1",
|
||||
"validator": "^13.9.0",
|
||||
"vite": "^6.3.6",
|
||||
"vite": "^6.0.0",
|
||||
"vite-plugin-compression2": "^1.3.3",
|
||||
"vue": "^2.7.10",
|
||||
"vue-fragment": "^1.6.0",
|
||||
@@ -5122,20 +5123,6 @@
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -5174,6 +5161,11 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/ga-gtag": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ga-gtag/-/ga-gtag-1.2.0.tgz",
|
||||
"integrity": "sha512-j9gxutMdpGMdwaX1SzOG31Ddm+IGFjeNf+N3Z5g+BBpS8FSXOALlrM+ORIGc/QKszGJEDlw+6PfIsJZICsqsGQ=="
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@@ -7134,21 +7126,6 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright/node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
||||
@@ -8551,10 +8528,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.3.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
|
||||
"integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
|
||||
"license": "MIT",
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
||||
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"eslint-config-habitrpg": "6.2.0",
|
||||
"eslint-plugin-mocha": "5.3.0",
|
||||
"eslint-plugin-vue": "7.20.0",
|
||||
"ga-gtag": "^1.2.0",
|
||||
"habitica-markdown": "^3.0.0",
|
||||
"hellojs": "^1.20.0",
|
||||
"intro.js": "^7.2.0",
|
||||
@@ -41,7 +42,7 @@
|
||||
"timers-browserify": "^2.0.12",
|
||||
"uuid": "^9.0.1",
|
||||
"validator": "^13.9.0",
|
||||
"vite": "^6.3.6",
|
||||
"vite": "^6.0.0",
|
||||
"vite-plugin-compression2": "^1.3.3",
|
||||
"vue": "^2.7.10",
|
||||
"vue-fragment": "^1.6.0",
|
||||
|
||||
@@ -203,9 +203,6 @@ export default {
|
||||
|
||||
return response;
|
||||
}, error => { // Set up Error interceptors
|
||||
if (!error.response) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
if (error.response.status >= 400) {
|
||||
const isBanned = this.checkForBannedUser(error);
|
||||
if (isBanned === true) return null; // eslint-disable-line consistent-return
|
||||
|
||||
@@ -1055,11 +1055,6 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_elegant_palace {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_elegant_palace.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_enchanted_music_room {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_enchanted_music_room.png');
|
||||
width: 141px;
|
||||
@@ -1756,11 +1751,6 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_nighttime_street_with_shops {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_nighttime_street_with_shops.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_ocean_sunrise {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_ocean_sunrise.png');
|
||||
width: 141px;
|
||||
@@ -2447,11 +2437,6 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_winter_desert_with_saguaros {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_winter_desert_with_saguaros.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_winter_fireworks {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_winter_fireworks.png');
|
||||
width: 141px;
|
||||
@@ -29470,11 +29455,6 @@
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.back_armoire_harpsichord {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_armoire_harpsichord.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.body_armoire_clownsBowtie {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/body_armoire_clownsBowtie.png');
|
||||
width: 114px;
|
||||
@@ -29865,11 +29845,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_loneCowpokeOutfit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_loneCowpokeOutfit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_lunarArmor {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_lunarArmor.png');
|
||||
width: 90px;
|
||||
@@ -30505,11 +30480,6 @@
|
||||
width: 114px;
|
||||
height: 87px;
|
||||
}
|
||||
.head_armoire_loneCowpokeHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_loneCowpokeHat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_lunarCrown {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_lunarCrown.png');
|
||||
width: 90px;
|
||||
@@ -30820,11 +30790,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_doubleBass {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_doubleBass.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_dragonTamerShield {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_dragonTamerShield.png');
|
||||
width: 90px;
|
||||
@@ -31030,11 +30995,6 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_prettyPinkGiftBox {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_prettyPinkGiftBox.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_ramHornShield {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_ramHornShield.png');
|
||||
width: 90px;
|
||||
@@ -31505,11 +31465,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_loneCowpokeOutfit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_loneCowpokeOutfit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_lunarArmor {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_lunarArmor.png');
|
||||
width: 90px;
|
||||
@@ -31805,11 +31760,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_armoire_bambooFlute {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_bambooFlute.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_armoire_barristerGavel {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_barristerGavel.png');
|
||||
width: 90px;
|
||||
@@ -32220,11 +32170,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_armoire_prettyPinkParasol {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_prettyPinkParasol.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_armoire_pushBroom {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_pushBroom.png');
|
||||
width: 114px;
|
||||
@@ -34115,46 +34060,6 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.back_mystery_202601 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_202601.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.back_mystery_202602 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_202602.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_mystery_202512 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_202512.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_mystery_202512 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202512.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_mystery_202602 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202602.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_mystery_202512 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_mystery_202512.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_mystery_202512 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_mystery_202512.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_mystery_202601 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_mystery_202601.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.back_mystery_201402 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_201402.png');
|
||||
width: 90px;
|
||||
@@ -38735,26 +38640,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_winter2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_winter2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_winter2026Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_winter2026Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_winter2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_winter2026Rogue.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.broad_armor_special_winter2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_winter2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_yeti {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_yeti.png');
|
||||
width: 90px;
|
||||
@@ -39050,26 +38935,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_winter2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_winter2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_winter2026Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_winter2026Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_winter2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_winter2026Rogue.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.head_special_winter2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_winter2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_yeti {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_yeti.png');
|
||||
width: 90px;
|
||||
@@ -39250,21 +39115,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_winter2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_winter2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_winter2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_winter2026Rogue.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.shield_special_winter2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_winter2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_yeti {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_yeti.png');
|
||||
width: 90px;
|
||||
@@ -39505,26 +39355,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_winter2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_winter2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_winter2026Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_winter2026Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_winter2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_winter2026Rogue.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.slim_armor_special_winter2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_winter2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_yeti {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_yeti.png');
|
||||
width: 90px;
|
||||
@@ -39765,26 +39595,6 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_winter2026Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_winter2026Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_winter2026Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_winter2026Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_winter2026Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_winter2026Rogue.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.weapon_special_winter2026Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_winter2026Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_yeti {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_yeti.png');
|
||||
width: 90px;
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 8.5 KiB |
@@ -1,9 +0,0 @@
|
||||
<svg width="378" height="176" viewBox="0 0 378 176" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 0H378V174C378 175.105 377.105 176 376 176H1.99999C0.895423 176 0 175.105 0 174V0Z" fill="url(#paint0_linear_2257_239)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_2257_239" x1="378" y1="0" x2="0" y2="0" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#925CF3"/>
|
||||
<stop offset="1" stop-color="#34B5C1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 448 B |
@@ -1,37 +0,0 @@
|
||||
<svg width="48" height="96" viewBox="0 0 48 96" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-3.10104 12.0483C-2.82088 9.43721 -3.53422 6.57214 -5.6115 5.24584C-7.68877 3.91954 -9.89543 4.92709 -10.1422 6.808C-10.3891 8.68891 -9.06061 9.83066 -4.97737 13.9337C-3.81821 15.0985 -3.3812 14.6594 -3.10104 12.0483Z" stroke="#FFA624" stroke-width="4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.34089 15.2054C4.45116 13.6561 7.27707 12.8443 9.45877 13.9889C11.6405 15.1334 11.8754 17.5575 10.3778 18.7127C8.88016 19.868 7.23193 19.2828 1.65411 17.781C0.0706697 17.3546 0.230624 16.7548 2.34089 15.2054Z" stroke="#FFBE5D" stroke-width="4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.549002 12.0098C-3.61871 9.59194 -3.87667 15.8322 -2.20457 16.8023C-0.532473 17.7724 4.71671 14.4277 0.549002 12.0098Z" fill="#EE9109"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-1.76917 16.0445L13.637 24.9825L9.18965 32.7229L-6.21656 23.785L-1.76917 16.0445Z" fill="#F8F9F9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-6.90457 13.0652L3.36623 19.0238L-1.08116 26.7643L-11.352 20.8057L-6.90457 13.0652Z" fill="#FFBE5D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-1.76917 16.0445L3.36623 19.0238L1.88377 21.604L-3.25163 18.6247L-1.76917 16.0445Z" fill="#FFA624"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-6.21656 23.785L6.62195 31.2333L-3.75529 49.2944L-16.5938 41.8461L-6.21656 23.785Z" fill="#F8F9F9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-3.64886 25.2747L6.62195 31.2333L5.13948 33.8134L-5.13132 27.8548L-3.64886 25.2747Z" fill="#DDF3F3"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.401307 24.1842L10.6721 30.1428L9.18965 32.7229L-1.08116 26.7643L0.401307 24.1842Z" fill="#DDF3F3"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.7924 38.4607L17.9387 42.0519L21.31 40.5834L24.8838 41.4413L23.4225 38.0537L24.2762 34.4625L20.9049 35.9309L17.3311 35.0731L18.7924 38.4607Z" fill="white" fill-opacity="0.5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-3.93867 71.2331L-4.79238 74.8243L-1.42111 73.3559L2.15271 74.2137L0.691383 70.8261L1.54509 67.2349L-1.82618 68.7033L-5.4 67.8455L-3.93867 71.2331Z" fill="white" fill-opacity="0.5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.8949 25.3807L35.0583 29.8802L37.9424 26.2452L42.4202 25.0761L38.8028 22.178L37.6393 17.6786L34.7552 21.3135L30.2775 22.4826L33.8949 25.3807Z" fill="white" fill-opacity="0.5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.2596 71.999L40.579 68.1435L45.9507 88.2881L31.6312 92.1436L26.2596 71.999Z" fill="#F8F9F9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9401 75.8545L26.2589 71.9966L31.6273 92.1421L17.3084 96L11.9401 75.8545Z" fill="#DDF3F3"/>
|
||||
<rect width="2.96589" height="20.8485" transform="matrix(0.965611 -0.25999 0.257652 0.966238 23.3957 72.7701)" fill="#FFA624"/>
|
||||
<rect width="2.96589" height="20.8485" transform="matrix(0.965611 -0.25999 0.257652 0.966238 26.2596 71.999)" fill="#FFBE5D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.9999 90.0369L30.8638 89.2658L31.6312 92.1436L28.7673 92.9147L27.9999 90.0369Z" fill="#EE9109"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3957 72.7701L26.2596 71.999L27.0269 74.8768L24.163 75.6479L23.3957 72.7701Z" fill="#EE9109"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9401 75.8545L23.3951 72.7682L24.162 75.6461L12.707 78.7325L11.9401 75.8545Z" fill="#C1E9E9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.5443 93.1213L27.9999 90.0369L28.7673 92.9147L17.3117 95.9991L16.5443 93.1213Z" fill="#C1E9E9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.1235 71.2279L40.579 68.1435L41.3464 71.0213L29.8908 74.1057L29.1235 71.2279Z" fill="#DDF3F3"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.7277 88.4947L45.1833 85.4103L45.9507 88.2881L34.4951 91.3725L33.7277 88.4947Z" fill="#DDF3F3"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.8638 89.2658L33.7277 88.4947L34.4951 91.3725L31.6312 92.1436L30.8638 89.2658Z" fill="#FFA624"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.2596 71.999L29.1235 71.2279L29.8908 74.1057L27.0269 74.8768L26.2596 71.999Z" fill="#FFA624"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.5224 56.3076C25.8087 53.7812 24.0792 51.3933 21.6588 50.9455C19.2383 50.4977 17.5679 52.2625 18.0403 54.0994C18.5126 55.9363 20.17 56.4948 25.4855 58.7621C26.9945 59.4057 27.236 58.834 26.5224 56.3076Z" stroke="#FFA624" stroke-width="4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.745 57.1864C34.124 54.9555 36.4415 53.1391 38.8911 53.3791C41.3406 53.6191 42.4621 55.7782 41.5042 57.413C40.5463 59.0479 38.7999 59.1258 33.0684 59.8329C31.4413 60.0337 31.366 59.4173 32.745 57.1864Z" stroke="#FFBE5D" stroke-width="4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.8923 54.898C25.1267 54.225 27.2139 60.108 29.1258 60.378C31.0378 60.648 34.6579 55.571 29.8923 54.898Z" fill="#EE9109"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.247 59.5115L46.8635 61.9994L45.6255 70.8503L28.0091 68.3625L29.247 59.5115Z" fill="#F8F9F9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.6306 57.0236L29.247 59.5114L28.0091 68.3624L10.3927 65.8745L11.6306 57.0236Z" fill="#DDF3F3"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3749 58.6822L35.1192 60.3408L33.8813 69.1917L22.137 67.5332L23.3749 58.6822Z" fill="#FFBE5D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3749 58.6822L29.247 59.5115L28.0091 68.3625L22.137 67.5332L23.3749 58.6822Z" fill="#FFA624"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.247 59.5115L35.1192 60.3408L34.7065 63.2911L28.8344 62.4618L29.247 59.5115Z" fill="#FFA624"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3749 58.6822L29.247 59.5115L28.8344 62.4618L22.9622 61.6326L23.3749 58.6822Z" fill="#EE9109"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.8053 62.9241L22.5496 64.5827L22.137 67.533L10.3927 65.8745L10.8053 62.9241Z" fill="#C1E9E9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M34.2939 66.2414L46.0382 67.9L45.6255 70.8503L33.8813 69.1917L34.2939 66.2414Z" fill="#DDF3F3"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.0 KiB |
@@ -30,23 +30,12 @@
|
||||
cursor: default;
|
||||
color: $gray-200;
|
||||
opacity: 1;
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
background-color: $gray-700;
|
||||
border: 2px solid transparent;
|
||||
box-shadow:
|
||||
0 1px 3px 0 rgba($black, 0.12),
|
||||
0 1px 2px 0 rgba($black, 0.24);
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
padding: 4px 12px;
|
||||
min-height: 32px;
|
||||
max-height: 32px;
|
||||
gap: 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
|
||||
.svg {
|
||||
color: $gray-200;
|
||||
color: $gray-300;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,10 +123,6 @@ h4 {
|
||||
background-color: $purple-300 !important;
|
||||
}
|
||||
|
||||
.bg-yellow-50 {
|
||||
background-color: $yellow-50 !important;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: $white !important;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g fill="#FFFFFF" fill-rule="nonzero">
|
||||
<polygon points="12.1973467 2 14 3.80265326 9.80187117 8 14 12.1973467 12.1973467 14 8 9.80187117 3.80265326 14 2 12.1973467 6.19812883 8 2 3.80265326 3.80265326 2 8 6.19812883"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 504 B |
|
Before Width: | Height: | Size: 5.4 KiB |
@@ -1,29 +0,0 @@
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M58.1792 31.6843L46.8536 22.3769L23.918 28.6988L18.861 42.5218L44.341 58.5813L58.1792 31.6843Z" fill="#FF944C"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M46.6218 34.5148L46.1108 26.1328L36.2812 28.8422L46.6218 34.5148Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M30.2393 39.0304L26.4518 31.5515L36.2813 28.8422L30.2393 39.0304Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M46.6218 34.5148L36.2813 28.8422L30.2393 39.0304L46.6218 34.5148Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M53.8301 32.5279L46.1108 26.1328L46.6218 34.5148L53.8301 32.5279Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M23.0309 41.0173L26.4518 31.5516L30.2393 39.0304L23.0309 41.0173Z" fill="#FA8537"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M53.8301 32.5279L46.6218 34.5148L43.0424 53.79L53.8301 32.5279Z" fill="#FA8537"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M23.0309 41.0173L30.2393 39.0304L43.0425 53.79L23.0309 41.0173Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M46.6218 34.5148L30.2393 39.0304L43.0425 53.79L46.6218 34.5148Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M50.555 4.15937L47.026 0.420004L38.7773 1.59601L36.4144 6.17539L44.5675 12.8919L50.555 4.15937Z" fill="#FFBE5D"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M46.414 4.62854L46.6034 1.6924L43.0682 2.1964L46.414 4.62854Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M40.5221 5.46854L39.5331 2.7004L43.0682 2.1964L40.5221 5.46854Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M46.414 4.62854L43.0683 2.1964L40.5221 5.46855L46.414 4.62854Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M49.0064 4.25894L46.6034 1.6924L46.414 4.62854L49.0064 4.25894Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M37.9296 5.83815L39.5331 2.70041L40.5221 5.46855L37.9296 5.83815Z" fill="#FFA624"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M49.0064 4.25893L46.414 4.62853L44.3259 11.1688L49.0064 4.25893Z" fill="#FFA624"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M37.9297 5.83815L40.5221 5.46855L44.326 11.1688L37.9297 5.83815Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M46.414 4.62854L40.5221 5.46855L44.326 11.1688L46.414 4.62854Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.2986 16.7775L24.6513 8.36623L11.1016 3.94533L4.07056 9.19883L11.614 25.6769L27.2986 16.7775Z" fill="#FF6165"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M20.5864 14.3719L23.0573 10.0026L17.2502 8.10789L20.5864 14.3719Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M10.908 11.2141L11.4432 6.21322L17.2502 8.10789L10.908 11.2141Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M20.5864 14.3719L17.2502 8.10789L10.9081 11.2141L20.5864 14.3719Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M24.8449 15.7613L23.0573 10.0026L20.5864 14.3719L24.8449 15.7613Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M6.64955 9.82464L11.4432 6.21321L10.908 11.2141L6.64955 9.82464Z" fill="#F23035"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M24.8449 15.7613L20.5864 14.3719L12.5221 22.8464L24.8449 15.7613Z" fill="#F23035"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M6.64959 9.82464L10.9081 11.2141L12.5221 22.8463L6.64959 9.82464Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M20.5864 14.3719L10.9081 11.2141L12.5221 22.8463L20.5864 14.3719Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -1,29 +0,0 @@
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.82083 31.6843L17.1464 22.3769L40.082 28.6988L45.139 42.5218L19.659 58.5813L5.82083 31.6843Z" fill="#24CC8F"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M17.3782 34.5148L17.8892 26.1328L27.7188 28.8422L17.3782 34.5148Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M33.7607 39.0304L37.5482 31.5515L27.7187 28.8422L33.7607 39.0304Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M17.3782 34.5148L27.7187 28.8422L33.7607 39.0304L17.3782 34.5148Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M10.1699 32.5279L17.8892 26.1328L17.3782 34.5148L10.1699 32.5279Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M40.9691 41.0173L37.5482 31.5516L33.7607 39.0304L40.9691 41.0173Z" fill="#1CA372"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M10.1699 32.5279L17.3782 34.5148L20.9576 53.79L10.1699 32.5279Z" fill="#1CA372"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M40.9691 41.0173L33.7607 39.0304L20.9575 53.79L40.9691 41.0173Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M17.3782 34.5148L33.7607 39.0304L20.9575 53.79L17.3782 34.5148Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.445 4.15937L16.974 0.420004L25.2227 1.59601L27.5856 6.17539L19.4325 12.8919L13.445 4.15937Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M17.586 4.62854L17.3966 1.6924L20.9318 2.1964L17.586 4.62854Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M23.4779 5.46854L24.4669 2.7004L20.9318 2.1964L23.4779 5.46854Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M17.586 4.62854L20.9317 2.1964L23.4779 5.46855L17.586 4.62854Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M14.9936 4.25894L17.3966 1.6924L17.586 4.62854L14.9936 4.25894Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M26.0704 5.83815L24.4669 2.70041L23.4779 5.46855L26.0704 5.83815Z" fill="#4F2A93"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M14.9936 4.25893L17.586 4.62853L19.6741 11.1688L14.9936 4.25893Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M26.0703 5.83815L23.4779 5.46855L19.674 11.1688L26.0703 5.83815Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M17.586 4.62854L23.4779 5.46855L19.674 11.1688L17.586 4.62854Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M36.7014 16.7775L39.3487 8.36623L52.8984 3.94533L59.9294 9.19883L52.386 25.6769L36.7014 16.7775Z" fill="#50B5E9"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M43.4136 14.3719L40.9427 10.0026L46.7498 8.10789L43.4136 14.3719Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M53.092 11.2141L52.5568 6.21322L46.7498 8.10789L53.092 11.2141Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M43.4136 14.3719L46.7498 8.10789L53.0919 11.2141L43.4136 14.3719Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M39.1551 15.7613L40.9427 10.0026L43.4136 14.3719L39.1551 15.7613Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M57.3504 9.82464L52.5568 6.21321L53.092 11.2141L57.3504 9.82464Z" fill="#46A7D9"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M39.1551 15.7613L43.4136 14.3719L51.4779 22.8464L39.1551 15.7613Z" fill="#46A7D9"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M57.3504 9.82464L53.0919 11.2141L51.4779 22.8463L57.3504 9.82464Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M43.4136 14.3719L53.0919 11.2141L51.4779 22.8463L43.4136 14.3719Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -117,7 +117,7 @@ export default {
|
||||
closeWithAction () {
|
||||
this.close();
|
||||
setTimeout(() => {
|
||||
this.$router.push(`/profile/${this.$store.state.user.data._id}#achievements`);
|
||||
this.$router.push({ name: 'achievements' });
|
||||
}, 200);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -81,7 +81,7 @@ export default {
|
||||
watch: {
|
||||
userIdentifier () {
|
||||
this.isSearching = true;
|
||||
this.$store.dispatch('admin:searchUsers', { userIdentifier: this.userIdentifier }).then(users => {
|
||||
this.$store.dispatch('adminPanel:searchUsers', { userIdentifier: this.userIdentifier }).then(users => {
|
||||
this.isSearching = false;
|
||||
if (users.length === 1) {
|
||||
this.loadUser(users[0]._id);
|
||||
|
||||
@@ -5,12 +5,6 @@
|
||||
class="row"
|
||||
>
|
||||
<div class="form col-12">
|
||||
<button
|
||||
class="btn btn-danger mt-3 float-right"
|
||||
@click="confirmDeleteHero"
|
||||
>
|
||||
Begin Member deletion
|
||||
</button>
|
||||
<basic-details
|
||||
:user-id="hero._id"
|
||||
:auth="hero.auth"
|
||||
@@ -102,53 +96,6 @@
|
||||
:reset-counter="resetCounter"
|
||||
@clear-data="clearData"
|
||||
/>
|
||||
<b-modal
|
||||
id="delete-member-modal"
|
||||
title="Delete Member"
|
||||
ok-title="Delete"
|
||||
ok-variant="danger"
|
||||
cancel-title="Cancel"
|
||||
@ok="deleteHero"
|
||||
>
|
||||
<b-modal-body>
|
||||
<p>
|
||||
Are you sure you want to delete this member?
|
||||
</p>
|
||||
<p class="errorMessage">
|
||||
Please note: This action cannot be undone!
|
||||
</p>
|
||||
<div class="ml-4">
|
||||
<div class="form-check">
|
||||
<input
|
||||
id="deleteAccountCheck"
|
||||
v-model="deleteHabiticaAccount"
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="deleteAccountCheck"
|
||||
>
|
||||
Delete Habitica account
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input
|
||||
id="deleteAmplitudeCheck"
|
||||
v-model="deleteAmplitudeData"
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="deleteAmplitudeCheck"
|
||||
>
|
||||
Delete Amplitude data
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</b-modal-body>
|
||||
</b-modal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -237,8 +184,6 @@ export default {
|
||||
hasParty: false,
|
||||
partyNotExistError: false,
|
||||
adminHasPrivForParty: true,
|
||||
deleteHabiticaAccount: true,
|
||||
deleteAmplitudeData: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -304,25 +249,6 @@ export default {
|
||||
|
||||
this.resetCounter += 1; // tell child components to reinstantiate from scratch
|
||||
},
|
||||
confirmDeleteHero () {
|
||||
if (this.hero._id === this.user._id) {
|
||||
window.alert('You cannot delete your own account.');
|
||||
return;
|
||||
}
|
||||
this.$root.$emit('bv::show::modal', 'delete-member-modal');
|
||||
},
|
||||
deleteHero () {
|
||||
this.$store.dispatch('hall:deleteHero', {
|
||||
uuid: this.hero._id,
|
||||
deleteHabiticaAccount: this.deleteHabiticaAccount,
|
||||
deleteAmplitudeData: this.deleteAmplitudeData,
|
||||
}).then(() => {
|
||||
this.$root.$emit('bv::hide::modal', 'delete-member-modal');
|
||||
this.$router.push({ name: 'adminPanel' });
|
||||
}).catch(err => {
|
||||
window.alert(err);
|
||||
});
|
||||
},
|
||||
hasUnsavedChanges (...comparisons) {
|
||||
for (const index in comparisons) {
|
||||
if (index && comparisons[index]) {
|
||||
|
||||
@@ -37,11 +37,7 @@
|
||||
Party ID
|
||||
</label>
|
||||
<strong class="col-sm-9 col-form-label">
|
||||
<router-link
|
||||
:to="{'name': 'groupAdminGroup', 'params': {'groupId': groupPartyData._id}}"
|
||||
>
|
||||
{{ groupPartyData._id }}
|
||||
</router-link>
|
||||
{{ groupPartyData._id }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
|
||||
@@ -15,25 +15,6 @@
|
||||
:class="{ 'open': expand }"
|
||||
>
|
||||
Subscription, Monthly Perks
|
||||
<span
|
||||
v-if="isSubscribed() && !isCancelled()"
|
||||
class="text-success float-right ml-3"
|
||||
>
|
||||
Active
|
||||
</span>
|
||||
<span
|
||||
v-else-if="isSubscribed() && isCancelled()"
|
||||
class="text-success float-right ml-3"
|
||||
>
|
||||
Active until {{ dateFormat(hero.purchased.plan.dateTerminated) }}
|
||||
</span>
|
||||
<span
|
||||
v-else-if="hero.purchased.plan.customerId && hero.purchased.plan.dateTerminated"
|
||||
class="text-warning float-right ml-3"
|
||||
>
|
||||
Inactive
|
||||
</span>
|
||||
|
||||
<b
|
||||
v-if="hasUnsavedChanges && !expand"
|
||||
class="text-warning float-right"
|
||||
@@ -65,7 +46,7 @@
|
||||
class="form-control"
|
||||
type="text"
|
||||
>
|
||||
<option value="Group Plan">
|
||||
<option value="groupPlan">
|
||||
Group Plan
|
||||
</option>
|
||||
<option value="Stripe">
|
||||
@@ -173,11 +154,7 @@
|
||||
>
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">
|
||||
<router-link
|
||||
:to="{ name: 'groupAdminGroup', params: { groupId: group._id } }"
|
||||
>
|
||||
{{ group.name }}
|
||||
</router-link>
|
||||
{{ group.name }}
|
||||
<small class="float-right">{{ group._id }}</small>
|
||||
</h6>
|
||||
<p class="card-text">
|
||||
@@ -268,7 +245,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<small
|
||||
v-if="isSubscribed() && !isCancelled()"
|
||||
v-if="!hero.purchased.plan.dateTerminated
|
||||
&& hero.purchased.plan.planId"
|
||||
class="text-success"
|
||||
>
|
||||
The subscription does not have a termination date and is active.
|
||||
@@ -441,79 +419,6 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<h2>Payment Details</h2>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="offset-sm-3 col-sm-9 mb-3">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary btn-sm"
|
||||
@click="getSubscriptionPaymentDetails"
|
||||
>
|
||||
Get Subscription Payment Details
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="paymentDetails"
|
||||
>
|
||||
<div
|
||||
v-for="(value, key) in paymentDetails"
|
||||
:key="key"
|
||||
class="form-group row"
|
||||
>
|
||||
<label class="col-sm-3 col-form-label">
|
||||
{{ getHumanReadablePaymentDetails(key).label }}:
|
||||
<span
|
||||
:id="`${key}_tooltip`"
|
||||
v-b-tooltip.hover.right="getHumanReadablePaymentDetails(key).help"
|
||||
class="info-icon"
|
||||
>?</span>
|
||||
</label>
|
||||
<strong class="col-sm-9 col-form-label">
|
||||
<span v-if="value === true">Yes</span>
|
||||
<span v-else-if="value === false">No</span>
|
||||
<span
|
||||
v-else-if="value instanceof String && isDate(value)"
|
||||
v-b-tooltip.hover="value"
|
||||
>
|
||||
{{ formatDate(value) }}
|
||||
</span>
|
||||
<span v-else-if="value === null">---</span>
|
||||
<span v-else>{{ value }}</span>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<a
|
||||
v-if="hero.purchased.plan.paymentMethod === 'Google'"
|
||||
class="btn btn-primary btn-sm"
|
||||
target="_blank"
|
||||
:href="playOrdersUrl"
|
||||
>
|
||||
Play Console
|
||||
</a>
|
||||
<a
|
||||
v-else-if="hero.purchased.plan.paymentMethod === 'Paypal'"
|
||||
class="btn btn-primary btn-sm"
|
||||
target="_blank"
|
||||
:href="'https://www.paypal.com/billing/subscriptions/' + paymentDetails.customerId"
|
||||
>
|
||||
PayPal Dashboard
|
||||
</a>
|
||||
<a
|
||||
v-else-if="hero.purchased.plan.paymentMethod === 'Stripe'"
|
||||
class="btn btn-primary btn-sm"
|
||||
target="_blank"
|
||||
:href="'https://dashboard.stripe.com/customers/' + paymentDetails.customerId"
|
||||
>
|
||||
Stripe Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="expand"
|
||||
@@ -569,36 +474,17 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/colors.scss';
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
.input-group-append {
|
||||
width: auto;
|
||||
|
||||
.input-group-append {
|
||||
width: auto;
|
||||
|
||||
.input-group-text {
|
||||
border-bottom-right-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
color: $gray-200;
|
||||
}
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
.input-group-text {
|
||||
border-bottom-right-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
color: $purple-400;
|
||||
cursor: pointer;
|
||||
margin-left: 0.2rem;
|
||||
background-color: $gray-500;
|
||||
padding: 0.1rem 0.3rem;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
|
||||
.info-icon:hover {
|
||||
background-color: $purple-400;
|
||||
color: white;
|
||||
color: $gray-200;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -609,55 +495,6 @@ import subscriptionBlocks from '@/../../common/script/content/subscriptionBlocks
|
||||
import saveHero from '../mixins/saveHero';
|
||||
import LoadingSpinner from '@/components/ui/loadingSpinner';
|
||||
|
||||
const PLAY_CONSOLE_ORDERS_BASE_URL = import.meta.env.PLAY_CONSOLE_ORDERS_BASE_URL;
|
||||
|
||||
const humanReadablePaymentDetails = {
|
||||
customerId: {
|
||||
label: 'Customer ID',
|
||||
help: 'The unique identifier for the customer in the payment system.',
|
||||
},
|
||||
purchaseDate: {
|
||||
label: 'Purchase Date',
|
||||
help: 'The date when the subscription was purchased or renewed.',
|
||||
},
|
||||
originalPurchaseDate: {
|
||||
label: 'Original Purchase Date',
|
||||
help: 'The date when the subscription was first purchased.',
|
||||
},
|
||||
productId: {
|
||||
label: 'Product ID',
|
||||
help: 'The identifier for the product associated with the subscription.',
|
||||
},
|
||||
transactionId: {
|
||||
label: 'Transaction ID',
|
||||
help: 'The unique identifier for the last transaction in the payment system.',
|
||||
},
|
||||
isCanceled: {
|
||||
label: 'Is Canceled',
|
||||
help: 'Indicates whether the subscription has been canceled by the user or the system.',
|
||||
},
|
||||
isExpired: {
|
||||
label: 'Is Expired',
|
||||
help: 'Indicates whether the subscription has expired. A cancelled subscription may still be active until the end of the billing cycle.',
|
||||
},
|
||||
expirationDate: {
|
||||
label: 'Termination Date',
|
||||
help: 'The date when the subscription will expire or has expired.',
|
||||
},
|
||||
nextPaymentDate: {
|
||||
label: 'Next Payment Date',
|
||||
help: 'The date when the next payment is due. If the subscription is canceled or expired, this may be null.',
|
||||
},
|
||||
lastPaymentDate: {
|
||||
label: 'Last Payment Date',
|
||||
help: 'The date when the lastpayment was made for the subscription.',
|
||||
},
|
||||
failedPayments: {
|
||||
label: 'Failed Payments',
|
||||
help: 'Number of times the payment failed for this subscription.',
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LoadingSpinner,
|
||||
@@ -683,7 +520,6 @@ export default {
|
||||
isConvertingToGroupPlan: false,
|
||||
groupPlanID: '',
|
||||
subscriptionBlocks,
|
||||
paymentDetails: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -717,9 +553,6 @@ export default {
|
||||
}
|
||||
return terminationDate;
|
||||
},
|
||||
playOrdersUrl () {
|
||||
return `${PLAY_CONSOLE_ORDERS_BASE_URL}${this.paymentDetails?.transactionId || ''}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
dateFormat (date) {
|
||||
@@ -750,20 +583,6 @@ export default {
|
||||
this.isConvertingToGroupPlan = true;
|
||||
this.hero.purchased.plan.owner = '';
|
||||
},
|
||||
getSubscriptionPaymentDetails () {
|
||||
this.$store.dispatch('admin:getSubscriptionPaymentDetails', { userIdentifier: this.hero._id })
|
||||
.then(details => {
|
||||
if (details) {
|
||||
this.paymentDetails = details;
|
||||
} else {
|
||||
alert('No payment details found.');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching subscription payment details:', error);
|
||||
alert(`Failed to fetch payment details: ${error.message || 'Unknown error'}`);
|
||||
});
|
||||
},
|
||||
saveClicked (e) {
|
||||
e.preventDefault();
|
||||
if (this.isConvertingToGroupPlan) {
|
||||
@@ -782,31 +601,6 @@ export default {
|
||||
this.$emit('changeUserIdentifier', id);
|
||||
}
|
||||
},
|
||||
getHumanReadablePaymentDetails (key) {
|
||||
return humanReadablePaymentDetails[key] || { label: key, help: '' };
|
||||
},
|
||||
isDate (date) {
|
||||
return moment(date).isValid();
|
||||
},
|
||||
formatDate (date) {
|
||||
return date ? moment(date).format('MM/DD/YYYY') : '---';
|
||||
},
|
||||
isSubscribed () {
|
||||
console.log(this.hero.purchased.plan.customerId, this.hero.purchased.plan.dateTerminated);
|
||||
return this.hero.purchased.plan
|
||||
&& this.hero.purchased.plan.customerId
|
||||
&& this.hero.purchased.plan.planId
|
||||
&& this.hero.purchased.plan.paymentMethod
|
||||
&& (
|
||||
!this.hero.purchased.plan.dateTerminated
|
||||
|| moment(this.hero.purchased.plan.dateTerminated).isAfter(moment())
|
||||
);
|
||||
},
|
||||
isCancelled () {
|
||||
return this.hero.purchased.plan
|
||||
&& this.hero.purchased.plan.dateTerminated
|
||||
&& this.hero.purchased.plan.dateTerminated !== '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -226,7 +226,7 @@ export default {
|
||||
}
|
||||
},
|
||||
async retrieveUserHistory () {
|
||||
const history = await this.$store.dispatch('admin:getUserHistory', { userIdentifier: this.hero._id });
|
||||
const history = await this.$store.dispatch('adminPanel:getUserHistory', { userIdentifier: this.hero._id });
|
||||
this.armoire = history.armoire;
|
||||
this.questInviteResponses = history.questInviteResponses;
|
||||
this.cron = history.cron;
|
||||
|
||||
@@ -8,13 +8,6 @@
|
||||
>
|
||||
{{ $t('adminPanel') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="hasPermission(user, 'groupSupport')"
|
||||
class="nav-link"
|
||||
:to="{name: 'groupAdmin'}"
|
||||
>
|
||||
{{ $t('groupAdmin') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="hasPermission(user, 'accessControl')"
|
||||
class="nav-link"
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<template>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"><slot name="label">{{ label }}</slot></label>
|
||||
<div class="col-sm-9">
|
||||
<slot>
|
||||
<textarea
|
||||
v-if="inputType === 'textarea'"
|
||||
:value="value"
|
||||
class="form-control"
|
||||
:rows="rows"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
></textarea>
|
||||
<input
|
||||
v-else
|
||||
:value="value"
|
||||
class="form-control"
|
||||
:type="inputType"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'input',
|
||||
},
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
},
|
||||
value: {
|
||||
type: [String, Boolean],
|
||||
},
|
||||
inputType: {
|
||||
type: String,
|
||||
default: 'text',
|
||||
},
|
||||
rows: {
|
||||
default: 3,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<form>
|
||||
<form-row
|
||||
v-model="group.name"
|
||||
:label="$t('groupName')"
|
||||
/>
|
||||
<form-row
|
||||
v-model="group.summary"
|
||||
:label="$t('guildSummary')"
|
||||
input-type="textarea"
|
||||
/>
|
||||
<form-row
|
||||
v-model="group.description"
|
||||
:label="$t('groupDescription')"
|
||||
input-type="textarea"
|
||||
rows="6"
|
||||
/>
|
||||
<form-row
|
||||
v-model="group.bannedWordsAllowed"
|
||||
:label="$t('bannedWordsAllowed')"
|
||||
input-type="checkbox"
|
||||
/>
|
||||
<form-row
|
||||
v-model="group.leaderOnly.challenges"
|
||||
:label="$t('leaderOnlyChallenges')"
|
||||
input-type="checkbox"
|
||||
/>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import formRow from '@/components/admin/formRow.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
formRow,
|
||||
},
|
||||
props: {
|
||||
group: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,69 +0,0 @@
|
||||
<template>
|
||||
<div v-if="hasPermission(user, 'groupSupport')">
|
||||
<h2>{{ group.name }}</h2>
|
||||
<supportContainer
|
||||
:title="$t('groupData')"
|
||||
>
|
||||
<groupData
|
||||
:group="group"
|
||||
/>
|
||||
</supportContainer>
|
||||
<supportContainer
|
||||
:title="$t('groupPlanSubscription')"
|
||||
/>
|
||||
<supportContainer
|
||||
v-if="group.type === 'party'"
|
||||
:title="$t('questDetails')"
|
||||
/>
|
||||
<supportContainer
|
||||
:title="$t('members')"
|
||||
>
|
||||
<members
|
||||
:group="group"
|
||||
/>
|
||||
</supportContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { userStateMixin } from '../../../../mixins/userState';
|
||||
import supportContainer from '../../supportContainer.vue';
|
||||
import groupData from './groupData.vue';
|
||||
import members from './members.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
supportContainer,
|
||||
groupData,
|
||||
members,
|
||||
},
|
||||
mixins: [userStateMixin],
|
||||
data () {
|
||||
return {
|
||||
groupId: '',
|
||||
group: {},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
groupId () {
|
||||
this.loadGroup(this.groupId);
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.groupId = this.$route.params.groupId;
|
||||
},
|
||||
methods: {
|
||||
clearData () {
|
||||
this.group = {};
|
||||
},
|
||||
async loadGroup (groupId) {
|
||||
this.$emit('changeGroupId', groupId);
|
||||
this.group = await this.$store.dispatch('admin:getGroup', { groupId });
|
||||
},
|
||||
async updateGroup () {
|
||||
await this.$store.dispatch('admin:updateGroup', { group: this.group });
|
||||
this.$emit('groupSaved', this.group);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,29 +0,0 @@
|
||||
<template>
|
||||
<form-row
|
||||
:label="$t('groupLeader')"
|
||||
>
|
||||
<strong class="col-form-label">
|
||||
<router-link
|
||||
:to="{'name': 'adminPanelUser', 'params': {'userIdentifier': group.leader }}"
|
||||
>
|
||||
{{ group.leader }}
|
||||
</router-link>
|
||||
</strong>
|
||||
</form-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import formRow from '@/components/admin/formRow.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
formRow,
|
||||
},
|
||||
props: {
|
||||
group: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,93 +0,0 @@
|
||||
<template>
|
||||
<div class="row standard-page col-12 d-flex justify-content-center">
|
||||
<div class="group-admin-content">
|
||||
<h1>{{ $t("groupAdmin") }}</h1>
|
||||
<form
|
||||
class="form-inline"
|
||||
@submit.prevent="loadGroup(groupID)"
|
||||
>
|
||||
<div class="input-group col pl-0 pr-0">
|
||||
<input
|
||||
v-model="groupID"
|
||||
class="form-control"
|
||||
type="text"
|
||||
placeholder="Group ID"
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
:disabled="!groupID"
|
||||
@click="loadGroup(groupID)"
|
||||
>
|
||||
Load
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<router-view
|
||||
class="mt-3"
|
||||
@changeGroupId="changeGroupId"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uidField {
|
||||
min-width: 45ch;
|
||||
}
|
||||
|
||||
.input-group-append {
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.group-admin-content {
|
||||
flex: 0 0 800px;
|
||||
max-width: 800px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import VueRouter from 'vue-router';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
const { isNavigationFailure, NavigationFailureType } = VueRouter;
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
groupID: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
mounted () {
|
||||
this.$store.dispatch('common:setTitle', {
|
||||
section: this.$t('groupAdmin'),
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
changeGroupId (id) {
|
||||
this.groupID = id;
|
||||
},
|
||||
async loadGroup (groupId) {
|
||||
if (this.$router.currentRoute.name === 'groupAdminGroup') {
|
||||
await this.$router.push({
|
||||
name: 'groupAdmin',
|
||||
});
|
||||
}
|
||||
await this.$router.push({
|
||||
name: 'groupAdminGroup',
|
||||
params: { groupId },
|
||||
}).catch(failure => {
|
||||
if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {
|
||||
this.$router.go();
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<div class="card mt-2">
|
||||
<div class="card-header">
|
||||
<h3
|
||||
class="mb-0 mt-0"
|
||||
:class="{'open': expand}"
|
||||
@click="expand = !expand"
|
||||
>
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
v-if="expand"
|
||||
class="card-body"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div
|
||||
v-if="expand && onSave"
|
||||
class="card-footer"
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary mt-1"
|
||||
@click="onSave"
|
||||
>
|
||||
{{ $t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
onSave: {
|
||||
type: Function,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
expand: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -43,11 +43,9 @@ export default {
|
||||
const AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||
const userId = parseSettings ? parseSettings.auth.apiId : '';
|
||||
const username = this.$store?.state?.user?.data?.auth?.local?.username || '';
|
||||
|
||||
return this.$t('accountSuspended', {
|
||||
userId,
|
||||
username,
|
||||
communityManagerEmail: COMMUNITY_MANAGER_EMAIL,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
@update-challenge="updateChallenge"
|
||||
/>
|
||||
<close-challenge-modal
|
||||
:members="members"
|
||||
:challenge-id="challenge._id"
|
||||
:prize="challenge.prize"
|
||||
:flag-count="challenge.flagCount"
|
||||
@@ -71,40 +72,32 @@
|
||||
</div>
|
||||
<div class="col-12 col-md-6 text-right">
|
||||
<div
|
||||
class="box member-count p-2"
|
||||
class="box member-count"
|
||||
@click="showMemberModal()"
|
||||
>
|
||||
<div class="box-content">
|
||||
<div class="icon-number-row">
|
||||
<div
|
||||
class="svg-icon member-icon"
|
||||
v-html="icons.memberIcon"
|
||||
></div>
|
||||
<span class="number">{{ challenge.memberCount }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-once
|
||||
class="details"
|
||||
>
|
||||
{{ $t('participantsTitle') }}
|
||||
</div>
|
||||
<div
|
||||
class="svg-icon member-icon"
|
||||
v-html="icons.memberIcon"
|
||||
></div>
|
||||
{{ challenge.memberCount }}
|
||||
<div
|
||||
v-once
|
||||
class="details"
|
||||
>
|
||||
{{ $t('participantsTitle') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="box prize-count p-2">
|
||||
<div class="box-content">
|
||||
<div class="icon-number-row">
|
||||
<div
|
||||
class="svg-icon gem-icon"
|
||||
v-html="icons.gemIcon"
|
||||
></div>
|
||||
<span class="number">{{ challenge.prize || 0 }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-once
|
||||
class="details"
|
||||
>
|
||||
{{ $t('prize') }}
|
||||
</div>
|
||||
<div class="box">
|
||||
<div
|
||||
class="svg-icon gem-icon"
|
||||
v-html="icons.gemIcon"
|
||||
></div>
|
||||
{{ challenge.prize || 0 }}
|
||||
<div
|
||||
v-once
|
||||
class="details"
|
||||
>
|
||||
{{ $t('prize') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -311,6 +304,7 @@
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
padding: 1em;
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
@@ -320,88 +314,22 @@
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
vertical-align: bottom;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&.member-count:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.box-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.icon-number-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 0.1em;
|
||||
|
||||
.number {
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
margin-left: 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
width: 30px;
|
||||
display: inline-block;
|
||||
margin-right: .2em;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.details {
|
||||
font-size: 12px;
|
||||
margin-top: 0.4em;
|
||||
color: $gray-200;
|
||||
width: 100%;
|
||||
padding: 0 4px;
|
||||
line-height: 1.15;
|
||||
word-break: break-word;
|
||||
max-height: 2.3em;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&.member-count {
|
||||
.icon-number-row {
|
||||
.svg-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.number {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
font-size: 11px;
|
||||
line-height: 1.1;
|
||||
max-height: 2.2em;
|
||||
}
|
||||
}
|
||||
|
||||
&.prize-count {
|
||||
.icon-number-row {
|
||||
.svg-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.number {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
font-size: 11px;
|
||||
line-height: 1.1;
|
||||
max-height: 2.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,6 +624,7 @@ export default {
|
||||
this.members = [];
|
||||
},
|
||||
closeChallenge () {
|
||||
this.initialMembersLoad();
|
||||
this.$root.$emit('bv::show::modal', 'close-challenge-modal');
|
||||
},
|
||||
edit () {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
id="close-challenge-modal"
|
||||
:title="$t('endChallenge')"
|
||||
size="md"
|
||||
:hide-header="false"
|
||||
>
|
||||
<div
|
||||
slot="modal-header"
|
||||
@@ -16,9 +15,6 @@
|
||||
>
|
||||
{{ $t('endChallenge') }}
|
||||
</h2>
|
||||
<close-x
|
||||
@close="$root.$emit('bv::hide::modal', 'close-challenge-modal')"
|
||||
/>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<span
|
||||
@@ -32,67 +28,28 @@
|
||||
class="col-12"
|
||||
>
|
||||
<div class="col-12">
|
||||
<div class="badge-section">
|
||||
<div
|
||||
class="gems-left"
|
||||
v-html="icons.gemsOrange"
|
||||
></div>
|
||||
<div
|
||||
class="challenge-badge"
|
||||
v-html="icons.endChallengeBadge"
|
||||
></div>
|
||||
<div
|
||||
class="gems-right"
|
||||
v-html="icons.gemsPurple"
|
||||
></div>
|
||||
<div class="support-habitica">
|
||||
<!-- @TODO: Add challenge achievement badge here-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<strong v-once>{{ $t('selectChallengeWinnersDescription') }}</strong>
|
||||
</div>
|
||||
<div class="col-12 search-input-container">
|
||||
<div class="search-input-wrapper">
|
||||
<div
|
||||
class="search-icon"
|
||||
v-html="icons.search"
|
||||
></div>
|
||||
<input
|
||||
v-model="searchTerm"
|
||||
class="search-input"
|
||||
type="text"
|
||||
placeholder="@Username"
|
||||
@input="searchMembers"
|
||||
@focus="showResults = true"
|
||||
@blur="handleBlur"
|
||||
>
|
||||
<div
|
||||
v-if="showResults && filteredMembers.length > 0"
|
||||
class="search-results"
|
||||
>
|
||||
<div
|
||||
v-for="member in filteredMembers"
|
||||
:key="member._id"
|
||||
class="search-result-item"
|
||||
@mousedown="selectMember(member)"
|
||||
>
|
||||
{{ getMemberDisplayName(member) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<member-search-dropdown
|
||||
:text="winnerText"
|
||||
:members="members"
|
||||
:challenge-id="challengeId"
|
||||
@member-selected="selectMember"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button
|
||||
class="btn award-winner-btn"
|
||||
:class="{'has-winner': winner._id}"
|
||||
:disabled="!winner._id"
|
||||
v-once
|
||||
class="btn btn-primary"
|
||||
@click="closeChallenge"
|
||||
>
|
||||
<span>{{ $t('awardWinners') }}</span>
|
||||
<div
|
||||
class="gem-icon"
|
||||
v-html="icons.gem"
|
||||
></div>
|
||||
<span>{{ prize }} {{ prize === 1 ? $t('gem') : $t('gems') }}</span>
|
||||
{{ $t('awardWinners') }}
|
||||
</button>
|
||||
</div>
|
||||
</span>
|
||||
@@ -103,27 +60,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<strong
|
||||
v-once
|
||||
class="delete-challenge-text"
|
||||
>{{ $t('doYouWantedToDeleteChallenge') }}</strong>
|
||||
</div>
|
||||
<div
|
||||
v-once
|
||||
class="col-12 refund-text"
|
||||
>
|
||||
{{ $t('deleteChallengeRefundDescription') }}
|
||||
<strong v-once>{{ $t('doYouWantedToDeleteChallenge') }}</strong>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button
|
||||
v-once
|
||||
class="btn btn-danger delete-challenge-btn"
|
||||
class="btn btn-danger"
|
||||
@click="deleteChallenge()"
|
||||
>
|
||||
<div
|
||||
class="svg-icon color delete-icon"
|
||||
v-html="icons.deleteIcon"
|
||||
></div>
|
||||
{{ $t('deleteChallenge') }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -138,7 +82,6 @@
|
||||
|
||||
<style lang='scss'>
|
||||
@import '@/assets/scss/colors.scss';
|
||||
@import '@/assets/scss/button.scss';
|
||||
|
||||
#close-challenge-modal {
|
||||
h2 {
|
||||
@@ -151,190 +94,26 @@
|
||||
|
||||
.header-wrap {
|
||||
width: 100%;
|
||||
padding-top: 32px;
|
||||
position: relative;
|
||||
padding-top: 2em;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.search-input-container {
|
||||
margin-top: 1em !important;
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
position: relative;
|
||||
width: 384px;
|
||||
.support-habitica {
|
||||
background-image: url('@/assets/svg/for-css/support-habitica-gems.svg?raw');
|
||||
width: 325px;
|
||||
height: 89px;
|
||||
margin: 0 auto;
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-55%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: $gray-200;
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding-left: 36px;
|
||||
padding-right: 12px;
|
||||
border: 1px solid $gray-400;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.2s ease, border-width 0.2s ease;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: $gray-300;
|
||||
}
|
||||
}
|
||||
|
||||
.search-results {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: $white;
|
||||
border: 1px solid $gray-400;
|
||||
border-top: none;
|
||||
border-radius: 0 0 4px 4px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.search-result-item {
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
background-color: $purple-600;
|
||||
color: $purple-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.delete-challenge-text {
|
||||
color: $maroon-50;
|
||||
}
|
||||
|
||||
.refund-text {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
color: $gray-50;
|
||||
margin-top: 0.5em !important;
|
||||
}
|
||||
|
||||
.delete-challenge-btn {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 24px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.delete-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
.award-winner-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-height: 32px;
|
||||
padding: 4px 12px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:not(:disabled) {
|
||||
background-color: $white;
|
||||
color: $gray-200;
|
||||
border: 1px solid $gray-400;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
|
||||
&.has-winner {
|
||||
background-color: $purple-200;
|
||||
color: $white;
|
||||
border-color: $purple-200;
|
||||
}
|
||||
|
||||
&:hover:not(.has-winner) {
|
||||
background-color: $gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
.gem-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: $gems-color;
|
||||
}
|
||||
}
|
||||
|
||||
.badge-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1.5rem;
|
||||
margin: -24px auto 0;
|
||||
padding: 0.5rem 0;
|
||||
|
||||
.gems-left, .gems-right {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.challenge-badge {
|
||||
width: 48px;
|
||||
height: 52px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-footer, .modal-header {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.footer-wrap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.col-12 {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.col-12:first-child {
|
||||
margin-top: 0;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.or {
|
||||
@@ -344,41 +123,21 @@
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
font-weight: bold;
|
||||
color: $gray-100;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import debounce from 'lodash/debounce';
|
||||
import searchIcon from '@/assets/svg/for-css/search.svg?raw';
|
||||
import deleteIcon from '@/assets/svg/delete.svg?raw';
|
||||
import gemIcon from '@/assets/svg/gem.svg?raw';
|
||||
import endChallengeBadge from '@/assets/svg/for-css/end_challenge_badge.svg?raw';
|
||||
import gemsOrange from '@/assets/svg/for-css/orange100_red100_yellow100_gems.svg?raw';
|
||||
import gemsPurple from '@/assets/svg/for-css/purple200_green10_blue100_gems.svg?raw';
|
||||
import closeX from '@/components/ui/closeX';
|
||||
import memberSearchDropdown from '@/components/members/memberSearchDropdown';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
closeX,
|
||||
memberSearchDropdown,
|
||||
},
|
||||
props: ['challengeId', 'prize', 'flagCount'],
|
||||
props: ['challengeId', 'members', 'prize', 'flagCount'],
|
||||
data () {
|
||||
return {
|
||||
winner: {},
|
||||
searchTerm: '',
|
||||
showResults: false,
|
||||
filteredMembers: [],
|
||||
isSearching: false,
|
||||
icons: Object.freeze({
|
||||
search: searchIcon,
|
||||
deleteIcon,
|
||||
gem: gemIcon,
|
||||
endChallengeBadge,
|
||||
gemsOrange,
|
||||
gemsPurple,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -390,58 +149,9 @@ export default {
|
||||
return this.flagCount > 0;
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.searchMembersDebounced = debounce(this.performSearch, 500);
|
||||
},
|
||||
methods: {
|
||||
searchMembers () {
|
||||
if (!this.searchTerm) {
|
||||
this.filteredMembers = [];
|
||||
this.isSearching = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.isSearching = true;
|
||||
this.searchMembersDebounced();
|
||||
},
|
||||
async performSearch () {
|
||||
if (!this.searchTerm) {
|
||||
this.filteredMembers = [];
|
||||
this.isSearching = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const searchTerm = this.searchTerm.replace('@', '');
|
||||
|
||||
try {
|
||||
const members = await this.$store.dispatch('members:getChallengeMembers', {
|
||||
challengeId: this.challengeId,
|
||||
searchTerm,
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
|
||||
this.filteredMembers = members.slice(0, 10);
|
||||
} catch (err) {
|
||||
this.filteredMembers = [];
|
||||
} finally {
|
||||
this.isSearching = false;
|
||||
}
|
||||
},
|
||||
getMemberDisplayName (member) {
|
||||
if (member.auth?.local?.username) {
|
||||
return `@${member.auth.local.username}`;
|
||||
}
|
||||
return member.profile?.name || '';
|
||||
},
|
||||
selectMember (member) {
|
||||
this.winner = member;
|
||||
this.searchTerm = this.getMemberDisplayName(member);
|
||||
this.showResults = false;
|
||||
},
|
||||
handleBlur () {
|
||||
setTimeout(() => {
|
||||
this.showResults = false;
|
||||
}, 200);
|
||||
},
|
||||
async closeChallenge () {
|
||||
this.challenge = await this.$store.dispatch('challenges:selectChallengeWinner', {
|
||||
|
||||
@@ -52,21 +52,17 @@
|
||||
<div
|
||||
v-if="!group.purchased.plan.dateTerminated
|
||||
&& group.purchased.plan.paymentMethod === 'Stripe'"
|
||||
class="btn btn-primary mb-3"
|
||||
class="btn btn-primary"
|
||||
@click="redirectToStripeEdit({groupId: group.id})"
|
||||
>
|
||||
{{ $t('subUpdateCard') }}
|
||||
</div>
|
||||
<div v-if="!group.purchased.plan.dateTerminated">
|
||||
<div class="small gray-50 mb-3" v-once>
|
||||
{{ $t('groupPlanBillingFYIShort') }}
|
||||
</div>
|
||||
<div
|
||||
class="btn btn-sm btn-danger"
|
||||
@click="cancelSubscriptionConfirm({group: group})"
|
||||
>
|
||||
{{ $t('cancelGroupSub') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="!group.purchased.plan.dateTerminated"
|
||||
class="btn btn-sm btn-danger"
|
||||
@click="cancelSubscriptionConfirm({group: group})"
|
||||
>
|
||||
{{ $t('cancelGroupSub') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -82,7 +82,9 @@
|
||||
<select-translated-array
|
||||
:items="[
|
||||
'groupParentChildren',
|
||||
'groupCouple',
|
||||
'groupFriends',
|
||||
'groupCoworkers',
|
||||
'groupManager',
|
||||
'groupTeacher'
|
||||
]"
|
||||
|
||||
@@ -218,19 +218,13 @@
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
|
||||
// somehow the browser felt like setting this 398px instead
|
||||
// now its fixed to 400 :)
|
||||
width: 400px;
|
||||
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
@media (max-width: 589px) {
|
||||
max-width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (max-width: 353px) {
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.quest-col {
|
||||
::v-deep {
|
||||
.item-wrapper {
|
||||
@@ -257,28 +251,6 @@
|
||||
::v-deep & {
|
||||
.modal-dialog {
|
||||
width: 448px !important;
|
||||
max-width: calc(100vw - 20px);
|
||||
margin: 0.5rem auto;
|
||||
display: flex;
|
||||
|
||||
@media (max-width: 468px) {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
@media (max-width: 353px) {
|
||||
width: 100% !important;
|
||||
margin: 0.25rem auto;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: 300px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,43 +1,37 @@
|
||||
<template>
|
||||
<div
|
||||
class="notification d-flex justify-content-center align-items-center"
|
||||
class="notification d-flex flex-column justify-content-center text-center"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/gifts_start.svg"
|
||||
class="gift-start"
|
||||
alt=""
|
||||
<strong
|
||||
v-once
|
||||
class="mx-auto mb-2"
|
||||
>
|
||||
<div class="content-wrapper d-flex flex-column justify-content-center text-center">
|
||||
<strong
|
||||
v-once
|
||||
class="mx-auto mb-2"
|
||||
>
|
||||
{{ $t('g1g1') }}
|
||||
</strong>
|
||||
<small
|
||||
v-once
|
||||
class="mx-4 mb-3"
|
||||
>
|
||||
{{ $t('g1g1Details') }}
|
||||
</small>
|
||||
<button
|
||||
class="btn btn-secondary mx-auto"
|
||||
@click="showSelectUser()"
|
||||
>
|
||||
{{ $t('sendGift') }}
|
||||
</button>
|
||||
</div>
|
||||
<img
|
||||
src="@/assets/images/gifts_start.svg"
|
||||
class="gift-end"
|
||||
alt=""
|
||||
{{ $t('g1g1') }}
|
||||
</strong>
|
||||
<small
|
||||
v-once
|
||||
class="mx-4 mb-3"
|
||||
>
|
||||
{{ $t('g1g1Details') }}
|
||||
</small>
|
||||
<div
|
||||
class="close-x"
|
||||
@click="remove()"
|
||||
class="btn-secondary mx-auto d-flex"
|
||||
@click="showSelectUser()"
|
||||
>
|
||||
<div
|
||||
class="svg-icon svg-close"
|
||||
v-once
|
||||
class="m-auto"
|
||||
>
|
||||
{{ $t('sendGift') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="notification-remove"
|
||||
@click.stop="remove()"
|
||||
>
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon"
|
||||
v-html="icons.close"
|
||||
></div>
|
||||
</div>
|
||||
@@ -47,89 +41,51 @@
|
||||
<style lang='scss' scoped>
|
||||
@import '@/assets/scss/colors.scss';
|
||||
|
||||
small {
|
||||
small, strong {
|
||||
color: $white;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-size: 14px;
|
||||
line-height: 1.714;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: $white;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-size: 14px;
|
||||
line-height: 1.714;
|
||||
}
|
||||
|
||||
.notification {
|
||||
background-image: url('@/assets/images/gifts_bg.svg');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-image: url('@/assets/images/g1g1-notif.png');
|
||||
height: 10rem;
|
||||
padding: 0;
|
||||
padding: 3rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
white-space: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
padding: 2rem;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.gift-start {
|
||||
height: 96px;
|
||||
width: auto;
|
||||
.notification-remove {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 0;
|
||||
}
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 4px;
|
||||
right: 24px;
|
||||
top: 24px;
|
||||
|
||||
.gift-end {
|
||||
height: 96px;
|
||||
width: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) scaleX(-1);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.close-x {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
|
||||
&:hover .svg-close {
|
||||
opacity: 0.75;
|
||||
.svg-icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.svg-close {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
.btn-secondary {
|
||||
width: 5.75rem;
|
||||
min-height: 1.5rem;
|
||||
border-radius: 2px;
|
||||
border-color: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import closeIcon from '@/assets/svg/close-white.svg?raw';
|
||||
import closeIcon from '@/assets/svg/close-teal.svg?raw';
|
||||
import { mapActions } from '@/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'eventKey'],
|
||||
props: ['notification'],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -138,11 +94,11 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
readNotification: 'notifications:readNotification',
|
||||
}),
|
||||
remove () {
|
||||
if (this.eventKey) {
|
||||
window.sessionStorage.setItem(`hide-g1g1-${this.eventKey}`, 'true');
|
||||
}
|
||||
this.$emit('notification-removed');
|
||||
this.readNotification({ notificationId: this.notification.id });
|
||||
},
|
||||
showSelectUser () {
|
||||
this.$root.$emit('bv::show::modal', 'select-user-modal');
|
||||
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
methods: {
|
||||
action () {
|
||||
this.$router.push(`/profile/${this.$store.state.user.data._id}#achievements`);
|
||||
this.$router.push({ name: 'achievements' });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
action () {
|
||||
this.$router.push(`/profile/${this.$store.state.user.data._id}#stats`);
|
||||
this.$router.push({ name: 'stats' });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -49,12 +49,6 @@
|
||||
v-if="showOnboardingGuide"
|
||||
:never-seen="hasSpecialBadge"
|
||||
/>
|
||||
<gift-one-get-one-notification
|
||||
v-if="shouldShowG1g1"
|
||||
:notification="g1g1Notification"
|
||||
:event-key="g1g1EventKey"
|
||||
@notification-removed="handleG1g1Removed"
|
||||
/>
|
||||
<component
|
||||
:is="notification.type"
|
||||
v-for="notification in notifications"
|
||||
@@ -120,7 +114,6 @@
|
||||
<script>
|
||||
import * as quests from '@/../../common/script/content/quests';
|
||||
import { hasCompletedOnboarding } from '@/../../common/script/libs/onboarding';
|
||||
import find from 'lodash/find';
|
||||
import { mapState, mapActions } from '@/libs/store';
|
||||
import notificationsIcon from '@/assets/svg/notifications.svg?raw';
|
||||
import MenuDropdown from '../ui/customMenuDropdown';
|
||||
@@ -158,7 +151,6 @@ export default {
|
||||
CARD_RECEIVED,
|
||||
CHALLENGE_INVITATION,
|
||||
GIFT_ONE_GET_ONE,
|
||||
GiftOneGetOneNotification: GIFT_ONE_GET_ONE,
|
||||
GROUP_TASK_ASSIGNED,
|
||||
GROUP_TASK_CLAIMED,
|
||||
GROUP_TASK_NEEDS_WORK,
|
||||
@@ -186,14 +178,17 @@ export default {
|
||||
hasSpecialBadge: false,
|
||||
quests,
|
||||
openStatus: undefined,
|
||||
g1g1Hidden: false,
|
||||
actionableNotifications: [
|
||||
'GUILD_INVITATION', 'PARTY_INVITATION', 'CHALLENGE_INVITATION',
|
||||
'QUEST_INVITATION',
|
||||
],
|
||||
// A list of notifications handled by this component,
|
||||
// listed in the order they should appear in the notifications panel.
|
||||
// NOTE: Those not listed here won't be shown in the notification panel!
|
||||
handledNotifications: [
|
||||
'NEW_STUFF',
|
||||
'ITEM_RECEIVED',
|
||||
'GIFT_ONE_GET_ONE',
|
||||
'GROUP_TASK_NEEDS_WORK',
|
||||
'GUILD_INVITATION',
|
||||
'PARTY_INVITATION',
|
||||
@@ -212,10 +207,7 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
currentEventList: 'worldState.data.currentEventList',
|
||||
}),
|
||||
...mapState({ user: 'user.data' }),
|
||||
notificationsOrder () {
|
||||
// Returns a map of NOTIFICATION_TYPE -> POSITION
|
||||
const orderMap = {};
|
||||
@@ -294,9 +286,9 @@ export default {
|
||||
|
||||
return notifications;
|
||||
},
|
||||
// The total number of notification, shown inside the dropdown
|
||||
notificationsCount () {
|
||||
const g1g1Count = this.shouldShowG1g1 ? 1 : 0;
|
||||
return this.notifications.length + g1g1Count;
|
||||
return this.notifications.length;
|
||||
},
|
||||
hasUnseenNotifications () {
|
||||
return this.notifications.some(notification => (notification.seen === false));
|
||||
@@ -307,30 +299,6 @@ export default {
|
||||
showOnboardingGuide () {
|
||||
return !hasCompletedOnboarding(this.user);
|
||||
},
|
||||
currentG1g1Event () {
|
||||
return find(this.currentEventList, event => event.promo === 'g1g1');
|
||||
},
|
||||
g1g1EventKey () {
|
||||
if (!this.currentG1g1Event || !this.currentG1g1Event.start) return null;
|
||||
const startDate = new Date(this.currentG1g1Event.start);
|
||||
return `${startDate.getFullYear()}-${startDate.getMonth()}`;
|
||||
},
|
||||
shouldShowG1g1 () {
|
||||
if (!this.currentG1g1Event) return false;
|
||||
const eventKey = this.g1g1EventKey;
|
||||
if (eventKey && window.sessionStorage.getItem(`hide-g1g1-${eventKey}`) === 'true') {
|
||||
return false;
|
||||
}
|
||||
return !this.g1g1Hidden;
|
||||
},
|
||||
g1g1Notification () {
|
||||
return {
|
||||
type: 'GIFT_ONE_GET_ONE',
|
||||
id: `g1g1-event-${this.currentG1g1Event?.start || 'default'}`,
|
||||
data: {},
|
||||
seen: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
const onboardingPanelState = getLocalSetting(CONSTANTS.keyConstants.ONBOARDING_PANEL_STATE);
|
||||
@@ -396,9 +364,6 @@ export default {
|
||||
isActionable (notification) {
|
||||
return this.actionableNotifications.indexOf(notification.type) !== -1;
|
||||
},
|
||||
handleG1g1Removed () {
|
||||
this.g1g1Hidden = true;
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
@@ -176,12 +176,7 @@ export default {
|
||||
}
|
||||
},
|
||||
showProfile (startingPage) {
|
||||
const userId = this.$store.state.user.data._id;
|
||||
let path = `/profile/${userId}`;
|
||||
if (startingPage !== 'profile') {
|
||||
path += `#${startingPage}`;
|
||||
}
|
||||
this.$router.push(path);
|
||||
this.$router.push({ name: startingPage });
|
||||
},
|
||||
toLearnMore () {
|
||||
this.$router.push({ name: 'subscription' });
|
||||
|
||||
@@ -454,14 +454,17 @@ export default {
|
||||
},
|
||||
isUserMentioned () {
|
||||
const message = this.msg;
|
||||
|
||||
if (message.highlight) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { user } = this;
|
||||
const displayName = user.profile.name;
|
||||
const { username } = user.auth.local;
|
||||
if (!username) return false;
|
||||
const usernamePattern = new RegExp(`@${escapeRegExp(username)}(?:\\b|(?=[^a-zA-Z0-9_]))`, 'i');
|
||||
message.highlight = usernamePattern.test(message.text);
|
||||
const pattern = `@(${escapeRegExp(displayName)}|${escapeRegExp(username)})(\\b)`;
|
||||
message.highlight = new RegExp(pattern, 'i').test(message.text);
|
||||
|
||||
return message.highlight;
|
||||
},
|
||||
flagCountDescription () {
|
||||
|
||||
@@ -328,8 +328,6 @@ export default {
|
||||
alreadyReadNotification,
|
||||
nextCron: null,
|
||||
handledNotifications,
|
||||
isInitialLoadComplete: false,
|
||||
pendingRebirthNotification: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -455,18 +453,6 @@ export default {
|
||||
|
||||
return this.runYesterDailies();
|
||||
},
|
||||
async showPendingRebirthModal () {
|
||||
if (this.pendingRebirthNotification) {
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'rebirth');
|
||||
|
||||
await axios.post('/api/v4/notifications/read', {
|
||||
notificationIds: [this.pendingRebirthNotification.id],
|
||||
});
|
||||
|
||||
this.pendingRebirthNotification = null;
|
||||
}
|
||||
},
|
||||
showDeathModal () {
|
||||
this.playSound('Death');
|
||||
this.$root.$emit('bv::show::modal', 'death');
|
||||
@@ -675,18 +661,6 @@ export default {
|
||||
this.showLevelUpNotifications(this.user.stats.lvl);
|
||||
}
|
||||
this.handleUserNotifications(this.user.notifications);
|
||||
|
||||
this.isInitialLoadComplete = true;
|
||||
|
||||
const hasRebirthConfirmationFlag = localStorage.getItem('show-rebirth-confirmation') === 'true';
|
||||
|
||||
if (hasRebirthConfirmationFlag) {
|
||||
localStorage.removeItem('show-rebirth-confirmation');
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'rebirth');
|
||||
} else {
|
||||
this.showPendingRebirthModal();
|
||||
}
|
||||
},
|
||||
async handleUserNotifications (after) {
|
||||
if (this.$store.state.isRunningYesterdailies) return;
|
||||
@@ -726,15 +700,8 @@ export default {
|
||||
this.$root.$emit('habitica:won-challenge', notification);
|
||||
break;
|
||||
case 'REBIRTH_ACHIEVEMENT':
|
||||
if (localStorage.getItem('show-rebirth-confirmation') === 'true') {
|
||||
markAsRead = false;
|
||||
} else if (!this.isInitialLoadComplete) {
|
||||
this.pendingRebirthNotification = notification;
|
||||
markAsRead = false;
|
||||
} else {
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'rebirth');
|
||||
}
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'rebirth');
|
||||
break;
|
||||
case 'STREAK_ACHIEVEMENT':
|
||||
this.text(`${this.$t('streaks')}: ${this.user.achievements.streak}`, () => {
|
||||
|
||||
@@ -197,7 +197,9 @@
|
||||
<select-translated-array
|
||||
:items="[
|
||||
'groupParentChildren',
|
||||
'groupCouple',
|
||||
'groupFriends',
|
||||
'groupCoworkers',
|
||||
'groupManager',
|
||||
'groupTeacher'
|
||||
]"
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.2);
|
||||
z-index: 9;
|
||||
height: 3rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (max-width: 683px) {
|
||||
height: auto;
|
||||
min-height: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
@@ -29,19 +23,6 @@
|
||||
padding: 0.75rem;
|
||||
|
||||
color: $gray-50;
|
||||
white-space: nowrap;
|
||||
|
||||
@media (max-width: 683px) {
|
||||
padding: 0.5rem;
|
||||
font-size: 13px;
|
||||
flex: 1 1 auto;
|
||||
min-width: fit-content;
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
padding: 0.5rem 0.4rem;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $purple-300;
|
||||
|
||||
@@ -189,7 +189,6 @@
|
||||
>
|
||||
</p>
|
||||
<div
|
||||
v-if="paymentMethodLogo.icon"
|
||||
class="svg svg-icon mb-4"
|
||||
:class="paymentMethodLogo.class"
|
||||
v-html="paymentMethodLogo.icon"
|
||||
@@ -206,13 +205,6 @@
|
||||
<div>{{ $t('subUpdateCard') }}</div>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-once
|
||||
v-if="!hasGroupPlan"
|
||||
class="small text-center mb-4"
|
||||
>
|
||||
{{ $t('subscriptionBillingFYIShort') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="purchasedPlanExtraMonthsDetails.months > 0"
|
||||
class="extra-months green-10 py-2 px-3 mb-4"
|
||||
@@ -415,13 +407,6 @@
|
||||
<div class="purple-bar my-auto"></div>
|
||||
</div>
|
||||
<div class="d-flex flex-column align-items-center mt-3">
|
||||
<div
|
||||
v-once
|
||||
v-if="!hasSubscription"
|
||||
class="small gray-100 w-50 text-center mb-5"
|
||||
>
|
||||
{{ $t('subscriptionBillingFYI') }}
|
||||
</div>
|
||||
<div
|
||||
v-once
|
||||
class="svg-icon svg-gift-box mb-2"
|
||||
@@ -646,7 +631,7 @@
|
||||
background-color: $purple-400;
|
||||
height: 1px;
|
||||
width: 50%;
|
||||
max-width: 417px;
|
||||
max-width: 432px;
|
||||
}
|
||||
|
||||
.purple-gradient {
|
||||
@@ -669,12 +654,6 @@
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.small {
|
||||
font-size: 12px;
|
||||
line-height: 1.67;
|
||||
max-width: 874px;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
border-radius: 8px;
|
||||
width: 192px;
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
class="staff col-6 p-0"
|
||||
>
|
||||
<div class="d-flex">
|
||||
<div
|
||||
<router-link
|
||||
class="title"
|
||||
:to="{'name': 'userProfile', 'params': {'userId': user.uuid}}"
|
||||
>
|
||||
{{ user.name }}
|
||||
</div>
|
||||
</router-link>
|
||||
<div
|
||||
v-if="user.type === 'Staff'"
|
||||
class="svg-icon staff-icon ml-1"
|
||||
v-html="icons.tierStaff"
|
||||
></div>
|
||||
|
||||
@@ -269,13 +269,7 @@
|
||||
|
||||
.modal-dialog {
|
||||
width: 448px;
|
||||
max-width: calc(100vw - 20px);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
|
||||
@media (max-width: 468px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.badge-dialog {
|
||||
@@ -352,23 +346,7 @@
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
max-width: 448px;
|
||||
margin: 0 auto;
|
||||
|
||||
@media (max-width: 468px) {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: 300px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
width: 448px;
|
||||
}
|
||||
|
||||
.item-wrapper {
|
||||
@@ -586,7 +564,7 @@
|
||||
|
||||
.limitedTime {
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
width: 446px;
|
||||
font-size: 0.75rem;
|
||||
margin: 24px 0 0 0;
|
||||
background-color: $purple-300;
|
||||
@@ -873,13 +851,8 @@ export default {
|
||||
return;
|
||||
}
|
||||
if (this.genericPurchase) {
|
||||
if (this.item.key === 'rebirth_orb') {
|
||||
localStorage.setItem('show-rebirth-confirmation', 'true');
|
||||
}
|
||||
await this.makeGenericPurchase(this.item, 'buyModal', this.selectedAmountToBuy);
|
||||
if (this.item.key !== 'rebirth_orb') {
|
||||
await this.purchased(this.item.text);
|
||||
}
|
||||
this.makeGenericPurchase(this.item, 'buyModal', this.selectedAmountToBuy);
|
||||
await this.purchased(this.item.text);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,22 +111,6 @@
|
||||
|
||||
.modal-dialog {
|
||||
width: 448px;
|
||||
max-width: calc(100vw - 20px);
|
||||
display: flex;
|
||||
|
||||
@media (max-width: 468px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: 300px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
|
||||
@@ -163,33 +163,8 @@
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
margin-top: 8%;
|
||||
width: 448px !important;
|
||||
max-width: calc(100vw - 20px);
|
||||
display: flex;
|
||||
|
||||
@media (max-width: 468px) {
|
||||
width: 100% !important;
|
||||
margin: 3rem auto 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 353px) {
|
||||
margin: 2.5rem auto 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.badge-dialog {
|
||||
left: -8px;
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: 300px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
@@ -120,9 +120,9 @@
|
||||
>
|
||||
<ul>
|
||||
<li>
|
||||
{{ $t('commGuideAKA', {habitName: 'Viirus', realName: 'Phillip'}) }}
|
||||
({{ $t('commGuideOnGitHub', {gitHubName: 'phillipthelen'}) }})
|
||||
- Developer
|
||||
{{ $t('commGuideAKA', {habitName: 'heyeilatan', realName: 'Natalie'}) }}
|
||||
({{ $t('commGuideOnGitHub', {gitHubName: 'CuriousMagpie'}) }})
|
||||
- Web Developer
|
||||
</li>
|
||||
<li>
|
||||
{{ $t('commGuideAKA', {habitName: 'redphoenix', realName: 'Vicky'}) }}
|
||||
@@ -133,6 +133,10 @@
|
||||
{{ $t('commGuideAKA', {habitName: 'Beffymaroo', realName: 'Beth'}) }}
|
||||
- Art, Community Management, Many Hats
|
||||
</li>
|
||||
<li>
|
||||
{{ $t('commGuideAKA', {habitName: 'SabreCat', realName: 'Sabe'}) }}
|
||||
- Web Developer
|
||||
</li>
|
||||
<li>
|
||||
{{ $t('commGuideAKA', {habitName: 'Apollo', realName: 'Tressley'}) }}
|
||||
- Designer
|
||||
@@ -142,12 +146,8 @@
|
||||
- Mobile Designer
|
||||
</li>
|
||||
<li>
|
||||
{{ $t('commGuideAKA', {habitName: 'SabreCat', realName: 'Kalista'}) }}
|
||||
- Web Developer
|
||||
</li>
|
||||
<li>
|
||||
{{ $t('commGuideAKA', {habitName: 'fizself', realName: 'Hafiz'}) }}
|
||||
- Developer
|
||||
{{ $t('commGuideAKA', {habitName: 'Viirus', realName: 'Phillip'}) }}
|
||||
- Mobile Developer
|
||||
</li>
|
||||
</ul>
|
||||
<p v-html="$t('commGuidePara013')"></p>
|
||||
@@ -156,7 +156,7 @@
|
||||
<em>
|
||||
Lemoness, lefnire, Slappybag, litenull, Shaner, Bobbyroberts99, wc8,
|
||||
Breadstrings, Megan, Blade, Daniel the Bard, deilann, shanaqui, Nakonana,
|
||||
Dewines, Alys, Fox_town, MaybeSteveRogers, Cantras, and heyeilatan.
|
||||
Dewines, Alys, Fox_town, MaybeSteveRogers, and Cantras.
|
||||
</em>
|
||||
</p>
|
||||
<h2 id="final">
|
||||
|
||||
@@ -45,9 +45,6 @@
|
||||
<p class="gray-200">
|
||||
{{ $t('billedMonthly') }}
|
||||
</p>
|
||||
<small class="gray-200">
|
||||
{{ $t('groupPlanBillingFYI') }}
|
||||
</small>
|
||||
</div>
|
||||
<div class="top-right"></div>
|
||||
<div class="d-flex justify-content-between align-items-middle w-100 gap-72 mb-100">
|
||||
@@ -117,9 +114,6 @@
|
||||
<p class="gray-200">
|
||||
{{ $t('billedMonthly') }}
|
||||
</p>
|
||||
<small class="gray-200">
|
||||
{{ $t('groupPlanBillingFYI') }}
|
||||
</small>
|
||||
</div>
|
||||
<div class="bot-right"></div>
|
||||
</div>
|
||||
@@ -180,11 +174,6 @@
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 12px;
|
||||
line-height: 1.67;
|
||||
}
|
||||
|
||||
// Major layout elements
|
||||
|
||||
.bottom-banner {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary d-flex align-items-center justify-content-center"
|
||||
:class="{'btn-disabled': !canSave}"
|
||||
:class="{disabled: !canSave}"
|
||||
type="button"
|
||||
@click="submit()"
|
||||
>
|
||||
@@ -162,13 +162,13 @@
|
||||
>
|
||||
<div
|
||||
class="habit-option-icon svg-icon no-transition"
|
||||
:class="task.up ? '' : 'icon-disabled'"
|
||||
:class="task.up ? '' : 'disabled'"
|
||||
v-html="icons.positive"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class="habit-option-label no-transition"
|
||||
:class="task.up ? cssClass('icon') : 'label-disabled'"
|
||||
:class="task.up ? cssClass('icon') : 'disabled'"
|
||||
>
|
||||
{{ $t('positive') }}
|
||||
</div>
|
||||
@@ -188,13 +188,13 @@
|
||||
>
|
||||
<div
|
||||
class="habit-option-icon no-transition svg-icon negative mx-auto"
|
||||
:class="task.down ? '' : 'icon-disabled'"
|
||||
:class="task.down ? '' : 'disabled'"
|
||||
v-html="icons.negative"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class="habit-option-label no-transition"
|
||||
:class="task.down ? cssClass('icon') : 'label-disabled'"
|
||||
:class="task.down ? cssClass('icon') : 'disabled'"
|
||||
>
|
||||
{{ $t('negative') }}
|
||||
</div>
|
||||
@@ -592,7 +592,7 @@
|
||||
<button
|
||||
class="btn btn-primary btn-footer
|
||||
d-flex align-items-center justify-content-center"
|
||||
:class="{'btn-disabled': !canSave}"
|
||||
:class="{disabled: !canSave}"
|
||||
type="button"
|
||||
@click="submit()"
|
||||
>
|
||||
@@ -881,14 +881,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.btn-disabled {
|
||||
.disabled {
|
||||
background-color: $white;
|
||||
border: 2px solid transparent;
|
||||
color: $gray-200;
|
||||
line-height: 1.714;
|
||||
box-shadow: 0px 1px 3px 0px rgba(26, 24, 29, 0.12), 0px 1px 2px 0px rgba(26, 24, 29, 0.24);
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
|
||||
&:focus {
|
||||
background-color: $white;
|
||||
@@ -950,7 +948,7 @@
|
||||
height: 10px;
|
||||
color: $white;
|
||||
|
||||
&.icon-disabled {
|
||||
&.disabled {
|
||||
color: $gray-200;
|
||||
}
|
||||
|
||||
@@ -964,7 +962,7 @@
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
|
||||
&.label-disabled {
|
||||
&.disabled {
|
||||
color: $gray-100;
|
||||
font-weight: normal;
|
||||
}
|
||||
@@ -1020,7 +1018,7 @@
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.input-group-outer.disabled .input-group-text {
|
||||
.disabled .input-group-text {
|
||||
color: $gray-200;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
.toggle-switch-inner:before {
|
||||
content: "";
|
||||
padding-left: 10px;
|
||||
background-color: $green-50;
|
||||
background-color: $green-10;
|
||||
}
|
||||
|
||||
.toggle-switch-inner:after {
|
||||
|
||||
@@ -1126,12 +1126,7 @@ export default {
|
||||
this.loadUser();
|
||||
this.oldTitle = this.$store.state.title;
|
||||
this.handleExternalLinks();
|
||||
// Check if there's a hash in the URL to determine the starting page
|
||||
let pageToSelect = this.startingPage;
|
||||
if (window.location.hash && (window.location.hash === '#stats' || window.location.hash === '#achievements')) {
|
||||
pageToSelect = window.location.hash.substring(1);
|
||||
}
|
||||
this.selectPage(pageToSelect);
|
||||
this.selectPage(this.startingPage);
|
||||
this.$root.$on('habitica:report-profile-result', () => {
|
||||
this.loadUser();
|
||||
});
|
||||
@@ -1216,15 +1211,10 @@ export default {
|
||||
},
|
||||
selectPage (page) {
|
||||
this.selectedPage = page || 'profile';
|
||||
const profileUserId = this.userId || this.userLoggedIn._id;
|
||||
let newPath = `/profile/${profileUserId}`;
|
||||
if (page !== 'profile') {
|
||||
newPath += `#${page}`;
|
||||
}
|
||||
window.history.replaceState(null, null, newPath);
|
||||
window.history.replaceState(null, null, '');
|
||||
this.$store.dispatch('common:setTitle', {
|
||||
section: this.$t('user'),
|
||||
subSection: this.$t(page),
|
||||
subSection: this.$t(this.startingPage),
|
||||
});
|
||||
},
|
||||
getNextIncentive () {
|
||||
|
||||
@@ -3,10 +3,14 @@ import isEqual from 'lodash/isEqual';
|
||||
import keys from 'lodash/keys';
|
||||
import pick from 'lodash/pick';
|
||||
import amplitude from 'amplitude-js';
|
||||
import { gtag, install } from 'ga-gtag';
|
||||
import Vue from 'vue';
|
||||
import getStore from '@/store';
|
||||
|
||||
const AMPLITUDE_KEY = import.meta.env.AMPLITUDE_KEY;
|
||||
const DEBUG_ENABLED = import.meta.env.DEBUG_ENABLED === 'true';
|
||||
const GA_ID = import.meta.env.GA_ID;
|
||||
const IS_PRODUCTION = import.meta.env.NODE_ENV === 'production';
|
||||
const REQUIRED_FIELDS = ['eventCategory', 'eventAction'];
|
||||
|
||||
let analyticsLoading = false;
|
||||
@@ -15,7 +19,7 @@ let analyticsReady = false;
|
||||
function _getConsentedUser () {
|
||||
const store = getStore();
|
||||
const user = store.state.user.data;
|
||||
if (!user?.preferences?.analyticsConsent) {
|
||||
if (!user?.preferences?.analyticsConsent || navigator.globalPrivacyControl) {
|
||||
return false;
|
||||
}
|
||||
return user;
|
||||
@@ -65,6 +69,10 @@ function _gatherUserStats (properties) {
|
||||
export function safeSetup (userId) {
|
||||
if (analyticsLoading || analyticsReady) return;
|
||||
analyticsLoading = true;
|
||||
install(GA_ID, {
|
||||
debug_mode: DEBUG_ENABLED || !IS_PRODUCTION,
|
||||
user_id: userId,
|
||||
});
|
||||
amplitude.getInstance().init(AMPLITUDE_KEY, userId);
|
||||
analyticsReady = true;
|
||||
analyticsLoading = false;
|
||||
@@ -82,6 +90,7 @@ export function track (properties, options = {}) {
|
||||
// Track events on the server by default
|
||||
if (trackOnClient === true) {
|
||||
amplitude.getInstance().logEvent(properties.eventAction, properties);
|
||||
gtag('event', properties.eventAction, properties);
|
||||
} else {
|
||||
const store = getStore();
|
||||
store.dispatch('analytics:trackEvent', properties);
|
||||
@@ -96,6 +105,7 @@ export function updateUser (properties = {}) {
|
||||
// Use nextTick to avoid blocking the UI
|
||||
Vue.nextTick(() => {
|
||||
_gatherUserStats(properties);
|
||||
gtag('set', 'user_properties', properties);
|
||||
forEach(properties, (value, key) => {
|
||||
const identify = new amplitude.Identify().set(key, value);
|
||||
amplitude.getInstance().identify(identify);
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import habiticaMarkdown from 'habitica-markdown/withMentions';
|
||||
import escapeRegExp from 'lodash/escapeRegExp';
|
||||
|
||||
export default function renderWithMentions (text, user) {
|
||||
if (!text) return null;
|
||||
const env = { userName: user.auth.local.username };
|
||||
let html = habiticaMarkdown.render(String(text), env);
|
||||
|
||||
if (user.auth.local.username) {
|
||||
const username = escapeRegExp(user.auth.local.username);
|
||||
const regex = new RegExp(`(<span class="at-text">@)(${username})(</span>)`, 'gi');
|
||||
html = html.replace(regex, (match, p1, p2, p3) => `${p1.replace('at-text', 'at-text at-highlight')}${p2}${p3}`);
|
||||
}
|
||||
|
||||
return html;
|
||||
const env = { userName: user.auth.local.username, displayName: user.profile.name };
|
||||
return habiticaMarkdown.render(String(text), env);
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ export default [
|
||||
uuid: '61b2c855-0a30-444c-bcc6-1cac876460b0',
|
||||
},
|
||||
{
|
||||
name: 'fizself',
|
||||
name: 'heyeilatan',
|
||||
type: 'Staff',
|
||||
uuid: 'e39ea3eb-28d2-48da-8568-7a5b0e64498e',
|
||||
uuid: 'f4e5c6da-0617-48bf-b3bd-9f97636774a8',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
}
|
||||
|
||||
.settings-content {
|
||||
flex: 0 0 751px;
|
||||
flex: 0 0 732px;
|
||||
max-width: unset;
|
||||
|
||||
::v-deep {
|
||||
|
||||
@@ -33,21 +33,6 @@
|
||||
v-html="$t('privacySettingsOverview') + ' ' + $t('learnMorePrivacy')"
|
||||
>
|
||||
</p>
|
||||
<div
|
||||
v-if="gpcEnabled"
|
||||
class="mx-4 px-3 py-2 mb-4 gpc-alert d-flex align-items-center black bg-yellow-50"
|
||||
>
|
||||
<div
|
||||
class="svg svg-icon mr-2"
|
||||
v-html="icons.alert"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="gpc-message"
|
||||
v-html="gpcInfo"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="d-flex justify-content-center"
|
||||
>
|
||||
@@ -106,29 +91,6 @@
|
||||
line-height: 1.33;
|
||||
}
|
||||
|
||||
.gpc-alert {
|
||||
border-radius: 4px;
|
||||
line-height: 1.714;
|
||||
|
||||
.gpc-message {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
::v-deep a {
|
||||
color: $black;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
width: 16px;
|
||||
opacity: 0.75;
|
||||
|
||||
::v-deep svg path {
|
||||
fill: $black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mb-28p {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
@@ -148,7 +110,6 @@ import ToggleSwitch from '@/components/ui/toggleSwitch.vue';
|
||||
import { GenericUserPreferencesMixin } from '@/pages/settings/components/genericUserPreferencesMixin';
|
||||
import { InlineSettingMixin } from '../components/inlineSettingMixin';
|
||||
import { mapState } from '@/libs/store';
|
||||
import alert from '@/assets/svg/for-css/alert.svg?raw';
|
||||
|
||||
export default {
|
||||
mixins: [
|
||||
@@ -159,32 +120,14 @@ export default {
|
||||
SaveCancelButtons,
|
||||
ToggleSwitch,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
alert,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
}),
|
||||
gpcEnabled () {
|
||||
return navigator.globalPrivacyControl;
|
||||
},
|
||||
gpcInfo () {
|
||||
const gpcUrl = 'https://globalprivacycontrol.org/';
|
||||
if (this.user.preferences.analyticsConsent) {
|
||||
return this.$t('gpcPlusAnalytics', { url: gpcUrl });
|
||||
}
|
||||
return this.$t('gpcWarning', { url: gpcUrl });
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
finalize () {
|
||||
this.setUserPreference('analyticsConsent');
|
||||
localStorage.setItem('analyticsConsent', this.user.preferences.analyticsConsent);
|
||||
this.mixinData.inlineSettingMixin.sharedState.inlineSettingUnsavedValues = false;
|
||||
},
|
||||
prefToggled () {
|
||||
@@ -192,10 +135,7 @@ export default {
|
||||
this.mixinData.inlineSettingMixin.sharedState.inlineSettingUnsavedValues = newVal;
|
||||
},
|
||||
resetControls () {
|
||||
if (this.mixinData.inlineSettingMixin.sharedState.inlineSettingUnsavedValues) {
|
||||
this.user.preferences.analyticsConsent = !this.user.preferences.analyticsConsent;
|
||||
this.mixinData.inlineSettingMixin.sharedState.inlineSettingUnsavedValues = false;
|
||||
}
|
||||
this.user.preferences.analyticsConsent = !this.user.preferences.analyticsConsent;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -263,12 +263,11 @@ export default {
|
||||
this.$store.dispatch('tasks:fetchUserTasks'),
|
||||
]).then(() => {
|
||||
this.$store.state.isUserLoaded = true;
|
||||
let analyticsConsent = localStorage.getItem('analyticsConsent');
|
||||
if (analyticsConsent !== null) {
|
||||
analyticsConsent = analyticsConsent === 'true';
|
||||
if (analyticsConsent !== this.user.preferences.analyticsConsent) {
|
||||
this.$store.dispatch('user:set', { 'preferences.analyticsConsent': analyticsConsent });
|
||||
}
|
||||
const analyticsConsent = localStorage.getItem('analyticsConsent');
|
||||
if (analyticsConsent !== null
|
||||
&& analyticsConsent !== this.user.preferences.analyticsConsent
|
||||
) {
|
||||
this.$store.dispatch('user:set', { 'preferences.analyticsConsent': analyticsConsent });
|
||||
}
|
||||
if (window && window['habitica-i18n']) {
|
||||
if (this.user.preferences.language === window['habitica-i18n'].language.code) {
|
||||
|
||||
@@ -24,8 +24,6 @@ const AdminContainerPage = () => import(/* webpackChunkName: "admin-panel" */'@/
|
||||
const AdminPanelPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/admin-panel');
|
||||
const AdminPanelUserPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/admin-panel/user-support');
|
||||
const AdminPanelSearchPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/admin-panel/search');
|
||||
const GroupAdminPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/groups');
|
||||
const GroupAdminGroupPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/groups/group-support');
|
||||
const BlockerPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/blocker');
|
||||
|
||||
// Tasks
|
||||
@@ -90,9 +88,6 @@ const router = new VueRouter({
|
||||
path: '/profile/:userId',
|
||||
props: true,
|
||||
},
|
||||
{ name: 'profile', path: '/user/profile' },
|
||||
{ name: 'stats', path: '/user/stats' },
|
||||
{ name: 'achievements', path: '/user/achievements' },
|
||||
{
|
||||
path: '/inventory',
|
||||
component: InventoryContainer,
|
||||
@@ -221,28 +216,6 @@ const router = new VueRouter({
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'groupAdmin',
|
||||
path: 'groups',
|
||||
component: GroupAdminPage,
|
||||
meta: {
|
||||
privilegeNeeded: [ // any one of these is enough to give access
|
||||
'groupSupport',
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'groupAdminGroup',
|
||||
path: ':groupId',
|
||||
component: GroupAdminGroupPage,
|
||||
meta: {
|
||||
privilegeNeeded: [
|
||||
'groupsSupport',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'blockers',
|
||||
path: 'blockers',
|
||||
@@ -372,10 +345,6 @@ router.beforeEach(async (to, from, next) => {
|
||||
if (to.params.startingPage !== undefined) {
|
||||
startingPage = to.params.startingPage;
|
||||
}
|
||||
// Check if there's a hash in the URL for stats or achievements
|
||||
if (to.hash === '#stats' || to.hash === '#achievements') {
|
||||
startingPage = to.hash.substring(1);
|
||||
}
|
||||
if (from.name === null) {
|
||||
store.state.postLoadModal = `profile/${to.params.userId}`;
|
||||
return next({ name: 'tasks' });
|
||||
@@ -396,18 +365,10 @@ router.beforeEach(async (to, from, next) => {
|
||||
}
|
||||
|
||||
if ((to.name === 'stats' || to.name === 'achievements' || to.name === 'profile') && from.name !== null) {
|
||||
const userId = store.state.user.data._id;
|
||||
let redirectPath = `/profile/${userId}`;
|
||||
if (to.name === 'stats') {
|
||||
redirectPath += '#stats';
|
||||
} else if (to.name === 'achievements') {
|
||||
redirectPath += '#achievements';
|
||||
}
|
||||
router.app.$emit('habitica:show-profile', {
|
||||
userId,
|
||||
startingPage: to.name,
|
||||
fromPath: from.path,
|
||||
toPath: redirectPath,
|
||||
toPath: to.path,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export async function searchUsers (store, payload) {
|
||||
const url = `/api/v4/admin/search/${payload.userIdentifier}`;
|
||||
const response = await axios.get(url);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function getUserHistory (store, payload) {
|
||||
const url = `/api/v4/admin/user/${payload.userIdentifier}/history`;
|
||||
const response = await axios.get(url);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function getSubscriptionPaymentDetails (store, payload) {
|
||||
const url = `/api/v4/admin/user/${payload.userIdentifier}/subscription-payment-details`;
|
||||
const response = await axios.get(url);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function getGroup (store, payload) {
|
||||
const url = `/api/v4/admin/groups/${payload.groupId}`;
|
||||
const response = await axios.get(url);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function updateGroup (store, payload) {
|
||||
const url = `/api/v4/admin/groups/${payload.groupId || payload.group._id}`;
|
||||
const response = await axios.put(url, payload.group);
|
||||
return response.data.data;
|
||||
}
|
||||
13
website/client/src/store/actions/adminPanel.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export async function searchUsers (store, payload) {
|
||||
const url = `/api/v4/admin/search/${payload.userIdentifier}`;
|
||||
const response = await axios.get(url);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function getUserHistory (store, payload) {
|
||||
const url = `/api/v4/admin/user/${payload.userIdentifier}/history`;
|
||||
const response = await axios.get(url);
|
||||
return response.data.data;
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import axios from 'axios';
|
||||
import { authAsCredentialsState, LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||
|
||||
const GA_ID = import.meta.env.GA_ID;
|
||||
|
||||
function saveLocalDataAuth (store, apiId, apiToken) {
|
||||
const credentialsObj = {
|
||||
auth: {
|
||||
@@ -121,6 +123,9 @@ export async function appleAuth (store, params) {
|
||||
export function logout (store, options = {}) {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
if (window.gtag) {
|
||||
window.gtag('config', GA_ID, { user_id: null });
|
||||
}
|
||||
const query = options.redirectToLogin === true ? '?redirectToLogin=true' : '';
|
||||
window.location.href = `/logout-server${query}`;
|
||||
}
|
||||
|
||||
@@ -38,9 +38,3 @@ export async function getHeroGroupPlans (store, payload) {
|
||||
const response = await axios.get(url);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function deleteHero (store, payload) {
|
||||
const url = `/api/v4/members/${payload.uuid}?deleteAccount=${payload.deleteHabiticaAccount}&deleteAmplitude=${payload.deleteAmplitudeData}`;
|
||||
const response = await axios.delete(url);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { flattenAndNamespace } from '@/libs/store/helpers/internals';
|
||||
|
||||
import * as admin from './admin';
|
||||
import * as adminPanel from './adminPanel';
|
||||
import * as common from './common';
|
||||
import * as user from './user';
|
||||
import * as tasks from './tasks';
|
||||
@@ -26,7 +26,7 @@ import * as blockers from './blockers';
|
||||
// Example: fetch in user.js -> 'user:fetch'
|
||||
|
||||
const actions = flattenAndNamespace({
|
||||
admin,
|
||||
adminPanel,
|
||||
common,
|
||||
user,
|
||||
tasks,
|
||||
|
||||
@@ -12,12 +12,12 @@ describe('renderWithMentions', () => {
|
||||
expect(result).to.be.null;
|
||||
});
|
||||
|
||||
test('does not highlight displayname to prevent impersonation', () => {
|
||||
test('highlights displayname', () => {
|
||||
const text = 'hello @displayedUser with text after';
|
||||
|
||||
const result = renderMarkdown(text, user('user', 'displayedUser'));
|
||||
expect(result).to.contain('<span class="at-text">@displayedUser</span>');
|
||||
expect(result).to.not.contain('<span class="at-text at-highlight">@displayedUser</span>');
|
||||
|
||||
expect(result).to.contain('<span class="at-text at-highlight">@displayedUser</span>');
|
||||
});
|
||||
|
||||
test('highlights username', () => {
|
||||
@@ -56,8 +56,7 @@ describe('renderWithMentions', () => {
|
||||
|
||||
const result = renderMarkdown(plainText, user('use', 'mentions'));
|
||||
|
||||
expect(result).to.contain('<span class="at-text">@mentions</span>');
|
||||
expect(result).to.not.contain('<span class="at-text at-highlight">@mentions</span>');
|
||||
expect(result).to.contain('<span class="at-text at-highlight">@mentions</span>');
|
||||
expect(result).to.contain('<span class="at-text at-highlight">@use</span>');
|
||||
expect(result).to.contain('<span class="at-text">@mail</span>');
|
||||
expect(result).to.not.contain('<span class="at-text at-highlight">@mentions</span>.com');
|
||||
|
||||
@@ -26,6 +26,7 @@ const envVars = [
|
||||
'EMAILS_COMMUNITY_MANAGER_EMAIL',
|
||||
'EMAILS_TECH_ASSISTANCE_EMAIL',
|
||||
'EMAILS_PRESS_ENQUIRY_EMAIL',
|
||||
'GA_ID',
|
||||
'STRIPE_PUB_KEY',
|
||||
'GOOGLE_CLIENT_ID',
|
||||
'APPLE_AUTH_CLIENT_ID',
|
||||
@@ -35,7 +36,7 @@ const envVars = [
|
||||
'TIME_TRAVEL_ENABLED',
|
||||
'DEBUG_ENABLED',
|
||||
'CONTENT_SWITCHOVER_TIME_OFFSET',
|
||||
'PLAY_CONSOLE_ORDERS_BASE_URL',
|
||||
// TODO necessary? if yes how not to mess up with vue cli? 'NODE_ENV'
|
||||
];
|
||||
|
||||
const envObject = {};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"achievement": "Постижение",
|
||||
"achievement": "Достижения",
|
||||
"onwards": "Напред!",
|
||||
"levelup": "Изпълнявайки целите си в истинския живот, Вие се качихте ниво и здравето Ви беше запълнено!",
|
||||
"reachedLevel": "Достигнахте Ниво <%= level %>",
|
||||
@@ -106,25 +106,5 @@
|
||||
"achievementSeasonalSpecialist": "Сезонен експерт",
|
||||
"achievementRedLetterDayText": "Са събрали всички Червени животни.",
|
||||
"achievementSeeingRedModalText": "Събрали сте всички Червени любимци!",
|
||||
"achievementSkeletonCrewText": "Събрали са всички Скелетни животни.",
|
||||
"achievementVioletsAreBlueText": "Събра всички сини пет-ове Памучен бонбон.",
|
||||
"achievementWildBlueYonderModalText": "Ти укроти всички маунт-ове Памучен бонбон синьо!",
|
||||
"achievementWildBlueYonderText": "Укроти всички маунт-ове Памучен бонбон синьо.",
|
||||
"achievementVioletsAreBlue": "Розите са червени, Теменужките са сини",
|
||||
"achievementVioletsAreBlueModalText": "Ти събра (или колекционира) всички домашни любимци (или пет-ове) от серията Памучен бонбон синьо!",
|
||||
"achievementWildBlueYonder": "Дивото синьо небе",
|
||||
"achievementSeasonalSpecialistText": "Завърши всички сезонни куестове от пролетта и зимата: Лов на яйца (Egg Hunt), Дядо Коледа-ловец (Trapper Santa) и Намери мечето (Find the Cub)!",
|
||||
"achievementSeasonalSpecialistModalText": "Вие завършихте всичките сезонни куестове!",
|
||||
"achievementDomesticatedModalText": "Ти събра (или колекционира) всички опитомени домашни любимци (пет-ове)!",
|
||||
"achievementDomesticatedText": "Излюпи (или Отгледа) всички стандартни цветове на опитомени домашни любимци (пет-ове): пор, морско свинче, петел, летящо прасе), плъх, заек, кон и крава!",
|
||||
"achievementShadyCustomerText": "Събра всички пет-ове Сянка.",
|
||||
"achievementShadyCustomerModalText": "Събра всички пет-ове Сянка.",
|
||||
"achievementShadyCustomer": "Сенчест тип",
|
||||
"achievementDomesticated": "И-Я–И–Я–ЙО",
|
||||
"achievementZodiacZookeeper": "Пазител на Зодиака",
|
||||
"achievementShadeOfItAll": "В сянката на света",
|
||||
"achievementShadeOfItAllText": "Опитоми всички сенчести коне.",
|
||||
"achievementZodiacZookeeperText": "Излюпи всички стандартни животни(базов цвят) от зодиака: Плъх, Крава, Заек, Змия, Овца, Маймуна, Кокошка, Вълк, Тигър, Летящо прасе, и Дракон!",
|
||||
"achievementZodiacZookeeperModalText": "Събрахте всички животни от зодиака!",
|
||||
"achievementBirdsOfAFeather": "От една порода"
|
||||
"achievementSkeletonCrewText": "Събрали са всички Скелетни животни."
|
||||
}
|
||||
|
||||
@@ -921,12 +921,5 @@
|
||||
"backgroundInsideForestWitchsCottageNotes": "Webe Zauber in der Hütte der Waldhexe.",
|
||||
"backgroundCastleKeepWithBannersText": "Burghalle mit Bannern",
|
||||
"backgroundCastleKeepWithBannersNotes": "Singe Geschichten von Heldentaten in einer Burghalle mit Bannern.",
|
||||
"backgrounds112025": "SET 138: Veröffentlicht im November 2025",
|
||||
"backgrounds122025": "SET 139: Veröffentlicht im Dezember 2025",
|
||||
"backgroundNighttimeStreetWithShopsNotes": "Genieße das warme Leuchten einer Nächtlichen Straße mit Geschäften.",
|
||||
"backgroundNighttimeStreetWithShopsText": "Nächtliche Straße mit Geschäften",
|
||||
"backgrounds012026": "SET 140: Veröffentlicht im Januar 2026",
|
||||
"backgrounds022026": "SET 141: Veröffentlicht im Februar 2026",
|
||||
"backgroundElegantPalaceText": "Eleganter Palast",
|
||||
"backgroundElegantPalaceNotes": "Bewundere die farbenfrohen Hallen eines Eleganten Palastes."
|
||||
"backgrounds112025": "SET 138: Veröffentlicht im November 2025"
|
||||
}
|
||||
|
||||
@@ -108,6 +108,5 @@
|
||||
"resetFlagCount": "Markierungszähler zurücksetzen",
|
||||
"cannotClone": "Diese Herausforderung kann nicht dupliziert werden, weil einer oder mehrere Spieler sie als unangemessen gemeldet haben. Einer der Mitarbeiter wird dich in Kürze mit Anweisungen kontaktieren. Wenn mehr als 48 Stunden vergangen sind, und du nichts von ihnen gehört hast, schicke bitte eine Email an admin@habitica.com, um Unterstützung zu erhalten.",
|
||||
"resetFlags": "Markierungen zurücksetzen",
|
||||
"messageChallengeFlagOfficial": "Offizielle Herausforderungen können nicht gemeldet werden.",
|
||||
"deleteChallengeRefundDescription": "Wenn du diese Herausforderung löschst, bekommst du den Preis in Edelsteinen erstattet und die Aufgaben der Herausforderung verbleiben auf der Aufgabentafel der Teilnehmer."
|
||||
"messageChallengeFlagOfficial": "Offizielle Herausforderungen können nicht gemeldet werden."
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"dontDespair": "Nicht verzweifeln!",
|
||||
"deathPenaltyDetails": "Du hast ein Level, Dein Gold und ein Stück Ausrüstung verloren, aber Du kannst alles durch harte Arbeit wieder zurückbekommen! Viel Glück -- Du schaffst das.",
|
||||
"refillHealthTryAgain": "Lebenspunkte wiederherstellen & Nochmal versuchen",
|
||||
"dyingOftenTips": "Passiert das öfters? <a href='/static/faq#prevent-damage' target='_blank'>Hier gibt es einige Tipps!</a>",
|
||||
"dyingOftenTips": "Passiert das öfters? <a href='https://habitica.fandom.com/wiki/Death_Mechanics#Strategies_for_Staying_Alive' target='_blank'>Hier gibt es einige Tipps!</a>",
|
||||
"losingHealthWarning": "Vorsicht - Du verlierst Lebenspunkte!",
|
||||
"losingHealthWarning2": "Lass Deine Lebenspunkte nicht auf null fallen! Sollte das passieren wirst Du ein Level, Dein Gold und einen Gegenstand Deiner Ausrüstung verlieren.",
|
||||
"toRegainHealth": "Um Deine Lebenspunkte wiederherzustellen:",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"faqQuestion29": "Wie kann ich HP wiederherstellen?",
|
||||
"webFaqAnswer29": "Du kannst 15 HP wiederherstellen, indem du einen Gesundheitstrank in deiner Belohnungsspalte für 25 Gold kaufst. Außerdem erhältst du immer volle HP, wenn du auflevelst!",
|
||||
"faqQuestion30": "Was passiert, wenn ich keine HP mehr habe?",
|
||||
"webFaqAnswer30": "Wenn deine HP Null erreichen, verlierst du ein Level, dessen Attribut-Punkt, dein gesamtes Gold und ein Ausrüstungsstück, das du wieder kaufen kannst. Du kannst dich wieder aufbauen, indem du Aufgaben erledigst und dich wieder hochlevelst.",
|
||||
"webFaqAnswer30": "Wenn deine HP Null erreichen, verlierst du eine Stufe, dein gesamtes Gold und ein Ausrüstungsstück, das du wieder kaufen kannst.",
|
||||
"faqQuestion31": "Warum habe ich HP verloren, wenn ich mit einer nicht-negativen Aufgabe interagiere?",
|
||||
"faqQuestion32": "Wie kann ich eine Klasse wählen?",
|
||||
"faqQuestion33": "Was ist der blaue Balken, der nach Level 10 erscheint?",
|
||||
@@ -243,7 +243,5 @@
|
||||
"subscriptionDetail470": "Gruppenabonnentenvorteile verhalten sich genauso wie die eines wiederkehrenden 1-Monats-Abonnements. Du erhältst eine Mystische Sanduhr am Anfang jedes Monats und die Anzahl an Edelsteinen, die du jeden Monat auf dem Marktplatz kaufen kannst, wird sich erhöhen bis zu einem Limit von 50.",
|
||||
"subscriptionPara3": "Wir hoffen, dass dieser neue Rhythmus besser vorhersagbar ist, mehr Zugang zur fantastischen Gegenstandauswahl im Laden des Zeitreisenden ermöglicht und noch mehr Motivation bietet, jeden Monat Fortschritte an deinen Aufgaben zu machen!",
|
||||
"faqQuestion67": "Was sind die Klassen in Habitica?",
|
||||
"webFaqAnswer67": "Klassen sind verschiedene Rollen, die dein Charakter spielen kann. Jede Klasse bietet ihre eigene Reihe von einzigartigen Vorteilen und Fähigkeiten beim Aufsteigen auf höhere Level. Diese Fähigkeiten können das Bearbeiten deiner Aufgaben ergänzen oder dabei helfen, deine Party beim Abschließen von Quests zu unterstützen.\n\nDeine Klasse bestimmt auch, welche Ausrüstung für dich in den Belohnungen, im Marktplatz und im Jahreszeitenmarkt zum Kauf erhältlich ist.\n\nHier ist eine Zusammenfassung jeder Klasse, um dir dabei zu helfen, diejenige zu wählen, welche am besten zu deinem Spielstil passt:\n#### **Krieger**\n* Die Krieger verursachen hohen Schaden bei Bossen und haben eine hohe Chance für kritische Treffer beim Abschließen von Aufgaben, was dich mit extra Erfahrung und Gold belohnt.\n* Stärke ist ihr primäres Attribut, welches den Schaden erhöht, den sie verursachen.\n* Ausdauer ist ihr sekundäres Attribut, welches den Schaden verringert, den sie erhalten.\n* Die Fähigkeiten der Krieger erhöhen die Ausdauer und Stärke der Gruppenmitglieder.\n* Erwäge, einen Krieger zu spielen, wenn du es liebst, Bosse zu bekämpfen und auch ein wenig Schutz möchtest, wenn du gelegentlich Aufgaben versäumst.\n#### **Heiler**\n* Die Heiler haben eine starke Verteidigung und können sich selbst, sowie Gruppenmitglieder, heilen.\n* Ausdauer ist ihr primäres Attribut, welches ihre Heilungen verstärkt und den Schaden, den sie erhalten, verringert.\n* Intelligenz ist ihr sekundäres Attribut, welches ihr Mana und ihre Erfahrung erhöht.\n* Die Fähigkeiten der Heiler bewirken, dass ihre Aufgaben weniger rot werden und erhöhen die Ausdauer der Gruppenmitglieder.\n* Erwäge, einen Heiler zu spielen, wenn du oft Aufgaben versäumst, und die Fähigkeit benötigst, dich selbst und deine Gruppenmitglieder zu heilen. Heiler erreichen schnell neue Level.\n#### **Magier**\n* Die Magier gewinnen schnell neue Level und viel Mana, und verursachen Schaden bei Bossen in Quests.\n* Intelligenz ist ihr primäres Attribut, welches ihr Mana und ihre Erfahrung erhöht.\n* Wahrnehmung ist ihr sekundäres Attribut, welches ihr gefundenes Gold und ihre gefundenen Gegenstände vermehrt.\n* Die Fähigkeiten der Magier bewirken, dass ihre Aufgaben Strähnen eingefroren werden, stellen das Mana ihrer Gruppenmitglieder wieder her, und erhöhen ihre Intelligenz.\n* Erwäge, einen Magier zu spielen, wenn du durch das schnelle Erreichen neuer Level und das Beisteuern von Schaden in Boss Quests motiviert wirst.\n#### **Schurke**\n* Die Schurken bekommen die meisten erbeuteten Gegenstände und das meiste Gold beim Erledigen von Aufgaben und haben eine höhere Chance, kritische Treffer zu erzielen, was ihnen noch mehr Erfahrung und Gold beschert.\n* Wahrnehmung ist ihr primäres Attribut, welches ihr gefundenes Gold und ihre gefundenen Gegenstände vermehrt.\n* Stärke ist ihr sekundäres Attribut, welches den Schaden erhöht, den sie verursachen.\n* Die Fähigkeiten der Schurken helfen ihnen, versäumten Tagesaufgaben auszuweichen, Gold zu klauen und die Wahrnehmung ihrer Gruppenmitglieder zu erhöhen.\n* Erwäge, einen Schurken zu spielen, wenn du durch Belohnungen sehr motiviert wirst.",
|
||||
"faqQuestion68": "Wie kann ich den Verlust von HP verhindern?",
|
||||
"webFaqAnswer68": "Wenn du häufig LP verlierst, probiere diese Tipps aus:\n\n– Pausiere deine täglichen Aufgaben. Die Schaltfläche „Schaden pausieren“ in den Einstellungen verhindert, dass du HP für verpasste Aufgaben verlierst.\n– Passe den Zeitplan deiner täglichen Aufgaben an. Indem du sie so einstellst, dass sie nie fällig sind, kannst du sie trotzdem abschließen und Belohnungen erhalten, ohne HP zu verlieren.\n– Versuche, Klassenfertigkeiten einzusetzen:\n– Schurken können „Schleichen“ einsetzen, um Schaden durch verpasste tägliche Aufgaben zu vermeiden.\n– Krieger können „Gewaltschlag“ einsetzen, um die Röte einer täglichen Aufgabe zu verringern und so den erlittenen Schaden beim Verpassen zu reduzieren.\n– Heiler können „Brennende Helle“ einsetzen, um die Röte einer täglichen Aufgabe zu verringern und so den erlittenen Schaden beim Verpassen zu reduzieren"
|
||||
"webFaqAnswer67": "Klassen sind verschiedene Rollen, die dein Charakter spielen kann. Jede Klasse bietet ihre eigene Reihe von einzigartigen Vorteilen und Fähigkeiten beim Aufsteigen auf höhere Level. Diese Fähigkeiten können das Bearbeiten deiner Aufgaben ergänzen oder dabei helfen, deine Party beim Abschließen von Quests zu unterstützen.\n\nDeine Klasse bestimmt auch, welche Ausrüstung für dich in den Belohnungen, im Marktplatz und im Jahreszeitenmarkt zum Kauf erhältlich ist.\n\nHier ist eine Zusammenfassung jeder Klasse, um dir dabei zu helfen, diejenige zu wählen, welche am besten zu deinem Spielstil passt:\n#### **Krieger**\n* Die Krieger verursachen hohen Schaden bei Bossen und haben eine hohe Chance für kritische Treffer beim Abschließen von Aufgaben, was dich mit extra Erfahrung und Gold belohnt.\n* Stärke ist ihr primäres Attribut, welches den Schaden erhöht, den sie verursachen.\n* Ausdauer ist ihr sekundäres Attribut, welches den Schaden verringert, den sie erhalten.\n* Die Fähigkeiten der Krieger erhöhen die Ausdauer und Stärke der Gruppenmitglieder.\n* Erwäge, einen Krieger zu spielen, wenn du es liebst, Bosse zu bekämpfen und auch ein wenig Schutz möchtest, wenn du gelegentlich Aufgaben versäumst.\n#### **Heiler**\n* Die Heiler haben eine starke Verteidigung und können sich selbst, sowie Gruppenmitglieder, heilen.\n* Ausdauer ist ihr primäres Attribut, welches ihre Heilungen verstärkt und den Schaden, den sie erhalten, verringert.\n* Intelligenz ist ihr sekundäres Attribut, welches ihr Mana und ihre Erfahrung erhöht.\n* Die Fähigkeiten der Heiler bewirken, dass ihre Aufgaben weniger rot werden und erhöhen die Ausdauer der Gruppenmitglieder.\n* Erwäge, einen Heiler zu spielen, wenn du oft Aufgaben versäumst, und die Fähigkeit benötigst, dich selbst und deine Gruppenmitglieder zu heilen. Heiler erreichen schnell neue Level.\n#### **Magier**\n* Die Magier gewinnen schnell neue Level und viel Mana, und verursachen Schaden bei Bossen in Quests.\n* Intelligenz ist ihr primäres Attribut, welches ihr Mana und ihre Erfahrung erhöht.\n* Wahrnehmung ist ihr sekundäres Attribut, welches ihr gefundenes Gold und ihre gefundenen Gegenstände vermehrt.\n* Die Fähigkeiten der Magier bewirken, dass ihre Aufgaben Strähnen eingefroren werden, stellen das Mana ihrer Gruppenmitglieder wieder her, und erhöhen ihre Intelligenz.\n* Erwäge, einen Magier zu spielen, wenn du durch das schnelle Erreichen neuer Level und das Beisteuern von Schaden in Boss Quests motiviert wirst.\n#### **Schurke**\n* Die Schurken bekommen die meisten erbeuteten Gegenstände und das meiste Gold beim Erledigen von Aufgaben und haben eine höhere Chance, kritische Treffer zu erzielen, was ihnen noch mehr Erfahrung und Gold beschert.\n* Wahrnehmung ist ihr primäres Attribut, welches ihr gefundenes Gold und ihre gefundenen Gegenstände vermehrt.\n* Stärke ist ihr sekundäres Attribut, welches den Schaden erhöht, den sie verursachen.\n* Die Fähigkeiten der Schurken helfen ihnen, versäumten Tagesaufgaben auszuweichen, Gold zu klauen und die Wahrnehmung ihrer Gruppenmitglieder zu erhöhen.\n* Erwäge, einen Schurken zu spielen, wenn du durch Belohnungen sehr motiviert wirst."
|
||||
}
|
||||
|
||||
@@ -28,16 +28,16 @@
|
||||
"marketing1Lead1Title": "Mache dein Leben zum Spiel",
|
||||
"marketing1Lead1": "Habitica ist die perfekte App, für alle die Probleme mit ToDo-Listen haben. Wir verwenden bekannte Spiel-Mechaniken wie Belohnungen in Gold, XP und Gegenstände, die dir dabei helfen, dich produktiver zu fühlen und dein Erfolgserlebnis zu steigern, wenn du Aufgaben vollendest. Je besser Du Dich dabei anstellst, umso weiter kommst Du im Spiel.",
|
||||
"marketing1Lead2Title": "Rüsten dich mit Stil aus",
|
||||
"marketing1Lead2": "Sammele Schwerter, Rüstungen und vieles mehr mit dem Gold, das du beim Vollenden von Aufgaben verdienst. Mit hunderten von Stücken zum Sammeln, aus denen du auswählen kannst, werden dir die Kombinationen zum Ausprobieren nie ausgehen. Optimiere deine Werte, deinen Style oder beides! ",
|
||||
"marketing1Lead2": "Sammele Schwerter, Rüstungen und vieles mehr mit Gold, welches du beim Vollenden von Aufgaben verdienst. Mit hunderten von Ausrüstungsstücken, die du sammeln und auswählen kannst, werden dir nie Kombinationen zum Ausprobieren ausgehen. Optimiere deine Statistik, deinen Style oder beides zusammen! ",
|
||||
"marketing1Lead3Title": "Verdiene Belohnungen für deine Bemühungen",
|
||||
"marketing1Lead3": "Etwas zu haben, auf das man sich freuen kann, mag den Unterschied ausmachen, ob man eine Aufgabe erledigt oder ob sie einen wochenlang quält. Wenn das Leben keine Belohnung bietet ist Habitica für dich da! Du wirst für jede Aufgabe belohnt, aber Überraschungen gibt es an jeder Ecke - also mach weiter so! ",
|
||||
"marketing2Header": "Verbünde dich mit Freunden",
|
||||
"marketing2Header": "Schließe dich mit Freunden zusammen",
|
||||
"marketing2Lead1Title": "Soziale Produktivität",
|
||||
"marketing2Lead1": "Hole dir einen Motivationsschub, indem du mit anderen zusammenarbeitest, konkurrierst und interagierst! Habitica wurde entwickelt, um den effektivsten Teil eines jeden Selbstverbesserungsprogramms zu nutzen: soziale Verantwortung.",
|
||||
"marketing2Lead2Title": "Bekämpfe Monster in Quests",
|
||||
"marketing2Lead2": "Nimm dich einer unserer hunderten von Quests mit einer Gruppe von Freunden an, um dich ins Getümmel zu stürzen. Die Monster der Quests bringen deine Verantwortlichkeit auf die Spitze. Wenn du vergisst, Zahnseide zu benutzen, schadet das allen!",
|
||||
"marketing2Lead3Title": "Fordert einander heraus",
|
||||
"marketing2Lead3": "Nimm an Herausforderungen teil, die von unserer Community erstellt wurden, und erhalte handverlesene Aufgabenlisten, die deinen Interessen und Zielen entsprechen. Gib dein Bestes, um den Edelsteinpreis zu gewinnen!",
|
||||
"marketing2Lead3": "Nimm an Herausforderungen teil, die von unserer Community erstellt wurden und erhalte zusammengestellte Aufgabenlisten, die deinen Interessen und Zielen entsprechen. Gib dein Bestes dabei, um den Edelsteinpreis zu wetteifern, der dem Gewinner verliehen wird!",
|
||||
"marketing3Header": "Weitere Möglichkeiten, Habitica zu nutzen",
|
||||
"marketing3Lead1": "Du kannst Habitica auf deinem Android- oder iOS-Gerät nutzen, um Aufgaben überall abzuhaken. Schau dir unsere preisgekrönten Apps an, um einen neuen Ansatz zur Erledigung von Aufgaben zu finden.",
|
||||
"marketing3Lead2Title": "Open-Source Community",
|
||||
@@ -124,7 +124,7 @@
|
||||
"passwordReset": "Wenn wir Deine E-Mail-Adresse oder Deinen Benutzernamen kennen, wurden Anweisungen zum Passwort-Zurücksetzen dorthin verschickt.",
|
||||
"invalidLoginCredentialsLong": "Deine E-Mail-Adresse, deine Benutzername oder Passwort sind nicht korrekt. Bitte versuche es erneut oder wähle \"Passwort vergessen.\"",
|
||||
"invalidCredentials": "Es gibt kein Konto, das diese Anmeldedaten verwendet.",
|
||||
"accountSuspended": "Dieser Account \"<%= userId %>\", wurde gesperrt. Für weitere Informationen oder um Widerspruch einzulegen, sende bitte eine E-Mail an admin@habitica.com mit deinem Habitica-Benutzernamen oder User-ID.",
|
||||
"accountSuspended": "Dieser Account, Benutzer-ID \"<%= userId %>\", wurde gesperrt wegen Verletzung der Community-Richtlinien (https://habitica.com/static/community-guidelines) oder der Allgemeinen Geschäftsbedingungen (https://habitica.com/static/terms). Für genauere Angaben oder um die Aufgebung der Sperre zu erbitten, kontaktiere bitte unseren Community Manager unter <%= communityManagerEmail %> oder bitte Deine Eltern oder Erziehungsberechtigten ihm zu schreiben. Bitte nenne Deine @Benutzer-ID in der E-Mail.",
|
||||
"accountSuspendedTitle": "Dieser Account wurde suspendiert",
|
||||
"unsupportedNetwork": "Dieses Netzwerk wird aktuell nicht unterstützt.",
|
||||
"cantDetachSocial": "Der Account hat nur noch diese Authentifizierung, sie kann nicht getrennt werden.",
|
||||
@@ -132,12 +132,12 @@
|
||||
"invalidReqParams": "Ungültige Anfrageparameter.",
|
||||
"memberIdRequired": "\"member\" muss eine gültige UUID sein.",
|
||||
"heroIdRequired": "\"herold\" muss eine gültige UUID sein.",
|
||||
"cannotFulfillReq": "Diese Mailadresse ist bereits in Gebrauch. Du kannst versuchen dich einzuloggen oder eine andere Mailadresse zur Registrierung verwenden. Wende dich an admin@habitica.com, falls du Hilfe benötigst.",
|
||||
"cannotFulfillReq": "Bitte gib eine gültige E-Mail-Adresse ein. Schreibe eine E-Mail an admin@habitica.com, falls dieser Fehler weiterhin auftritt.",
|
||||
"modelNotFound": "Diese Vorlage existiert nicht.",
|
||||
"signUpWithSocial": "Mit <%= social %> fortfahren",
|
||||
"loginWithSocial": "Mit <%= social %> anmelden",
|
||||
"confirmPassword": "Passwort bestätigen",
|
||||
"usernameLimitations": "Benutzernamen können jederzeit geändert werden. Sie müssen zwischen 1 und 20 Zeichen lang sein und dürfen nur Buchstaben von a bis z, Zahlen von 0 bis 9, Bindestriche und Unterstriche beinhalten.",
|
||||
"usernameLimitations": "Benutzernamen können jederzeit geändert werden. Sie müssen zwischen 1 und 20 Zeichen lang sein und dürfen nur Buchstaben von A bis Z, Zahlen von 0 bis 9, Bindestriche und Unterstriche beinhalten.",
|
||||
"usernamePlaceholder": "z.B., HabitRabbit",
|
||||
"emailPlaceholder": "z.B., gryphon@beispiel.com",
|
||||
"passwordPlaceholder": "z.B., ******************",
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
"weaponSpecialFallRogueText": "Silberner Pflock",
|
||||
"weaponSpecialFallRogueNotes": "Befördert Untote dauerhaft ins Jenseits. Notfalls auch gegen Werwölfe einsetzbar - Vielseitigkeit kann nie schaden. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2014 Herbstausrüstung.",
|
||||
"weaponSpecialFallWarriorText": "Krabbige Klaue der Wissenschaft",
|
||||
"weaponSpecialFallWarriorNotes": "Diese Krabbige Klaue ist technisch auf dem neusten Stand! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2014 Herbstausrüstung.",
|
||||
"weaponSpecialFallWarriorNotes": "Diese Krabbige Klaue ist technisch auf dem neusten Stand! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2014 Sommerausrüstung.",
|
||||
"weaponSpecialFallMageText": "Fliegender Besen",
|
||||
"weaponSpecialFallMageNotes": "Dieser fliegende Besen ist schneller als ein Drache! Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2014 Herbstausrüstung.",
|
||||
"weaponSpecialFallHealerText": "Skarabäus-Zauberstab",
|
||||
@@ -526,7 +526,7 @@
|
||||
"armorSpecialFall2015RogueText": "Geflügelte Kampfrüstung",
|
||||
"armorSpecialFall2015RogueNotes": "Flieg in den Kampf! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2015 Herbstausrüstung.",
|
||||
"armorSpecialFall2015WarriorText": "Vogelscheuchenrüstung",
|
||||
"armorSpecialFall2015WarriorNotes": "Zwar nur mit Stroh ausgestopft, ist diese Rüstung doch extrem rüstig! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2015 Herbstausrüstung.",
|
||||
"armorSpecialFall2015WarriorNotes": "Obwohl sie nur mit Stroh ausgestopft ist, ist diese Rüstung extrem rüstig! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2015 Herbstausrüstung.",
|
||||
"armorSpecialFall2015MageText": "Genähte Roben",
|
||||
"armorSpecialFall2015MageNotes": "Jede Masche dieser Rüstung schimmert mit Zauberei. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2015 Herbstausrüstung.",
|
||||
"armorSpecialFall2015HealerText": "Roben des Tränkebrauers",
|
||||
@@ -1873,7 +1873,7 @@
|
||||
"weaponSpecialFall2019WarriorText": "Krallen-Kriegsgabel",
|
||||
"weaponSpecialFall2019RogueNotes": "Ob Du ein Orchester dirigierst oder eine Arie singst, dieses Hilfsmittel hält Deine Hände frei für dramatische Gesten! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2019 Herbstausrüstung.",
|
||||
"weaponSpecialFall2019RogueText": "Notenständer",
|
||||
"headSpecialFall2019RogueNotes": "Hast Du diese Kopfbedeckung in einer Auktion vermeintlich verwünschter Kostümstücke oder auf dem Speicher eines exzentrischen Großelternteils gefunden? Welchen Ursprungs auch immer, ihr Alter und ihre Abnutzung tragen zu Deiner mystischen Aura bei. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2019 Herbstausrüstung.",
|
||||
"headSpecialFall2019RogueNotes": "Hast Du diese Kopfbedeckung in einer Auktion vermeintlich verwünschter Kostümstücke oder auf dem Speicher eines extentrischen Großelternteils gefunden? Welchen Ursprungs auch immer, ihr Alter und ihre Abnutzung tragen zu Deiner mystischen Aura bei. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2019 Herbstausrüstung.",
|
||||
"headSpecialFall2019RogueText": "Antiker Opernhut",
|
||||
"armorMystery201909Notes": "Deine robuste Außenschale ist schützend, aber es ist angeraten nach Eichhörnchen Ausschau zu halten... Gewährt keinen Attributionsbonus. Abonnentengegenstand, September 2019.",
|
||||
"armorMystery201909Text": "Affabler Eichelanzug",
|
||||
@@ -2215,9 +2215,9 @@
|
||||
"armorSpecialWinter2021RogueText": "Efeu-Grünes Gewand",
|
||||
"weaponSpecialWinter2021HealerNotes": "Dirigiere deine Kämpfe mit unvorhersehbarem Schwung, wie ein Schneegestöber! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2020-2021 Winterausrüstung.",
|
||||
"weaponSpecialWinter2021HealerText": "Flocken Flanken Rute",
|
||||
"weaponSpecialWinter2021MageNotes": "Diese mächtige Waffe ist definitiv mehr als nur eine Phase! Konzentriere deine Kräfte, fokussiere auf den Verlauf des Monates und studiere den Lauf von Zeit und Raum. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2020-2021 Winterausrüstung.",
|
||||
"weaponSpecialWinter2021MageNotes": "Diese mächtige Waffe ist nicht nur eine Phase! Konzentriere deine Kräfte, fokussiere den Verlauf eines Monates und studiere den Lauf von Zeit und Raum. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2020-2021 Winterausrüstung.",
|
||||
"weaponSpecialWinter2021MageText": "Magischer Mond-Phaser",
|
||||
"weaponSpecialWinter2021WarriorNotes": "Hiermit kannst Du die größten Fische an Land ziehen! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2020-2021 Winterausrüstung.",
|
||||
"weaponSpecialWinter2021WarriorNotes": "Hiermit kannst Du die größten Frische an Land ziehen! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2020-2021 Winterausrüstung.",
|
||||
"weaponSpecialWinter2021WarriorText": "Mächtige Angelrute",
|
||||
"weaponSpecialWinter2021RogueNotes": "Tarnung und Waffe in einem, die giftigen Früchte der Stechpalme helfen dir mit den schwierigsten Aufgaben umzugehen. Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2020-2021 Winterausrüstung.",
|
||||
"weaponSpecialWinter2021RogueText": "Ilex-Beeren Morgenstern",
|
||||
@@ -2409,7 +2409,7 @@
|
||||
"weaponSpecialFall2021MageNotes": "Wissen sucht Wissen. Geformt aus Erinnerungen und Sehnsüchten giert diese furchteinflößende Hand nach mehr. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
|
||||
"weaponSpecialFall2021HealerText": "Beschwörungszauberstab",
|
||||
"headArmoireHeraldsCapNotes": "Dieser Herolds-Hut kommt mit einer flotten Feder. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Herolds Set (Gegenstand 2 von 4).",
|
||||
"armorSpecialFall2021RogueNotes": "Es hat einen Totenkopf, eine Ledertunika und Metallnieten! Großartig! Allerdings bietet es kein luftdichtes Siegel gegen Pampe! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
|
||||
"armorSpecialFall2021RogueNotes": "Es hat einen Totenkopf, eine Ledertunika und Metallnieten! Großartig! Allerdings bietet es kein luftdichtes Siegel gegen Pampe! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
|
||||
"armorSpecialFall2021WarriorText": "Formaler Wollanzug",
|
||||
"armorSpecialFall2021WarriorNotes": "Ein atemberaubender Anzug, perfekt für die Überquerung von Brücken in stockdunkler Nacht. Erhöht Ausdauer um <%= con %>. Limiterte Ausgabe 2021, Herbstausrüstung.",
|
||||
"armorSpecialFall2021MageText": "Robe der abgrundtiefen Finsternis",
|
||||
@@ -2861,7 +2861,7 @@
|
||||
"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 scharfe Klinge mit dir zur See gebracht hast. Achte nur darauf, dass sie sicher verstaut ist, wenn nicht in Benutzung. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Piraten Set (Gegenstand 3 von 3).",
|
||||
"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.",
|
||||
@@ -2891,7 +2891,7 @@
|
||||
"weaponMystery202408Text": "Arkanes Aegis",
|
||||
"weaponMystery202408Notes": "Ein magisches Bläschen-Schild, das dich vor gegnerischen Zaubersprüchen schützt, oder dir hilft, im Wasser oder in der Luft zu schweben. Gewährt keinen Attributbonus. August 2024 Abonnentengegenstand.",
|
||||
"weaponArmoireDragonKnightsLanceText": "Drachenritter Lanze",
|
||||
"weaponArmoireDragonKnightsLanceNotes": "Diese rot-silberne Lanze hat so manchen Gegner aus dem Sattel seines Reittiers gehoben. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Drachenritter Set (Gegenstand 3 von 3).",
|
||||
"weaponArmoireDragonKnightsLanceNotes": "Diese rot-silberne Lanze hat so manchen Gegner aus dem Sattel seines Reittiers gehoben. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Drachenritter Set (Gegenstand 3 von 3)",
|
||||
"armorSpecialSummer2024WarriorText": "Walhai Schwanzflosse",
|
||||
"armorSpecialSummer2024WarriorNotes": "Nachdem du dich in einen echten Walhai Krieger verwandelt hast, schwimm kühn auf deine Aufgaben zu! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024 Sommerausrüstung.",
|
||||
"armorSpecialSummer2024MageText": "Seeanemonen Flosse",
|
||||
@@ -2925,14 +2925,14 @@
|
||||
"armorSpecialFall2024HealerNotes": "Sei eins mit der Galaxis und hypnotisiere Zuschauer mit dieser Rüstung. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2024 Herbstausrüstung.",
|
||||
"armorSpecialFall2024MageText": "Unterwelt Hexer Rüstung",
|
||||
"armorSpecialFall2024MageNotes": "Sei eins mit der Unterwelt und umarme die Macht der Magier, die vor dir diese Rüstung trugen. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2024 Herbstausrüstung.",
|
||||
"weaponArmoireFunnyFoolBatonNotes": "Du kannst mit einem Schwung deines Stabes eine Pointe vortragen, Aufmerksamkeit erregen oder Beifall ernten. Erhöht Ausdauer und Stärke jeweils um <%= attrs %>. Verzauberter Schrank: Lustiges Narren-Set (Gegenstand 3 von 3).",
|
||||
"weaponArmoireFunnyFoolBatonNotes": "Du kannst mit einem Schwung Deines Stabes eine Pointe vortragen, die Aufmerksamkeit erregen oder Beifall ernten. Erhöht Ausdauer und Stärke jeweils um <%= attrs %>. Verzauberter Schrank: Lustiges Narren-Set (Gegenstand 3 von 3)",
|
||||
"armorArmoireTeaGownText": "Teekränzchen Kleid",
|
||||
"armorArmoireTeaGownNotes": "Du bist zäh, kreativ, brilliant und so modisch! Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Teekränzchen Set (Gegenstand 1 von 3).",
|
||||
"armorMystery202401Text": "Verschneite Zauberer Roben",
|
||||
"armorMystery202401Notes": "Diese Roben erscheinen filigran wie Schneeflocken, aber werden dich reichlich warm halten, während du deine winterliche Magie wirkst. Gewährt keinen Attributbonus. Januar 2024 Abonnentengegenstand.",
|
||||
"armorMystery202406Notes": "Suche deine Feinde heim mit Stil und Flair! Gewährt keinen Attributbonus. Juni 2024 Abonnentengegenstand.",
|
||||
"armorMystery202407Text": "Liebenswerter Axolotl Anzug",
|
||||
"weaponArmoireSpookyCandyBucketNotes": "Mit einem epischen Kostüm wie diesem wirst du so viele Süßigkeiten bekommen! Gut, dass du diesen Eimer ohne Boden hast, um das alles aufzunehmen. Versuch, nicht zu naschen, bevor du nach Hause kommst. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Süßes oder Saures Set (Gegenstand 2 von 2).",
|
||||
"weaponArmoireSpookyCandyBucketNotes": "Mit einem epischen Kostüm wie diesem wirst du derart viel Süßigkeiten bekommen! Gut, dass du diesen bodenlosen Eimer hast, um das alles aufzunehmen. Versuch, nicht zu naschen, bevor du nach Hause kommst. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Süßes oder Saures Set (Gegenstand 2 von 2)",
|
||||
"weaponArmoireSpookyCandyBucketText": "Grusliger Süßigkeiten Eimer",
|
||||
"armorMystery202407Notes": "Gleite durch Seen und Kanäle mit deinem hin und her fegenden rosa Schwanz! Gewährt keinen Attributbonus. Juli 2024 Abonnentengegenstand.",
|
||||
"armorArmoireJewelersApronText": "Juweliers-Schürze",
|
||||
@@ -2957,7 +2957,7 @@
|
||||
"armorArmoireKarateGiText": "Karategi",
|
||||
"armorArmoireKarateGiNotes": "Diese leichte Karate-Uniform ist perfekt für Training oder Wettbewerbe. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Karate-Set (Gegenstand 1 von 10).",
|
||||
"weaponArmoireStormKnightAxeText": "Axt des Sturmritters",
|
||||
"weaponArmoireStormKnightAxeNotes": "Sammle deine Wut und schlage wie ein Donnerschlag zu! Erhöht Stärke um <%= str %>. Verzauberter Schrank: Sturmritter-Set (Gegenstand 3 von 3).",
|
||||
"weaponArmoireStormKnightAxeNotes": "Sammle deine Wut und schlage wie ein Donnerschlag zu! Erhöht Stärke um <%= str %>. Verzauberter Schrank: Sturmritter-Set (Gegenstand 3 von 3)",
|
||||
"armorArmoireDiagonalRainbowShirtNotes": "Ein Klecks Farbe mit einem Schuss Stil. Sei fröhlich! Erhöht Ausdauer und Wahrnehmung um jeweils <%= attrs %> . Verzauberter Schrank: Regenbogen-Set (Gegenstand 2 von 2).",
|
||||
"armorArmoireAdmiralsUniformText": "Admirals-Uniform",
|
||||
"armorArmoireAdmiralsUniformNotes": "Wir salutieren dir! Diese Marineuniform signalisiert, dass du bereit bist, das Kommando sowohl von deinen Aufgaben als auch von einem Schiff zu übernehmen. Erhöht Ausdauer und Stärke um jeweils <%= attrs %> . Verzauberter Schrank: Admirals-Set (Gegenstand 2 von 2).",
|
||||
@@ -3074,7 +3074,7 @@
|
||||
"headSpecialFall2024RogueText": "Schwarze Katzenmaske",
|
||||
"headSpecialFall2024HealerText": "Space Invader-Maske",
|
||||
"headSpecialWinter2025HealerNotes": "Es ist nicht nötig, sie zu entwirren, da sie bereits die Form eines Hutes haben. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
|
||||
"headSpecialWinter2025MageText": "Aurora Kopfschmuck",
|
||||
"headSpecialWinter2025MageText": "Aurorahut",
|
||||
"headSpecialWinter2025MageNotes": "Dieser Hut ist mehr als nur ein schicker Fascinator, er lässt dich wie das Polarlicht selbst aussehen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Winterausrüstung 2024-2025.",
|
||||
"headSpecialSummer2024MageText": "Seeanemonen-Hut",
|
||||
"headSpecialSummer2024HealerText": "Seeschneckenhaus",
|
||||
@@ -3315,7 +3315,7 @@
|
||||
"headMystery202504Notes": "Trage diese mysteriöse Visage, um unentdeckt unter den oskursten Fabelwesen der Welt zu verweilen. Gewährt keinen Attributbonus. April 2025 Abonnentengegenstand.",
|
||||
"headArmoireSillierBlueTophatNotes": "Etwas Klasse, etwas Raffinesse. Erhöht Stärke und Ausdauer um jeweils <%= attrs %>. Verzauberter Schrank: Noch Lächerlicherer Smoking Set (Gegenstand 2 von 2).",
|
||||
"weaponArmoireGildedKnightsSpearText": "Vergoldeter Ritter Speer",
|
||||
"weaponArmoireGildedKnightsSpearNotes": "Mit dieser Waffe kannst du sicherstellen, dass jeder immer seine Schulden bezahlt. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Vergoldeter Ritter Set (Gegenstand 3 von 3).",
|
||||
"weaponArmoireGildedKnightsSpearNotes": "Mit dieser Waffe kannst du sicherstellen, dass jeder immer seine Schulden bezahlt. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Vergoldeter Ritter Set (Gegenstand 3 von 3)",
|
||||
"armorArmoireGildedKnightsPlateNotes": "In dieser Rüstung bist du fast unbesiegbar. Deine Feinde werden dich sicher dröhnen hören! Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Vergoldeter Ritter Set (Gegenstand 2 von 3)",
|
||||
"armorArmoireGildedKnightsPlateText": "Vergoldeter Ritter Rüstung",
|
||||
"headArmoireGildedKnightsHelmText": "Vergoldeter Ritter Helm",
|
||||
@@ -3330,7 +3330,7 @@
|
||||
"weaponSpecialSummer2025RogueNotes": "Dieser Tentakel wird deine Ziele eng umklammern, so dass du den Schwung nicht verlierst, wenn du deine Aufgaben erledigst. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Sommerausrüstung 2025.",
|
||||
"weaponSpecialSummer2025HealerText": "Ruderschnecken Flügelpaddel",
|
||||
"weaponSpecialSummer2025HealerNotes": "Beschreibe rudernd einen Doppelkreis, während du dich vorwärts bewegst, und bei deinen Aufgaben tolle Fortschritte machst. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Sommerausrüstung 2025.",
|
||||
"weaponArmoireBeekeepersSmokerNotes": "Benutze dies, um deine Bienen zu beruhigen, damit du den Honig besser holen kannst. Die Bienen wird es nicht stören. Um ehrlich zu sein, wir alle könnten von Zeit zu Zeit ein paar extra Minuten Ruhe gebrauchen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Imker Set (Gegenstand 3 von 4).",
|
||||
"weaponArmoireBeekeepersSmokerNotes": "Benutze dies, um deine Bienen zu beruhigen, damit du den Honig besser holen kannst. Die Bienen wird es nicht stören. Ehrlich, wir alle könnten von Zeit zu Zeit ein paar extra Minuten Ruhe gebrauchen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Imker Set (Gegenstand 3 von 4)",
|
||||
"weaponArmoireBeekeepersSmokerText": "Smoker",
|
||||
"armorSpecialSummer2025WarriorText": "Kammmuschel Rüstung",
|
||||
"armorSpecialSummer2025WarriorNotes": "Diese Rüstung macht dich nicht nur robust, sondern auch schnell. Kampf oder Flucht - es ist deine Wahl! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe Sommerausrüstung 2025.",
|
||||
@@ -3344,7 +3344,7 @@
|
||||
"armorArmoireBeekeepersSuitNotes": "Schütze dich, während du nach deinen fleißigen Hummeln schaust. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Imker Set (Gegenstand 2 von 4)",
|
||||
"headSpecialSummer2025RogueNotes": "Deine Sehkraft wird sich verbessern sobald Du diese Maske aufsetzt. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Sommer 2025 Ausrüstung.",
|
||||
"weaponSpecialSummer2025MageText": "Zweigkoralle",
|
||||
"weaponSpecialSummer2025MageNotes": "Verzweige dich mit deinen Talenten und Fähigkeiten, um eine Reihe von verschiedenen Aufgaben anzugreifen. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe Sommerausrüstung 2025.",
|
||||
"weaponSpecialSummer2025MageNotes": "Verzweige dich mit deinen Talenten und Fähigkeiten, um eine Reihe von verschiedenen Aufgaben anzugreifen. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe Sommerausrüstung 2025",
|
||||
"headSpecialSummer2025WarriorText": "Kammmuschelhelm",
|
||||
"headSpecialSummer2025WarriorNotes": "Undurchdringlich und perfekt zugespitzt wird dich dieser Helm sogar vor Seesternen beschützen. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Sommerausrüstung 2025.",
|
||||
"headSpecialSummer2025RogueText": "Tintenfischmaske",
|
||||
@@ -3386,58 +3386,5 @@
|
||||
"weaponMystery202508Text": "Funkelnde Blutrote klinge",
|
||||
"weaponMystery202508Notes": "Diese wirbelnde Klinge wird jedes Monster oder rote Tagesaufgabe, die deinen Weg kreuzen, in Schrecken versetzen! Gewährt keinen Attributbonus. August 2025 Abonnentengegenstand.",
|
||||
"weaponMystery202511Text": "Frostschwert",
|
||||
"weaponMystery202511Notes": "Der eisige Glanz dieses Schwertes wird selbst mit dunkelroten Aufgaben kurzen Prozess machen. Gewährt keinen Attributbonus. Novermber 2025 Abonnentengegenstand.",
|
||||
"weaponArmoireBlacksmithsHammerText": "Schmiedehammer",
|
||||
"weaponArmoireBlacksmithsHammerNotes": "Dieser Hammer ist für Metallarbeiten, er ist aber auch ideal geeignet inmitten von rotglühenden Kohlen und rotglühenden Tagesaufgaben. Erhöht Stärke um <%= str %>. Verzauberter Schrank: Schmiedeset (Gegenstand 3 von 3).",
|
||||
"armorSpecialFall2025WarriorText": "Sasquatch Rüstung",
|
||||
"armorSpecialFall2025WarriorNotes": "Weder deine großen Füße, noch dein großer Körper wird zu groß sein um in diese saisonale Rüstung zu passen. Erhöht Ausdauer um <%= con %>. Limitierte Herbstausrüstung 2025.",
|
||||
"armorSpecialFall2025RogueText": "Skelett Rüstung",
|
||||
"armorSpecialFall2025HealerText": "Kobold Rüstung",
|
||||
"armorSpecialFall2025HealerNotes": "Diese saisonale Rüstung lässt dich mit den dunklen Wäldern verschmelzen um einen strategischen Rückzug anzutreten. Erhöht Ausdauer um <%= con %>. Limitierte Herbstausrüstung 2025.",
|
||||
"armorSpecialFall2025MageText": "Maskierter Geist Rüstung",
|
||||
"armorSpecialFall2025MageNotes": "Diese saisonale Rüstung wird körperlos sobald du sie anziehst. Erhöht Intelligenz um <%= int %>. Limitierte Herbstausrüstung 2025.",
|
||||
"armorMystery202509Text": "Robe des Windgepeitschten Wanderers",
|
||||
"armorMystery202509Notes": "Helle Seide schützt dich vor dem Wetter - sowohl heiß als auch kalt. Gewährt keinen Attributbonus. September 2025 Abonnentengegenstand.",
|
||||
"armorArmoireRedWaistcoatText": "Rote Weste",
|
||||
"armorArmoireSoftOrangeSuitText": "Weicher Orangener Anzug",
|
||||
"armorArmoireBlacksmithsApronText": "Schmiedeschürze",
|
||||
"armorArmoireBlacksmithsApronNotes": "Diese Schürze fühlt sich nicht so schwer an, wie sie aussieht, sobald du sie trägst. Sie wird dich vor Funken schützen und dir gleichzeitig ermöglichen, dich frei zu bewegen. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Schmied Set (Gegenstand 2 von 3).",
|
||||
"armorArmoireBlackPartyDressText": "Schwarzes Party Kleid",
|
||||
"armorArmoireBlackPartyDressNotes": "Du bist stark, schlau, tüchtig und so modisch! Erhöht Stärke, Intelligenz und Ausdauer um jeweils <%= attrs %>. Verzauberter Schrank: Schwarzes Haarschleifen-Set (Gegenstand 2 von 2).",
|
||||
"headSpecialFall2025WarriorText": "Sasquatch Maske",
|
||||
"headSpecialFall2025WarriorNotes": "Rund und haarig - diese Maske bedeckt deinen Kopf, während du alle deine wichtigen Aufgaben abdeckst. Erhöht Stärke um <%= str %>. Limitierte Herbstausrüstung 2025.",
|
||||
"headSpecialFall2025RogueText": "Skelett Maske",
|
||||
"headSpecialFall2025RogueNotes": "Blass und vermummt - diese Maske bedeckt deinen Kopf, während du alle deine wichtigen Aufgaben abdeckst. Erhöht Wahrnehmung um <%= per %>. Limitierte Herbstausrüstung 2025.",
|
||||
"headSpecialFall2025HealerText": "Kobold Maske",
|
||||
"headSpecialFall2025MageText": "Maskierter Geist Maske",
|
||||
"headSpecialFall2025MageNotes": "Ätherisch und glühend - diese Maske bedeckt deinen Kopf, während du alle deine wichtigen Aufgaben abdeckst. Erhöht Wahrnehmung um <%= per %>. Limitierte Herbstausrüstung 2025.",
|
||||
"armorArmoireRedWaistcoatNotes": "Sieh elegant und umwerfend aus, während du deine Aufgaben bewältigst. In der Westentasche ist etwas geheimes versteckt — was denkst du, könnte es sein? Erhöht Ausdauer und Stärke um jeweils <%= attrs %>. Verzauberter Schrank: Rote Weste Set (Gegenstand 2 von 2)",
|
||||
"armorArmoireSoftOrangeSuitNotes": "Orange ist eine lebhafte Farbe. Zieh dies an, wenn du zu Bett gehst und in allen Abenteuern, denen du in deinen Träumen begegnest, wirst du sicher Erfolg haben. Erhöht Ausdauer und Stärke um jeweils <%= attrs %> . Verzauberter Schrank: Oranges Loungewear-Set (Gegenstand 2 von 3).",
|
||||
"headSpecialFall2025HealerNotes": "Markant und gehörnt - diese Maske bedeckt deinen Kopf, während du alle deine wichtigen Aufgaben abdeckst. Erhöht Intelligenz um <%= int %>. Limitierte Herbstausrüstung 2025.",
|
||||
"headArmoireRedNewsieHatText": "Rote Zeitungsjungenmütze",
|
||||
"headArmoireRedNewsieHatNotes": "Extra! Extra! Lesen Sie alles darüber: Diese Mütze ist bequem, modisch und praktisch. Erhöht die Wahrnehmung und Intelligenz um jeweils <%= attrs %>. Verzauberter Kleiderschrank: Rotes Weste-Set (Item 1 von 2)",
|
||||
"headArmoireFloppyOrangeHatText": "Orangener Schlapphut",
|
||||
"headArmoireFloppyOrangeHatNotes": "In diesen simplen Hut wurden zahlreiche Zauber eingearbeitet, die ihm eine auffällige orange Farbe verleihen. Erhöht alle Werte um jeweils <%= attrs %>. Verzauberter Kleiderschrank: Orangenes Loungewear-Set (Item 1 von 3).",
|
||||
"headArmoireBlackHairbowText": "Schwarze Haarschleife",
|
||||
"headArmoireBlackHairbowNotes": "Werde stark, klug und herzhaft, während du diese wunderschöne schwarze Haarschleife trägst! Erhöht Stärke, Intelligenz und Konstitution um jeweils <%= attrs %>. Verzauberter Kleiderschrank: Schwarzes Haarschleifen-Set (Item 1 von 2).",
|
||||
"headArmoireBlacksmithsGogglesText": "Schmiedebrille",
|
||||
"shieldSpecialFall2025RogueNotes": "Eine mächtige Waffe, mit der Sie Ihre To-Do's um die Hälfte reduzieren können. Erhöht Stärke um <%= str %>. Limitierte Ausgabe Herbst 2025 Ausrüstung.",
|
||||
"shieldSpecialFall2025HealerText": "Koboldschild",
|
||||
"shieldMystery202508Text": "Brillante Cyan-Klinge",
|
||||
"shieldMystery202508Notes": "Wenn Sie schon eine rotierende Klinge cool fanden, probieren Sie doch mal zwei! Bietet keinen Vorteil. August 2025 Abonnentengegenstand.",
|
||||
"shieldMystery202511Text": "Frostschild",
|
||||
"shieldMystery202511Notes": "Dieser robuste Schild aus eisigem Gestein schützt dich vor schlechten Gewohnheiten, ohne deine Hände zu vereisen. Verleiht keinen Vorteil. November 2025 Abonnentengegenstand.",
|
||||
"shieldArmoireSoftOrangePillowText": "Weiches orangenes Kissen",
|
||||
"backMystery202510Text": "Gleitende Ghulflügel",
|
||||
"backMystery202510Notes": "Fliege mit diesen riesigen Flügeln lautlos durch den heimgesuchten Himmel. Verleiht keinen Vorteil. Oktober 2025 Abonnentengegenstand.",
|
||||
"bodyMystery202509Notes": "Dieser Schal schützt dein Gesicht vor Wind und sieht auch noch verdammt cool aus. Bietet keinen Vorteil. September 2025 Abonnentengegenstand.",
|
||||
"eyewearMystery202510Text": "Gleitende Ghul-Augen",
|
||||
"eyewearMystery202510Notes": "Diese gruseligen Augen leuchten wie der Erntemond. Verleiht keinen Vorteil. Oktober 2025 Abonnentengegenstand.",
|
||||
"headArmoireBlacksmithsGogglesNotes": "Bei der Arbeit in einer Schmiede benötigen Sie einen bruchsicheren und hitzebeständigen Augenschutz. Erhöht die Wahrnehmung um <%= per %>. Verzauberter Schrank: Schmiedeset (Item 1 von 3).",
|
||||
"shieldSpecialFall2025WarriorText": "Sasquatch Schild",
|
||||
"shieldSpecialFall2025WarriorNotes": "Verschaffe dir etwas mehr Zeit zum Nachdenken und Planen, indem du dich vor deinen nächsten Tagesaufgaben abschirmst. Erhöht die Konstitution um <%= con %>. Limitierte Auflage Herbst 2025 Ausrüstung.",
|
||||
"shieldSpecialFall2025HealerNotes": "Verschaffe dir etwas mehr Zeit, um Vorräte zu sammeln, indem du dich vor deinen Aufgaben abschirmst. Erhöht die Konstitution um <%= con %>. Limitierte Ausgabe Herbst 2025 Ausrüstung.",
|
||||
"shieldArmoireSoftOrangePillowNotes": "Der vorbereitete Krieger packt für jede Expedition ein Kissen ein. Mach dich bereit, neue Verpflichtungen zu übernehmen ... sogar während du ein Nickerchen machst. Erhöht Intelligenz und Wahrnehmung um jeweils <%= attrs %>. Verzauberter Kleiderschrank: Orangenes Loungewear-Set (Gegenstand 3 von 3).",
|
||||
"bodyMystery202509Text": "Schal des windgepeitschten Wanderers",
|
||||
"armorSpecialFall2025RogueNotes": "Ein hartes und schmales Ziel in dieser saisonalen Rüstung ist am schwersten zu treffen. Erhöht die Wahrnehmung um <%= per %>. Limitierte Ausgabe Herbst 2025 Ausrüstung."
|
||||
"weaponMystery202511Notes": "Der eisige Glanz dieses Schwertes wird selbst mit dunkelroten Aufgaben kurzen Prozess machen. Gewährt keinen Attributbonus. Novermber 2025 Abonnentengegenstand."
|
||||
}
|
||||
|
||||
@@ -241,6 +241,5 @@
|
||||
"titleCustomizations": "Individualisierungen",
|
||||
"targetUserNotExist": "Zielbenutzer: '<%= userName %>' existiert nicht.",
|
||||
"newMessage": "Neue Nachricht",
|
||||
"rememberToBeKind": "Bitte sei freundlich, respektvoll, und folge den <a href='/static/community-guidelines' target='_blank'>Community-Richtlinien</a>.",
|
||||
"gem": "Edelstein"
|
||||
"rememberToBeKind": "Bitte sei freundlich, respektvoll, und folge den <a href='/static/community-guidelines' target='_blank'>Community-Richtlinien</a>."
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
"optional": "Optional",
|
||||
"needsTextPlaceholder": "Gib Deine Nachricht hier ein.",
|
||||
"leaderOnlyChallenges": "Nur die Gruppenleitung kann Herausforderungen erstellen",
|
||||
"sendGift": "Geschenk schicken",
|
||||
"sendGift": "Ein Geschenk schicken",
|
||||
"inviteFriends": "Lade Freunde ein",
|
||||
"inviteByEmail": "Lade per E-Mail ein",
|
||||
"inviteMembersHowTo": "Leute einladen: mit einer gültigen E-Mailadresse oder der 36-stelligen Nutzer ID. Wenn eine E-Mailadresse noch nicht registriert ist, laden wir diejenigen nach Habitica ein.",
|
||||
@@ -365,6 +365,12 @@
|
||||
"groupUseDefault": "Wähle eine Antwort",
|
||||
"createGroup": "Erstelle eine Gruppe",
|
||||
"groupUse": "Was beschreibt den Zweck Deiner Gruppe am Besten?*",
|
||||
"groupParentChildren": "Eltern(teile), die Aufgaben für ihre Kinder erstellen",
|
||||
"groupCouple": "Ein Paar, das sich Aufgaben teilt",
|
||||
"groupFriends": "Freunde, die sich Aufgaben teilen",
|
||||
"groupCoworkers": "Arbeitskollegen, die sich Aufgaben teilen",
|
||||
"groupManager": "Ein Manager, der Aufgaben für seine Mitarbeiter erstellt",
|
||||
"groupTeacher": "Ein Lehrer, der Aufgaben für seine Schüler oder Studierenden erstellt",
|
||||
"nameStar": "Name*",
|
||||
"descriptionOptional": "Beschreibung",
|
||||
"descriptionOptionalText": "Füge eine Beschreibung hinzu",
|
||||
@@ -422,9 +428,5 @@
|
||||
"readyToUpgrade": "Bereit zum Aufrüsten?",
|
||||
"interestedLearningMore": "Willst du mehr erfahren?",
|
||||
"checkGroupPlanFAQ": "Schau in die <a href='/static/faq#what-is-group-plan'>Gruppenpläne FAQ</a> um herauszufinden, wie du deine gemeinsamen Aufgaben optimal nutzen kannst.",
|
||||
"messageCopiedToClipboard": "Nachricht in Zwischenablage kopiert.",
|
||||
"groupTeacher": "Nutzung in der Bildung",
|
||||
"groupParentChildren": "Nutzung mit der Familie",
|
||||
"groupManager": "Nutzung für die Arbeit",
|
||||
"groupFriends": "Nutzung mit Freunden"
|
||||
"messageCopiedToClipboard": "Nachricht in Zwischenablage kopiert."
|
||||
}
|
||||
|
||||
@@ -234,18 +234,18 @@
|
||||
"fall2023BogCreatureHealerSet": "Sumpf Kreatur (Heiler)",
|
||||
"anniversaryGryphatricePrice": "Besitze es heute für <strong>$9.99</strong> oder <strong>60 Edelsteine</strong>",
|
||||
"wantToPayWithMoneyText": "Willst du mit Stripe, Paypal oder Amazon bezahlen?",
|
||||
"jubilantSuccess": "Du hast das <strong>Jubelnde Greifatrix</strong> erfolgreich gekauft!",
|
||||
"jubilantSuccess": "Du hast das <strong>Jubilierende Greifatrix</strong> erfolgreich gekauft!",
|
||||
"takeMeToStable": "Bring mich zum Stall",
|
||||
"ownJubilantGryphatrice": "<strong>Du besitzt das Jubelnde Greifatrix!</strong> Besuche den Stall, um es auszurüsten!",
|
||||
"ownJubilantGryphatrice": "<strong>Du besitzt das Jubilierende Greifatrix!</strong> Besuche den Stall, um es auszurüsten!",
|
||||
"celebrateAnniversary": "Feiere Habiticas 10. Geburtstag mit untenstehenden Geschenken und exklusiven Gegenständen!",
|
||||
"celebrateBirthday": "Feiere Habiticas 10. Geburtstag mit Geschenken und exklusiven Gegenständen!",
|
||||
"jubilantGryphatricePromo": "Animiertes Jubelndes Greifatrix Haustier",
|
||||
"jubilantGryphatricePromo": "Animiertes Jubilierender Greifatrix Haustier",
|
||||
"limitedEdition": "Limitierte Ausgabe",
|
||||
"anniversaryGryphatriceText": "Das seltene Jubelnde Greifatrix schließt sich den Geburtstagsfeiern an! Verpass nicht deine Chance, dieses exklusive animierte Haustier zu besitzen.",
|
||||
"anniversaryGryphatriceText": "Das seltene Jubilierende Greifatrix schließt sich den Geburtstagsfeiern an! Verpass nicht deine Chance, dieses exklusive animierte Haustier zu besitzen.",
|
||||
"buyNowMoneyButton": "Kaufe Jetzt für $9.99",
|
||||
"buyNowGemsButton": "Kaufe Jetzt für 60 Edelsteine",
|
||||
"wantToPayWithGemsText": "Willst du mit Edelsteinen bezahlen?",
|
||||
"anniversaryLimitations": "Dies ist eine zeitlich begrenzte Aktion, die am 30. Januar um 8:00 AM ET (13:00 UTC) startet und am 8. Februar um 11:59 PM ET (04:59 UTC) endet. Die limitierte Ausgabe des Jubelnden Greifatrix und zehn magische Schlüpfelixiere werden in diesem Zeitraum zum Kauf angeboten. Die anderen Geschenke, die im Gratis Abschnitt aufgeführt sind, werden automatisch an alle Accounts geliefert, die in den 30 Tagen vor dem Tag aktiv waren, an dem das Geschenk versendet wird. Accounts, die nach dem Versenden der Geschenke erstellt sind, werden die Geschenke nicht beanspruchen können.",
|
||||
"anniversaryLimitations": "Dies ist eine zeitlich begrenzte Aktion, die am 30. Januar um 8:00 AM ET (13:00 UTC) startet und am 8. Februar um 11:59 PM ET (04:59 UTC) endet. Die Limitierte Ausgabe des Jubilierenden Greifatrix und zehn Magische Schlüpfelixiere werden in diesem Zeitraum zum Kauf angeboten. Die anderen Geschenke, die im Gratis Abschnitt aufgeführt sind, werden automatisch an alle Accounts geliefert, die in den 30 Tagen vor dem Tag aktiv waren, an dem das Geschenk versendet wird. Accounts, die nach dem Versenden der Geschenke erstellt sind, werden die Geschenke nicht beanspruchen können.",
|
||||
"plentyOfPotionsText": "Wir bringen 10 der beliebtesten Magischen Schlüpfelixiere der Community zurück. Geh rüber zum Marktplatz, um deine Sammlung zu vervollständigen!",
|
||||
"visitTheMarketButton": "Besuche den Marktplatz",
|
||||
"fourForFree": "Vier gratis",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"stable": "Haustiere und Reittiere",
|
||||
"stable": "Haus- und Reittiere",
|
||||
"pets": "Haustiere",
|
||||
"activePet": "Aktives Haustier",
|
||||
"noActivePet": "Kein aktives Haustier",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"settings": "Einstellungen",
|
||||
"language": "Sprache",
|
||||
"americanEnglishGovern": "Im Fall von Bedeutungsunterschieden gilt die englische Version.",
|
||||
"helpWithTranslation": "Hast du Interesse, bei der Übersetzung von Habitica helfen? Toll! Dann besuche doch die <a href=\"https://translate.habitica.com\"> Habitica's Weblate Seite</a>!",
|
||||
"helpWithTranslation": "Hast du Interesse, bei der Übersetzung von Habitica helfen? Toll! Dann besuche doch die <a href=\"/groups/guild/7732f64c-33ee-4cce-873c-fc28f147a6f7\">Aspiring Linguists Guild</a>!",
|
||||
"stickyHeader": "Kopfzeile anheften",
|
||||
"newTaskEdit": "Neue Aufgaben im Bearbeiten-Modus öffnen",
|
||||
"reverseChatOrder": "Zeige die Chat-Nachrichten in umgekehrter Reihenfolge",
|
||||
@@ -271,7 +271,5 @@
|
||||
"privacyOverview": "Heutzutage scheint jedes Unternehmen von deinen Daten profitieren zu wollen. Das kann es schwierig machen, die richtige App zur Verbesserung deiner Gewohnheiten zu finden. Habitica verwendet Cookies, die Daten nur zur Leistungsanalyse, zur Bearbeitung von Supportanfragen und zur Bereitstellung des bestmöglichen gamifizierten Erlebnisses speichern. Du kannst dies jederzeit in deinen Kontoeinstellungen ändern.",
|
||||
"privacySettingsOverview": "Habitica verwendet Cookies zur Leistungsanalyse, Bearbeitung von Supportanfragen und Bereitstellung des bestmöglichen gamifizierten Erlebnisses. Hierfür benötigen wir die folgenden Berechtigungen. Du kannst dies jederzeit in deinen Kontoeinstellungen ändern.",
|
||||
"performanceAnalytics": "Leistung und Analyse",
|
||||
"usedForSupport": "Diese werden verwendet, um Benutzererfahrung, Leistung und Dienste unserer Websites und Apps zu verbessern. Diese Daten werden von unserem Support-Team für die Bearbeitung von Anfragen und Fehlermeldungen verwendet.",
|
||||
"gpcWarning": "<a href='<%= url %>' target='_blank'>GPC</a> ist aktiv. Wenn du unten Tracking aktivierst, überschreibt es dies und sendet Daten an unsere Analytics Partner.",
|
||||
"gpcPlusAnalytics": "<a href='<%= url %>' target='_blank'>GPC</a> ist aktiv. Du hast Tracking und dem Senden von Daten an unsere Analytics Partner zugestimmt."
|
||||
"usedForSupport": "Diese werden verwendet, um Benutzererfahrung, Leistung und Dienste unserer Websites und Apps zu verbessern. Diese Daten werden von unserem Support-Team für die Bearbeitung von Anfragen und Fehlermeldungen verwendet."
|
||||
}
|
||||
|
||||
@@ -3,9 +3,5 @@
|
||||
"siteBlockers": "Site Blockers",
|
||||
"newsroom": "Newsroom",
|
||||
"adminBlockerTypeDescription": "<b>IP-Address</b> - Block access for a specific IP-Address\n\nClient - Block access for a client based on the \"x-client\" header.\n\nE-Mail - Blocks e-mails from being used for signup.",
|
||||
"adminBlockerAreaDescription": "A blocker can either apply to the full site, completely blocking any access. Or it can apply to purchases, which still allows the site to be accessed.",
|
||||
"groupAdmin": "Group Admin",
|
||||
"groupSupportDescription": "Manage groups and their members. You can search for groups by ID, or load your own group by leaving the field blank.",
|
||||
"groupData": "Group Data",
|
||||
"groupPlanSubscription": "Group Plan Subscription"
|
||||
"adminBlockerAreaDescription": "A blocker can either apply to the full site, completely blocking any access. Or it can apply to purchases, which still allows the site to be accessed."
|
||||
}
|
||||
|
||||
@@ -1051,18 +1051,6 @@
|
||||
"backgroundCastleKeepWithBannersText": "Castle Hall with Banners",
|
||||
"backgroundCastleKeepWithBannersNotes": "Sing tales of heroic deeds in a Castle Hall with Banners.",
|
||||
|
||||
"backgrounds122025": "SET 139: Released December 2025",
|
||||
"backgroundNighttimeStreetWithShopsText": "Nighttime Street with Shops",
|
||||
"backgroundNighttimeStreetWithShopsNotes": "Enjoy the warm glow of a Nighttime Street with Shops.",
|
||||
|
||||
"backgrounds012026": "SET 140: Released January 2026",
|
||||
"backgroundWinterDesertWithSaguarosText": "Winter Desert with Saguaros",
|
||||
"backgroundWinterDesertWithSaguarosNotes": "Breathe the crisp air of a Winter Desert with Saguaros.",
|
||||
|
||||
"backgrounds022026": "SET 141: Released February 2026",
|
||||
"backgroundElegantPalaceText": "Elegant Palace",
|
||||
"backgroundElegantPalaceNotes": "Admire the colorful halls of an Elegant Palace.",
|
||||
|
||||
"timeTravelBackgrounds": "Steampunk Backgrounds",
|
||||
"backgroundAirshipText": "Airship",
|
||||
"backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.",
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
"awardWinners": "Award Winner",
|
||||
"doYouWantedToDeleteChallenge": "Do you want to delete this Challenge?",
|
||||
"deleteChallenge": "Delete Challenge",
|
||||
"deleteChallengeRefundDescription": "If you delete this Challenge, you will be refunded the Gem prize and the Challenge tasks will remain on the participants' task boards.",
|
||||
"challengeNamePlaceholder": "What is your Challenge name?",
|
||||
"challengeSummary": "Summary",
|
||||
"challengeSummaryPlaceholder": "Write a short description advertising your Challenge to other Habiticans. What is the main purpose of your Challenge and why should people join it? Try to include useful keywords in the description so that Habiticans can easily find it when they search!",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"dontDespair": "Don't despair!",
|
||||
"deathPenaltyDetails": "You lost a Level, your Gold, and a piece of Equipment, but you can get them all back with hard work! Good luck--you'll do great.",
|
||||
"refillHealthTryAgain": "Refill Health & Try Again",
|
||||
"dyingOftenTips": "Is this happening often? <a href='/static/faq#prevent-damage' target='_blank'>Here are some tips!</a>",
|
||||
"dyingOftenTips": "Is this happening often? <a href='https://habitica.fandom.com/wiki/Death_Mechanics#Strategies_for_Staying_Alive' target='_blank'>Here are some tips!</a>",
|
||||
"losingHealthWarning": "Careful - You're Losing Health!",
|
||||
"losingHealthWarning2": "Don't let your Health drop to zero! If you do, you'll lose a level, your Gold, and a piece of equipment.",
|
||||
"toRegainHealth": "To regain Health:",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"webFaqAnswer29": "You can recover 15 HP by purchasing a Health Potion from your Rewards column for 25 Gold. Additionally, you will always recover full HP when you level up!",
|
||||
|
||||
"faqQuestion30": "What happens when I run out of HP?",
|
||||
"webFaqAnswer30": "If your HP reaches zero, you'll lose one level, that level's stat point, all of your Gold, and a piece of equipment that can be repurchased. You can rebuild by completing tasks and leveling up again.",
|
||||
"webFaqAnswer30": "If your HP reaches zero, you’ll lose one level, all of your Gold, and a piece of Equipment that can be repurchased.",
|
||||
|
||||
"faqQuestion31": "Why did I lose HP when interacting with a non-negative task?",
|
||||
"webFaqAnswer31": "If you complete a task and lose HP when you shouldn’t have, you encountered a delay while the server is syncing changes made on other platforms. For example, if you use Gold, Mana, or lose HP on the mobile app and then complete a task on the website, the server is simply confirming everything is in sync.",
|
||||
@@ -135,9 +135,6 @@
|
||||
"faqQuestion67": "What are the classes in Habitica?",
|
||||
"webFaqAnswer67": "Classes are different roles that your character can play. Each class provides its own set of unique benefits and skills as you level up. These skills can complement the way you interact with your tasks or help you contribute to completing Quests in your Party.\n\nYour class also determines the Equipment that will be available to you for purchase in your Rewards, the Market, and the Seasonal Shop.\n\nHere’s a rundown of each class to help you choose which one is best suited to your playstyle:\n#### **Warrior**\n* Warriors deal high damage to bosses and have a high chance of critical hits when completing tasks, rewarding you extra Experience and Gold.\n* Strength is their primary stat, raising the damage they do.\n* Constitution is their secondary stat, lowering the damage they take.\n* Warriors' skills buff their Party mates' Constitution and Strength.\n* Consider playing as a Warrior if you love to fight bosses but also want some protection if you miss tasks occasionally.\n#### **Healer**\n* Healers have high defense and can heal themselves as well as their Party mates.\n* Constitution is their primary stat, increasing their heals and lowering the damage they take.\n* Intelligence is their secondary stat, increasing their Mana and Experience.\n* Healers' skills make their tasks less red and buff their Party mates' Constitution.\n* Consider playing as a Healer if you miss tasks often and need the ability to heal yourself or your Party members. Healers also level up quickly.\n#### **Mage**\n* Mages level up quickly, gain lots of Mana, and damage bosses in Quests.\n* Intelligence is their primary stat, increasing their Mana and Experience.\n* Perception is their secondary stat, increasing their Gold and item drops.\n* Mages' skills freeze their task streaks, restore their Party mates' Mana, and buff their Intelligence.\n* Consider playing as a Mage if you are motivated by progressing quickly through levels and contributing damage to boss Quests.\n#### **Rogue**\n* Rogues get the most item drops and Gold from completing tasks, and have a high chance of critical hits, getting even more Experience and Gold.\n* Perception is their primary stat, increasing their Gold and item drops.\n* Strength is their secondary stat, raising the damage they do.\n* Rogues' skills help them dodge missed Dailies, pilfer Gold, and buff their Party mates’ Perception.\n* Consider playing as a Rogue if you’re highly motivated by rewards.",
|
||||
|
||||
"faqQuestion68": "How do I prevent losing HP?",
|
||||
"webFaqAnswer68": "If you find yourself losing HP often, try some of these tips:\n\n- Pause your Dailies. The \"Pause Damage\" button in Settings will prevent you from losing HP for missed Dailies.\n- Adjust the schedule of your Dailies. By setting them to never be due, you can still complete them for rewards without risking HP loss.\n- Try using class skills:\n\t- Rogues can cast Stealth to prevent damage from missed Dailies\n\t- Warriors can cast Brutal Smash to reduce a Daily's redness, lowering damage taken if missed\n\t- Healers can cast Searing Brightness to reduce Dailies' redness, lowering damage taken if missed",
|
||||
|
||||
"iosFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), use the Ask a Question form [LINK NEEDED]! We're happy to help.",
|
||||
"androidFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), use the Ask a Question form [LINK NEEDED]! We're happy to help.",
|
||||
"webFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), use the Ask a Question form [LINK NEEDED]! We're happy to help.",
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
"passwordReset": "If we have your email or username on file, instructions for setting a new password have been sent to your email.",
|
||||
"invalidLoginCredentialsLong": "Your email, username, or password are incorrect. Please try again or use \"Forgot Password.\"",
|
||||
"invalidCredentials": "There is no account that uses those credentials.",
|
||||
"accountSuspended": "Your account @<%= username %> has been blocked. For additional information, or to request an appeal, email admin@habitica.com with your Habitica username or User ID.",
|
||||
"accountSuspended": "This account, User ID \"<%= userId %>\", has been blocked for breaking the Community Guidelines (https://habitica.com/static/community-guidelines) or Terms of Service (https://habitica.com/static/terms). For details or to ask to be unblocked, please email our Community Manager at <%= communityManagerEmail %> or ask your parent or guardian to email them. Please include your @Username in the email.",
|
||||
"accountSuspendedTitle": "Account has been suspended",
|
||||
"unsupportedNetwork": "This network is not currently supported.",
|
||||
"cantDetachSocial": "Account lacks another authentication method; can't detach this authentication method.",
|
||||
@@ -142,7 +142,7 @@
|
||||
"invalidReqParams": "Invalid request parameters.",
|
||||
"memberIdRequired": "\"member\" must be a valid UUID.",
|
||||
"heroIdRequired": "\"heroId\" must be a valid UUID.",
|
||||
"cannotFulfillReq": "This email address is already in use. You can try logging in or use a different email to register. If you need help, reach out to admin@habitica.com.",
|
||||
"cannotFulfillReq": "Please enter a valid email address. Email admin@habitica.com if this error persists.",
|
||||
"enterValidEmail": "Please enter a valid email address.",
|
||||
"modelNotFound": "This model does not exist.",
|
||||
"signUpWithSocial": "Continue with <%= social %>",
|
||||
|
||||
@@ -155,13 +155,13 @@
|
||||
"weaponSpecialSummerHealerNotes": "This wand, made of aquamarine and live coral, is very attractive to schools of fish. Increases Intelligence by <%= int %>. Limited Edition 2014 Summer Gear.",
|
||||
|
||||
"weaponSpecialFallRogueText": "Silver Stake",
|
||||
"weaponSpecialFallRogueNotes": "Dispatches undead. Also grants a bonus against werewolves, because you can never be too careful. Increases Strength by <%= str %>. Limited Edition 2014 Fall Gear.",
|
||||
"weaponSpecialFallRogueNotes": "Dispatches undead. Also grants a bonus against werewolves, because you can never be too careful. Increases Strength by <%= str %>. Limited Edition 2014 Autumn Gear.",
|
||||
"weaponSpecialFallWarriorText": "Grabby Claw of Science",
|
||||
"weaponSpecialFallWarriorNotes": "This grabby claw is at the very cutting edge of technology. Increases Strength by <%= str %>. Limited Edition 2014 Fall Gear.",
|
||||
"weaponSpecialFallWarriorNotes": "This grabby claw is at the very cutting edge of technology. Increases Strength by <%= str %>. Limited Edition 2014 Autumn Gear.",
|
||||
"weaponSpecialFallMageText": "Magic Broom",
|
||||
"weaponSpecialFallMageNotes": "This enchanted broom flies faster than a dragon! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2014 Fall Gear.",
|
||||
"weaponSpecialFallMageNotes": "This enchanted broom flies faster than a dragon! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2014 Autumn Gear.",
|
||||
"weaponSpecialFallHealerText": "Scarab Wand",
|
||||
"weaponSpecialFallHealerNotes": "The scarab on this wand protects and heals its wielder. Increases Intelligence by <%= int %>. Limited Edition 2014 Fall Gear.",
|
||||
"weaponSpecialFallHealerNotes": "The scarab on this wand protects and heals its wielder. Increases Intelligence by <%= int %>. Limited Edition 2014 Autumn Gear.",
|
||||
|
||||
"weaponSpecialWinter2015RogueText": "Ice Spike",
|
||||
"weaponSpecialWinter2015RogueNotes": "You truly, definitely, absolutely just picked these up off of the ground. Increases Strength by <%= str %>. Limited Edition 2014-2015 Winter Gear.",
|
||||
@@ -191,13 +191,13 @@
|
||||
"weaponSpecialSummer2015HealerNotes": "Cures seasickness and sea sickness! Increases Intelligence by <%= int %>. Limited Edition 2015 Summer Gear.",
|
||||
|
||||
"weaponSpecialFall2015RogueText": "Bat-tle Ax",
|
||||
"weaponSpecialFall2015RogueNotes": "Fearsome To Do's cower before the flapping of this ax. Increases Strength by <%= str %>. Limited Edition 2015 Fall Gear.",
|
||||
"weaponSpecialFall2015RogueNotes": "Fearsome To Do's cower before the flapping of this ax. Increases Strength by <%= str %>. Limited Edition 2015 Autumn Gear.",
|
||||
"weaponSpecialFall2015WarriorText": "Wooden Plank",
|
||||
"weaponSpecialFall2015WarriorNotes": "Great for elevating things in cornfields and/or smacking tasks. Increases Strength by <%= str %>. Limited Edition 2015 Fall Gear.",
|
||||
"weaponSpecialFall2015WarriorNotes": "Great for elevating things in cornfields and/or smacking tasks. Increases Strength by <%= str %>. Limited Edition 2015 Autumn Gear.",
|
||||
"weaponSpecialFall2015MageText": "Enchanted Thread",
|
||||
"weaponSpecialFall2015MageNotes": "A powerful Stitch Witch can control this enchanted thread without even touching it! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2015 Fall Gear.",
|
||||
"weaponSpecialFall2015MageNotes": "A powerful Stitch Witch can control this enchanted thread without even touching it! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2015 Autumn Gear.",
|
||||
"weaponSpecialFall2015HealerText": "Swamp-Slime Potion",
|
||||
"weaponSpecialFall2015HealerNotes": "Brewed to perfection! Now you just have to convince yourself to drink it. Increases Intelligence by <%= int %>. Limited Edition 2015 Fall Gear.",
|
||||
"weaponSpecialFall2015HealerNotes": "Brewed to perfection! Now you just have to convince yourself to drink it. Increases Intelligence by <%= int %>. Limited Edition 2015 Autumn Gear.",
|
||||
|
||||
"weaponSpecialWinter2016RogueText": "Cocoa Mug",
|
||||
"weaponSpecialWinter2016RogueNotes": "Warming drink, or boiling projectile? You decide... Increases Strength by <%= str %>. Limited Edition 2015-2016 Winter Gear.",
|
||||
@@ -227,13 +227,13 @@
|
||||
"weaponSpecialSummer2016HealerNotes": "One spike harms, the other heals. Increases Intelligence by <%= int %>. Limited Edition 2016 Summer Gear.",
|
||||
|
||||
"weaponSpecialFall2016RogueText": "Spiderbite Dagger",
|
||||
"weaponSpecialFall2016RogueNotes": "Feel the sting of the spider's bite! Increases Strength by <%= str %>. Limited Edition 2016 Fall Gear.",
|
||||
"weaponSpecialFall2016RogueNotes": "Feel the sting of the spider's bite! Increases Strength by <%= str %>. Limited Edition 2016 Autumn Gear.",
|
||||
"weaponSpecialFall2016WarriorText": "Attacking Roots",
|
||||
"weaponSpecialFall2016WarriorNotes": "Attack your tasks with these twisting roots! Increases Strength by <%= str %>. Limited Edition 2016 Fall Gear.",
|
||||
"weaponSpecialFall2016WarriorNotes": "Attack your tasks with these twisting roots! Increases Strength by <%= str %>. Limited Edition 2016 Autumn Gear.",
|
||||
"weaponSpecialFall2016MageText": "Ominous Orb",
|
||||
"weaponSpecialFall2016MageNotes": "Don't ask this orb to tell your future... Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2016 Fall Gear.",
|
||||
"weaponSpecialFall2016MageNotes": "Don't ask this orb to tell your future... Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2016 Autumn Gear.",
|
||||
"weaponSpecialFall2016HealerText": "Venomous Serpent",
|
||||
"weaponSpecialFall2016HealerNotes": "One bite harms, and another bite heals. Increases Intelligence by <%= int %>. Limited Edition 2016 Fall Gear.",
|
||||
"weaponSpecialFall2016HealerNotes": "One bite harms, and another bite heals. Increases Intelligence by <%= int %>. Limited Edition 2016 Autumn Gear.",
|
||||
|
||||
"weaponSpecialWinter2017RogueText": "Ice Axe",
|
||||
"weaponSpecialWinter2017RogueNotes": "This axe is great for attack, defense, and ice-climbing! Increases Strength by <%= str %>. Limited Edition 2016-2017 Winter Gear.",
|
||||
@@ -263,20 +263,20 @@
|
||||
"weaponSpecialSummer2017HealerNotes": "A single touch from this pearl-tipped wand soothes away all wounds. Increases Intelligence by <%= int %>. Limited Edition 2017 Summer Gear.",
|
||||
|
||||
"weaponSpecialFall2017RogueText": "Candied Apple Mace",
|
||||
"weaponSpecialFall2017RogueNotes": "Defeat your foes with sweetness! Increases Strength by <%= str %>. Limited Edition 2017 Fall Gear.",
|
||||
"weaponSpecialFall2017RogueNotes": "Defeat your foes with sweetness! Increases Strength by <%= str %>. Limited Edition 2017 Autumn Gear.",
|
||||
"weaponSpecialFall2017WarriorText": "Candy Corn Lance",
|
||||
"weaponSpecialFall2017WarriorNotes": "All your foes will cower before this tasty-looking lance, regardless of whether they're ghosts, monsters, or red To Do's. Increases Strength by <%= str %>. Limited Edition 2017 Fall Gear.",
|
||||
"weaponSpecialFall2017WarriorNotes": "All your foes will cower before this tasty-looking lance, regardless of whether they're ghosts, monsters, or red To Do's. Increases Strength by <%= str %>. Limited Edition 2017 Autumn Gear.",
|
||||
"weaponSpecialFall2017MageText": "Spooky Staff",
|
||||
"weaponSpecialFall2017MageNotes": "The eyes of the glowing skull on this staff radiate magic and mystery. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2017 Fall Gear.",
|
||||
"weaponSpecialFall2017MageNotes": "The eyes of the glowing skull on this staff radiate magic and mystery. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2017 Autumn Gear.",
|
||||
"weaponSpecialFall2017HealerText": "Creepy Candelabra",
|
||||
"weaponSpecialFall2017HealerNotes": "This light dispels fear and lets others know you're here to help. Increases Intelligence by <%= int %>. Limited Edition 2017 Fall Gear.",
|
||||
"weaponSpecialFall2017HealerNotes": "This light dispels fear and lets others know you're here to help. Increases Intelligence by <%= int %>. Limited Edition 2017 Autumn Gear.",
|
||||
|
||||
"weaponSpecialWinter2018RogueText": "Peppermint Hook",
|
||||
"weaponSpecialWinter2018RogueNotes": "Perfect for climbing walls or distracting your foes with sweet, sweet candy. Increases Strength by <%= str %>. Limited Edition 2017-2018 Winter Gear.",
|
||||
"weaponSpecialWinter2018WarriorText": "Holiday Bow Hammer",
|
||||
"weaponSpecialWinter2018WarriorNotes": "The sparkly appearance of this bright weapon will dazzle your enemies as you swing it! Increases Strength by <%= str %>. Limited Edition 2017-2018 Winter Gear.",
|
||||
"weaponSpecialWinter2018MageText": "Holiday Confetti",
|
||||
"weaponSpecialWinter2018MageNotes": "Magic—and glitter—is in the air! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2017-2018 Winter Gear.",
|
||||
"weaponSpecialWinter2018MageNotes": "Magic--and glitter--is in the air! Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2017-2018 Winter Gear.",
|
||||
"weaponSpecialWinter2018HealerText": "Mistletoe Wand",
|
||||
"weaponSpecialWinter2018HealerNotes": "This mistletoe ball is sure to enchant and delight passersby! Increases Intelligence by <%= int %>. Limited Edition 2017-2018 Winter Gear.",
|
||||
|
||||
@@ -299,13 +299,13 @@
|
||||
"weaponSpecialSummer2018HealerNotes": "With a benevolent gesture, you command healing water to flow through your dominions in waves. Increases Intelligence by <%= int %>. Limited Edition 2018 Summer Gear.",
|
||||
|
||||
"weaponSpecialFall2018RogueText": "Vial of Clarity",
|
||||
"weaponSpecialFall2018RogueNotes": "When you need to come back to your senses, when you need a little boost to make the right decision, take a deep breath and a sip. It'll be OK! Increases Strength by <%= str %>. Limited Edition 2018 Fall Gear.",
|
||||
"weaponSpecialFall2018RogueNotes": "When you need to come back to your senses, when you need a little boost to make the right decision, take a deep breath and a sip. It'll be OK! Increases Strength by <%= str %>. Limited Edition 2018 Autumn Gear.",
|
||||
"weaponSpecialFall2018WarriorText": "Whip of Minos",
|
||||
"weaponSpecialFall2018WarriorNotes": "Not quite long enough to unwind behind you for keeping your bearings in a maze. Well, maybe a very small maze. Increases Strength by <%= str %>. Limited Edition 2018 Fall Gear.",
|
||||
"weaponSpecialFall2018WarriorNotes": "Not quite long enough to unwind behind you for keeping your bearings in a maze. Well, maybe a very small maze. Increases Strength by <%= str %>. Limited Edition 2018 Autumn Gear.",
|
||||
"weaponSpecialFall2018MageText": "Staff of Sweetness",
|
||||
"weaponSpecialFall2018MageNotes": "This is no ordinary lollipop! The glowing orb of magic sugar atop this staff has the power to make good habits stick to you. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2018 Fall Gear.",
|
||||
"weaponSpecialFall2018MageNotes": "This is no ordinary lollipop! The glowing orb of magic sugar atop this staff has the power to make good habits stick to you. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2018 Autumn Gear.",
|
||||
"weaponSpecialFall2018HealerText": "Starving Staff",
|
||||
"weaponSpecialFall2018HealerNotes": "Just keep this staff fed, and it will bestow Blessings. If you forget to feed it, keep your fingers out of reach. Increases Intelligence by <%= int %>. Limited Edition 2018 Fall Gear.",
|
||||
"weaponSpecialFall2018HealerNotes": "Just keep this staff fed, and it will bestow Blessings. If you forget to feed it, keep your fingers out of reach. Increases Intelligence by <%= int %>. Limited Edition 2018 Autumn Gear.",
|
||||
|
||||
"weaponSpecialWinter2019RogueText": "Poinsettia Bouquet",
|
||||
"weaponSpecialWinter2019RogueNotes": "Use this festive bouquet to further camouflage yourself, or generously gift it to brighten a friend's day! Increases Strength by <%= str %>. Limited Edition 2018-2019 Winter Gear.",
|
||||
@@ -335,13 +335,13 @@
|
||||
"weaponSpecialSummer2019HealerNotes": "The bubbles from this wand capture healing energy and ancient oceanic magic. Increases Intelligence by <%= int %>. Limited Edition 2019 Summer Gear.",
|
||||
|
||||
"weaponSpecialFall2019RogueText": "Music Stand",
|
||||
"weaponSpecialFall2019RogueNotes": "Whether you're conducting the orchestra or singing an aria, this helpful device keeps your hands free for dramatic gestures! Increases Strength by <%= str %>. Limited Edition 2019 Fall Gear.",
|
||||
"weaponSpecialFall2019RogueNotes": "Whether you're conducting the orchestra or singing an aria, this helpful device keeps your hands free for dramatic gestures! Increases Strength by <%= str %>. Limited Edition 2019 Autumn Gear.",
|
||||
"weaponSpecialFall2019WarriorText": "Talon Trident",
|
||||
"weaponSpecialFall2019WarriorNotes": "Prepare to rend your foes with the talons of a raven! Increases Strength by <%= str %>. Limited Edition 2019 Fall Gear.",
|
||||
"weaponSpecialFall2019WarriorNotes": "Prepare to rend your foes with the talons of a raven! Increases Strength by <%= str %>. Limited Edition 2019 Autumn Gear.",
|
||||
"weaponSpecialFall2019MageText": "One-Eyed Staff",
|
||||
"weaponSpecialFall2019MageNotes": "Be it forging thunderbolts, raising fortifications, or simply striking terror into the hearts of mortals, this staff lends the power of giants to work wonders. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2019 Fall Gear.",
|
||||
"weaponSpecialFall2019MageNotes": "Be it forging thunderbolts, raising fortifications, or simply striking terror into the hearts of mortals, this staff lends the power of giants to work wonders. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2019 Autumn Gear.",
|
||||
"weaponSpecialFall2019HealerText": "Fearsome Phylactery",
|
||||
"weaponSpecialFall2019HealerNotes": "This phylactery can call on the spirits of tasks long slain and use their healing power. Increases Intelligence by <%= int %>. Limited Edition 2019 Fall Gear.",
|
||||
"weaponSpecialFall2019HealerNotes": "This phylactery can call on the spirits of tasks long slain and use their healing power. Increases Intelligence by <%= int %>. Limited Edition 2019 Autumn Gear.",
|
||||
|
||||
"weaponSpecialWinter2020RogueText": "Lantern Rod",
|
||||
"weaponSpecialWinter2020RogueNotes": "Darkness is a Rogue's element. Who better, then, to light the way in the darkest time of year? Increases Strength by <%= str %>. Limited Edition 2019-2020 Winter Gear.",
|
||||
@@ -371,13 +371,13 @@
|
||||
"weaponSpecialSummer2020HealerNotes": "As the currents wear away sharp edges, so shall your magic soften your friends' pain. Increases Intelligence by <%= int %>. Limited Edition 2020 Summer Gear.",
|
||||
|
||||
"weaponSpecialFall2020RogueText": "Sharp Katar",
|
||||
"weaponSpecialFall2020RogueNotes": "Pierce your foe with one sharp strike! Even the thickest armor will give way to your blade. Increases Strength by <%= str %>. Limited Edition 2020 Fall Gear.",
|
||||
"weaponSpecialFall2020RogueNotes": "Pierce your foe with one sharp strike! Even the thickest armor will give way to your blade. Increases Strength by <%= str %>. Limited Edition 2020 Autumn Gear.",
|
||||
"weaponSpecialFall2020WarriorText": "Spectre's Sword",
|
||||
"weaponSpecialFall2020WarriorNotes": "This sword went into the afterlife with a powerful Warrior, and returns for you to wield! Increases Strength by <%= str %>. Limited Edition 2020 Fall Gear.",
|
||||
"weaponSpecialFall2020WarriorNotes": "This sword went into the afterlife with a powerful Warrior, and returns for you to wield! Increases Strength by <%= str %>. Limited Edition 2020 Autumn Gear.",
|
||||
"weaponSpecialFall2020MageText": "Three Visions",
|
||||
"weaponSpecialFall2020MageNotes": "If aught should escape your mage sight, the brilliant crystals atop this staff shall illuminate what you overlooked. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2020 Fall Gear.",
|
||||
"weaponSpecialFall2020MageNotes": "If aught should escape your mage sight, the brilliant crystals atop this staff shall illuminate what you overlooked. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2020 Autumn Gear.",
|
||||
"weaponSpecialFall2020HealerText": "Cocoon Cane",
|
||||
"weaponSpecialFall2020HealerNotes": "Now that your transformation is complete, this remnant of your life as a pupa now serves as the divining rod with which you measure destinies. Increases Intelligence by <%= int %>. Limited Edition 2020 Fall Gear.",
|
||||
"weaponSpecialFall2020HealerNotes": "Now that your transformation is complete, this remnant of your life as a pupa now serves as the divining rod with which you measure destinies. Increases Intelligence by <%= int %>. Limited Edition 2020 Autumn Gear.",
|
||||
|
||||
"weaponSpecialWinter2021RogueText": "Holly Berry Flail",
|
||||
"weaponSpecialWinter2021RogueNotes": "Both disguise and weapon, this holly flail will help you handle the toughest tasks. Increases Strength by <%= str %>. Limited Edition 2020-2021 Winter Gear.",
|
||||
@@ -411,13 +411,13 @@
|
||||
|
||||
|
||||
"weaponSpecialFall2021RogueText": "Dripping Goo",
|
||||
"weaponSpecialFall2021RogueNotes": "What on Earth did you get into? When people say Rogues have sticky fingers, this is not what they mean! Increases Strength by <%= str %>. Limited Edition 2021 Fall Gear.",
|
||||
"weaponSpecialFall2021RogueNotes": "What on Earth did you get into? When people say Rogues have sticky fingers, this is not what they mean! Increases Strength by <%= str %>. Limited Edition 2021 Autumn Gear.",
|
||||
"weaponSpecialFall2021WarriorText": "Horse Rider's Axe",
|
||||
"weaponSpecialFall2021WarriorNotes": "This stylized, single-bladed axe is ideal for chopping... pumpkins! Increases Strength by <%= str %>. Limited Edition 2021 Fall Gear.",
|
||||
"weaponSpecialFall2021WarriorNotes": "This stylized, single-bladed axe is ideal for chopping... pumpkins! Increases Strength by <%= str %>. Limited Edition 2021 Autumn Gear.",
|
||||
"weaponSpecialFall2021MageText": "Staff of Pure Thought",
|
||||
"weaponSpecialFall2021MageNotes": "Knowledge seeks knowledge. Formed of memories and desires, this fearsome hand grasps for more. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2021 Fall Gear.",
|
||||
"weaponSpecialFall2021MageNotes": "Knowledge seeks knowledge. Formed of memories and desires, this fearsome hand grasps for more. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2021 Autumn Gear.",
|
||||
"weaponSpecialFall2021HealerText": "Summoning Wand",
|
||||
"weaponSpecialFall2021HealerNotes": "Use this wand to summon healing flames and a ghostly creature to help you. Increases Intelligence by <%= int %>. Limited Edition 2021 Fall Gear.",
|
||||
"weaponSpecialFall2021HealerNotes": "Use this wand to summon healing flames and a ghostly creature to help you. Increases Intelligence by <%= int %>. Limited Edition 2021 Autumn Gear.",
|
||||
|
||||
"weaponSpecialWinter2022RogueText": "Shooting Star Firework",
|
||||
"weaponSpecialWinter2022RogueNotes": "Silver and gold are beloved of Rogues, right? These are totally on theme. Increases Strength by <%= str %>. Limited Edition 2021-2022 Winter Gear.",
|
||||
@@ -569,15 +569,6 @@
|
||||
"weaponSpecialFall2025MageText": "Masked Ghost Axe",
|
||||
"weaponSpecialFall2025MageNotes": "A mighty weapon to cut a safe path through an autumn forest full of frights. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition Fall 2025 Gear.",
|
||||
|
||||
"weaponSpecialWinter2026WarriorText": "Rime Scythe",
|
||||
"weaponSpecialWinter2026WarriorNotes": "Scythes help cut, reap, and cover large areas—all things you need when refining a task list. Increases Strength by <%= str %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
"weaponSpecialWinter2026RogueText": "Ski Pole",
|
||||
"weaponSpecialWinter2026RogueNotes": "Ski poles help you maintain balance, stability, and timing—all things you need to be truly productive. Increases Strength by <%= str %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
"weaponSpecialWinter2026HealerText": "Polar Staff",
|
||||
"weaponSpecialWinter2026HealerNotes": "Staffs help with support, stability, and direction—all things that help you truly conquer a task list. Increases Intelligence by <%= int %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
"weaponSpecialWinter2026MageText": "Candelabra Staff",
|
||||
"weaponSpecialWinter2026MageNotes": "Candelabras help by holding multiple candles at a time—follow its lead the next time you need to multitask. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
|
||||
"weaponMystery201411Text": "Pitchfork of Feasting",
|
||||
"weaponMystery201411Notes": "Stab your enemies or dig in to your favorite foods - this versatile pitchfork does it all! Confers no benefit. November 2014 Subscriber Item.",
|
||||
"weaponMystery201502Text": "Shimmery Winged Staff of Love and Also Truth",
|
||||
@@ -622,10 +613,6 @@
|
||||
"weaponMystery202508Notes": "This spinning blade will terrify any monster or red Daily that crosses your path! Confers no benefit. August 2025 Subscriber Item.",
|
||||
"weaponMystery202511Text": "Frost Sword",
|
||||
"weaponMystery202511Notes": "The icy glow of this sword will make quick work of even dark red tasks. Confers no benefit. November 2025 Subscriber Item.",
|
||||
"weaponMystery202512Text": "Cookie Champion's Blade",
|
||||
"weaponMystery202512Notes": "A shining sword cast from sugar, mint, and arcane enchantments. Confers no benefit. December 2025 Subscriber Item.",
|
||||
"weaponMystery202601Text": "Winter's Aegis",
|
||||
"weaponMystery202601Notes": "An icy bubble shield that grants magical protection from opposing elements. Confers no benefit. January 2026 Subscriber Item.",
|
||||
|
||||
"weaponMystery301404Text": "Steampunk Cane",
|
||||
"weaponMystery301404Notes": "Excellent for taking a turn about town. March 3015 Subscriber Item. Confers no benefit.",
|
||||
@@ -661,7 +648,7 @@
|
||||
"weaponArmoireBasicLongbowText": "Basic Longbow",
|
||||
"weaponArmoireBasicLongbowNotes": "A serviceable hand-me-down bow. Increases Strength by <%= str %>. Enchanted Armoire: Basic Archer Set (Item 1 of 3).",
|
||||
"weaponArmoireHabiticanDiplomaText": "Habitican Diploma",
|
||||
"weaponArmoireHabiticanDiplomaNotes": "A certificate of significant achievement—well done! Increases Intelligence by <%= int %>. Enchanted Armoire: Graduate Set (Item 1 of 3).",
|
||||
"weaponArmoireHabiticanDiplomaNotes": "A certificate of significant achievement -- well done! Increases Intelligence by <%= int %>. Enchanted Armoire: Graduate Set (Item 1 of 3).",
|
||||
"weaponArmoireSandySpadeText": "Sandy Spade",
|
||||
"weaponArmoireSandySpadeNotes": "A tool for digging, as well as flicking sand into the eyes of enemy monsters. Increases Strength by <%= str %>. Enchanted Armoire: Seaside Set (Item 1 of 3).",
|
||||
"weaponArmoireCannonText": "Cannon",
|
||||
@@ -821,7 +808,7 @@
|
||||
"weaponArmoireCleaningClothText": "Cleaning Cloth",
|
||||
"weaponArmoireCleaningClothNotes": "Take this tidying tool on your adventures and always be able to polish a pretty plaque or wipe a wooden windowsill. Increases Strength and Constitution by <%= attrs %> each. Enchanted Armoire: Cleaning Supplies Set Two (Item 3 of 3)",
|
||||
"weaponArmoireRidingBroomText": "Riding Broom",
|
||||
"weaponArmoireRidingBroomNotes": "Run all your most magical errands on this fine broom—or, just take it for a joyride around the neighborhood. Whee! Increases Strength by <%= str %> and Intelligence by <%= int %>. Enchanted Armoire: Spooky Sorcery Set (Item 1 of 3)",
|
||||
"weaponArmoireRidingBroomNotes": "Run all your most magical errands on this fine broom--or, just take it for a joyride around the neighborhood. Whee! Increases Strength by <%= str %> and Intelligence by <%= int %>. Enchanted Armoire: Spooky Sorcery Set (Item 1 of 3)",
|
||||
"weaponArmoireRollingPinText": "Rolling Pin",
|
||||
"weaponArmoireRollingPinNotes": "Roll your dough as thin as you like in-between bonking bad habits when they pop up around you like a certain rodent-bopping game. Increases Strength by <%= str %>. Enchanted Armoire: Cooking Implements Set 2 (Item 2 of 2).",
|
||||
"weaponArmoireScholarlyTextbooksText": "Scholarly Textbooks",
|
||||
@@ -850,10 +837,6 @@
|
||||
"weaponArmoireBeekeepersSmokerNotes": "Use this to calm your bees so you can retrieve some honey. The bees won’t mind. Honestly, we could all use a few extra minutes of calm from time to time. Increases Intelligence by <%= int %>. Enchanted Armoire: Beekeeper Set (Item 3 of 4).",
|
||||
"weaponArmoireBlacksmithsHammerText": "Blacksmith's Hammer",
|
||||
"weaponArmoireBlacksmithsHammerNotes": "This hammer is for metalworking, but it is perfectly adept amidst hot red coals and hot red Daily tasks, as well. Increases Strength by <%= str %>. Enchanted Armoire: Blacksmith Set (Item 3 of 3).",
|
||||
"weaponArmoireBambooFluteText": "Bamboo Flute",
|
||||
"weaponArmoireBambooFluteNotes": "Hwhoooo! Hu-whooooo! Gather your party for a meditation session or self-care nap while relaxing to tunes played on this bamboo flute. Increases Constitution and Intelligence by <%= attrs %> each. Enchanted Armoire: Musical Instrument Set 2 (Item 2 of 3)",
|
||||
"weaponArmoirePrettyPinkParasolText": "Pretty Pink Parasol",
|
||||
"weaponArmoirePrettyPinkParasolNotes": "Pretty and practical is the preeminent permutation. And for a particularly impressive presentation, give this parasol a spin! Increases all stats by <%= attrs %> each. Enchanted Armoire: Pretty in Pink Set (Item 1 of 2)",
|
||||
|
||||
"armor": "armor",
|
||||
"armorCapitalized": "Armor",
|
||||
@@ -999,13 +982,13 @@
|
||||
"armorSpecialSummerHealerNotes": "This garment of shimmering scales transforms its wearer into a real Seahealer! Increases Constitution by <%= con %>. Limited Edition 2014 Summer Gear.",
|
||||
|
||||
"armorSpecialFallRogueText": "Bloodred Robes",
|
||||
"armorSpecialFallRogueNotes": "Vivid. Velvet. Vampiric. Increases Perception by <%= per %>. Limited Edition 2014 Fall Gear.",
|
||||
"armorSpecialFallRogueNotes": "Vivid. Velvet. Vampiric. Increases Perception by <%= per %>. Limited Edition 2014 Autumn Gear.",
|
||||
"armorSpecialFallWarriorText": "Lab-coat of Science",
|
||||
"armorSpecialFallWarriorNotes": "Protects you from mysterious potion spills. Increases Constitution by <%= con %>. Limited Edition 2014 Fall Gear.",
|
||||
"armorSpecialFallWarriorNotes": "Protects you from mysterious potion spills. Increases Constitution by <%= con %>. Limited Edition 2014 Autumn Gear.",
|
||||
"armorSpecialFallMageText": "Witchy Wizard Robes",
|
||||
"armorSpecialFallMageNotes": "This robe has plenty of pockets to hold extra helpings of eye of newt and tongue of frog. Increases Intelligence by <%= int %>. Limited Edition 2014 Fall Gear.",
|
||||
"armorSpecialFallMageNotes": "This robe has plenty of pockets to hold extra helpings of eye of newt and tongue of frog. Increases Intelligence by <%= int %>. Limited Edition 2014 Autumn Gear.",
|
||||
"armorSpecialFallHealerText": "Gauzy Gear",
|
||||
"armorSpecialFallHealerNotes": "Charge into battle pre-bandaged! Increases Constitution by <%= con %>. Limited Edition 2014 Fall Gear.",
|
||||
"armorSpecialFallHealerNotes": "Charge into battle pre-bandaged! Increases Constitution by <%= con %>. Limited Edition 2014 Autumn Gear.",
|
||||
|
||||
"armorSpecialWinter2015RogueText": "Icicle Drake Armor",
|
||||
"armorSpecialWinter2015RogueNotes": "This armor is freezing cold, but it will definitely be worth it when you uncover the untold riches at the center of the Icicle Drake hives. Not that you are looking for any such untold riches, because you are truly, definitely, absolutely a genuine Icicle Drake, okay?! Stop asking questions! Increases Perception by <%= per %>. Limited Edition 2014-2015 Winter Gear.",
|
||||
@@ -1035,13 +1018,13 @@
|
||||
"armorSpecialSummer2015HealerNotes": "This armor lets everyone know that you are an honest merchant sailor who would never dream of behaving like a scalawag. Increases Constitution by <%= con %>. Limited Edition 2015 Summer Gear.",
|
||||
|
||||
"armorSpecialFall2015RogueText": "Bat-tle Armor",
|
||||
"armorSpecialFall2015RogueNotes": "Fly into bat-tle! Increases Perception by <%= per %>. Limited Edition 2015 Fall Gear.",
|
||||
"armorSpecialFall2015RogueNotes": "Fly into bat-tle! Increases Perception by <%= per %>. Limited Edition 2015 Autumn Gear.",
|
||||
"armorSpecialFall2015WarriorText": "Scarecrow Armor",
|
||||
"armorSpecialFall2015WarriorNotes": "Despite being stuffed with straw, this armor is extremely hefty! Increases Constitution by <%= con %>. Limited Edition 2015 Fall Gear.",
|
||||
"armorSpecialFall2015WarriorNotes": "Despite being stuffed with straw, this armor is extremely hefty! Increases Constitution by <%= con %>. Limited Edition 2015 Autumn Gear.",
|
||||
"armorSpecialFall2015MageText": "Stitched Robes",
|
||||
"armorSpecialFall2015MageNotes": "Every stitch in this armor shimmers with enchantment. Increases Intelligence by <%= int %>. Limited Edition 2015 Fall Gear.",
|
||||
"armorSpecialFall2015MageNotes": "Every stitch in this armor shimmers with enchantment. Increases Intelligence by <%= int %>. Limited Edition 2015 Autumn Gear.",
|
||||
"armorSpecialFall2015HealerText": "Potioner Robes",
|
||||
"armorSpecialFall2015HealerNotes": "What? Of course that was a potion of constitution. No, you are definitely not turning into a frog! Don't be ribbiticulous. Increases Constitution by <%= con %>. Limited Edition 2015 Fall Gear.",
|
||||
"armorSpecialFall2015HealerNotes": "What? Of course that was a potion of constitution. No, you are definitely not turning into a frog! Don't be ribbiticulous. Increases Constitution by <%= con %>. Limited Edition 2015 Autumn Gear.",
|
||||
|
||||
"armorSpecialWinter2016RogueText": "Cocoa Armor",
|
||||
"armorSpecialWinter2016RogueNotes": "This leather armor keeps you nice and toasty. Is it actually made from cocoa? You'll never tell. Increases Perception by <%= per %>. Limited Edition 2015-2016 Winter Gear.",
|
||||
@@ -1071,13 +1054,13 @@
|
||||
"armorSpecialSummer2016HealerNotes": "This spiky garment transforms its wearer into a real Seahorse Healer! Increases Constitution by <%= con %>. Limited Edition 2016 Summer Gear.",
|
||||
|
||||
"armorSpecialFall2016RogueText": "Black Widow Armor",
|
||||
"armorSpecialFall2016RogueNotes": "The eyes on this armor are constantly blinking. Increases Perception by <%= per %>. Limited Edition 2016 Fall Gear.",
|
||||
"armorSpecialFall2016RogueNotes": "The eyes on this armor are constantly blinking. Increases Perception by <%= per %>. Limited Edition 2016 Autumn Gear.",
|
||||
"armorSpecialFall2016WarriorText": "Slime-Streaked Armor",
|
||||
"armorSpecialFall2016WarriorNotes": "Mysteriously moist and mossy! Increases Constitution by <%= con %>. Limited Edition 2016 Fall Gear.",
|
||||
"armorSpecialFall2016WarriorNotes": "Mysteriously moist and mossy! Increases Constitution by <%= con %>. Limited Edition 2016 Autumn Gear.",
|
||||
"armorSpecialFall2016MageText": "Cloak of Wickedness",
|
||||
"armorSpecialFall2016MageNotes": "When your cloak flaps, you hear the sound of cackling laughter. Increases Intelligence by <%= int %>. Limited Edition 2016 Fall Gear.",
|
||||
"armorSpecialFall2016MageNotes": "When your cloak flaps, you hear the sound of cackling laughter. Increases Intelligence by <%= int %>. Limited Edition 2016 Autumn Gear.",
|
||||
"armorSpecialFall2016HealerText": "Gorgon Robes",
|
||||
"armorSpecialFall2016HealerNotes": "These robes are actually made of stone. How are they so comfortable? Increases Constitution by <%= con %>. Limited Edition 2016 Fall Gear.",
|
||||
"armorSpecialFall2016HealerNotes": "These robes are actually made of stone. How are they so comfortable? Increases Constitution by <%= con %>. Limited Edition 2016 Autumn Gear.",
|
||||
|
||||
"armorSpecialWinter2017RogueText": "Frosty Armor",
|
||||
"armorSpecialWinter2017RogueNotes": "This stealthy suit reflects light to dazzle unsuspecting tasks as you take your rewards from them! Increases Perception by <%= per %>. Limited Edition 2016-2017 Winter Gear.",
|
||||
@@ -1107,13 +1090,13 @@
|
||||
"armorSpecialSummer2017HealerNotes": "This garment of silvery scales transforms its wearer into a real Seahealer! Increases Constitution by <%= con %>. Limited Edition 2017 Summer Gear.",
|
||||
|
||||
"armorSpecialFall2017RogueText": "Pumpkin Patch Robes",
|
||||
"armorSpecialFall2017RogueNotes": "Need to hide out? Crouch among the Jack o' Lanterns and these robes will conceal you! Increases Perception by <%= per %>. Limited Edition 2017 Fall Gear.",
|
||||
"armorSpecialFall2017RogueNotes": "Need to hide out? Crouch among the Jack o' Lanterns and these robes will conceal you! Increases Perception by <%= per %>. Limited Edition 2017 Autumn Gear.",
|
||||
"armorSpecialFall2017WarriorText": "Strong and Sweet Armor",
|
||||
"armorSpecialFall2017WarriorNotes": "This armor will protect you like a delicious candy shell. Increases Constitution by <%= con %>. Limited Edition 2017 Fall Gear.",
|
||||
"armorSpecialFall2017WarriorNotes": "This armor will protect you like a delicious candy shell. Increases Constitution by <%= con %>. Limited Edition 2017 Autumn Gear.",
|
||||
"armorSpecialFall2017MageText": "Masquerade Robes",
|
||||
"armorSpecialFall2017MageNotes": "What masquerade ensemble would be complete without dramatic and sweeping robes? Increases Intelligence by <%= int %>. Limited Edition 2017 Fall Gear.",
|
||||
"armorSpecialFall2017MageNotes": "What masquerade ensemble would be complete without dramatic and sweeping robes? Increases Intelligence by <%= int %>. Limited Edition 2017 Autumn Gear.",
|
||||
"armorSpecialFall2017HealerText": "Haunted House Armor",
|
||||
"armorSpecialFall2017HealerNotes": "Your heart is an open door. And your shoulders are roofing tiles! Increases Constitution by <%= con %>. Limited Edition 2017 Fall Gear.",
|
||||
"armorSpecialFall2017HealerNotes": "Your heart is an open door. And your shoulders are roofing tiles! Increases Constitution by <%= con %>. Limited Edition 2017 Autumn Gear.",
|
||||
|
||||
"armorSpecialWinter2018RogueText": "Reindeer Costume",
|
||||
"armorSpecialWinter2018RogueNotes": "You look so cute and fuzzy, who could suspect you are after holiday loot? Increases Perception by <%= per %>. Limited Edition 2017-2018 Winter Gear.",
|
||||
@@ -1143,13 +1126,13 @@
|
||||
"armorSpecialSummer2018HealerNotes": "These cerulean vestments reveal that you have land-walking feet... well. Not even a monarch can be expected to be perfect. Increases Constitution by <%= con %>. Limited Edition 2018 Summer Gear.",
|
||||
|
||||
"armorSpecialFall2018RogueText": "Alter Ego Frock Coat",
|
||||
"armorSpecialFall2018RogueNotes": "Style for the day. Comfort and protection for the night. Increases Perception by <%= per %>. Limited Edition 2018 Fall Gear.",
|
||||
"armorSpecialFall2018RogueNotes": "Style for the day. Comfort and protection for the night. Increases Perception by <%= per %>. Limited Edition 2018 Autumn Gear.",
|
||||
"armorSpecialFall2018WarriorText": "Minotaur Platemail",
|
||||
"armorSpecialFall2018WarriorNotes": "Complete with hooves to drum a soothing cadence as you walk your meditative labyrinth. Increases Constitution by <%= con %>. Limited Edition 2018 Fall Gear.",
|
||||
"armorSpecialFall2018WarriorNotes": "Complete with hooves to drum a soothing cadence as you walk your meditative labyrinth. Increases Constitution by <%= con %>. Limited Edition 2018 Autumn Gear.",
|
||||
"armorSpecialFall2018MageText": "Candymancer's Robes",
|
||||
"armorSpecialFall2018MageNotes": "The fabric of these robes has magic candy woven right in! However, we recommend you not attempt to eat them. Increases Intelligence by <%= int %>. Limited Edition 2018 Fall Gear.",
|
||||
"armorSpecialFall2018MageNotes": "The fabric of these robes has magic candy woven right in! However, we recommend you not attempt to eat them. Increases Intelligence by <%= int %>. Limited Edition 2018 Autumn Gear.",
|
||||
"armorSpecialFall2018HealerText": "Robes of Carnivory",
|
||||
"armorSpecialFall2018HealerNotes": "It's made from plants, but that doesn't mean it's vegetarian. Bad habits are afraid to come within miles of these robes. Increases Constitution by <%= con %>. Limited Edition 2018 Fall Gear.",
|
||||
"armorSpecialFall2018HealerNotes": "It's made from plants, but that doesn't mean it's vegetarian. Bad habits are afraid to come within miles of these robes. Increases Constitution by <%= con %>. Limited Edition 2018 Autumn Gear.",
|
||||
|
||||
"armorSpecialWinter2019RogueText": "Poinsettia Armor",
|
||||
"armorSpecialWinter2019RogueNotes": "With holiday greenery all about, no one will notice an extra shrubbery! You can move through seasonal gatherings with ease and stealth. Increases Perception by <%= per %>. Limited Edition 2018-2019 Winter Gear.",
|
||||
@@ -1179,13 +1162,13 @@
|
||||
"armorSpecialSummer2019HealerNotes": "Glide sleekly through warm coastal waters with this elegant tail. Increases Constitution by <%= con %>. Limited Edition 2019 Summer Gear.",
|
||||
|
||||
"armorSpecialFall2019RogueText": "Caped Opera Coat",
|
||||
"armorSpecialFall2019RogueNotes": "This outfit comes complete with white gloves, and is ideal for brooding in your private box above the stage or making startling entrances down grand staircases. Increases Perception by <%= per %>. Limited Edition 2019 Fall Gear.",
|
||||
"armorSpecialFall2019RogueNotes": "This outfit comes complete with white gloves, and is ideal for brooding in your private box above the stage or making startling entrances down grand staircases. Increases Perception by <%= per %>. Limited Edition 2019 Autumn Gear.",
|
||||
"armorSpecialFall2019WarriorText": "Wings of Night",
|
||||
"armorSpecialFall2019WarriorNotes": "These feathered robes grant the power of flight, allowing you to soar over any battle. Increases Constitution by <%= con %>. Limited Edition 2019 Fall Gear.",
|
||||
"armorSpecialFall2019WarriorNotes": "These feathered robes grant the power of flight, allowing you to soar over any battle. Increases Constitution by <%= con %>. Limited Edition 2019 Autumn Gear.",
|
||||
"armorSpecialFall2019MageText": "Smock of Polyphemus",
|
||||
"armorSpecialFall2019MageNotes": "Its namesake met a terrible fate. But you will not be so easily tricked! Garb yourself in this mantle of legend and nobody will surpass you. Increases Intelligence by <%= int %>. Limited Edition 2019 Fall Gear.",
|
||||
"armorSpecialFall2019MageNotes": "Its namesake met a terrible fate. But you will not be so easily tricked! Garb yourself in this mantle of legend and nobody will surpass you. Increases Intelligence by <%= int %>. Limited Edition 2019 Autumn Gear.",
|
||||
"armorSpecialFall2019HealerText": "Robes of Darkness",
|
||||
"armorSpecialFall2019HealerNotes": "It's said these robes are made of pure night. Use the dark power wisely! Increases Constitution by <%= con %>. Limited Edition 2019 Fall Gear.",
|
||||
"armorSpecialFall2019HealerNotes": "It's said these robes are made of pure night. Use the dark power wisely! Increases Constitution by <%= con %>. Limited Edition 2019 Autumn Gear.",
|
||||
|
||||
"armorSpecialWinter2020RogueText": "Poofy Parka",
|
||||
"armorSpecialWinter2020RogueNotes": "While no doubt you can brave storms with the inner warmth of your drive and devotion, it doesn't hurt to dress for the weather. Increases Perception by <%= per %>. Limited Edition 2019-2020 Winter Gear.",
|
||||
@@ -1206,7 +1189,7 @@
|
||||
"armorSpecialSpring2020HealerNotes": "Wrap yourself in soft iris leaves and petals to fool enemies into underestimating your healing power. Increases Constitution by <%= con %>. Limited Edition 2020 Spring Gear.",
|
||||
|
||||
"armorSpecialSummer2020RogueText": "Crocodile Disguise",
|
||||
"armorSpecialSummer2020RogueNotes": "A crocodile makes the perfect Rogue, waiting for the perfect moment to strike. Borrow their skills—and their explosive speed. Increases Perception by <%= per %>. Limited Edition 2020 Summer Gear.",
|
||||
"armorSpecialSummer2020RogueNotes": "A crocodile makes the perfect Rogue, waiting for the perfect moment to strike. Borrow their skills--and their explosive speed. Increases Perception by <%= per %>. Limited Edition 2020 Summer Gear.",
|
||||
"armorSpecialSummer2020WarriorText": "Rainbow Trout Tail",
|
||||
"armorSpecialSummer2020WarriorNotes": "You'll be the bright fish in a dull stream, with these dazzling scales! Increases Constitution by <%= con %>. Limited Edition 2020 Summer Gear.",
|
||||
"armorSpecialSummer2020MageText": "Oarfish Armor",
|
||||
@@ -1215,13 +1198,13 @@
|
||||
"armorSpecialSummer2020HealerNotes": "You are as patient as the ocean, as strong as the currents, as dependable as the tides. Increases Constitution by <%= con %>. Limited Edition 2020 Summer Gear.",
|
||||
|
||||
"armorSpecialFall2020RogueText": "Statuesque Armor",
|
||||
"armorSpecialFall2020RogueNotes": "Take on the strength of stone with this armor, guaranteed to repel the fiercest attacks. Increases Perception by <%= per %>. Limited Edition 2020 Fall Gear.",
|
||||
"armorSpecialFall2020RogueNotes": "Take on the strength of stone with this armor, guaranteed to repel the fiercest attacks. Increases Perception by <%= per %>. Limited Edition 2020 Autumn Gear.",
|
||||
"armorSpecialFall2020WarriorText": "Revenant's Robes",
|
||||
"armorSpecialFall2020WarriorNotes": "These robes once guarded a powerful Warrior from harm. They say the Warrior's spirit lingers in the cloth to guard a worthy successor. Increases Constitution by <%= con %>. Limited Edition 2020 Fall Gear.",
|
||||
"armorSpecialFall2020WarriorNotes": "These robes once guarded a powerful Warrior from harm. They say the Warrior's spirit lingers in the cloth to guard a worthy successor. Increases Constitution by <%= con %>. Limited Edition 2020 Autumn Gear.",
|
||||
"armorSpecialFall2020MageText": "Aloft Upon Enlightenment",
|
||||
"armorSpecialFall2020MageNotes": "These wide-winged robes give the impression of hovering or flight, symbolizing the far-seeing perspective granted by vast knowledge. Increases Intelligence by <%= int %>. Limited Edition 2020 Fall Gear.",
|
||||
"armorSpecialFall2020MageNotes": "These wide-winged robes give the impression of hovering or flight, symbolizing the far-seeing perspective granted by vast knowledge. Increases Intelligence by <%= int %>. Limited Edition 2020 Autumn Gear.",
|
||||
"armorSpecialFall2020HealerText": "Hawkmoth Wings",
|
||||
"armorSpecialFall2020HealerNotes": "Your splendor unfurls by night, and those who witness you in flight wonder at what this omen could mean. Increases Constitution by <%= con %>. Limited Edition 2020 Fall Gear.",
|
||||
"armorSpecialFall2020HealerNotes": "Your splendor unfurls by night, and those who witness you in flight wonder at what this omen could mean. Increases Constitution by <%= con %>. Limited Edition 2020 Autumn Gear.",
|
||||
|
||||
"armorSpecialWinter2021RogueText": "Ivy-Green Garb",
|
||||
"armorSpecialWinter2021RogueNotes": "Melt into the shadows of the evergreen wood! Increases Perception by <%= per %>. Limited Edition 2020-2021 Winter Gear.",
|
||||
@@ -1251,13 +1234,13 @@
|
||||
"armorSpecialSummer2021HealerNotes": "Your enemies might suspect you're a featherweight, but this armor will keep you safe while you help your Party. Increases Constitution by <%= con %>. Limited Edition 2021 Summer Gear.",
|
||||
|
||||
"armorSpecialFall2021RogueText": "Unfortunately Not Slimeproof Armor",
|
||||
"armorSpecialFall2021RogueNotes": "It's got a skullcap, leather tunic, and metal rivets! It's great! But it does not provide a hermetic seal against goop! Increases Perception by <%= per %>. Limited Edition 2021 Fall Gear.",
|
||||
"armorSpecialFall2021RogueNotes": "It's got a skullcap, leather tunic, and metal rivets! It's great! But it does not provide a hermetic seal against goop! Increases Perception by <%= per %>. Limited Edition 2021 Autumn Gear.",
|
||||
"armorSpecialFall2021WarriorText": "Formal Wool Suit",
|
||||
"armorSpecialFall2021WarriorNotes": "A stunning suit that’s perfect to wear when crossing bridges in the dead of night. Increases Constitution by <%= con %>. Limited Edition 2021 Fall Gear.",
|
||||
"armorSpecialFall2021WarriorNotes": "A stunning suit that’s perfect to wear when crossing bridges in the dead of night. Increases Constitution by <%= con %>. Limited Edition 2021 Autumn Gear.",
|
||||
"armorSpecialFall2021MageText": "Gown of the Darkness Beneath",
|
||||
"armorSpecialFall2021MageNotes": "Collars with many pointy protrusions are the high fashion of low villains. Increases Intelligence by <%= int %>. Limited Edition 2021 Fall Gear.",
|
||||
"armorSpecialFall2021MageNotes": "Collars with many pointy protrusions are the high fashion of low villains. Increases Intelligence by <%= int %>. Limited Edition 2021 Autumn Gear.",
|
||||
"armorSpecialFall2021HealerText": "Summoner's Robes",
|
||||
"armorSpecialFall2021HealerNotes": "Made of durable, flame-resistant fabric, these robes are perfect to wear when conjuring healing flames. Increases Constitution by <%= con %>. Limited Edition 2021 Fall Gear.",
|
||||
"armorSpecialFall2021HealerNotes": "Made of durable, flame-resistant fabric, these robes are perfect to wear when conjuring healing flames. Increases Constitution by <%= con %>. Limited Edition 2021 Autumn Gear.",
|
||||
|
||||
"armorSpecialWinter2022RogueText": "Dazzling Explosion",
|
||||
"armorSpecialWinter2022RogueNotes": "If they're seeing stars, they're not seeing you! Yes, let's go with that. Increases Perception by <%= per %>. Limited Edition 2021-2022 Winter Gear.",
|
||||
@@ -1403,15 +1386,6 @@
|
||||
"armorSpecialFall2025MageText": "Masked Ghost Armor",
|
||||
"armorSpecialFall2025MageNotes": "This seasonal armor becomes noncorporeal only after you put it on. Increases Intelligence by <%= int %>. Limited Edition Fall 2025 Gear.",
|
||||
|
||||
"armorSpecialWinter2026WarriorText": "Rime Reaper Suit",
|
||||
"armorSpecialWinter2026WarriorNotes": "Icicles will snap and slide with every step on your way to completing your Dailies. Increases Constitution by <%= con %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
"armorSpecialWinter2026RogueText": "Ski Suit and Skis",
|
||||
"armorSpecialWinter2026RogueNotes": "Go speedily swishing down the slopes on your way to completing your Dailies. Increases Perception by <%= per %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
"armorSpecialWinter2026HealerText": "Polar Robe",
|
||||
"armorSpecialWinter2026HealerNotes": "Like a natural light show, you will be stunning on your way to completing your Dailies. Increases Constitution by <%= con %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
"armorSpecialWinter2026MageText": "Midwinter Candle Robe",
|
||||
"armorSpecialWinter2026MageNotes": "Glide smoothly along your path like wax on your way to completing your Dailies. Increases Intelligence by <%= int %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
|
||||
"armorMystery201402Text": "Messenger Robes",
|
||||
"armorMystery201402Notes": "Shimmering and strong, these robes have many pockets to carry letters. Confers no benefit. February 2014 Subscriber Item.",
|
||||
"armorMystery201403Text": "Forest Walker Armor",
|
||||
@@ -1548,8 +1522,6 @@
|
||||
"armorMystery202504Notes": "Abominable? More like adorable! Confers no benefit. April 2025 Subscriber Item.",
|
||||
"armorMystery202509Text": "Windswept Wanderer's Robe",
|
||||
"armorMystery202509Notes": "Bright silks protect you from the weather, hot or cold. Confers no benefit. September 2025 Subscriber Item.",
|
||||
"armorMystery202512Text": "Cookie Champion Armor",
|
||||
"armorMystery202512Notes": "Ready for battle in this plate that is both sweet and strong. Confers no benefit. December 2025 Subscriber Item.",
|
||||
|
||||
"armorMystery301404Text": "Steampunk Suit",
|
||||
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
|
||||
@@ -1649,7 +1621,7 @@
|
||||
"armorArmoireCoverallsOfBookbindingText": "Coveralls of Bookbinding",
|
||||
"armorArmoireCoverallsOfBookbindingNotes": "Everything you need in a set of coveralls, including pockets for everything. A pair of goggles, loose change, a golden ring... Increases Constitution by <%= con %> and Perception by <%= per %>. Enchanted Armoire: Bookbinder Set (Item 2 of 4).",
|
||||
"armorArmoireRobeOfSpadesText": "Robe of Spades",
|
||||
"armorArmoireRobeOfSpadesNotes": "These luxuriant robes conceal hidden pockets for treasures or weapons—your choice! Increases Strength by <%= str %>. Enchanted Armoire: Ace of Spades Set (Item 2 of 3).",
|
||||
"armorArmoireRobeOfSpadesNotes": "These luxuriant robes conceal hidden pockets for treasures or weapons--your choice! Increases Strength by <%= str %>. Enchanted Armoire: Ace of Spades Set (Item 2 of 3).",
|
||||
"armorArmoireSoftBlueSuitText": "Soft Blue Suit",
|
||||
"armorArmoireSoftBlueSuitNotes": "Blue is a calming colour. So calming, some even wear this soft outfit to sleep... zZz. Increases Intelligence by <%= int %> and Perception by <%= per %>. Enchanted Armoire: Blue Loungewear Set (Item 2 of 3).",
|
||||
"armorArmoireSoftGreenSuitText": "Soft Green Suit",
|
||||
@@ -1711,7 +1683,7 @@
|
||||
"armorArmoireMedievalLaundryDressText": "Laundry Dress",
|
||||
"armorArmoireMedievalLaundryDressNotes": "Put on your apron and roll up your sleeves: it's time to get the laundry done! Increases Constitution by <%= con %>. Enchanted Armoire: Medieval Launderers Set (Item 2 of 6).",
|
||||
"armorArmoireBathtubText": "Bathtub",
|
||||
"armorArmoireBathtubNotes": "Time for a little R&R? Here's your own personal bathtub—and a guarantee that the water is always the right temperature! Increases Constitution by <%= con %>. Enchanted Armoire: Bubble Bath Set (Item 2 of 4).",
|
||||
"armorArmoireBathtubNotes": "Time for a little R&R? Here's your own personal bathtub -- and a guarantee that the water is always the right temperature! Increases Constitution by <%= con %>. Enchanted Armoire: Bubble Bath Set (Item 2 of 4).",
|
||||
"armorArmoireBagpipersKiltText": "Bagpiper's Kilt",
|
||||
"armorArmoireBagpipersKiltNotes": "A good sturdy kilt will serve you well. Increases Constitution by <%= con %>. Enchanted Armoire: Bagpiper Set (Item 2 of 3).",
|
||||
"armorArmoireHeraldsTunicText": "Herald's Tunic",
|
||||
@@ -1798,8 +1770,6 @@
|
||||
"armorArmoireBlacksmithsApronNotes": "This apron doesn’t feel as heavy as it looks once you’ve got it on. It will shield you from stray sparks while allowing you to maneuver freely. Increases Constitution by <%= con %>. Enchanted Armoire: Blacksmith Set (Item 2 of 3).",
|
||||
"armorArmoireBlackPartyDressText": "Black Party Dress",
|
||||
"armorArmoireBlackPartyDressNotes": "You’re strong, smart, hearty, and so fashionable! Increases Strength, Intelligence, and Constitution by <%= attrs %> each. Enchanted Armoire: Black Hairbow Set (Item 2 of 2).",
|
||||
"armorArmoireLoneCowpokeOutfitText": "Lone Cowpoke Outfit",
|
||||
"armorArmoireLoneCowpokeOutfitNotes": "Whoa, there! Want to make a statement when you ride into town as a mysterious stranger ready to be productive? Here’s the perfect outfit, complete with chaps and a shining, silver belt buckle. Increases Constitution by <%= con %>. Enchanted Armoire: Lone Cowpoke Set (Item 2 of 2)",
|
||||
|
||||
"headgear": "helm",
|
||||
"headgearCapitalized": "Headgear",
|
||||
@@ -1868,7 +1838,7 @@
|
||||
"headSpecialLunarWarriorHelmText": "Lunar Warrior Helm",
|
||||
"headSpecialLunarWarriorHelmNotes": "The power of the moon will strengthen you in battle! Increases Strength and Intelligence by <%= attrs %> each.",
|
||||
"headSpecialMammothRiderHelmText": "Mammoth Rider Helm",
|
||||
"headSpecialMammothRiderHelmNotes": "Don't let its fluffiness fool you—this hat will grant you piercing powers of perception! Increases Perception by <%= per %>.",
|
||||
"headSpecialMammothRiderHelmNotes": "Don't let its fluffiness fool you--this hat will grant you piercing powers of perception! Increases Perception by <%= per %>.",
|
||||
"headSpecialPageHelmText": "Page Helm",
|
||||
"headSpecialPageHelmNotes": "Chainmail: for the stylish AND the practical. Increases Perception by <%= per %>.",
|
||||
"headSpecialRoguishRainbowMessengerHoodText": "Roguish Rainbow Messenger Hood",
|
||||
@@ -1924,13 +1894,13 @@
|
||||
"headSpecialSummerHealerNotes": "Enables its wearer to heal damaged reefs. Increases Intelligence by <%= int %>. Limited Edition 2014 Summer Gear.",
|
||||
|
||||
"headSpecialFallRogueText": "Bloodred Hood",
|
||||
"headSpecialFallRogueNotes": "A Vampire Smiter's identity must always be hidden. Increases Perception by <%= per %>. Limited Edition 2014 Fall Gear.",
|
||||
"headSpecialFallRogueNotes": "A Vampire Smiter's identity must always be hidden. Increases Perception by <%= per %>. Limited Edition 2014 Autumn Gear.",
|
||||
"headSpecialFallWarriorText": "Monster Scalp of Science",
|
||||
"headSpecialFallWarriorNotes": "Graft on this helm! It's only SLIGHTLY used. Increases Strength by <%= str %>. Limited Edition 2014 Fall Gear.",
|
||||
"headSpecialFallWarriorNotes": "Graft on this helm! It's only SLIGHTLY used. Increases Strength by <%= str %>. Limited Edition 2014 Autumn Gear.",
|
||||
"headSpecialFallMageText": "Pointy Hat",
|
||||
"headSpecialFallMageNotes": "Magic is woven into every thread of this hat. Increases Perception by <%= per %>. Limited Edition 2014 Fall Gear.",
|
||||
"headSpecialFallMageNotes": "Magic is woven into every thread of this hat. Increases Perception by <%= per %>. Limited Edition 2014 Autumn Gear.",
|
||||
"headSpecialFallHealerText": "Head Bandages",
|
||||
"headSpecialFallHealerNotes": "Highly sanitary and very fashionable. Increases Intelligence by <%= int %>. Limited Edition 2014 Fall Gear.",
|
||||
"headSpecialFallHealerNotes": "Highly sanitary and very fashionable. Increases Intelligence by <%= int %>. Limited Edition 2014 Autumn Gear.",
|
||||
|
||||
"headSpecialNye2014Text": "Silly Party Hat",
|
||||
"headSpecialNye2014Notes": "You've received a Silly Party Hat! Wear it with pride while ringing in the New Year! Confers no benefit.",
|
||||
@@ -1962,13 +1932,13 @@
|
||||
"headSpecialSummer2015HealerNotes": "With your sailor's cap set firmly on your head, you can navigate even the stormiest seas! Increases Intelligence by <%= int %>. Limited Edition 2015 Summer Gear.",
|
||||
|
||||
"headSpecialFall2015RogueText": "Bat-tle Wings",
|
||||
"headSpecialFall2015RogueNotes": "Echolocate your enemies with this powerful helm! Increases Perception by <%= per %>. Limited Edition 2015 Fall Gear.",
|
||||
"headSpecialFall2015RogueNotes": "Echolocate your enemies with this powerful helm! Increases Perception by <%= per %>. Limited Edition 2015 Autumn Gear.",
|
||||
"headSpecialFall2015WarriorText": "Scarecrow Hat",
|
||||
"headSpecialFall2015WarriorNotes": "Everyone would want this hat—if they only had a brain. Increases Strength by <%= str %>. Limited Edition 2015 Fall Gear.",
|
||||
"headSpecialFall2015WarriorNotes": "Everyone would want this hat--if they only had a brain. Increases Strength by <%= str %>. Limited Edition 2015 Autumn Gear.",
|
||||
"headSpecialFall2015MageText": "Stitched Hat",
|
||||
"headSpecialFall2015MageNotes": "Every stitch in this hat augments its power. Increases Perception by <%= per %>. Limited Edition 2015 Fall Gear.",
|
||||
"headSpecialFall2015MageNotes": "Every stitch in this hat augments its power. Increases Perception by <%= per %>. Limited Edition 2015 Autumn Gear.",
|
||||
"headSpecialFall2015HealerText": "Hat of Frog",
|
||||
"headSpecialFall2015HealerNotes": "This is an extremely serious hat that is worthy of only the most advanced potioners. Increases Intelligence by <%= int %>. Limited Edition 2015 Fall Gear.",
|
||||
"headSpecialFall2015HealerNotes": "This is an extremely serious hat that is worthy of only the most advanced potioners. Increases Intelligence by <%= int %>. Limited Edition 2015 Autumn Gear.",
|
||||
|
||||
"headSpecialNye2015Text": "Ridiculous Party Hat",
|
||||
"headSpecialNye2015Notes": "You've received a Ridiculous Party Hat! Wear it with pride while ringing in the New Year! Confers no benefit.",
|
||||
@@ -2000,13 +1970,13 @@
|
||||
"headSpecialSummer2016HealerNotes": "This helm indicates that the wearer was trained by the magical healing seahorses of Dilatory. Increases Intelligence by <%= int %>. Limited Edition 2016 Summer Gear.",
|
||||
|
||||
"headSpecialFall2016RogueText": "Black Widow Helm",
|
||||
"headSpecialFall2016RogueNotes": "The legs on this helm are constantly twitching. Increases Perception by <%= per %>. Limited Edition 2016 Fall Gear.",
|
||||
"headSpecialFall2016RogueNotes": "The legs on this helm are constantly twitching. Increases Perception by <%= per %>. Limited Edition 2016 Autumn Gear.",
|
||||
"headSpecialFall2016WarriorText": "Gnarled Bark Helm",
|
||||
"headSpecialFall2016WarriorNotes": "This swamp-sogged helm is covered with bits of bog. Increases Strength by <%= str %>. Limited Edition 2016 Fall Gear.",
|
||||
"headSpecialFall2016WarriorNotes": "This swamp-sogged helm is covered with bits of bog. Increases Strength by <%= str %>. Limited Edition 2016 Autumn Gear.",
|
||||
"headSpecialFall2016MageText": "Hood of Wickedness",
|
||||
"headSpecialFall2016MageNotes": "Conceal your plotting beneath this shadowy hood. Increases Perception by <%= per %>. Limited Edition 2016 Fall Gear.",
|
||||
"headSpecialFall2016MageNotes": "Conceal your plotting beneath this shadowy hood. Increases Perception by <%= per %>. Limited Edition 2016 Autumn Gear.",
|
||||
"headSpecialFall2016HealerText": "Medusa's Crown",
|
||||
"headSpecialFall2016HealerNotes": "Woe to anyone who looks you in the eyes... Increases Intelligence by <%= int %>. Limited Edition 2016 Fall Gear.",
|
||||
"headSpecialFall2016HealerNotes": "Woe to anyone who looks you in the eyes... Increases Intelligence by <%= int %>. Limited Edition 2016 Autumn Gear.",
|
||||
|
||||
"headSpecialNye2016Text": "Whimsical Party Hat",
|
||||
"headSpecialNye2016Notes": "You've received a Whimsical Party Hat! Wear it with pride while ringing in the New Year! Confers no benefit.",
|
||||
@@ -2038,13 +2008,13 @@
|
||||
"headSpecialSummer2017HealerNotes": "This helm is made up of friendly sea creatures who are temporarily resting on your head, giving you sage advice. Increases Intelligence by <%= int %>. Limited Edition 2017 Summer Gear.",
|
||||
|
||||
"headSpecialFall2017RogueText": "Jack-o-Lantern Helm",
|
||||
"headSpecialFall2017RogueNotes": "Ready for treats? Time to don this festive, glowing helm! Increases Perception by <%= per %>. Limited Edition 2017 Fall Gear.",
|
||||
"headSpecialFall2017RogueNotes": "Ready for treats? Time to don this festive, glowing helm! Increases Perception by <%= per %>. Limited Edition 2017 Autumn Gear.",
|
||||
"headSpecialFall2017WarriorText": "Candy Corn Helm",
|
||||
"headSpecialFall2017WarriorNotes": "This helm might look like a treat, but wayward tasks won't find it so sweet! Increases Strength by <%= str %>. Limited Edition 2017 Fall Gear.",
|
||||
"headSpecialFall2017WarriorNotes": "This helm might look like a treat, but wayward tasks won't find it so sweet! Increases Strength by <%= str %>. Limited Edition 2017 Autumn Gear.",
|
||||
"headSpecialFall2017MageText": "Masquerade Helm",
|
||||
"headSpecialFall2017MageNotes": "When you appear in this feathery hat, everyone will be left guessing the identity of the magical stranger in the room! Increases Perception by <%= per %>. Limited Edition 2017 Fall Gear.",
|
||||
"headSpecialFall2017MageNotes": "When you appear in this feathery hat, everyone will be left guessing the identity of the magical stranger in the room! Increases Perception by <%= per %>. Limited Edition 2017 Autumn Gear.",
|
||||
"headSpecialFall2017HealerText": "Haunted House Helm",
|
||||
"headSpecialFall2017HealerNotes": "Invite spooky spirits and friendly creatures to seek your healing powers in this helm! Increases Intelligence by <%= int %>. Limited Edition 2017 Fall Gear.",
|
||||
"headSpecialFall2017HealerNotes": "Invite spooky spirits and friendly creatures to seek your healing powers in this helm! Increases Intelligence by <%= int %>. Limited Edition 2017 Autumn Gear.",
|
||||
|
||||
"headSpecialNye2017Text": "Fanciful Party Hat",
|
||||
"headSpecialNye2017Notes": "You've received a Fanciful Party Hat! Wear it with pride while ringing in the New Year! Confers no benefit.",
|
||||
@@ -2076,13 +2046,13 @@
|
||||
"headSpecialSummer2018HealerNotes": "Adorned with aquamarine, this finned diadem marks leadership of folk, fish, and those who are a bit of both! Increases Intelligence by <%= int %>. Limited Edition 2018 Summer Gear.",
|
||||
|
||||
"headSpecialFall2018RogueText": "Alter Ego Face",
|
||||
"headSpecialFall2018RogueNotes": "Most of us hide away our inward struggles. This mask shows that we all experience tension between our good and bad impulses. Plus it comes with a sweet hat! Increases Perception by <%= per %>. Limited Edition 2018 Fall Gear.",
|
||||
"headSpecialFall2018RogueNotes": "Most of us hide away our inward struggles. This mask shows that we all experience tension between our good and bad impulses. Plus it comes with a sweet hat! Increases Perception by <%= per %>. Limited Edition 2018 Autumn Gear.",
|
||||
"headSpecialFall2018WarriorText": "Minotaur Visage",
|
||||
"headSpecialFall2018WarriorNotes": "This fearsome mask shows you can really take your tasks by the horns! Increases Strength by <%= str %>. Limited Edition 2018 Fall Gear.",
|
||||
"headSpecialFall2018WarriorNotes": "This fearsome mask shows you can really take your tasks by the horns! Increases Strength by <%= str %>. Limited Edition 2018 Autumn Gear.",
|
||||
"headSpecialFall2018MageText": "Candymancer's Hat",
|
||||
"headSpecialFall2018MageNotes": "This pointy hat is imbued with powerful spells of sweetness. Careful, if it gets wet it may become sticky! Increases Perception by <%= per %>. Limited Edition 2018 Fall Gear.",
|
||||
"headSpecialFall2018MageNotes": "This pointy hat is imbued with powerful spells of sweetness. Careful, if it gets wet it may become sticky! Increases Perception by <%= per %>. Limited Edition 2018 Autumn Gear.",
|
||||
"headSpecialFall2018HealerText": "Ravenous Helm",
|
||||
"headSpecialFall2018HealerNotes": "This helm is fashioned from a carnivorous plant renowned for its ability to dispatch zombies and other inconveniences. Just watch out that it doesn't chew on your head. Increases Intelligence by <%= int %>. Limited Edition 2018 Fall Gear.",
|
||||
"headSpecialFall2018HealerNotes": "This helm is fashioned from a carnivorous plant renowned for its ability to dispatch zombies and other inconveniences. Just watch out that it doesn't chew on your head. Increases Intelligence by <%= int %>. Limited Edition 2018 Autumn Gear.",
|
||||
|
||||
"headSpecialNye2018Text": "Outlandish Party Hat",
|
||||
"headSpecialNye2018Notes": "You've received an Outlandish Party Hat! Wear it with pride while ringing in the New Year! Confers no benefit.",
|
||||
@@ -2114,13 +2084,13 @@
|
||||
"headSpecialSummer2019HealerNotes": "The spiraling structure of this shell will help you hear any cry for help across the seven seas. Increases Intelligence by <%= int %>. Limited Edition 2019 Summer Gear.",
|
||||
|
||||
"headSpecialFall2019RogueText": "Antique Opera Hat",
|
||||
"headSpecialFall2019RogueNotes": "Did you find this headpiece at an auction of possibly-cursed costume pieces, or in the attic of an eccentric grandparent? Whatever its origin, its age and wear add to your air of mystery. Increases Perception by <%= per %>. Limited Edition 2019 Fall Gear.",
|
||||
"headSpecialFall2019RogueNotes": "Did you find this headpiece at an auction of possibly-cursed costume pieces, or in the attic of an eccentric grandparent? Whatever its origin, its age and wear add to your air of mystery. Increases Perception by <%= per %>. Limited Edition 2019 Autumn Gear.",
|
||||
"headSpecialFall2019WarriorText": "Obsidian Skull Helmet",
|
||||
"headSpecialFall2019WarriorNotes": "The dark eye-sockets of this skull helmet will daunt the bravest of your enemies. Increases Strength by <%= str %>. Limited Edition 2019 Fall Gear.",
|
||||
"headSpecialFall2019WarriorNotes": "The dark eye-sockets of this skull helmet will daunt the bravest of your enemies. Increases Strength by <%= str %>. Limited Edition 2019 Autumn Gear.",
|
||||
"headSpecialFall2019MageText": "Cyclops Mask",
|
||||
"headSpecialFall2019MageNotes": "Its single baleful eye does inhibit depth perception, but that is a small price to pay for the way it hones your focus to a single, intense point. Increases Perception by <%= per %>. Limited Edition 2019 Fall Gear.",
|
||||
"headSpecialFall2019MageNotes": "Its single baleful eye does inhibit depth perception, but that is a small price to pay for the way it hones your focus to a single, intense point. Increases Perception by <%= per %>. Limited Edition 2019 Autumn Gear.",
|
||||
"headSpecialFall2019HealerText": "Dark Miter",
|
||||
"headSpecialFall2019HealerNotes": "Don this dark miter to harness the powers of the fearsome Lich. Increases Intelligence by <%= int %>. Limited Edition 2019 Fall Gear.",
|
||||
"headSpecialFall2019HealerNotes": "Don this dark miter to harness the powers of the fearsome Lich. Increases Intelligence by <%= int %>. Limited Edition 2019 Autumn Gear.",
|
||||
|
||||
"headSpecialNye2019Text": "Outrageous Party Hat",
|
||||
"headSpecialNye2019Notes": "You've received an Outrageous Party Hat! Wear it with pride while ringing in the New Year! Confers no benefit.",
|
||||
@@ -2152,13 +2122,13 @@
|
||||
"headSpecialSummer2020HealerNotes": "Stand tall, that beachcombers may keep their hands out of your hair. Increases Intelligence by <%= int %>. Limited Edition 2020 Summer Gear.",
|
||||
|
||||
"headSpecialFall2020RogueText": "Two-Headed Stone Mask",
|
||||
"headSpecialFall2020RogueNotes": "Look twice, act once: this mask makes it easy. Increases Perception by <%= per %>. Limited Edition 2020 Fall Gear.",
|
||||
"headSpecialFall2020RogueNotes": "Look twice, act once: this mask makes it easy. Increases Perception by <%= per %>. Limited Edition 2020 Autumn Gear.",
|
||||
"headSpecialFall2020WarriorText": "Creepy Cowl",
|
||||
"headSpecialFall2020WarriorNotes": "The Warrior who once wore this never flinched from the weightiest tasks! But others may flinch from you when you wear it... Increases Strength by <%= str %>. Limited Edition 2020 Fall Gear.",
|
||||
"headSpecialFall2020WarriorNotes": "The Warrior who once wore this never flinched from the weightiest tasks! But others may flinch from you when you wear it... Increases Strength by <%= str %>. Limited Edition 2020 Autumn Gear.",
|
||||
"headSpecialFall2020MageText": "Awakened Clarity",
|
||||
"headSpecialFall2020MageNotes": "With this cap seated perfectly on your brow, your third eye opens, allowing you to focus on what is otherwise invisible: mana flows, restless spirits, and forgotten To-Dos. Increases Perception by <%= per %>. Limited Edition 2020 Fall Gear.",
|
||||
"headSpecialFall2020MageNotes": "With this cap seated perfectly on your brow, your third eye opens, allowing you to focus on what is otherwise invisible: mana flows, restless spirits, and forgotten To-Dos. Increases Perception by <%= per %>. Limited Edition 2020 Autumn Gear.",
|
||||
"headSpecialFall2020HealerText": "Death's Head Mask",
|
||||
"headSpecialFall2020HealerNotes": "The dreadful pallor of this skull-like visage shines as a warning to all mortals: Time is fleeting! Attend to thy deadlines, before it is too late! Increases Intelligence by <%= int %>. Limited Edition 2020 Fall Gear.",
|
||||
"headSpecialFall2020HealerNotes": "The dreadful pallor of this skull-like visage shines as a warning to all mortals: Time is fleeting! Attend to thy deadlines, before it is too late! Increases Intelligence by <%= int %>. Limited Edition 2020 Autumn Gear.",
|
||||
|
||||
"headSpecialWinter2021RogueText": "Ivy Mask",
|
||||
"headSpecialWinter2021RogueNotes": "A rogue can go unseen in the woods with a mask like this. Increases Perception by <%= per %>. Limited Edition 2020-2021 Winter Gear.",
|
||||
@@ -2197,13 +2167,13 @@
|
||||
"headSpecialSummer2022HealerNotes": "Fish don't have ears, you say? Wait til you tell them the news. Increases Intelligence by <%= int %>. Limited Edition 2022 Summer Gear.",
|
||||
|
||||
"headSpecialFall2021RogueText": "You Have Been Engulfed",
|
||||
"headSpecialFall2021RogueNotes": "Welp, you're stuck. Now you are doomed to roam dungeon corridors, collecting debris. DOOOOMED! Increases Perception by <%= per %>. Limited Edition 2021 Fall Gear.",
|
||||
"headSpecialFall2021RogueNotes": "Welp, you're stuck. Now you are doomed to roam dungeon corridors, collecting debris. DOOOOMED! Increases Perception by <%= per %>. Limited Edition 2021 Autumn Gear.",
|
||||
"headSpecialFall2021WarriorText": "Headless Cravat",
|
||||
"headSpecialFall2021WarriorNotes": "Lose your head over this formal collar and tie that complete your suit. Increases Strength by <%= str %>. Limited Edition 2021 Fall Gear.",
|
||||
"headSpecialFall2021WarriorNotes": "Lose your head over this formal collar and tie that complete your suit. Increases Strength by <%= str %>. Limited Edition 2021 Autumn Gear.",
|
||||
"headSpecialFall2021MageText": "Brain Eater Mask",
|
||||
"headSpecialFall2021MageNotes": "The tentacles surrounding the mouth grab prey and hold its delicious thoughts close for you to savor. Increases Perception by <%= per %>. Limited Edition 2021 Fall Gear.",
|
||||
"headSpecialFall2021MageNotes": "The tentacles surrounding the mouth grab prey and hold its delicious thoughts close for you to savor. Increases Perception by <%= per %>. Limited Edition 2021 Autumn Gear.",
|
||||
"headSpecialFall2021HealerText": "Summoner's Mask",
|
||||
"headSpecialFall2021HealerNotes": "Your own magic turns your hair into shocking, bright flames when you don this mask. Increases Intelligence by <%= int %>. Limited Edition 2021 Fall Gear.",
|
||||
"headSpecialFall2021HealerNotes": "Your own magic turns your hair into shocking, bright flames when you don this mask. Increases Intelligence by <%= int %>. Limited Edition 2021 Autumn Gear.",
|
||||
|
||||
"headSpecialWinter2022RogueText": "Thundering Finale",
|
||||
"headSpecialWinter2022RogueNotes": "What? Huh? There's a Rogue where? I'm sorry, I can't hear anything over these fireworks! Increases Perception by <%= per %>. Limited Edition 2021-2022 Winter Gear.",
|
||||
@@ -2313,7 +2283,7 @@
|
||||
"headSpecialWinter2025RogueNotes": "There is definitely some magic in this hat, because it transforms you into a snow person. Just don’t let the bunny get too close to your carrot nose. Increases Perception by <%= per %>. Limited Edition Winter 2024-2025 Gear.",
|
||||
"headSpecialWinter2025HealerText": "Tangle of String Lights",
|
||||
"headSpecialWinter2025HealerNotes": "Don’t bother untangling these because they are already in the shape of a hat. Increases Intelligence by <%= int %>. Limited Edition Winter 2024-2025 Gear.",
|
||||
"headSpecialWinter2025MageText": "Aurora Headdress",
|
||||
"headSpecialWinter2025MageText": "Aurora Hat",
|
||||
"headSpecialWinter2025MageNotes": "More than just a fancy fascinator, this hat makes you look like the aurora borealis itself. Increases Perception by <%= per %>. Limited Edition Winter 2024-2025 Gear.",
|
||||
|
||||
"headSpecialSpring2025WarriorText": "Sunshine Helmet",
|
||||
@@ -2343,15 +2313,6 @@
|
||||
"headSpecialFall2025MageText": "Masked Ghost Mask",
|
||||
"headSpecialFall2025MageNotes": "Ethereal and glowy, this mask covers your head while you cover all your important tasks. Increases Perception by <%= per %>. Limited Edition Fall 2025 Gear.",
|
||||
|
||||
"headSpecialWinter2026WarriorText": "Rime Reaper Helmet",
|
||||
"headSpecialWinter2026WarriorNotes": "Maintain focus and concentration as you set your sights on greater goals this season. Increases Strength by <%= str %>. Limited Edition 2025-2026 Winter Gear.",
|
||||
"headSpecialWinter2026RogueText": "Ski Mask and Goggles",
|
||||
"headSpecialWinter2026RogueNotes": "Maintain focus and vision as you set your sights on greater goals this season. Increases Perception by <%= per %>. Limited Edition 2025-2026 Winter Gear.",
|
||||
"headSpecialWinter2026HealerText": "Polar Bear Mask",
|
||||
"headSpecialWinter2026HealerNotes": "Maintain focus and clarity as you set your sights on greater goals this season. Increases Intelligence by <%= int %>. Limited Edition 2025-2026 Winter Gear.",
|
||||
"headSpecialWinter2026MageText": "Midwinter Candle Hat",
|
||||
"headSpecialWinter2026MageNotes": "Maintain focus and illumination as you set your sights on greater goals this season. Increases Perception by <%= per %>. Limited Edition 2025-2026 Winter Gear.",
|
||||
|
||||
"headSpecialGaymerxText": "Rainbow Warrior Helm",
|
||||
"headSpecialGaymerxNotes": "In celebration of the GaymerX Conference, this special helmet is decorated with a radiant, colorful rainbow pattern! GaymerX is a game convention celebrating LGTBQ and gaming and is open to everyone.",
|
||||
|
||||
@@ -2535,10 +2496,6 @@
|
||||
"headMystery202504Notes": "Wear this mysterious visage to dwell undetected among the world’s most obscure cyptids. Confers no benefit. April 2025 Subscriber Item.",
|
||||
"headMystery202507Text": "Spunky Skater Cap",
|
||||
"headMystery202507Notes": "Backwards hats are still cool, right? Confers no benefit. July 2025 Subscriber Item.",
|
||||
"headMystery202512Text": "Cookie Champion Helm",
|
||||
"headMystery202512Notes": "Gingerbread forged with ancient magic will protect you as long as you can hold off your urge to try a bite! Confers no benefit. December 2025 Subscriber Item.",
|
||||
"headMystery202602Text": "Sakura Fox Ears",
|
||||
"headMystery202602Notes": " Your hearing will be sharpened by these ears such that you can hear the buds of blossoms growing on tree branches as spring approaches. Confers no benefit. February 2026 Subscriber Item.",
|
||||
|
||||
"headMystery301404Text": "Fancy Top Hat",
|
||||
"headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.",
|
||||
@@ -2767,8 +2724,6 @@
|
||||
"headArmoireBlackHairbowNotes": "Become strong, smart, and hearty while wearing this beautiful Black Hairbow! Increases Strength, Intelligence, and Constitution by <%= attrs %> each. Enchanted Armoire: Black Hairbow Set (Item 1 of 2).",
|
||||
"headArmoireBlacksmithsGogglesText": "Blacksmith's Goggles",
|
||||
"headArmoireBlacksmithsGogglesNotes": "Shatter and heat-resistant ocular protection is yours when you’re working in a forge. Increases Perception by <%= per %>. Enchanted Armoire: Blacksmith Set (Item 1 of 3).",
|
||||
"headArmoireLoneCowpokeHatText": "Lone Cowpoke Hat",
|
||||
"headArmoireLoneCowpokeHatNotes": "Howdy there, pardner! D’you hate when you’re out on the range, workin’ on tasks, and sun gets in your eyes? Well, good thing you’ve got a hat for that now. Increases Perception by <%= per %>. Enchanted Armoire: Lone Cowpoke Set (Item 1 of 2)",
|
||||
|
||||
"offhand": "off-hand item",
|
||||
"offHandCapitalized": "Off-Hand Item",
|
||||
@@ -2841,9 +2796,9 @@
|
||||
"shieldSpecialSummerHealerNotes": "No one will dare to attack the coral reef when faced with this shiny shield! Increases Constitution by <%= con %>. Limited Edition 2014 Summer Gear.",
|
||||
|
||||
"shieldSpecialFallWarriorText": "Potent Potion of Science",
|
||||
"shieldSpecialFallWarriorNotes": "Spills mysteriously on lab coats. Increases Constitution by <%= con %>. Limited Edition 2014 Fall Gear.",
|
||||
"shieldSpecialFallWarriorNotes": "Spills mysteriously on lab coats. Increases Constitution by <%= con %>. Limited Edition 2014 Autumn Gear.",
|
||||
"shieldSpecialFallHealerText": "Jeweled Shield",
|
||||
"shieldSpecialFallHealerNotes": "This glittery shield was found in an ancient tomb. Increases Constitution by <%= con %>. Limited Edition 2014 Fall Gear.",
|
||||
"shieldSpecialFallHealerNotes": "This glittery shield was found in an ancient tomb. Increases Constitution by <%= con %>. Limited Edition 2014 Autumn Gear.",
|
||||
|
||||
"shieldSpecialWinter2015WarriorText": "Gumdrop Shield",
|
||||
"shieldSpecialWinter2015WarriorNotes": "This seemingly-sugary shield is actually made of nutritious, gelatinous vegetables. Increases Constitution by <%= con %>. Limited Edition 2014-2015 Winter Gear.",
|
||||
@@ -2861,9 +2816,9 @@
|
||||
"shieldSpecialSummer2015HealerNotes": "Use this shield to bash away bilge rats. Increases Constitution by <%= con %>. Limited Edition 2015 Summer Gear.",
|
||||
|
||||
"shieldSpecialFall2015WarriorText": "Birdseed Bag",
|
||||
"shieldSpecialFall2015WarriorNotes": "It's true that you're supposed to be SCARING the crows, but there's nothing wrong with making friends! Increases Constitution by <%= con %>. Limited Edition 2015 Fall Gear.",
|
||||
"shieldSpecialFall2015WarriorNotes": "It's true that you're supposed to be SCARING the crows, but there's nothing wrong with making friends! Increases Constitution by <%= con %>. Limited Edition 2015 Autumn Gear.",
|
||||
"shieldSpecialFall2015HealerText": "Stirring Stick",
|
||||
"shieldSpecialFall2015HealerNotes": "This stick can stir anything without melting, dissolving, or bursting into flame! It can also be used to fiercely poke enemy tasks. Increases Constitution by <%= con %>. Limited Edition 2015 Fall Gear.",
|
||||
"shieldSpecialFall2015HealerNotes": "This stick can stir anything without melting, dissolving, or bursting into flame! It can also be used to fiercely poke enemy tasks. Increases Constitution by <%= con %>. Limited Edition 2015 Autumn Gear.",
|
||||
|
||||
"shieldSpecialWinter2016WarriorText": "Sled Shield",
|
||||
"shieldSpecialWinter2016WarriorNotes": "Use this sled to block attacks, or ride it triumphantly into battle! Increases Constitution by <%= con %>. Limited Edition 2015-2016 Winter Gear.",
|
||||
@@ -2881,9 +2836,9 @@
|
||||
"shieldSpecialSummer2016HealerNotes": "Sometimes mistakenly called a Starfish Shield. Increases Constitution by <%= con %>. Limited Edition 2016 Summer Gear.",
|
||||
|
||||
"shieldSpecialFall2016WarriorText": "Defensive Roots",
|
||||
"shieldSpecialFall2016WarriorNotes": "Defend against Dailies with these writhing roots! Increases Constitution by <%= con %>. Limited Edition 2016 Fall Gear.",
|
||||
"shieldSpecialFall2016WarriorNotes": "Defend against Dailies with these writhing roots! Increases Constitution by <%= con %>. Limited Edition 2016 Autumn Gear.",
|
||||
"shieldSpecialFall2016HealerText": "Gorgon Shield",
|
||||
"shieldSpecialFall2016HealerNotes": "Don't admire your own reflection in this. Increases Constitution by <%= con %>. Limited Edition 2016 Fall Gear.",
|
||||
"shieldSpecialFall2016HealerNotes": "Don't admire your own reflection in this. Increases Constitution by <%= con %>. Limited Edition 2016 Autumn Gear.",
|
||||
|
||||
"shieldSpecialWinter2017WarriorText": "Puck Shield",
|
||||
"shieldSpecialWinter2017WarriorNotes": "Made from a giant hockey puck, this shield can stand up to quite a beating. Increases Constitution by <%= con %>. Limited Edition 2016-2017 Winter Gear.",
|
||||
@@ -2901,9 +2856,9 @@
|
||||
"shieldSpecialSummer2017HealerNotes": "This magical oyster constantly generates pearls as well as protection. Increases Constitution by <%= con %>. Limited Edition 2017 Summer Gear.",
|
||||
|
||||
"shieldSpecialFall2017WarriorText": "Candy Corn Shield",
|
||||
"shieldSpecialFall2017WarriorNotes": "This candy shield has mighty protective powers, so try not to nibble on it! Increases Constitution by <%= con %>. Limited Edition 2017 Fall Gear.",
|
||||
"shieldSpecialFall2017WarriorNotes": "This candy shield has mighty protective powers, so try not to nibble on it! Increases Constitution by <%= con %>. Limited Edition 2017 Autumn Gear.",
|
||||
"shieldSpecialFall2017HealerText": "Haunted Orb",
|
||||
"shieldSpecialFall2017HealerNotes": "This orb occasionally screeches. We're sorry, we're not sure why. But it sure looks nifty! Increases Constitution by <%= con %>. Limited Edition 2017 Fall Gear.",
|
||||
"shieldSpecialFall2017HealerNotes": "This orb occasionally screeches. We're sorry, we're not sure why. But it sure looks nifty! Increases Constitution by <%= con %>. Limited Edition 2017 Autumn Gear.",
|
||||
|
||||
"shieldSpecialWinter2018WarriorText": "Magic Gift Bag",
|
||||
"shieldSpecialWinter2018WarriorNotes": "Just about any useful thing you need can be found in this sack, if you know the right magic words to whisper. Increases Constitution by <%= con %>. Limited Edition 2017-2018 Winter Gear.",
|
||||
@@ -2921,11 +2876,11 @@
|
||||
"shieldSpecialSummer2018HealerNotes": "This shield can produce a dome of air for the benefit of land-dwelling visitors to your watery realm. Increases Constitution by <%= con %>. Limited Edition 2018 Summer Gear.",
|
||||
|
||||
"shieldSpecialFall2018RogueText": "Vial of Temptation",
|
||||
"shieldSpecialFall2018RogueNotes": "This bottle represents all the distractions and troubles that keep you from being your best self. Resist! We're cheering for you! Increases Strength by <%= str %>. Limited Edition 2018 Fall Gear.",
|
||||
"shieldSpecialFall2018RogueNotes": "This bottle represents all the distractions and troubles that keep you from being your best self. Resist! We're cheering for you! Increases Strength by <%= str %>. Limited Edition 2018 Autumn Gear.",
|
||||
"shieldSpecialFall2018WarriorText": "Brilliant Shield",
|
||||
"shieldSpecialFall2018WarriorNotes": "Super shiny to dissuade any troublesome Gorgons from playing peek-a-boo around the corners! Increases Constitution by <%= con %>. Limited Edition 2018 Fall Gear.",
|
||||
"shieldSpecialFall2018WarriorNotes": "Super shiny to dissuade any troublesome Gorgons from playing peek-a-boo around the corners! Increases Constitution by <%= con %>. Limited Edition 2018 Autumn Gear.",
|
||||
"shieldSpecialFall2018HealerText": "Hungry Shield",
|
||||
"shieldSpecialFall2018HealerNotes": "With its wide-open maw, this shield will absorb all your enemies' blows. Increases Constitution by <%= con %>. Limited Edition 2018 Fall Gear.",
|
||||
"shieldSpecialFall2018HealerNotes": "With its wide-open maw, this shield will absorb all your enemies' blows. Increases Constitution by <%= con %>. Limited Edition 2018 Autumn Gear.",
|
||||
|
||||
"shieldSpecialWinter2019WarriorText": "Frozen Shield",
|
||||
"shieldSpecialWinter2019WarriorNotes": "This shield was fashioned using the thickest sheets of ice from the oldest glacier in the Stoïkalm Steppes. Increases Constitution by <%= con %>. Limited Edition 2018-2019 Winter Gear.",
|
||||
@@ -2945,9 +2900,9 @@
|
||||
"shieldSpecialSummer2019MageNotes": "Sweating in the summer sun? No! Performing a simple elemental conjuration to fill the lily pond. Increases Perception by <%= per %>. Limited Edition 2019 Summer Gear.",
|
||||
|
||||
"shieldSpecialFall2019WarriorText": "Raven-Dark Shield",
|
||||
"shieldSpecialFall2019WarriorNotes": "The dark sheen of a raven's feather made solid, this shield will frustrate all attacks. Increases Constitution by <%= con %>. Limited Edition 2019 Fall Gear.",
|
||||
"shieldSpecialFall2019WarriorNotes": "The dark sheen of a raven's feather made solid, this shield will frustrate all attacks. Increases Constitution by <%= con %>. Limited Edition 2019 Autumn Gear.",
|
||||
"shieldSpecialFall2019HealerText": "Grotesque Grimoire",
|
||||
"shieldSpecialFall2019HealerNotes": "Harness the dark side of the Healer's arts with this Grimoire! Increases Constitution by <%= con %>. Limited Edition 2019 Fall Gear.",
|
||||
"shieldSpecialFall2019HealerNotes": "Harness the dark side of the Healer's arts with this Grimoire! Increases Constitution by <%= con %>. Limited Edition 2019 Autumn Gear.",
|
||||
|
||||
"shieldSpecialWinter2020WarriorText": "Round Conifer Cone",
|
||||
"shieldSpecialWinter2020WarriorNotes": "Use it as a shield until the seeds drop, and then you can put it on a wreath! Increases Constitution by <%= con %>. Limited Edition 2019-2020 Winter Gear.",
|
||||
@@ -2965,11 +2920,11 @@
|
||||
"shieldSpecialSummer2020HealerNotes": "As the motion of sand and water turns trash to treasure, so shall your magic turn wounds to strength. Increases Constitution by <%= con %>. Limited Edition 2020 Summer Gear.",
|
||||
|
||||
"shieldSpecialFall2020RogueText": "Swift Katar",
|
||||
"shieldSpecialFall2020RogueNotes": "Wielding a katar, you'd better be quick on your feet... This blade will serve you well if you strike fast, but don't over-commit! Increases Strength by <%= str %>. Limited Edition 2020 Fall Gear.",
|
||||
"shieldSpecialFall2020RogueNotes": "Wielding a katar, you'd better be quick on your feet... This blade will serve you well if you strike fast, but don't over-commit! Increases Strength by <%= str %>. Limited Edition 2020 Autumn Gear.",
|
||||
"shieldSpecialFall2020WarriorText": "Spirit's Shield",
|
||||
"shieldSpecialFall2020WarriorNotes": "It may look insubstantial, but this spectral shield can keep you safe from all kinds of harm. Increases Constitution by <%= con %>. Limited Edition 2020 Fall Gear.",
|
||||
"shieldSpecialFall2020WarriorNotes": "It may look insubstantial, but this spectral shield can keep you safe from all kinds of harm. Increases Constitution by <%= con %>. Limited Edition 2020 Autumn Gear.",
|
||||
"shieldSpecialFall2020HealerText": "Cocoon Carryall",
|
||||
"shieldSpecialFall2020HealerNotes": "Is it another moth you carry, still undergoing metamorphosis? Or simply a silken handbag, containing your tools of healing and prophecy? Increases Constitution by <%= con %>. Limited Edition 2020 Fall Gear.",
|
||||
"shieldSpecialFall2020HealerNotes": "Is it another moth you carry, still undergoing metamorphosis? Or simply a silken handbag, containing your tools of healing and prophecy? Increases Constitution by <%= con %>. Limited Edition 2020 Autumn Gear.",
|
||||
|
||||
"shieldSpecialWinter2021WarriorText": "Big Fish",
|
||||
"shieldSpecialWinter2021WarriorNotes": "Tell all your friends about the REALLY big fish you've caught! But whether you tell them he's made of plastic and sings songs is up to you. Increases Constitution by <%= con %>. Limited Edition 2020-2021 Winter Gear.",
|
||||
@@ -2987,9 +2942,9 @@
|
||||
"shieldSpecialSummer2021HealerNotes": "So much potential in this shield! But for now you can use it to protect your friends. Increases Constitution by <%= con %>. Limited Edition 2021 Summer Gear.",
|
||||
|
||||
"shieldSpecialFall2021WarriorText": "Jack-o-Lantern Shield",
|
||||
"shieldSpecialFall2021WarriorNotes": "This festive shield with its crooked smile will both protect you and light your way on a dark night. It nicely doubles for a head, should you need one! Increases Constitution by <%= con %>. Limited Edition 2021 Fall Gear.",
|
||||
"shieldSpecialFall2021WarriorNotes": "This festive shield with its crooked smile will both protect you and light your way on a dark night. It nicely doubles for a head, should you need one! Increases Constitution by <%= con %>. Limited Edition 2021 Autumn Gear.",
|
||||
"shieldSpecialFall2021HealerText": "Summoned Creature",
|
||||
"shieldSpecialFall2021HealerNotes": "An ethereal being rises from your magical flames to grant you extra protection. Increases Constitution by <%= con %>. Limited Edition 2021 Fall Gear.",
|
||||
"shieldSpecialFall2021HealerNotes": "An ethereal being rises from your magical flames to grant you extra protection. Increases Constitution by <%= con %>. Limited Edition 2021 Autumn Gear.",
|
||||
|
||||
"shieldSpecialWinter2022WarriorText": "Jingle Bell Shield",
|
||||
"shieldSpecialWinter2022WarriorNotes": "This is a jingle bell, jingle bell, jingle bell shield. Jingle bell protect and jingle bell deflect. Increases Constitution by <%= con %>. Limited Edition 2021-2022 Winter Gear.",
|
||||
@@ -3081,11 +3036,6 @@
|
||||
"shieldSpecialFall2025HealerText": "Kobold Shield",
|
||||
"shieldSpecialFall2025HealerNotes": "Buy yourself some extra time to gather supplies by shielding yourself from your chores. Increases Constitution by <%= con %>. Limited Edition Fall 2025 Gear.",
|
||||
|
||||
"shieldSpecialWinter2026WarriorText": "Rime Shield",
|
||||
"shieldSpecialWinter2026WarriorNotes": "Stop obstacles cold with this handy, spikey shield. Increases Constitution by <%= con %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
"shieldSpecialWinter2026HealerText": "Starburst",
|
||||
"shieldSpecialWinter2026HealerNotes": "Stars help with wayfinding, energy, and illumination—all things that help you better conquer a task list. Increases Constitution by <%= con %>. Limited Edition Winter 2025-2026 Gear.",
|
||||
|
||||
"shieldMystery201601Text": "Resolution Slayer",
|
||||
"shieldMystery201601Notes": "This blade can be used to parry away all distractions. Confers no benefit. January 2016 Subscriber Item.",
|
||||
"shieldMystery201701Text": "Time-Freezer Shield",
|
||||
@@ -3145,7 +3095,7 @@
|
||||
"shieldArmoireMushroomDruidShieldText": "Mushroom Druid Shield",
|
||||
"shieldArmoireMushroomDruidShieldNotes": "Though made from a mushroom, there's nothing mushy about this tough shield! Increases Constitution by <%= con %> and Strength by <%= str %>. Enchanted Armoire: Mushroom Druid Set (Item 3 of 3).",
|
||||
"shieldArmoireFestivalParasolText": "Festival Parasol",
|
||||
"shieldArmoireFestivalParasolNotes": "This lightweight parasol will shield you from the glare—whether it's from the sun or from dark red Dailies! Increases Constitution by <%= con %>. Enchanted Armoire: Festival Attire Set (Item 2 of 3).",
|
||||
"shieldArmoireFestivalParasolNotes": "This lightweight parasol will shield you from the glare--whether it's from the sun or from dark red Dailies! Increases Constitution by <%= con %>. Enchanted Armoire: Festival Attire Set (Item 2 of 3).",
|
||||
"shieldArmoireVikingShieldText": "Viking Shield",
|
||||
"shieldArmoireVikingShieldNotes": "This sturdy shield of wood and hide can stand up to the most daunting of foes. Increases Perception by <%= per %> and Intelligence by <%= int %>. Enchanted Armoire: Viking Set (Item 3 of 3).",
|
||||
"shieldArmoireSwanFeatherFanText": "Swan Feather Fan",
|
||||
@@ -3239,7 +3189,7 @@
|
||||
"shieldArmoireBouncyBubblesText": "Bouncy Bubbles",
|
||||
"shieldArmoireBouncyBubblesNotes": "Complete your relaxing bath with these exuberant bubbles! Increases Strength by <%= str %>. Enchanted Armoire: Bubble Bath Set (Item 4 of 4).",
|
||||
"shieldArmoireBagpipesText": "Bagpipes",
|
||||
"shieldArmoireBagpipesNotes": "The uncharitable might say you're planning to wake the dead with these bagpipes—but you know you're just motivating your Party to success! Increases Strength by <%= str %>. Enchanted Armoire: Bagpiper Set (Item 3 of 3).",
|
||||
"shieldArmoireBagpipesNotes": "The uncharitable might say you're planning to wake the dead with these bagpipes -- but you know you're just motivating your Party to success! Increases Strength by <%= str %>. Enchanted Armoire: Bagpiper Set (Item 3 of 3).",
|
||||
"shieldArmoireHeraldsMessageScrollText": "Herald's Message Scroll",
|
||||
"shieldArmoireHeraldsMessageScrollNotes": "What exciting news does this scroll contain? Could it be about a new pet or a long habit streak? Increases Perception by <%= per %>. Enchanted Armoire: Herald Set (Item 4 of 4)",
|
||||
"shieldArmoireSoftBlackPillowText": "Soft Black Pillow",
|
||||
@@ -3294,10 +3244,6 @@
|
||||
"shieldArmoireFlyFishingRodNotes": "Put a lure on this long and flexible rod and fish will mistake it for an insect every single time. Increases Strength and Intelligence by <%= attrs %> each. Enchanted Armoire: Fly Fishing Set (Item 3 of 3)",
|
||||
"shieldArmoireSoftOrangePillowText": "Soft Orange Pillow",
|
||||
"shieldArmoireSoftOrangePillowNotes": "The ready warrior packs a pillow for any expedition. Get ready to take on new obligations… even while you nap. Increases Intelligence and Perception by <%= attrs %> each. Enchanted Armoire: Orange Loungewear Set (Item 3 of 3).",
|
||||
"shieldArmoireDoubleBassText": "Double Bass",
|
||||
"shieldArmoireDoubleBassNotes": "Bom doo bom brrrr brr brr brrrr! Gather your party for some grounding or dancing as you listen to music on this deep double bass. Increases Constitution and Strength by <%= attrs %> each. Enchanted Armoire: Musical Instrument Set 2 (Item 3 of 3)",
|
||||
"shieldArmoirePrettyPinkGiftBoxText": "Pretty Pink Present",
|
||||
"shieldArmoirePrettyPinkGiftBoxNotes": "Is this gift from a dear friend? A caring relative? A true love? A secret admirer? Whoever sent it knows you’ll be pleased with what’s inside. Increases all stats by <%= attrs %> each. Enchanted Armoire: Pretty in Pink Set (Item 2 of 2)",
|
||||
|
||||
"back": "Back Accessory",
|
||||
"backBase0Text": "No Back Accessory",
|
||||
@@ -3388,13 +3334,6 @@
|
||||
"backMystery202507Notes": "Your steed for the sidewalks and halfpipes. Confers no benefit. July 2025 Subscriber Item.",
|
||||
"backMystery202510Text": "Gliding Ghoul Wings",
|
||||
"backMystery202510Notes": "Fly silently across the haunted skies with these giant wings. Confers no benefit. October 2025 Subscriber Item.",
|
||||
"backMystery202601Text": "Winter's Sigil",
|
||||
"backMystery202601Notes": "This mark grants the user control over the elements of the season of cold and frost. Confers no benefit. January 2026 Subscriber Item.",
|
||||
"backMystery202602Text": "Five Tails of Sakura",
|
||||
"backMystery202602Notes": "These fluffy tails are the color of cherry blossoms, a reminder that spring is on the way! Confers no benefit. February 2026 Subscriber Item.",
|
||||
|
||||
"backArmoireHarpsichordText": "Harpsichord",
|
||||
"backArmoireHarpsichordNotes": "Pting! Ptiiing! Gather your party for a dinner or picnic and listen to a tinny melody on this harpsichord. Increases Perception and Intelligence by <%= attrs %> each. Enchanted Armoire: Musical Instrument Set 2 (Item 1 of 3)",
|
||||
|
||||
"backSpecialWonderconRedText": "Mighty Cape",
|
||||
"backSpecialWonderconRedNotes": "Swishes with strength and beauty. Confers no benefit. Special Edition Convention Item.",
|
||||
@@ -3613,7 +3552,7 @@
|
||||
"headAccessoryMystery201908Text": "Footloose Faun Horns",
|
||||
"headAccessoryMystery201908Notes": "If wearing horns floats your goat, you're in luck! Confers no benefit. August 2019 Subscriber Item.",
|
||||
"headAccessoryMystery202004Text": "Mighty Monarch Antennae",
|
||||
"headAccessoryMystery202004Notes": "They twitch just a bit if the scent of flowers drifts by—use them to find a pretty garden! Confers no benefit. April 2020 Subscriber Item.",
|
||||
"headAccessoryMystery202004Notes": "They twitch just a bit if the scent of flowers drifts by--use them to find a pretty garden! Confers no benefit. April 2020 Subscriber Item.",
|
||||
"headAccessoryMystery202005Text": "Wondrous Wyvern Horns",
|
||||
"headAccessoryMystery202005Notes": "With such mighty horns, what creature dares challenge you? Confers no benefit. May 2020 Subscriber Item.",
|
||||
"headAccessoryMystery202009Text": "Marvelous Moth Antennae",
|
||||
@@ -3707,9 +3646,9 @@
|
||||
"eyewearSpecialWonderconBlackNotes": "Your motives are definitely legitimate. Confers no benefit. Special Edition Convention Item.",
|
||||
|
||||
"eyewearSpecialFall2019RogueText": "Bone-White Half Mask",
|
||||
"eyewearSpecialFall2019RogueNotes": "You'd think a full mask would protect your identity better, but people tend to be too awestruck by its stark design to take note of any identifying features left revealed. Confers no benefit. Limited Edition 2019 Fall Gear.",
|
||||
"eyewearSpecialFall2019RogueNotes": "You'd think a full mask would protect your identity better, but people tend to be too awestruck by its stark design to take note of any identifying features left revealed. Confers no benefit. Limited Edition 2019 Autumn Gear.",
|
||||
"eyewearSpecialFall2019HealerText": "Dark Visage",
|
||||
"eyewearSpecialFall2019HealerNotes": "Steel yourself against the toughest foes with this inscrutable mask. Confers no benefit. Limited Edition 2019 Fall Gear.",
|
||||
"eyewearSpecialFall2019HealerNotes": "Steel yourself against the toughest foes with this inscrutable mask. Confers no benefit. Limited Edition 2019 Autumn Gear.",
|
||||
|
||||
"eyewearMystery201503Text": "Aquamarine Eyewear",
|
||||
"eyewearMystery201503Notes": "Don't get poked in the eye by these shimmering gems! Confers no benefit. March 2015 Subscriber Item.",
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"notEnoughGems": "Not enough Gems",
|
||||
"alreadyHave": "Whoops! You already have this item. No need to buy it again!",
|
||||
"delete": "Delete",
|
||||
"gem": "Gem",
|
||||
"gems": "Gems",
|
||||
"needMoreGems": "Need More Gems?",
|
||||
"needMoreGemsInfo": "Purchase Gems now, or become a subscriber to buy Gems with Gold, get monthly mystery items, enjoy increased drop caps and more!",
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
"needsTextPlaceholder": "Type your message here.",
|
||||
"messageCopiedToClipboard": "Message copied to clipboard.",
|
||||
"leaderOnlyChallenges": "Only group leader can create challenges",
|
||||
"sendGift": "Send Gift",
|
||||
"sendGift": "Send a Gift",
|
||||
"selectGift": "Select Gift",
|
||||
"selectSubscription": "Select Subscription",
|
||||
"sendGiftToWhom": "Who would you like to send a gift to?",
|
||||
@@ -358,10 +358,12 @@
|
||||
"createGroup": "Create a Group",
|
||||
"groupUse": "Which best describes the use of your Group?*",
|
||||
"groupUseDefault": "Choose an answer",
|
||||
"groupParentChildren": "Using with my household",
|
||||
"groupFriends": "Using with friends",
|
||||
"groupManager": "Using for work",
|
||||
"groupTeacher": "Using for education",
|
||||
"groupParentChildren": "Parent(s) setting up tasks for children",
|
||||
"groupCouple": "Couple sharing tasks",
|
||||
"groupFriends": "Friends sharing tasks",
|
||||
"groupCoworkers": "Coworkers sharing tasks",
|
||||
"groupManager": "Manager setting up tasks for employees",
|
||||
"groupTeacher": "Teacher setting up tasks for students",
|
||||
"gettingStarted": "Getting Started",
|
||||
"nameStar": "Name*",
|
||||
"nameStarText": "Add a title",
|
||||
@@ -426,7 +428,5 @@
|
||||
"tavernDiscontinuedLinks": "Read more about the <a href='/static/faq/tavern-and-guilds'>Tavern and Guild Service Discontinuation</a> or head back to the <a href='/'>homepage</a>.",
|
||||
"chatSunsetWarning": "⚠️ <strong>Habitica Guilds and Tavern chat will be discontinued on 8/8/2023.</strong> <a href='/static/faq/tavern-and-guilds'>Click here</a> to read more about this change.",
|
||||
"interestedLearningMore": "Interested in Learning More?",
|
||||
"checkGroupPlanFAQ": "Check out the <a href='/static/faq#what-is-group-plan'>Group Plans FAQ</a> to learn how to get the most out of your shared task experience.",
|
||||
"groupPlanBillingFYI": "Group Plan subscriptions automatically renew unless you cancel at least 24 hours before the end of your current period. You can cancel from the Group Billing tab of your Group Plan. You will be charged within 24 hours before your subscription renews, based on the number of members in your Group Plan at that time. If you add members between payment periods, you'll see an additional prorated charge for their benefits at your next billing cycle.",
|
||||
"groupPlanBillingFYIShort": "Group Plan subscriptions automatically renew unless you cancel at least 24 hours before the end of your current period. You will be charged within 24 hours before your subscription renews, based on the number of members in your Group Plan at that time. If you add members between payment periods, you'll see an additional prorated charge for their benefits at your next billing cycle."
|
||||
"checkGroupPlanFAQ": "Check out the <a href='/static/faq#what-is-group-plan'>Group Plans FAQ</a> to learn how to get the most out of your shared task experience."
|
||||
}
|
||||
|
||||
@@ -239,10 +239,6 @@
|
||||
"fall2025SkeletonRogueSet": "Skeleton Rogue Set",
|
||||
"fall2025KoboldHealerSet": "Kobold Healer Set",
|
||||
"fall2025MaskedGhostMageSet": "Masked Ghost Mage Set",
|
||||
"winter2026RimeReaperWarriorSet": "Rime Reaper Warrior Set",
|
||||
"winter2026SkiRogueSet": "Ski Rogue Set",
|
||||
"winter2026PolarBearHealerSet": "Polar Bear Healer Set",
|
||||
"winter2026MidwinterCandleMageSet": "Midwinter Candle Mage Set",
|
||||
"winterPromoGiftHeader": "GIFT A SUBSCRIPTION, GET ONE FREE!",
|
||||
"winterPromoGiftDetails1": "Until January 6th only, when you gift somebody a subscription, you get the same subscription for yourself for free!",
|
||||
"winterPromoGiftDetails2": "Please note that if you or your gift recipient already have a recurring subscription, the gifted subscription will only start after that subscription is cancelled or has expired. Thanks so much for your support! <3",
|
||||
|
||||