mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 06:07:21 +01:00
Compare commits
48 Commits
fiz/iap-re
...
v5.39.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93f0c240f9 | ||
|
|
ad04b077a4 | ||
|
|
7ffc454320 | ||
|
|
dae0fbff16 | ||
|
|
5648092112 | ||
|
|
275b15b773 | ||
|
|
1025635e34 | ||
|
|
836cbdb81e | ||
|
|
be922de7ba | ||
|
|
3a2f5e724d | ||
|
|
8a105c6a14 | ||
|
|
7f1c64a50e | ||
|
|
125f472f34 | ||
|
|
bafd273475 | ||
|
|
365cb1c2eb | ||
|
|
876d5a67d6 | ||
|
|
3078af8f2a | ||
|
|
dad1440138 | ||
|
|
12773d539e | ||
|
|
ae4130b108 | ||
|
|
ad0614282e | ||
|
|
5a7704aed7 | ||
|
|
2feadd6125 | ||
|
|
efe0b3cd9e | ||
|
|
96731da380 | ||
|
|
0c5dd5d8b5 | ||
|
|
2f943a22e6 | ||
|
|
666184d7e4 | ||
|
|
17d22dda3f | ||
|
|
d1a18c121d | ||
|
|
836d7f3991 | ||
|
|
ace9c3c46a | ||
|
|
068640311e | ||
|
|
f26d2a59ae | ||
|
|
03c7e9172e | ||
|
|
6fdc072ec3 | ||
|
|
e68661c04b | ||
|
|
4f567592ea | ||
|
|
63c9b7a894 | ||
|
|
eaec39188e | ||
|
|
ba6940eb81 | ||
|
|
f8a3e4d673 | ||
|
|
2727da6f6c | ||
|
|
fa97852e38 | ||
|
|
2c7da25a25 | ||
|
|
9a072e3e76 | ||
|
|
98a6535dc3 | ||
|
|
9948e8ee44 |
Submodule habitica-images updated: 8b0cae9e63...e3215f16f9
@@ -10,7 +10,7 @@ function setUpServer () {
|
||||
|
||||
setupNconf();
|
||||
|
||||
// We require src/server and npt src/index because
|
||||
// We require src/server and not src/index because
|
||||
// 1. nconf is already setup
|
||||
// 2. we don't need clustering
|
||||
require('../website/server/server'); // eslint-disable-line global-require
|
||||
|
||||
@@ -11,7 +11,7 @@ const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
/*
|
||||
* Award users every extant pet and mount
|
||||
* Award every extant piece of equippable gear
|
||||
*/
|
||||
|
||||
async function updateUser (user) {
|
||||
|
||||
76
package-lock.json
generated
76
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"version": "5.36.6",
|
||||
"version": "5.39.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "habitica",
|
||||
"version": "5.36.6",
|
||||
"version": "5.39.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
@@ -59,7 +59,6 @@
|
||||
"morgan": "^1.10.0",
|
||||
"nconf": "^0.12.1",
|
||||
"node-gcm": "^1.0.5",
|
||||
"nodemon": "^3.1.9",
|
||||
"on-headers": "^1.0.2",
|
||||
"passport": "^0.5.3",
|
||||
"passport-facebook": "^3.0.0",
|
||||
@@ -16011,55 +16010,6 @@
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
||||
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
|
||||
"integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^7.5.3",
|
||||
"simple-update-notifier": "^2.0.0",
|
||||
"supports-color": "^5.5.0",
|
||||
"touch": "^3.1.0",
|
||||
"undefsafe": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"nodemon": "bin/nodemon.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/semver": {
|
||||
"version": "7.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/noop-logger": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
|
||||
@@ -19423,28 +19373,6 @@
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-update-notifier": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
||||
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
|
||||
"dependencies": {
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-update-notifier/node_modules/semver": {
|
||||
"version": "7.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/sinon": {
|
||||
"version": "15.2.0",
|
||||
"resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "5.36.6",
|
||||
"version": "5.39.0",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
@@ -106,8 +106,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 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"mongo:test": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data-testing --number 1 --quiet",
|
||||
"mongo:dev": "run-rs -v 7.0.23 -l ubuntu2404 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"mongo:test": "run-rs -v 7.0.23 -l ubuntu2404 --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"
|
||||
|
||||
@@ -8,7 +8,17 @@ const TASK_VALUE_CHANGE_FACTOR = 0.9747;
|
||||
const MIN_TASK_VALUE = -47.27;
|
||||
|
||||
async function updateTeamTasks (team) {
|
||||
if (team.purchased.plan.dateTerminated) {
|
||||
const dateTerminated = new Date(team.purchased.plan.dateTerminated);
|
||||
if (dateTerminated < new Date()) {
|
||||
team.purchased.plan.customerId = undefined;
|
||||
team.markModified('purchased.plan');
|
||||
return team.save();
|
||||
}
|
||||
}
|
||||
|
||||
const toSave = [];
|
||||
|
||||
let teamLeader = await User.findOne({ _id: team.leader }, 'preferences').exec();
|
||||
|
||||
if (!teamLeader) { // why would this happen?
|
||||
@@ -93,12 +103,7 @@ async function updateTeamTasks (team) {
|
||||
export default async function processTeamsCron () {
|
||||
const activeTeams = await Group.find({
|
||||
'purchased.plan.customerId': { $exists: true },
|
||||
$or: [
|
||||
{ 'purchased.plan.dateTerminated': { $exists: false } },
|
||||
{ 'purchased.plan.dateTerminated': null },
|
||||
{ 'purchased.plan.dateTerminated': { $gt: new Date() } },
|
||||
],
|
||||
}).exec();
|
||||
}, { cron: 1, leader: 1, purchased: 1 }).exec();
|
||||
|
||||
const cronPromises = activeTeams.map(updateTeamTasks);
|
||||
return Promise.all(cronPromises);
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import nconf from 'nconf';
|
||||
import requireAgain from 'require-again';
|
||||
import {
|
||||
generateRes,
|
||||
generateReq,
|
||||
} from '../../../helpers/api-unit.helper';
|
||||
import { authWithHeaders as authWithHeadersFactory } from '../../../../website/server/middlewares/auth';
|
||||
|
||||
const authPath = '../../../../website/server/middlewares/auth';
|
||||
|
||||
describe('auth middleware', () => {
|
||||
let res; let req; let
|
||||
@@ -16,6 +19,7 @@ describe('auth middleware', () => {
|
||||
|
||||
describe('auth with headers', () => {
|
||||
it('allows to specify a list of user field that we do not want to load', done => {
|
||||
const authWithHeadersFactory = requireAgain(authPath).authWithHeaders;
|
||||
const authWithHeaders = authWithHeadersFactory({
|
||||
userFieldsToExclude: ['items'],
|
||||
});
|
||||
@@ -35,6 +39,7 @@ describe('auth middleware', () => {
|
||||
});
|
||||
|
||||
it('makes sure some fields are always included', done => {
|
||||
const authWithHeadersFactory = requireAgain(authPath).authWithHeaders;
|
||||
const authWithHeaders = authWithHeadersFactory({
|
||||
userFieldsToExclude: [
|
||||
'items', 'auth.timestamps',
|
||||
@@ -60,5 +65,57 @@ describe('auth middleware', () => {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('errors with InvalidCredentialsError and code when token is wrong', done => {
|
||||
const authWithHeadersFactory = requireAgain(authPath).authWithHeaders;
|
||||
const authWithHeaders = authWithHeadersFactory({ userFieldsToExclude: [] });
|
||||
|
||||
req.headers['x-api-user'] = user._id;
|
||||
req.headers['x-api-key'] = 'totally-wrong-token';
|
||||
|
||||
authWithHeaders(req, res, err => {
|
||||
expect(err).to.exist;
|
||||
expect(err.name).to.equal('InvalidCredentialsError');
|
||||
expect(err.code).to.equal('invalid_credentials');
|
||||
expect(err.message).to.equal(res.t('invalidCredentials'));
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when ENFORCE_CLIENT_HEADER is true', () => {
|
||||
let authFactory;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox.stub(nconf, 'get').withArgs('ENFORCE_CLIENT_HEADER').returns('true');
|
||||
authFactory = requireAgain(authPath).authWithHeaders;
|
||||
});
|
||||
|
||||
it('errors with missingClientHeader when x-client header is not present', done => {
|
||||
const authWithHeaders = authFactory({ userFieldsToExclude: [] });
|
||||
|
||||
req.headers['x-api-user'] = user._id;
|
||||
req.headers['x-api-key'] = user;
|
||||
authWithHeaders(req, res, err => {
|
||||
expect(err).to.exist;
|
||||
expect(err.name).to.equal('BadRequest');
|
||||
expect(err.message).to.equal(res.t('missingClientHeader'));
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allows request to pass when x-client header is present', done => {
|
||||
const authWithHeaders = authFactory({ userFieldsToExclude: [] });
|
||||
|
||||
req.headers['x-api-user'] = user._id;
|
||||
req.headers['x-api-key'] = user.apiToken;
|
||||
req.headers['x-client'] = 'habitica-web';
|
||||
|
||||
authWithHeaders(req, res, err => {
|
||||
if (err) return done(err);
|
||||
expect(res.locals.user).to.exist;
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
197
test/api/unit/middlewares/blocker.test.js
Normal file
197
test/api/unit/middlewares/blocker.test.js
Normal file
@@ -0,0 +1,197 @@
|
||||
import nconf from 'nconf';
|
||||
import requireAgain from 'require-again';
|
||||
import {
|
||||
generateRes,
|
||||
generateReq,
|
||||
generateNext,
|
||||
} from '../../../helpers/api-unit.helper';
|
||||
import { Forbidden } from '../../../../website/server/libs/errors';
|
||||
import { apiError } from '../../../../website/server/libs/apiError';
|
||||
import { model as Blocker } from '../../../../website/server/models/blocker';
|
||||
|
||||
function checkIPBlockedErrorThrown (next) {
|
||||
expect(next).to.have.been.calledOnce;
|
||||
const calledWith = next.getCall(0).args;
|
||||
expect(calledWith[0].message).to.equal(apiError('ipAddressBlocked'));
|
||||
expect(calledWith[0] instanceof Forbidden).to.equal(true);
|
||||
}
|
||||
|
||||
function checkClientBlockedErrorThrown (next) {
|
||||
expect(next).to.have.been.calledOnce;
|
||||
const calledWith = next.getCall(0).args;
|
||||
expect(calledWith[0].message).to.equal(apiError('clientBlocked'));
|
||||
expect(calledWith[0] instanceof Forbidden).to.equal(true);
|
||||
}
|
||||
|
||||
function checkErrorNotThrown (next) {
|
||||
expect(next).to.have.been.calledOnce;
|
||||
const calledWith = next.getCall(0).args;
|
||||
expect(typeof calledWith[0] === 'undefined').to.equal(true);
|
||||
}
|
||||
|
||||
describe('Blocker middleware', () => {
|
||||
const pathToBlocker = '../../../../website/server/middlewares/blocker';
|
||||
|
||||
let res; let req; let next;
|
||||
|
||||
beforeEach(() => {
|
||||
res = generateRes();
|
||||
req = generateReq();
|
||||
next = generateNext();
|
||||
});
|
||||
|
||||
describe('Blocking IPs', () => {
|
||||
it('is disabled when the env var is not defined', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns(undefined);
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('is disabled when the env var is an empty string', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns('');
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('is disabled when the env var contains comma separated empty strings', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns(' , , ');
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('does not throw when the ip does not match', () => {
|
||||
req.ip = '192.168.1.1';
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns('192.168.1.2');
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('does not throw when the blocker IP does not match', async () => {
|
||||
req.ip = '192.168.1.1';
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
if (event === 'change') {
|
||||
callback({ operation: 'add', blocker: { type: 'ipaddress', area: 'full', value: '192.168.1.2' } });
|
||||
}
|
||||
},
|
||||
});
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('does not throw when a client is blocked', async () => {
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
if (event === 'change') {
|
||||
callback({ operation: 'add', blocker: { type: 'client', area: 'full', value: '192.168.1.1' } });
|
||||
}
|
||||
},
|
||||
});
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('throws when the blocker IP is blocked', async () => {
|
||||
req.ip = '192.168.1.1';
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
if (event === 'change') {
|
||||
callback({ operation: 'add', blocker: { type: 'ipaddress', area: 'full', value: '192.168.1.1' } });
|
||||
}
|
||||
},
|
||||
});
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkIPBlockedErrorThrown(next);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Blocking clients', () => {
|
||||
beforeEach(() => {
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns('');
|
||||
req.headers['x-client'] = 'test-client';
|
||||
});
|
||||
it('is disabled when no clients are blocked', () => {
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('does not throw when the client does not match', async () => {
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
if (event === 'change') {
|
||||
callback({ operation: 'add', blocker: { type: 'client', area: 'full', value: 'another-client' } });
|
||||
}
|
||||
},
|
||||
});
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('throws when the client is blocked', async () => {
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
if (event === 'change') {
|
||||
callback({ operation: 'add', blocker: { type: 'client', area: 'full', value: 'test-client' } });
|
||||
}
|
||||
},
|
||||
});
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkClientBlockedErrorThrown(next);
|
||||
});
|
||||
|
||||
it('does not throw when an ip is blocked', async () => {
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
if (event === 'change') {
|
||||
callback({ operation: 'add', blocker: { type: 'ipaddress', area: 'full', value: 'test-client' } });
|
||||
}
|
||||
},
|
||||
});
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('updates the list when data changes', async () => {
|
||||
let blockCallback;
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
blockCallback = callback;
|
||||
if (event === 'change') {
|
||||
callback({ operation: 'add', blocker: { type: 'client', area: 'full', value: 'another-client' } });
|
||||
}
|
||||
},
|
||||
});
|
||||
const attachBlocker = requireAgain(pathToBlocker).default;
|
||||
attachBlocker(req, res, next);
|
||||
checkErrorNotThrown(next);
|
||||
blockCallback({ operation: 'add', blocker: { type: 'client', area: 'full', value: 'test-client' } });
|
||||
attachBlocker(req, res, next);
|
||||
expect(next).to.have.been.calledTwice;
|
||||
const calledWith = next.getCall(1).args;
|
||||
expect(calledWith[0].message).to.equal(apiError('clientBlocked'));
|
||||
expect(calledWith[0] instanceof Forbidden).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
import nconf from 'nconf';
|
||||
import requireAgain from 'require-again';
|
||||
import {
|
||||
generateRes,
|
||||
generateReq,
|
||||
generateNext,
|
||||
} from '../../../helpers/api-unit.helper';
|
||||
import { Forbidden } from '../../../../website/server/libs/errors';
|
||||
import { apiError } from '../../../../website/server/libs/apiError';
|
||||
|
||||
function checkErrorThrown (next) {
|
||||
expect(next).to.have.been.calledOnce;
|
||||
const calledWith = next.getCall(0).args;
|
||||
expect(calledWith[0].message).to.equal(apiError('ipAddressBlocked'));
|
||||
expect(calledWith[0] instanceof Forbidden).to.equal(true);
|
||||
}
|
||||
|
||||
function checkErrorNotThrown (next) {
|
||||
expect(next).to.have.been.calledOnce;
|
||||
const calledWith = next.getCall(0).args;
|
||||
expect(typeof calledWith[0] === 'undefined').to.equal(true);
|
||||
}
|
||||
|
||||
describe('ipBlocker middleware', () => {
|
||||
const pathToIpBlocker = '../../../../website/server/middlewares/ipBlocker';
|
||||
|
||||
let res; let req; let next;
|
||||
|
||||
beforeEach(() => {
|
||||
res = generateRes();
|
||||
req = generateReq();
|
||||
next = generateNext();
|
||||
});
|
||||
|
||||
it('is disabled when the env var is not defined', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns(undefined);
|
||||
const attachIpBlocker = requireAgain(pathToIpBlocker).default;
|
||||
attachIpBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('is disabled when the env var is an empty string', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns('');
|
||||
const attachIpBlocker = requireAgain(pathToIpBlocker).default;
|
||||
attachIpBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('is disabled when the env var contains comma separated empty strings', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns(' , , ');
|
||||
const attachIpBlocker = requireAgain(pathToIpBlocker).default;
|
||||
attachIpBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('does not throw when the ip does not match', () => {
|
||||
req.ip = '192.168.1.1';
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns('192.168.1.2');
|
||||
const attachIpBlocker = requireAgain(pathToIpBlocker).default;
|
||||
attachIpBlocker(req, res, next);
|
||||
|
||||
checkErrorNotThrown(next);
|
||||
});
|
||||
|
||||
it('throws when the ip is blocked', () => {
|
||||
req.ip = '192.168.1.1';
|
||||
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns('192.168.1.1');
|
||||
const attachIpBlocker = requireAgain(pathToIpBlocker).default;
|
||||
attachIpBlocker(req, res, next);
|
||||
|
||||
checkErrorThrown(next);
|
||||
});
|
||||
});
|
||||
@@ -1,9 +1,13 @@
|
||||
import moment from 'moment';
|
||||
import requireAgain from 'require-again';
|
||||
import { model as User } from '../../../../website/server/models/user';
|
||||
import { model as NewsPost } from '../../../../website/server/models/newsPost';
|
||||
import { model as Group } from '../../../../website/server/models/group';
|
||||
import { model as Blocker } from '../../../../website/server/models/blocker';
|
||||
import common from '../../../../website/common';
|
||||
|
||||
const pathToUserSchema = '../../../../website/server/models/user/schema';
|
||||
|
||||
describe('User Model', () => {
|
||||
describe('.toJSON()', () => {
|
||||
it('keeps user._tmp when calling .toJSON', () => {
|
||||
@@ -912,4 +916,73 @@ describe('User Model', () => {
|
||||
expect(user.toJSON().flags.newStuff).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validates email', () => {
|
||||
it('does not throw an error for a valid email', () => {
|
||||
const user = new User();
|
||||
user.auth.local.email = 'hello@example.com';
|
||||
const errors = user.validateSync();
|
||||
expect(errors.errors['auth.local.email']).to.not.exist;
|
||||
});
|
||||
|
||||
it('throws an error if email is not valid', () => {
|
||||
const user = new User();
|
||||
user.auth.local.email = 'invalid-email';
|
||||
const errors = user.validateSync();
|
||||
expect(errors.errors['auth.local.email'].message).to.equal(common.i18n.t('invalidEmail'));
|
||||
});
|
||||
|
||||
it('throws an error if email is using a restricted domain', () => {
|
||||
const user = new User();
|
||||
user.auth.local.email = 'scammer@habitica.com';
|
||||
const errors = user.validateSync();
|
||||
expect(errors.errors['auth.local.email'].message).to.equal(common.i18n.t('invalidEmailDomain', { domains: 'habitica.com, habitrpg.com' }));
|
||||
});
|
||||
|
||||
it('throws an error if email was blocked specifically', () => {
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: 'blocked@example.com' } });
|
||||
},
|
||||
});
|
||||
const schema = requireAgain(pathToUserSchema).UserSchema;
|
||||
const valid = schema.paths['auth.local.email'].options.validate.every(v => v.validator('blocked@example.com'));
|
||||
expect(valid).to.equal(false);
|
||||
});
|
||||
|
||||
it('throws an error if email domain was blocked', () => {
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: '@example.com' } });
|
||||
},
|
||||
});
|
||||
const schema = requireAgain(pathToUserSchema).UserSchema;
|
||||
const valid = schema.paths['auth.local.email'].options.validate.every(v => v.validator('blocked@example.com'));
|
||||
expect(valid).to.equal(false);
|
||||
});
|
||||
|
||||
it('throws an error if user portion of email was blocked', () => {
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: 'blocked@' } });
|
||||
},
|
||||
});
|
||||
const schema = requireAgain(pathToUserSchema).UserSchema;
|
||||
const valid = schema.paths['auth.local.email'].options.validate.every(v => v.validator('blocked@example.com'));
|
||||
expect(valid).to.equal(false);
|
||||
});
|
||||
|
||||
it('does not throw an error if email is not blocked', () => {
|
||||
sandbox.stub(Blocker, 'watchBlockers').returns({
|
||||
on: (event, callback) => {
|
||||
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: '@example.com' } });
|
||||
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: 'blocked@' } });
|
||||
callback({ operation: 'add', blocker: { type: 'email', area: 'full', value: 'bad@test.com' } });
|
||||
},
|
||||
});
|
||||
const schema = requireAgain(pathToUserSchema).UserSchema;
|
||||
const valid = schema.paths['auth.local.email'].options.validate.every(v => v.validator('good@test.com'));
|
||||
expect(valid).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -238,6 +238,28 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
|
||||
expect(isPassValid).to.equal(true);
|
||||
});
|
||||
|
||||
it('changes the apiToken on password reset', async () => {
|
||||
const user = await generateUser();
|
||||
const previousToken = user.apiToken;
|
||||
|
||||
const code = encrypt(JSON.stringify({
|
||||
userId: user._id,
|
||||
expiresAt: moment().add({ days: 1 }),
|
||||
}));
|
||||
await user.updateOne({
|
||||
'auth.local.passwordResetCode': code,
|
||||
});
|
||||
|
||||
await api.post(`${endpoint}`, {
|
||||
newPassword: 'my new password',
|
||||
confirmPassword: 'my new password',
|
||||
code,
|
||||
});
|
||||
|
||||
await user.sync();
|
||||
expect(user.apiToken).to.not.eql(previousToken);
|
||||
});
|
||||
|
||||
it('renders the success page and convert the password from sha1 to bcrypt', async () => {
|
||||
const user = await generateUser();
|
||||
|
||||
|
||||
@@ -110,6 +110,18 @@ describe('POST /user/auth/local/login', () => {
|
||||
expect(isValidPassword).to.equal(true);
|
||||
});
|
||||
|
||||
it('sets auth.timestamps.updated', async () => {
|
||||
const oldUpdated = new Date(user.auth.timestamps.updated);
|
||||
// login
|
||||
await api.post(endpoint, {
|
||||
username: user.auth.local.email,
|
||||
password,
|
||||
});
|
||||
|
||||
await user.sync();
|
||||
expect(user.auth.timestamps.updated).to.be.greaterThan(oldUpdated);
|
||||
});
|
||||
|
||||
it('user uses social authentication and has no password', async () => {
|
||||
await user.unset({
|
||||
'auth.local.hashed_password': 1,
|
||||
|
||||
@@ -167,5 +167,24 @@ describe('POST /user/auth/social', () => {
|
||||
|
||||
await expect(getProperty('users', user._id, '_ABtests')).to.eventually.be.a('object');
|
||||
});
|
||||
|
||||
it('sets auth.timestamps.updated', async () => {
|
||||
let oldUpdated = new Date(user.auth.timestamps.updated);
|
||||
await user.post(endpoint, {
|
||||
authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase
|
||||
network,
|
||||
});
|
||||
await user.sync();
|
||||
expect(user.auth.timestamps.updated).to.be.greaterThan(oldUpdated);
|
||||
oldUpdated = new Date(user.auth.timestamps.updated);
|
||||
|
||||
// Do it again to ensure it updates even when nothing else changes
|
||||
await api.post(endpoint, {
|
||||
authResponse: { access_token: randomAccessToken }, // eslint-disable-line camelcase
|
||||
network,
|
||||
});
|
||||
await user.sync();
|
||||
expect(user.auth.timestamps.updated).to.be.greaterThan(oldUpdated);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,11 +27,30 @@ describe('PUT /user/auth/update-password', async () => {
|
||||
newPassword,
|
||||
confirmPassword: newPassword,
|
||||
});
|
||||
expect(response).to.eql({});
|
||||
|
||||
expect(response).to.exist;
|
||||
expect(response.apiToken).to.exist;
|
||||
|
||||
await user.sync();
|
||||
expect(user.auth.local.hashed_password).to.not.eql(previousHashedPassword);
|
||||
});
|
||||
|
||||
it('should change the apiToken on password change', async () => {
|
||||
const previousToken = user.apiToken;
|
||||
const response = await user.put(ENDPOINT, {
|
||||
password,
|
||||
newPassword,
|
||||
confirmPassword: newPassword,
|
||||
});
|
||||
|
||||
const newToken = response.apiToken;
|
||||
expect(newToken).to.exist;
|
||||
|
||||
await user.sync();
|
||||
expect(user.apiToken).to.eql(newToken);
|
||||
expect(user.apiToken).to.not.eql(previousToken);
|
||||
});
|
||||
|
||||
it('returns an error when confirmPassword does not match newPassword', async () => {
|
||||
await expect(user.put(ENDPOINT, {
|
||||
password,
|
||||
|
||||
@@ -133,21 +133,21 @@ describe('Content Schedule', () => {
|
||||
});
|
||||
|
||||
it('sets the end date for a gala', () => {
|
||||
const date = new Date('2024-05-20');
|
||||
const date = new Date('2024-05-31');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2024-06-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2024-06-01T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('sets the end date for a winter gala', () => {
|
||||
const date = new Date('2024-12-22');
|
||||
const date = new Date('2025-02-28');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-01T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('sets the end date in new year for a winter gala', () => {
|
||||
const date = new Date('2025-01-04');
|
||||
const date = new Date('2025-02-28');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-01T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('uses correct date for first hours of the month', () => {
|
||||
|
||||
@@ -111,6 +111,7 @@ import axios from 'axios';
|
||||
import * as Analytics from '@/libs/analytics';
|
||||
import { mapState } from '@/libs/store';
|
||||
import snackbars from '@/components/snackbars/notifications';
|
||||
import { LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||
|
||||
const COMMUNITY_MANAGER_EMAIL = import.meta.env.EMAILS_COMMUNITY_MANAGER_EMAIL;
|
||||
|
||||
@@ -222,11 +223,10 @@ export default {
|
||||
|
||||
const errorData = error.response.data;
|
||||
const errorMessage = errorData.message || errorData;
|
||||
const errorCode = errorData.error;
|
||||
|
||||
// Check for conditions to reset the user auth
|
||||
// TODO use a specific error like NotificationNotFound instead of checking for the string
|
||||
const invalidUserMessage = [this.$t('invalidCredentials'), 'Missing authentication headers.'];
|
||||
if (invalidUserMessage.indexOf(errorMessage) !== -1) {
|
||||
// If 'invalid_credentials' signaled, force logout
|
||||
if (error.response.status === 401 && errorCode === 'invalid_credentials') {
|
||||
this.$store.dispatch('auth:logout', { redirectToLogin: true });
|
||||
return null;
|
||||
}
|
||||
@@ -269,6 +269,17 @@ export default {
|
||||
const loadingScreen = document.getElementById('loading-screen');
|
||||
if (loadingScreen) document.body.removeChild(loadingScreen);
|
||||
|
||||
// Check if we need to show password change success message
|
||||
if (sessionStorage.getItem('passwordChangeSuccess') === 'true') {
|
||||
sessionStorage.removeItem('passwordChangeSuccess');
|
||||
this.$store.dispatch('snackbars:add', {
|
||||
title: 'Habitica',
|
||||
text: this.$t('passwordSuccess'),
|
||||
type: 'success',
|
||||
timeout: true,
|
||||
});
|
||||
}
|
||||
|
||||
this.$router.onReady(() => {
|
||||
if (this.isStaticPage || !this.isUserLoggedIn) {
|
||||
this.hideLoadingScreen();
|
||||
@@ -280,7 +291,7 @@ export default {
|
||||
this.loading = false;
|
||||
},
|
||||
checkForBannedUser (error) {
|
||||
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
||||
const AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||
const errorMessage = error.response.data.message;
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
height: 96px;
|
||||
}
|
||||
|
||||
.Mount_Head_Gryphon-Gryphatrice, .Mount_Body_Gryphon-Gryphatrice {
|
||||
.Mount_Head_Gryphon-Gryphatrice, .Mount_Body_Gryphon-Gryphatrice, .Mount_Head_Dragon-Hydra, .Mount_Body_Dragon-Hydra {
|
||||
width: 135px;
|
||||
height: 135px;
|
||||
}
|
||||
@@ -190,6 +190,14 @@
|
||||
background: url("https://habitica-assets.s3.amazonaws.com/mobileApp/images/BackerOnly-Mount-Body-Gryphatrice.gif") no-repeat;
|
||||
}
|
||||
|
||||
.Mount_Head_Dragon-Hydra {
|
||||
background: url("https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Dragon-Hydra.gif") no-repeat;
|
||||
}
|
||||
|
||||
.Mount_Body_Dragon-Hydra {
|
||||
background: url("https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Dragon-Hydra.gif") no-repeat;
|
||||
}
|
||||
|
||||
.background_airship, .background_clocktower, .background_steamworks {
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
|
||||
@@ -635,6 +635,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_autumn_swamp {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_autumn_swamp.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_autumn_tree_tunnel {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_autumn_tree_tunnel.png');
|
||||
width: 141px;
|
||||
@@ -810,6 +815,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_castle_keep_with_banners {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_castle_keep_with_banners.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cemetery_gate {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_cemetery_gate.png');
|
||||
width: 141px;
|
||||
@@ -1546,6 +1556,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_inside_forest_witchs_cottage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_inside_forest_witchs_cottage.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_iridescent_clouds {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_iridescent_clouds.png');
|
||||
width: 141px;
|
||||
@@ -2191,6 +2206,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_sunny_street_with_shops {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_sunny_street_with_shops.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_sunset_meadow {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_sunset_meadow.png');
|
||||
width: 141px;
|
||||
@@ -29560,6 +29580,16 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_blackPartyDress {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_blackPartyDress.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_blacksmithsApron {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_blacksmithsApron.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_blueMoonShozoku {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_blueMoonShozoku.png');
|
||||
width: 114px;
|
||||
@@ -29900,6 +29930,11 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_redWaistcoat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_redWaistcoat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_robeOfDiamonds {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_robeOfDiamonds.png');
|
||||
width: 114px;
|
||||
@@ -29990,6 +30025,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_softOrangeSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_softOrangeSuit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_softPinkSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_softPinkSuit.png');
|
||||
width: 114px;
|
||||
@@ -30190,11 +30230,21 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_blackHairbow {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_blackHairbow.png');
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_blackSpookySorceryHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_blackSpookySorceryHat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_blacksmithsGoggles {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_blacksmithsGoggles.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_blueFloppyHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_blueFloppyHat.png');
|
||||
width: 90px;
|
||||
@@ -30305,6 +30355,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_floppyOrangeHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_floppyOrangeHat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_flutteryWig {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_flutteryWig.png');
|
||||
width: 114px;
|
||||
@@ -30535,6 +30590,11 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_redNewsieHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_redNewsieHat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_regalCrown {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_regalCrown.png');
|
||||
width: 114px;
|
||||
@@ -30995,6 +31055,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_softOrangePillow {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_softOrangePillow.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_softPinkPillow {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_softPinkPillow.png');
|
||||
width: 114px;
|
||||
@@ -31135,6 +31200,16 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_blackPartyDress {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_blackPartyDress.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_blacksmithsApron {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_blacksmithsApron.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_blueMoonShozoku {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_blueMoonShozoku.png');
|
||||
width: 114px;
|
||||
@@ -31475,6 +31550,11 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_redWaistcoat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_redWaistcoat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_robeOfDiamonds {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_robeOfDiamonds.png');
|
||||
width: 114px;
|
||||
@@ -31565,6 +31645,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_softOrangeSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_softOrangeSuit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_softPinkSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_softPinkSuit.png');
|
||||
width: 114px;
|
||||
@@ -31715,6 +31800,11 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_armoire_blacksmithsHammer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_blacksmithsHammer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_armoire_blueKite {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_blueKite.png');
|
||||
width: 114px;
|
||||
@@ -33005,6 +33095,26 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_fall2025Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_fall2025Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_fall2025Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_fall2025Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_fall2025Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_fall2025Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_fall2025Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_fall2025Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_special_fallHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_special_fallHealer.png');
|
||||
width: 90px;
|
||||
@@ -33235,6 +33345,26 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_fall2025Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_fall2025Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_fall2025Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_fall2025Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_fall2025Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_fall2025Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_fall2025Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_fall2025Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_special_fallHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_special_fallHealer.png');
|
||||
width: 90px;
|
||||
@@ -33405,6 +33535,21 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_fall2025Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_fall2025Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_fall2025Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_fall2025Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_fall2025Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_fall2025Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_special_fallHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_special_fallHealer.png');
|
||||
width: 90px;
|
||||
@@ -33620,6 +33765,26 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_fall2025Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_fall2025Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_fall2025Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_fall2025Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_fall2025Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_fall2025Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_fall2025Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_fall2025Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_special_fallHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_special_fallHealer.png');
|
||||
width: 90px;
|
||||
@@ -33840,6 +34005,26 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_fall2025Healer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_fall2025Healer.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_fall2025Mage {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_fall2025Mage.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_fall2025Rogue {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_fall2025Rogue.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_fall2025Warrior {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_fall2025Warrior.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.weapon_special_fallHealer {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_special_fallHealer.png');
|
||||
width: 90px;
|
||||
@@ -35635,6 +35820,51 @@
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_mystery_202508 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_mystery_202508.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.weapon_mystery_202508 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_mystery_202508.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.back_mystery_202510 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/back_mystery_202510.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.body_mystery_202509 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/body_mystery_202509.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.broad_armor_mystery_202509 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_202509.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.eyewear_mystery_202510 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/eyewear_mystery_202510.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_mystery_202511 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_mystery_202511.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_mystery_202509 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_mystery_202509.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.weapon_mystery_202511 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_mystery_202511.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_mystery_301404 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png');
|
||||
width: 90px;
|
||||
|
||||
@@ -46,13 +46,11 @@
|
||||
|
||||
.background {
|
||||
background-repeat: repeat-x;
|
||||
|
||||
height:216px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
@@ -67,6 +65,13 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.shop-message {
|
||||
position: relative;
|
||||
height: 76px;
|
||||
margin: 71px auto;
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.npc {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
@@ -97,9 +97,9 @@ import { mapState } from '@/libs/store';
|
||||
import Sprite from '@/components/ui/sprite';
|
||||
|
||||
export default {
|
||||
components: [
|
||||
components: {
|
||||
Sprite,
|
||||
],
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
maxHealth,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="row standard-page col-12 d-flex justify-content-center">
|
||||
<div class="admin-panel-content">
|
||||
<h1>Admin Panel</h1>
|
||||
<h1>{{ $t("adminPanel") }}</h1>
|
||||
<form
|
||||
class="form-inline"
|
||||
@submit.prevent="searchUsers(userIdentifier)"
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.$store.dispatch('common:setTitle', {
|
||||
section: 'Admin Panel',
|
||||
section: this.$t('adminPanel'),
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
@@ -55,7 +55,7 @@
|
||||
<script>
|
||||
import VueRouter from 'vue-router';
|
||||
import { mapState } from '@/libs/store';
|
||||
import LoadingSpinner from '../ui/loadingSpinner';
|
||||
import LoadingSpinner from '../../ui/loadingSpinner';
|
||||
|
||||
const { isNavigationFailure, NavigationFailureType } = VueRouter;
|
||||
|
||||
@@ -38,12 +38,17 @@
|
||||
>
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input
|
||||
:id="permission.key"
|
||||
v-model="hero.permissions[permission.key]"
|
||||
:disabled="!hasPermission(user, permission.key)"
|
||||
:disabled="!hasPermission(user, permission.key)
|
||||
|| (hero.permissions.fullAccess && permission.key !== 'fullAccess')"
|
||||
class="custom-control-input"
|
||||
type="checkbox"
|
||||
>
|
||||
<label class="custom-control-label">
|
||||
<label
|
||||
class="custom-control-label"
|
||||
:for="permission.key"
|
||||
>
|
||||
{{ permission.name }}<br>
|
||||
<small class="text-secondary">{{ permission.description }}</small>
|
||||
</label>
|
||||
@@ -124,7 +129,10 @@
|
||||
value="Save"
|
||||
class="btn btn-primary mt-1"
|
||||
>
|
||||
<b v-if="hasUnsavedChanges" class="text-warning float-right">
|
||||
<b
|
||||
v-if="hasUnsavedChanges"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</div>
|
||||
@@ -147,7 +155,7 @@ import markdownDirective from '@/directives/markdown';
|
||||
import saveHero from '../mixins/saveHero';
|
||||
|
||||
import { mapState } from '@/libs/store';
|
||||
import { userStateMixin } from '../../../mixins/userState';
|
||||
import { userStateMixin } from '../../../../mixins/userState';
|
||||
|
||||
const permissionList = [
|
||||
{
|
||||
@@ -175,6 +183,11 @@ const permissionList = [
|
||||
name: 'Challenge Admin',
|
||||
description: 'Can create official habitica challenges and admin all challenges',
|
||||
},
|
||||
{
|
||||
key: 'accessControl',
|
||||
name: 'Access Control',
|
||||
description: 'Can manage IP-Address, Client and E-Mail blockers',
|
||||
},
|
||||
{
|
||||
key: 'coupons',
|
||||
name: 'Coupon Creator',
|
||||
@@ -126,7 +126,7 @@
|
||||
@click="changeApiToken()"
|
||||
>
|
||||
Change API Token
|
||||
</a>
|
||||
</a>
|
||||
<div
|
||||
v-if="tokenModified"
|
||||
>
|
||||
@@ -46,7 +46,7 @@
|
||||
:
|
||||
<span :class="{ ownedItem: !item.neverOwned }">{{ item.text }}</span>
|
||||
</span>
|
||||
- {{ itemType }}.{{item.key}} - <i> {{ item.set }}</i>
|
||||
- {{ itemType }}.{{ item.key }} - <i> {{ item.set }}</i>
|
||||
|
||||
<div
|
||||
v-if="item.modified"
|
||||
@@ -16,9 +16,9 @@
|
||||
:hero="hero"
|
||||
:reset-counter="resetCounter"
|
||||
:has-unsaved-changes="hasUnsavedChanges([hero.flags, unModifiedHero.flags],
|
||||
[hero.auth, unModifiedHero.auth],
|
||||
[hero.balance, unModifiedHero.balance],
|
||||
[hero.secret, unModifiedHero.secret])"
|
||||
[hero.auth, unModifiedHero.auth],
|
||||
[hero.balance, unModifiedHero.balance],
|
||||
[hero.secret, unModifiedHero.secret])"
|
||||
/>
|
||||
|
||||
<subscription-and-perks
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
<contributor-details
|
||||
:hero="hero"
|
||||
:hasUnsavedChanges="hasUnsavedChanges(
|
||||
:has-unsaved-changes="hasUnsavedChanges(
|
||||
[hero.contributor, unModifiedHero.contributor],
|
||||
[hero.permissions, unModifiedHero.permissions],
|
||||
[hero.secret, unModifiedHero.secret],
|
||||
@@ -149,7 +149,7 @@ import Achievements from './achievements.vue';
|
||||
import UserHistory from './userHistory.vue';
|
||||
import Stats from './stats.vue';
|
||||
|
||||
import { userStateMixin } from '../../../mixins/userState';
|
||||
import { userStateMixin } from '../../../../mixins/userState';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -32,38 +32,43 @@
|
||||
></p>
|
||||
</div>
|
||||
<div v-if="userHasParty">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Party ID
|
||||
</label>
|
||||
<strong class="col-sm-9 col-form-label">
|
||||
{{ groupPartyData._id }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Estimated Member Count
|
||||
</label>
|
||||
<strong class="col-sm-9 col-form-label">
|
||||
{{ groupPartyData.memberCount }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Leader
|
||||
</label>
|
||||
<strong class="col-sm-9 col-form-label">
|
||||
<span v-if="userIsPartyLeader">User is the party leader</span>
|
||||
<span v-else>Party leader is
|
||||
<router-link :to="{'name': 'userProfile', 'params': {'userId': groupPartyData.leader}}">
|
||||
{{ groupPartyData.leader }}
|
||||
</router-link>
|
||||
</span>
|
||||
</strong>
|
||||
</div>
|
||||
<div
|
||||
class="btn btn-danger"
|
||||
@click="removeFromParty()">Remove from Party</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Party ID
|
||||
</label>
|
||||
<strong class="col-sm-9 col-form-label">
|
||||
{{ groupPartyData._id }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Estimated Member Count
|
||||
</label>
|
||||
<strong class="col-sm-9 col-form-label">
|
||||
{{ groupPartyData.memberCount }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Leader
|
||||
</label>
|
||||
<strong class="col-sm-9 col-form-label">
|
||||
<span v-if="userIsPartyLeader">User is the party leader</span>
|
||||
<span v-else>Party leader is
|
||||
<router-link
|
||||
:to="{'name': 'userProfile', 'params': {'userId': groupPartyData.leader}}"
|
||||
>
|
||||
{{ groupPartyData.leader }}
|
||||
</router-link>
|
||||
</span>
|
||||
</strong>
|
||||
</div>
|
||||
<div
|
||||
class="btn btn-danger"
|
||||
@click="removeFromParty()"
|
||||
>
|
||||
Remove from Party
|
||||
</div>
|
||||
</div>
|
||||
<strong v-else>User is not in a party.</strong>
|
||||
<div class="subsection-start">
|
||||
@@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<form @submit.prevent="saveHero({hero: {
|
||||
_id: hero._id,
|
||||
flags: hero.flags,
|
||||
balance: hero.balance,
|
||||
auth: hero.auth,
|
||||
secret: hero.secret,
|
||||
}, msg: 'Privileges or Gems or Moderation Notes'})">
|
||||
<form
|
||||
@submit.prevent="saveHero({hero: {
|
||||
_id: hero._id,
|
||||
flags: hero.flags,
|
||||
balance: hero.balance,
|
||||
auth: hero.auth,
|
||||
secret: hero.secret,
|
||||
}, msg: 'Privileges or Gems or Moderation Notes'})"
|
||||
>
|
||||
<div class="card mt-2">
|
||||
<div class="card-header">
|
||||
<h3
|
||||
@@ -14,9 +16,12 @@
|
||||
@click="expand = !expand"
|
||||
>
|
||||
Privileges, Gem Balance
|
||||
<b v-if="hasUnsavedChanges && !expand" class="text-warning float-right">
|
||||
Unsaved changes
|
||||
</b>
|
||||
<b
|
||||
v-if="hasUnsavedChanges && !expand"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
@@ -133,7 +138,10 @@
|
||||
value="Save"
|
||||
class="btn btn-primary mt-1"
|
||||
>
|
||||
<b v-if="hasUnsavedChanges" class="text-warning float-right">
|
||||
<b
|
||||
v-if="hasUnsavedChanges"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</div>
|
||||
@@ -8,9 +8,12 @@
|
||||
@click="expand = !expand"
|
||||
>
|
||||
Stats
|
||||
<b v-if="hasUnsavedChanges && !expand" class="text-warning float-right">
|
||||
Unsaved changes
|
||||
</b>
|
||||
<b
|
||||
v-if="hasUnsavedChanges && !expand"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
@@ -18,47 +21,60 @@
|
||||
class="card-body"
|
||||
>
|
||||
<stats-row
|
||||
v-model="hero.stats.hp"
|
||||
label="Health"
|
||||
color="red-label"
|
||||
:max="maxHealth"
|
||||
v-model="hero.stats.hp" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.exp"
|
||||
label="Experience"
|
||||
color="yellow-label"
|
||||
min="0"
|
||||
:max="maxFieldHardCap"
|
||||
v-model="hero.stats.exp" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.mp"
|
||||
label="Mana"
|
||||
color="blue-label"
|
||||
min="0"
|
||||
:max="maxFieldHardCap"
|
||||
v-model="hero.stats.mp" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.lvl"
|
||||
label="Level"
|
||||
step="1"
|
||||
min="0"
|
||||
:max="maxLevelHardCap"
|
||||
v-model="hero.stats.lvl" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.gp"
|
||||
label="Gold"
|
||||
min="0"
|
||||
:max="maxFieldHardCap"
|
||||
v-model="hero.stats.gp" />
|
||||
/>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">Selected Class</label>
|
||||
<div class="col-sm-9">
|
||||
<select
|
||||
id="selectedClass"
|
||||
v-model="hero.stats.class"
|
||||
class="form-control"
|
||||
:disabled="hero.stats.lvl < 10"
|
||||
>
|
||||
<option value="warrior">Warrior</option>
|
||||
<option value="wizard">Mage</option>
|
||||
<option value="healer">Healer</option>
|
||||
<option value="rogue">Rogue</option>
|
||||
</select>
|
||||
id="selectedClass"
|
||||
v-model="hero.stats.class"
|
||||
class="form-control"
|
||||
:disabled="hero.stats.lvl < 10"
|
||||
>
|
||||
<option value="warrior">
|
||||
Warrior
|
||||
</option>
|
||||
<option value="wizard">
|
||||
Mage
|
||||
</option>
|
||||
<option value="healer">
|
||||
Healer
|
||||
</option>
|
||||
<option value="rogue">
|
||||
Rogue
|
||||
</option>
|
||||
</select>
|
||||
<small>
|
||||
When changing class, players usually need stat points deallocated as well.
|
||||
</small>
|
||||
@@ -67,50 +83,59 @@
|
||||
|
||||
<h3>Stat Points</h3>
|
||||
<stats-row
|
||||
v-model="hero.stats.points"
|
||||
label="Unallocated"
|
||||
min="0"
|
||||
step="1"
|
||||
:max="maxStatPoints"
|
||||
v-model="hero.stats.points" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.str"
|
||||
label="Strength"
|
||||
color="red-label"
|
||||
min="0"
|
||||
:max="maxStatPoints"
|
||||
step="1"
|
||||
v-model="hero.stats.str" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.int"
|
||||
label="Intelligence"
|
||||
color="blue-label"
|
||||
min="0"
|
||||
:max="maxStatPoints"
|
||||
step="1"
|
||||
v-model="hero.stats.int" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.per"
|
||||
label="Perception"
|
||||
color="purple-label"
|
||||
min="0"
|
||||
:max="maxStatPoints"
|
||||
step="1"
|
||||
v-model="hero.stats.per" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.con"
|
||||
label="Constitution"
|
||||
color="yellow-label"
|
||||
min="0"
|
||||
:max="maxStatPoints"
|
||||
step="1"
|
||||
v-model="hero.stats.con" />
|
||||
/>
|
||||
<div class="form-group row">
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-warning btn-sm"
|
||||
@click="deallocateStatPoints">
|
||||
@click="deallocateStatPoints"
|
||||
>
|
||||
Deallocate all stat points
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row" v-if="statPointsIncorrect">
|
||||
<div
|
||||
v-if="statPointsIncorrect"
|
||||
class="form-group row"
|
||||
>
|
||||
<div class="offset-sm-3 col-sm-9 text-danger">
|
||||
Error: Sum of stat points should equal the users level
|
||||
</div>
|
||||
@@ -118,35 +143,40 @@
|
||||
|
||||
<h3>Buffs</h3>
|
||||
<stats-row
|
||||
v-model="hero.stats.buffs.str"
|
||||
label="Strength"
|
||||
color="red-label"
|
||||
min="0"
|
||||
step="1"
|
||||
v-model="hero.stats.buffs.str" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.buffs.int"
|
||||
label="Intelligence"
|
||||
color="blue-label"
|
||||
min="0"
|
||||
step="1"
|
||||
v-model="hero.stats.buffs.int" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.buffs.per"
|
||||
label="Perception"
|
||||
color="purple-label"
|
||||
min="0"
|
||||
step="1"
|
||||
v-model="hero.stats.buffs.per" />
|
||||
/>
|
||||
<stats-row
|
||||
v-model="hero.stats.buffs.con"
|
||||
label="Constitution"
|
||||
color="yellow-label"
|
||||
min="0"
|
||||
step="1"
|
||||
v-model="hero.stats.buffs.con" />
|
||||
/>
|
||||
<div class="form-group row">
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-warning btn-sm"
|
||||
@click="resetBuffs">
|
||||
@click="resetBuffs"
|
||||
>
|
||||
Reset Buffs
|
||||
</button>
|
||||
</div>
|
||||
@@ -161,7 +191,10 @@
|
||||
value="Save"
|
||||
class="btn btn-primary mt-1"
|
||||
>
|
||||
<b v-if="hasUnsavedChanges" class="text-warning float-right">
|
||||
<b
|
||||
v-if="hasUnsavedChanges"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</div>
|
||||
@@ -189,7 +222,7 @@ import markdownDirective from '@/directives/markdown';
|
||||
import saveHero from '../mixins/saveHero';
|
||||
|
||||
import { mapState } from '@/libs/store';
|
||||
import { userStateMixin } from '../../../mixins/userState';
|
||||
import { userStateMixin } from '../../../../mixins/userState';
|
||||
|
||||
import StatsRow from './stats-row';
|
||||
|
||||
@@ -6,49 +6,71 @@
|
||||
}, msg: 'Subscription Perks' })"
|
||||
>
|
||||
<div class="card mt-2">
|
||||
<div class="card-header"
|
||||
@click="expand = !expand">
|
||||
<div
|
||||
class="card-header"
|
||||
@click="expand = !expand"
|
||||
>
|
||||
<h3
|
||||
class="mb-0 mt-0"
|
||||
:class="{ 'open': expand }"
|
||||
>
|
||||
Subscription, Monthly Perks
|
||||
<b v-if="hasUnsavedChanges && !expand" class="text-warning float-right">
|
||||
Unsaved changes
|
||||
</b>
|
||||
<b
|
||||
v-if="hasUnsavedChanges && !expand"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
v-if="expand"
|
||||
class="card-body"
|
||||
>
|
||||
<div
|
||||
<div
|
||||
class="form-group row"
|
||||
>
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Payment method:
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input v-model="hero.purchased.plan.paymentMethod"
|
||||
<input
|
||||
v-if="!isRegularPaymentMethod"
|
||||
v-model="hero.purchased.plan.paymentMethod"
|
||||
class="form-control"
|
||||
type="text"
|
||||
v-if="!isRegularPaymentMethod"
|
||||
>
|
||||
<select
|
||||
<select
|
||||
v-else
|
||||
v-model="hero.purchased.plan.paymentMethod"
|
||||
class="form-control"
|
||||
type="text"
|
||||
>
|
||||
<option value="groupPlan">Group Plan</option>
|
||||
<option value="Stripe">Stripe</option>
|
||||
<option value="Apple">Apple</option>
|
||||
<option value="Google">Google</option>
|
||||
<option value="Amazon Payments">Amazon</option>
|
||||
<option value="PayPal">PayPal</option>
|
||||
<option value="Gift">Gift</option>
|
||||
<option value="">Clear out</option>
|
||||
</select>
|
||||
v-model="hero.purchased.plan.paymentMethod"
|
||||
class="form-control"
|
||||
type="text"
|
||||
>
|
||||
<option value="groupPlan">
|
||||
Group Plan
|
||||
</option>
|
||||
<option value="Stripe">
|
||||
Stripe
|
||||
</option>
|
||||
<option value="Apple">
|
||||
Apple
|
||||
</option>
|
||||
<option value="Google">
|
||||
Google
|
||||
</option>
|
||||
<option value="Amazon Payments">
|
||||
Amazon
|
||||
</option>
|
||||
<option value="PayPal">
|
||||
PayPal
|
||||
</option>
|
||||
<option value="Gift">
|
||||
Gift
|
||||
</option>
|
||||
<option value="">
|
||||
Clear out
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -58,25 +80,40 @@
|
||||
Payment schedule:
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input v-model="hero.purchased.plan.planId"
|
||||
<input
|
||||
v-if="!isRegularPlanId"
|
||||
v-model="hero.purchased.plan.planId"
|
||||
class="form-control"
|
||||
type="text"
|
||||
v-if="!isRegularPlanId"
|
||||
>
|
||||
<select
|
||||
<select
|
||||
v-else
|
||||
v-model="hero.purchased.plan.planId"
|
||||
class="form-control"
|
||||
type="text"
|
||||
>
|
||||
<option value="basic_earned">Monthly recurring</option>
|
||||
<option value="basic_3mo">3 Months recurring</option>
|
||||
<option value="basic_6mo">6 Months recurring</option>
|
||||
<option value="basic_12mo">12 Months recurring</option>
|
||||
<option value="group_monthly">Group Plan (legacy)</option>
|
||||
<option value="group_plan_auto">Group Plan (auto)</option>
|
||||
<option value="">Clear out</option>
|
||||
</select>
|
||||
v-model="hero.purchased.plan.planId"
|
||||
class="form-control"
|
||||
type="text"
|
||||
>
|
||||
<option value="basic_earned">
|
||||
Monthly recurring
|
||||
</option>
|
||||
<option value="basic_3mo">
|
||||
3 Months recurring
|
||||
</option>
|
||||
<option value="basic_6mo">
|
||||
6 Months recurring
|
||||
</option>
|
||||
<option value="basic_12mo">
|
||||
12 Months recurring
|
||||
</option>
|
||||
<option value="group_monthly">
|
||||
Group Plan (legacy)
|
||||
</option>
|
||||
<option value="group_plan_auto">
|
||||
Group Plan (auto)
|
||||
</option>
|
||||
<option value="">
|
||||
Clear out
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -86,43 +123,50 @@
|
||||
Customer ID:
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input
|
||||
v-model="hero.purchased.plan.customerId"
|
||||
class="form-control"
|
||||
type="text"
|
||||
>
|
||||
<input
|
||||
v-model="hero.purchased.plan.customerId"
|
||||
class="form-control"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row"
|
||||
v-if="hero.purchased.plan.planId === 'group_plan_auto'">
|
||||
<div
|
||||
v-if="hero.purchased.plan.planId === 'group_plan_auto'"
|
||||
class="form-group row"
|
||||
>
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Group Plan Memberships:
|
||||
</label>
|
||||
<div class="col-sm-9 col-form-label">
|
||||
<loading-spinner
|
||||
v-if="!groupPlans"
|
||||
dark-color=true
|
||||
/>
|
||||
v-if="!groupPlans"
|
||||
dark-color="true"
|
||||
/>
|
||||
<b
|
||||
v-else-if="groupPlans.length === 0"
|
||||
class="text-danger col-form-label"
|
||||
v-else-if="groupPlans.length === 0"
|
||||
class="text-danger col-form-label"
|
||||
>User is not part of an active group plan!</b>
|
||||
<div
|
||||
v-else
|
||||
v-for="group in groupPlans"
|
||||
v-else
|
||||
:key="group._id"
|
||||
class="card mb-2">
|
||||
class="card mb-2"
|
||||
>
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">{{ group.name }}
|
||||
<h6 class="card-title">
|
||||
{{ group.name }}
|
||||
<small class="float-right">{{ group._id }}</small>
|
||||
</h6>
|
||||
<p class="card-text">
|
||||
<strong>Leader: </strong>
|
||||
<a
|
||||
v-if="group.leader !== hero._id"
|
||||
@click="switchUser(group.leader)"
|
||||
>{{ group.leader }}</a>
|
||||
<strong v-else class="text-success">This user</strong>
|
||||
<a
|
||||
v-if="group.leader !== hero._id"
|
||||
@click="switchUser(group.leader)"
|
||||
>{{ group.leader }}</a>
|
||||
<strong
|
||||
v-else
|
||||
class="text-success"
|
||||
>This user</strong>
|
||||
</p>
|
||||
<p class="card-text">
|
||||
<strong>Members: </strong> {{ group.memberCount }}
|
||||
@@ -190,16 +234,21 @@
|
||||
<strong class="input-group-text">
|
||||
{{ dateFormat(hero.purchased.plan.dateTerminated) }}
|
||||
</strong>
|
||||
<a class="btn btn-danger"
|
||||
href="#"
|
||||
<a
|
||||
v-if="!hero.purchased.plan.dateTerminated && hero.purchased.plan.planId"
|
||||
v-b-modal.sub_termination_modal
|
||||
v-if="!hero.purchased.plan.dateTerminated && hero.purchased.plan.planId">
|
||||
class="btn btn-danger"
|
||||
href="#"
|
||||
>
|
||||
Terminate
|
||||
</a>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<small v-if="!hero.purchased.plan.dateTerminated
|
||||
&& hero.purchased.plan.planId" class="text-success">
|
||||
<small
|
||||
v-if="!hero.purchased.plan.dateTerminated
|
||||
&& hero.purchased.plan.planId"
|
||||
class="text-success"
|
||||
>
|
||||
The subscription does not have a termination date and is active.
|
||||
</small>
|
||||
</div>
|
||||
@@ -235,11 +284,13 @@
|
||||
step="any"
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<a class="btn btn-warning"
|
||||
<a
|
||||
v-if="hero.purchased.plan.dateTerminated && hero.purchased.plan.extraMonths > 0"
|
||||
class="btn btn-warning"
|
||||
@click="applyExtraMonths"
|
||||
v-if="hero.purchased.plan.dateTerminated && hero.purchased.plan.extraMonths > 0">
|
||||
>
|
||||
Apply Credit
|
||||
</a>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-secondary">
|
||||
@@ -339,19 +390,24 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row"
|
||||
v-if="!isConvertingToGroupPlan && hero.purchased.plan.planId !== 'group_plan_auto'">
|
||||
<div
|
||||
v-if="!isConvertingToGroupPlan && hero.purchased.plan.planId !== 'group_plan_auto'"
|
||||
class="form-group row"
|
||||
>
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary btn-sm"
|
||||
@click="beginGroupPlanConvert">
|
||||
@click="beginGroupPlanConvert"
|
||||
>
|
||||
Begin converting to group plan subscription
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row"
|
||||
v-if="isConvertingToGroupPlan">
|
||||
<div
|
||||
v-if="isConvertingToGroupPlan"
|
||||
class="form-group row"
|
||||
>
|
||||
<label class="col-sm-3 col-form-label">
|
||||
Group Plan group ID:
|
||||
</label>
|
||||
@@ -374,25 +430,40 @@
|
||||
class="btn btn-primary mt-1"
|
||||
@click="saveClicked"
|
||||
>
|
||||
<b v-if="hasUnsavedChanges" class="text-warning float-right">
|
||||
<b
|
||||
v-if="hasUnsavedChanges"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<b-modal id="sub_termination_modal" title="Set Termination Date">
|
||||
<b-modal
|
||||
id="sub_termination_modal"
|
||||
title="Set Termination Date"
|
||||
>
|
||||
<p>
|
||||
You can set the sub benefit termination date to today or to the last
|
||||
day of the current billing cycle. Any extra subscription credit will
|
||||
then be processed and automatically added onto the selected date.
|
||||
</p>
|
||||
<template #modal-footer>
|
||||
<div class="mt-3 btn btn-secondary" @click="$bvModal.hide('sub_termination_modal')">
|
||||
<div
|
||||
class="mt-3 btn btn-secondary"
|
||||
@click="$bvModal.hide('sub_termination_modal')"
|
||||
>
|
||||
Close
|
||||
</div>
|
||||
<div class="mt-3 btn btn-danger" @click="terminateSubscription()">
|
||||
<div
|
||||
class="mt-3 btn btn-danger"
|
||||
@click="terminateSubscription()"
|
||||
>
|
||||
Set to Today
|
||||
</div>
|
||||
<div class="mt-3 btn btn-danger" @click="terminateSubscription(todayWithRemainingCycle)">
|
||||
<div
|
||||
class="mt-3 btn btn-danger"
|
||||
@click="terminateSubscription(todayWithRemainingCycle)"
|
||||
>
|
||||
Set to {{ todayWithRemainingCycle.utc().format('MM/DD/YYYY') }}
|
||||
</div>
|
||||
</template>
|
||||
@@ -420,15 +491,15 @@
|
||||
import isUUID from 'validator/es/lib/isUUID';
|
||||
import moment from 'moment';
|
||||
import { getPlanContext } from '@/../../common/script/cron';
|
||||
import subscriptionBlocks from '@/../../common/script/content/subscriptionBlocks';
|
||||
import saveHero from '../mixins/saveHero';
|
||||
import subscriptionBlocks from '../../../../../common/script/content/subscriptionBlocks';
|
||||
import LoadingSpinner from '@/components/ui/loadingSpinner';
|
||||
|
||||
export default {
|
||||
mixins: [saveHero],
|
||||
components: {
|
||||
LoadingSpinner,
|
||||
},
|
||||
mixins: [saveHero],
|
||||
props: {
|
||||
hero: {
|
||||
type: Object,
|
||||
@@ -22,8 +22,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PurchaseHistoryTable from '../../ui/purchaseHistoryTable.vue';
|
||||
import { userStateMixin } from '../../../mixins/userState';
|
||||
import PurchaseHistoryTable from '../../../ui/purchaseHistoryTable.vue';
|
||||
import { userStateMixin } from '../../../../mixins/userState';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -180,7 +180,7 @@
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { userStateMixin } from '../../../mixins/userState';
|
||||
import { userStateMixin } from '../../../../mixins/userState';
|
||||
|
||||
export default {
|
||||
filters: {
|
||||
@@ -13,9 +13,12 @@
|
||||
@click="expand = !expand"
|
||||
>
|
||||
User Profile
|
||||
<b v-if="hasUnsavedChanges && !expand" class="text-warning float-right">
|
||||
Unsaved changes
|
||||
</b>
|
||||
<b
|
||||
v-if="hasUnsavedChanges && !expand"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
@@ -66,7 +69,10 @@
|
||||
value="Save"
|
||||
class="btn btn-primary mt-1"
|
||||
>
|
||||
<b v-if="hasUnsavedChanges" class="text-warning float-right">
|
||||
<b
|
||||
v-if="hasUnsavedChanges"
|
||||
class="text-warning float-right"
|
||||
>
|
||||
Unsaved changes
|
||||
</b>
|
||||
</div>
|
||||
@@ -86,7 +92,7 @@ import markdownDirective from '@/directives/markdown';
|
||||
import saveHero from '../mixins/saveHero';
|
||||
|
||||
import { mapState } from '@/libs/store';
|
||||
import { userStateMixin } from '../../../mixins/userState';
|
||||
import { userStateMixin } from '../../../../mixins/userState';
|
||||
|
||||
function resetData (self) {
|
||||
self.expand = false;
|
||||
133
website/client/src/components/admin/blocker/blocker_form.vue
Normal file
133
website/client/src/components/admin/blocker/blocker_form.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div style="display: contents">
|
||||
<td>
|
||||
<select
|
||||
v-model="blocker.type"
|
||||
class="form-control"
|
||||
@change="onTypeChanged"
|
||||
>
|
||||
<option value="ipaddress">
|
||||
IP-Address
|
||||
</option>
|
||||
<option value="client">
|
||||
Client Identifier
|
||||
</option>
|
||||
<option value="email">
|
||||
E-Mail
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
v-model="blocker.area"
|
||||
class="form-control"
|
||||
>
|
||||
<option value="full">
|
||||
Full
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
v-model="blocker.value"
|
||||
class="form-control"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
:class="{ 'is-invalid input-invalid': !isValid }"
|
||||
@input="validateValue"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
v-model="blocker.reason"
|
||||
class="form-control"
|
||||
>
|
||||
</td>
|
||||
<td
|
||||
colspan="3"
|
||||
class="text-right"
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:disabled="!isValid"
|
||||
:class="{ disabled: !isValid }"
|
||||
@click="$emit('save', blocker)"
|
||||
>
|
||||
<span>Save</span>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
@click="$emit('cancel')"
|
||||
>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
</td>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.btn-primary.disabled {
|
||||
background: #4F2A93;
|
||||
color: white;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import isIP from 'validator/es/lib/isIP';
|
||||
|
||||
export default {
|
||||
name: 'BlockerForm',
|
||||
props: {
|
||||
isNew: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
blocker: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
type: '',
|
||||
area: '',
|
||||
value: '',
|
||||
reason: '',
|
||||
}),
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isValid: false,
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.validateValue();
|
||||
},
|
||||
methods: {
|
||||
onTypeChanged () {
|
||||
if (this.blocker.type === 'email') {
|
||||
this.blocker.area = 'full';
|
||||
}
|
||||
this.validateValue();
|
||||
},
|
||||
validateValue () {
|
||||
if (this.blocker.type === 'ipaddress') {
|
||||
this.validateValueAsIpAddress();
|
||||
} else if (this.blocker.type === 'client') {
|
||||
this.validateValueAsClient();
|
||||
} else if (this.blocker.type === 'email') {
|
||||
this.validateValueAsEmail();
|
||||
}
|
||||
},
|
||||
validateValueAsEmail () {
|
||||
const emailRegex = /^([a-zA-Z0-9._%+-]*)@(?:[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})?$/;
|
||||
this.isValid = emailRegex.test(this.blocker.value) && this.blocker.value.length > 3;
|
||||
},
|
||||
validateValueAsIpAddress () {
|
||||
this.isValid = isIP(this.blocker.value);
|
||||
},
|
||||
validateValueAsClient () {
|
||||
this.isValid = this.blocker.value.length > 0;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
238
website/client/src/components/admin/blocker/index.vue
Normal file
238
website/client/src/components/admin/blocker/index.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div class="row standard-page col-12 d-flex justify-content-center">
|
||||
<div class="blocker-content">
|
||||
<h1>
|
||||
Blockers
|
||||
<button
|
||||
class="btn btn-primary float-right"
|
||||
@click="showCreateForm = true"
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
</h1>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Type <span
|
||||
id="type_tooltip"
|
||||
class="info-icon"
|
||||
>?</span>
|
||||
<b-tooltip
|
||||
target="type_tooltip"
|
||||
>
|
||||
<b>IP-Address</b> - Block access for a specific IP-Address
|
||||
<br>
|
||||
<br>
|
||||
<b>Client</b> - Block access for a client based on the "x-client" header.
|
||||
<br>
|
||||
<br>
|
||||
<b>E-Mail</b> - Blocks e-mails from being used for signup.
|
||||
</b-tooltip>
|
||||
</th>
|
||||
<th>
|
||||
Area <span
|
||||
id="area_tooltip"
|
||||
class="info-icon"
|
||||
>?</span>
|
||||
<b-tooltip
|
||||
target="area_tooltip"
|
||||
>
|
||||
<b>Full</b> - Block access to the entire site.
|
||||
<br>
|
||||
<br>
|
||||
<b>Payments</b> - Block access to any payment related functionality.
|
||||
</b-tooltip>
|
||||
</th>
|
||||
<th>Value</th>
|
||||
<th>Reason</th>
|
||||
<th>Source</th>
|
||||
<th>Created at</th>
|
||||
<th class="btncol"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-if="showCreateForm">
|
||||
<BlockerForm
|
||||
:is-new="true"
|
||||
:blocker="newBlocker"
|
||||
@save="createBlocker"
|
||||
@cancel="showCreateForm = false"
|
||||
/>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="blocker in blockers"
|
||||
:key="blocker._id"
|
||||
>
|
||||
<BlockerForm
|
||||
v-if="blocker._id === editedBlockerId"
|
||||
:blocker="blocker"
|
||||
@save="saveBlocker(blocker)"
|
||||
@cancel="editedBlockerId = null"
|
||||
/>
|
||||
<template v-else>
|
||||
<td>{{ getTypeName(blocker.type) }}</td>
|
||||
<td>{{ getAreaName(blocker.area) }}</td>
|
||||
<td>{{ blocker.value }}</td>
|
||||
<td>{{ blocker.reason || "--" }}</td>
|
||||
<td>{{ blocker.blockSource }}</td>
|
||||
<td>{{ blocker.createdAt }}</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
@click="editBlocker(blocker._id)"
|
||||
>
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon icon-16"
|
||||
v-html="icons.editIcon"
|
||||
></span>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
@click="deleteBlocker(blocker._id)"
|
||||
>
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon icon-16"
|
||||
v-html="icons.deleteIcon"
|
||||
></span>
|
||||
</button>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/colors.scss';
|
||||
|
||||
.blocker-content {
|
||||
flex: 0 0 100%;
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.4rem 0.75rem;
|
||||
}
|
||||
|
||||
.btncol {
|
||||
width: 123px;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
font-size: 0.8rem;
|
||||
color: $purple-400;
|
||||
cursor: pointer;
|
||||
margin-left: 0.5rem;
|
||||
background-color: $gray-500;
|
||||
padding: 0.1rem 0.3rem;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
|
||||
.info-icon:hover {
|
||||
background-color: $purple-400;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import editIcon from '@/assets/svg/edit.svg?raw';
|
||||
import deleteIcon from '@/assets/svg/delete.svg?raw';
|
||||
import BlockerForm from './blocker_form.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BlockerForm,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showCreateForm: false,
|
||||
newBlocker: {
|
||||
type: '',
|
||||
area: 'full',
|
||||
value: '',
|
||||
reason: '',
|
||||
},
|
||||
blockers: [],
|
||||
editedBlockerId: null,
|
||||
icons: Object.freeze({
|
||||
editIcon,
|
||||
deleteIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
mounted () {
|
||||
this.$store.dispatch('common:setTitle', {
|
||||
section: this.$t('siteBlockers'),
|
||||
});
|
||||
this.loadBlockers();
|
||||
},
|
||||
methods: {
|
||||
async loadBlockers () {
|
||||
this.blockers = await this.$store.dispatch('blockers:getBlockers');
|
||||
},
|
||||
editBlocker (id) {
|
||||
this.editedBlockerId = id;
|
||||
},
|
||||
async saveBlocker (blocker) {
|
||||
await this.$store.dispatch('blockers:updateBlocker', { blocker });
|
||||
this.editedBlockerId = null;
|
||||
this.loadBlockers();
|
||||
},
|
||||
async deleteBlocker (blockerId) {
|
||||
if (!window.confirm('Are you sure you want to delete this blocker?')) {
|
||||
return;
|
||||
}
|
||||
await this.$store.dispatch('blockers:deleteBlocker', { blockerId });
|
||||
this.loadBlockers();
|
||||
},
|
||||
async createBlocker (blocker) {
|
||||
await this.$store.dispatch('blockers:createBlocker', { blocker });
|
||||
this.showCreateForm = false;
|
||||
this.newBlocker = {
|
||||
type: '',
|
||||
area: 'full',
|
||||
value: '',
|
||||
reason: '',
|
||||
};
|
||||
this.loadBlockers();
|
||||
},
|
||||
|
||||
getTypeName (type) {
|
||||
switch (type) {
|
||||
case 'ipaddress':
|
||||
return 'IP-Address';
|
||||
case 'email':
|
||||
return 'E-Mail';
|
||||
case 'client':
|
||||
return 'Client Identifier';
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
},
|
||||
getAreaName (area) {
|
||||
switch (area) {
|
||||
case 'full':
|
||||
return 'Full';
|
||||
case 'payments':
|
||||
return 'Payments';
|
||||
default:
|
||||
return area;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
40
website/client/src/components/admin/container.vue
Normal file
40
website/client/src/components/admin/container.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<secondary-menu class="col-12">
|
||||
<router-link
|
||||
v-if="hasPermission(user, 'userSupport')"
|
||||
class="nav-link"
|
||||
:to="{name: 'adminPanel'}"
|
||||
>
|
||||
{{ $t('adminPanel') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="hasPermission(user, 'accessControl')"
|
||||
class="nav-link"
|
||||
:to="{name: 'blockers'}"
|
||||
>
|
||||
{{ $t('siteBlockers') }}
|
||||
</router-link>
|
||||
</secondary-menu><div class="col-12">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from '@/libs/store';
|
||||
import SecondaryMenu from '@/components/secondaryMenu';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SecondaryMenu,
|
||||
},
|
||||
mixins: [
|
||||
userStateMixin,
|
||||
],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -276,9 +276,9 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="time-travel"
|
||||
v-if="TIME_TRAVEL_ENABLED && user?.permissions?.fullAccess"
|
||||
:key="lastTimeJump"
|
||||
class="time-travel"
|
||||
>
|
||||
<a
|
||||
class="btn btn-secondary mr-1"
|
||||
@@ -299,7 +299,7 @@
|
||||
@click="resetTime()"
|
||||
>
|
||||
Reset
|
||||
</a>
|
||||
</a>
|
||||
</div>
|
||||
<a
|
||||
class="btn btn-secondary mr-1"
|
||||
|
||||
@@ -220,7 +220,6 @@
|
||||
v-if="forgotPassword"
|
||||
id="forgot-form"
|
||||
@submit.prevent="handleSubmit"
|
||||
@keyup.enter="handleSubmit"
|
||||
>
|
||||
<div class="text-center">
|
||||
<div>
|
||||
@@ -268,7 +267,6 @@
|
||||
v-if="resetPasswordSetNewOne"
|
||||
id="reset-password-set-new-one-form"
|
||||
@submit.prevent="handleSubmit"
|
||||
@keyup.enter="handleSubmit"
|
||||
>
|
||||
<div class="text-center">
|
||||
<div>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
<script>
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
import { LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||
|
||||
const COMMUNITY_MANAGER_EMAIL = import.meta.env.EMAILS_COMMUNITY_MANAGER_EMAIL; // eslint-disable-line
|
||||
|
||||
@@ -39,7 +40,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
bannedMessage () {
|
||||
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
||||
const AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||
const userId = parseSettings ? parseSettings.auth.apiId : '';
|
||||
|
||||
|
||||
@@ -227,7 +227,8 @@
|
||||
<div class="quest-icon">
|
||||
<Sprite
|
||||
class="quest"
|
||||
:image-name="`inventory_quest_scroll_${questData.key}`" />
|
||||
:image-name="`inventory_quest_scroll_${questData.key}`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -286,7 +286,7 @@
|
||||
:to="{ name: 'adminPanelUser',
|
||||
params: { userIdentifier: hero._id } }"
|
||||
>
|
||||
admin panel
|
||||
{{ $t("adminPanel") }}
|
||||
</router-link>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
@@ -295,14 +295,6 @@
|
||||
{{ $t('help') }}
|
||||
</router-link>
|
||||
<div class="topbar-dropdown">
|
||||
<router-link
|
||||
v-if="user.permissions.fullAccess ||
|
||||
user.permissions.userSupport"
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
:to="{name: 'adminPanel'}"
|
||||
>
|
||||
Admin Panel
|
||||
</router-link>
|
||||
<router-link
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
:to="{name: 'faq'}"
|
||||
@@ -336,6 +328,61 @@
|
||||
>{{ $t('requestFeature') }}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
v-if="hasElevatedPrivileges"
|
||||
class="topbar-item droppable"
|
||||
:class="{
|
||||
'active': $route.path.startsWith('/admin')}"
|
||||
>
|
||||
<div
|
||||
class="chevron rotate"
|
||||
@click="dropdownMobile($event)"
|
||||
>
|
||||
<div
|
||||
v-once
|
||||
class="chevron-icon-down"
|
||||
v-html="icons.chevronDown"
|
||||
></div>
|
||||
</div>
|
||||
<router-link
|
||||
v-if="hasPermission(user, 'userSupport')"
|
||||
class="nav-link"
|
||||
:to="{name: 'adminPanel'}"
|
||||
>
|
||||
{{ $t('admin') }}
|
||||
</router-link>
|
||||
<a
|
||||
v-else
|
||||
href="#"
|
||||
class="nav-link"
|
||||
>
|
||||
{{ $t('admin') }}
|
||||
</a>
|
||||
<div class="topbar-dropdown">
|
||||
<router-link
|
||||
v-if="hasPermission(user, 'userSupport')"
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
:to="{name: 'adminPanel'}"
|
||||
>
|
||||
{{ $t("adminPanel") }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="hasPermission(user, 'accessControl')"
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
:to="{name: 'blockers'}"
|
||||
>
|
||||
{{ $t("siteBlockers") }}
|
||||
</router-link>
|
||||
<a
|
||||
v-if="hasPermission(user, 'news')"
|
||||
class="topbar-dropdown-item dropdown-item"
|
||||
target="_blank"
|
||||
href="https://panel.habitica.com"
|
||||
>
|
||||
{{ $t('newsroom') }}
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</b-navbar-nav>
|
||||
<div class="currency-tray form-inline">
|
||||
<div
|
||||
@@ -757,6 +804,7 @@ import selectUserModal from '@/components/payments/selectUserModal';
|
||||
import sync from '@/mixins/sync';
|
||||
import userDropdown from './userDropdown';
|
||||
import reportBug from '@/mixins/reportBug.js';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -769,7 +817,7 @@ export default {
|
||||
selectUserModal,
|
||||
userDropdown,
|
||||
},
|
||||
mixins: [sync, reportBug],
|
||||
mixins: [sync, reportBug, userStateMixin],
|
||||
data () {
|
||||
return {
|
||||
isUserDropdownOpen: false,
|
||||
@@ -802,6 +850,12 @@ export default {
|
||||
params: { groupId: this.groupPlans[0]._id },
|
||||
};
|
||||
},
|
||||
hasElevatedPrivileges () {
|
||||
return this.user.permissions.fullAccess
|
||||
|| this.user.permissions.userSupport
|
||||
|| this.user.permissions.accessControl
|
||||
|| this.user.permissions.news;
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
await this.getUserGroupPlans();
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
<Sprite
|
||||
slot="icon"
|
||||
class="mt-3"
|
||||
:image-name="notification.data.icon" />
|
||||
:image-name="notification.data.icon"
|
||||
/>
|
||||
</base-notification>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
></div>
|
||||
<Sprite
|
||||
slot="icon"
|
||||
:image-name="mysteryClass" />
|
||||
:image-name="mysteryClass"
|
||||
/>
|
||||
</base-notification>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -81,9 +81,10 @@ import moment from 'moment';
|
||||
import habiticaMarkdown from 'habitica-markdown';
|
||||
import { mapState } from '@/libs/store';
|
||||
import seasonalNPC from '@/mixins/seasonalNPC';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
|
||||
export default {
|
||||
mixins: [seasonalNPC],
|
||||
mixins: [seasonalNPC, userStateMixin],
|
||||
data () {
|
||||
return {
|
||||
posts: [],
|
||||
@@ -107,7 +108,7 @@ export default {
|
||||
if (lastPublishedPost) this.posts.push(lastPublishedPost);
|
||||
|
||||
// If the user is authorized, show any draft
|
||||
if (this.user && (this.user.permissions.news || this.user.permissions.fullAccess)) {
|
||||
if (this.user && (this.hasPermission(this.user, 'news'))) {
|
||||
this.posts.unshift(
|
||||
...postsFromServer
|
||||
.filter(p => !p.published || moment().isBefore(p.publishDate)),
|
||||
|
||||
@@ -41,30 +41,58 @@
|
||||
<div class="standard-page">
|
||||
<div class="featuredItems">
|
||||
<div
|
||||
v-if="isSubscribed || (hasTrinket && !isSubscribed)"
|
||||
class="background"
|
||||
:class="{'background-closed': closed, 'background-open': !closed }"
|
||||
:style="{'background-image': imageURLs.background}"
|
||||
>
|
||||
<div
|
||||
class="npc"
|
||||
:class="{'closed': closed }"
|
||||
:style="{'background-image': imageURLs.npc}"
|
||||
>
|
||||
<div class="featured-label">
|
||||
<span class="rectangle"></span><span
|
||||
<span class="rectangle"></span>
|
||||
<span
|
||||
v-once
|
||||
class="text"
|
||||
>{{ $t('timeTravelers') }}</span><span class="rectangle"></span>
|
||||
>
|
||||
{{ $t('timeTravelers') }}
|
||||
</span>
|
||||
<span class="rectangle"></span>
|
||||
</div>
|
||||
</div><div
|
||||
v-if="closed"
|
||||
class="content"
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div
|
||||
class="background"
|
||||
:style="{'background-image': imageURLs.background}"
|
||||
>
|
||||
<div class="featured-label with-border closed">
|
||||
<span class="rectangle"></span><span
|
||||
<div
|
||||
class="npc"
|
||||
:style="{'background-image': imageURLs.npc}"
|
||||
>
|
||||
<div class="featured-label">
|
||||
<span class="rectangle"></span>
|
||||
<span
|
||||
v-once
|
||||
class="text"
|
||||
>
|
||||
{{ $t('timeTravelers') }}
|
||||
</span>
|
||||
<span class="rectangle"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="!isSubscribed && !hasTrinket"
|
||||
class="shop-message featured-label with-border closed"
|
||||
>
|
||||
<span class="rectangle"></span>
|
||||
<span
|
||||
v-once
|
||||
class="text"
|
||||
>{{ $t('timeTravelersPopoverNoSubMobile') }}</span><span class="rectangle"></span>
|
||||
>
|
||||
{{ $t('timeTravelersPopoverNoSubMobile') }}
|
||||
</span>
|
||||
<span class="rectangle"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -126,7 +154,8 @@
|
||||
</template>
|
||||
</itemRows>
|
||||
</div>
|
||||
</div><buyQuestModal
|
||||
</div>
|
||||
<buyQuestModal
|
||||
:item="selectedItemToBuy || {}"
|
||||
:price-type="selectedItemToBuy ? selectedItemToBuy.currency : ''"
|
||||
:with-pin="true"
|
||||
@@ -163,6 +192,7 @@ import _throttle from 'lodash/throttle';
|
||||
import _groupBy from 'lodash/groupBy';
|
||||
import _map from 'lodash/map';
|
||||
import _find from 'lodash/find';
|
||||
import moment from 'moment';
|
||||
import isPinned from '@/../../common/script/libs/isPinned';
|
||||
import shops from '@/../../common/script/libs/shops';
|
||||
import { mapState } from '@/libs/store';
|
||||
@@ -233,15 +263,18 @@ export default {
|
||||
userItems: 'user.data.items',
|
||||
currentEventList: 'worldState.data.currentEventList',
|
||||
}),
|
||||
|
||||
closed () {
|
||||
return this.user.purchased.plan.consecutive.trinkets === 0;
|
||||
isSubscribed () {
|
||||
const now = new Date();
|
||||
const { plan } = this.user.purchased;
|
||||
return plan && plan.customerId
|
||||
&& (!plan.dateTerminated || moment(plan.dateTerminated).isAfter(now));
|
||||
},
|
||||
hasTrinket () {
|
||||
return this.user.purchased.plan.consecutive.trinkets > 0;
|
||||
},
|
||||
|
||||
shop () {
|
||||
return shops.getTimeTravelersShop(this.user);
|
||||
},
|
||||
|
||||
categories () {
|
||||
const apiCategories = this.shop.categories;
|
||||
|
||||
@@ -302,10 +335,8 @@ export default {
|
||||
}
|
||||
});
|
||||
this.currentEvent = _find(this.currentEventList, event => Boolean(['winter', 'spring', 'summer', 'fall'].includes(event.season)));
|
||||
if (!this.currentEvent || !this.currentEvent.season || this.currentEvent.season === 'thanksgiving' || this.closed) {
|
||||
if (!this.currentEvent || !this.currentEvent.season || this.currentEvent.season === 'thanksgiving') {
|
||||
this.imageURLs.background = 'url(/static/npc/normal/time_travelers_background.png)';
|
||||
this.imageURLs.npc = this.closed ? 'url(/static/npc/normal/time_travelers_closed_banner.png)'
|
||||
: 'url(/static/npc/normal/time_travelers_open_banner.png)';
|
||||
} else {
|
||||
this.imageURLs.background = `url(/static/npc/${this.currentEvent.season}/time_travelers_background.png)`;
|
||||
this.imageURLs.npc = `url(/static/npc/${this.currentEvent.season}/time_travelers_open_banner.png)`;
|
||||
|
||||
@@ -7,10 +7,15 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-5 mb-md-0">
|
||||
<img :src="makeUrl('features_taskboard.png')" class="img-fluid">
|
||||
<img
|
||||
:src="makeUrl('features_taskboard.png')"
|
||||
class="img-fluid"
|
||||
>
|
||||
<h2>{{ $t('marketing1Lead1Title') }}</h2>
|
||||
<div class="row justify-content-md-center">
|
||||
<p class="col col-lg-8 col-xl-6 margin-auto description">{{ $t('marketing1Lead1') }}</p>
|
||||
<p class="col col-lg-8 col-xl-6 margin-auto description">
|
||||
{{ $t('marketing1Lead1') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -18,12 +23,16 @@
|
||||
<div class="col-md-6 mb-5 mb-md-0">
|
||||
<img :src="makeUrl('features_gear.png')">
|
||||
<h2>{{ $t('marketing1Lead2Title') }}</h2>
|
||||
<p class="description">{{ $t('marketing1Lead2') }}</p>
|
||||
<p class="description">
|
||||
{{ $t('marketing1Lead2') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-5 mb-md-0">
|
||||
<img :src="makeUrl('features_items.png')">
|
||||
<h2>{{ $t('marketing1Lead3Title') }}</h2>
|
||||
<p class="description">{{ $t('marketing1Lead3') }}</p>
|
||||
<p class="description">
|
||||
{{ $t('marketing1Lead3') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
@@ -35,19 +44,26 @@
|
||||
<div class="row mb-5">
|
||||
<div class="col-12">
|
||||
<h2>{{ $t('marketing2Lead1Title') }}</h2>
|
||||
<p class="description">{{ $t('marketing2Lead1') }}</p>
|
||||
<p class="description">
|
||||
{{ $t('marketing2Lead1') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-5 mb-md-0">
|
||||
<img :src="makeUrl('features_monsters.png')">
|
||||
<h2>{{ $t('marketing2Lead2Title') }}</h2>
|
||||
<p class="description" v-markdown="$t('marketing2Lead2')"></p>
|
||||
<p
|
||||
v-markdown="$t('marketing2Lead2')"
|
||||
class="description"
|
||||
></p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-5 mb-md-0">
|
||||
<img :src="makeUrl('features_challenges.png')">
|
||||
<h2>{{ $t('marketing2Lead3Title') }}</h2>
|
||||
<p class="description">{{ $t('marketing2Lead3') }}</p>
|
||||
<p class="description">
|
||||
{{ $t('marketing2Lead3') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
@@ -60,12 +76,18 @@
|
||||
<div class="col-md-6 mb-5 mb-md-0">
|
||||
<img :src="makeUrl('features_mobile.png')">
|
||||
<h2>{{ $t('marketing3Lead1Title') }}</h2>
|
||||
<p class="description" v-markdown="$t('marketing3Lead1')"></p>
|
||||
<p
|
||||
v-markdown="$t('marketing3Lead1')"
|
||||
class="description"
|
||||
></p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-5 mb-md-0">
|
||||
<img :src="makeUrl('features_opensource.png')">
|
||||
<h2>{{ $t('marketing3Lead2Title') }}</h2>
|
||||
<p class="description" v-markdown="$t('marketing3Lead2')"></p>
|
||||
<p
|
||||
v-markdown="$t('marketing3Lead2')"
|
||||
class="description"
|
||||
></p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
@@ -80,7 +102,9 @@
|
||||
<img src="@/assets/images/marketing/education.png">
|
||||
<div class="media-body">
|
||||
<h2>{{ $t('marketing4Lead1Title') }}</h2>
|
||||
<p class="description">{{ $t('marketing4Lead1') }}</p>
|
||||
<p class="description">
|
||||
{{ $t('marketing4Lead1') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,7 +113,9 @@
|
||||
<img src="@/assets/images/marketing/wellness.png">
|
||||
<div class="media-body">
|
||||
<h2>{{ $t('marketing4Lead2Title') }}</h2>
|
||||
<p class="description">{{ $t('marketing4Lead2') }}</p>
|
||||
<p class="description">
|
||||
{{ $t('marketing4Lead2') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
821
website/client/src/components/static/privacyReview.vue
Normal file
821
website/client/src/components/static/privacyReview.vue
Normal file
@@ -0,0 +1,821 @@
|
||||
<template>
|
||||
<!-- eslint-disable max-len -->
|
||||
<div class="container-fluid">
|
||||
<h1>HabitRPG Privacy Policy</h1>
|
||||
<p class="strong pagemeta">
|
||||
Last Updated September 1, 2025.
|
||||
</p>
|
||||
<p>
|
||||
This Privacy Policy applies when you interact with us through <a href="https://habitica.com">Habitica.com</a> (the “<strong>Site</strong>”), our mobile apps, and/or through any other feature or service owned or controlled by HabitRPG, Inc. ("<strong>HabitRPG</strong>", "<strong>we</strong>", or "<strong>us</strong>") that posts, links to, or references this Privacy Policy (collectively, the "<strong>Service(s)</strong>"). This Privacy Policy informs you of our practices regarding the collection, use, and disclosure of personal information we receive from users of our Services. By accessing or using the Services, you consent to our Privacy Policy and our collection, use, and disclosure of your information as described in this policy, our <a href="https://habitica.com/static/terms">Terms of Use</a>, and any additional policies and terms you may agree to in connection with the Services.
|
||||
</p>
|
||||
<h1>Table of Contents</h1>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#section_1">Collection of Information</a>
|
||||
<ol>
|
||||
<li><a href="#section_1_1">Information you Provide Directly</a></li>
|
||||
<li><a href="#section_1_2">Information We Collect Automatically</a></li>
|
||||
<li><a href="#section_1_3">Location Data</a></li>
|
||||
<li><a href="#section_1_2">Information Collected By and/or Disclosed to Third Parties</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#section_2">Purpose and Use of Information We Collect</a></li>
|
||||
<li><a href="#section_3">Service Providers</a></li>
|
||||
<li><a href="#section_4">Sweepstakes, Contests, and Promotions</a></li>
|
||||
<li><a href="#section_5">Security</a></li>
|
||||
<li><a href="#section_6">Data Retention</a></li>
|
||||
<li><a href="#section_7">General Audience Services</a></li>
|
||||
<li><a href="#section_8">Consent to International Transfer</a></li>
|
||||
<li><a href="#section_9">Your Choices</a></li>
|
||||
<li><a href="#section_10">Changes to This Privacy Policy</a></li>
|
||||
<li><a href="#section_11">Jurisdiction-Specific Rights</a></li>
|
||||
<li><a href="#section_12">Contact Us</a></li>
|
||||
</ol>
|
||||
<h2 id="section_1">
|
||||
1. Collection of Information
|
||||
</h2>
|
||||
<p>
|
||||
We and our third-party service providers and business partners may collect information from you directly and/or automatically when you visit the Site or use the Services. We and our third-party service providers may also collect information about you from third parties. Some of this information may be considered "personal information" or "personal data" under applicable laws (collectively, “personal information”). We consider information that identifies you as a specific, identified individual (such as your name, phone number, and email address) to be personal information. We also, where required by applicable law, consider additional types of identifying data, like IP addresses and cookie identifiers, to be personal information.
|
||||
</p>
|
||||
<p>
|
||||
We may, in accordance with applicable law, take your personal information and de-identify or pseudonymize it to make it non-personally identifiable, either by combining it with information about other individuals and/or by hashing the information or otherwise removing characteristics that make the information personally identifiable. We maintain and use de-identified or pseudonymized data without attempting to re-identify it, except where permitted by applicable law, such as to determine whether our de-identification processes satisfy legal requirements. We will treat de-identified or pseudonymized information as non-personal to the fullest extent allowed by applicable law.
|
||||
</p>
|
||||
<p>
|
||||
We may collect the following categories of personal information from or about you:
|
||||
</p>
|
||||
<p>
|
||||
<u>Identifiers and Contact Information</u>. This category includes names, addresses, telephone numbers, mobile numbers, email addresses, signatures, account names, dates of birth, bank account information, and other similar contact information and identifiers.
|
||||
</p>
|
||||
<p>
|
||||
<u>Commercial Information</u>. This category includes, without limitation, products and services purchased, obtained, or considered, or other purchasing or consuming histories or tendencies.
|
||||
</p>
|
||||
<p>
|
||||
<u>Internet or Other Electronic Network Activity Information</u>. This category includes, without limitation, browsing history, search history, or a consumer’s interactions with a website, application, or advertisement.
|
||||
</p>
|
||||
<p>
|
||||
<u>Geolocation Data</u>. This category includes, without limitation, location information collected when using our Services.
|
||||
</p>
|
||||
<p>
|
||||
<u>Sensitive Personal Information</u>. This category includes:
|
||||
</p>
|
||||
<ul>
|
||||
<li>racial or ethnic origin, citizenship or immigration status, or religious beliefs;</li>
|
||||
<li>mental or physical health diagnosis;</li>
|
||||
<li>sexual orientation; and</li>
|
||||
<li>information collected from a known child.</li>
|
||||
</ul>
|
||||
<p><strong>
|
||||
NOTE: Please do not provide us “sensitive personal information” or “sensitive personal data”, as those terms are defined under applicable privacy laws, unless we directly request that you do so. If you feel, after careful consideration, that it is necessary to provide us certain sensitive personal information or data, please provide us the minimum amount of such information or data that is necessary.
|
||||
</strong></p>
|
||||
<h3 id="section_1_1">
|
||||
1.1 Information You Provide Directly
|
||||
</h3>
|
||||
<p>
|
||||
We may ask you to provide certain personal information when you use the Services. This information may include contact information (such as your name and email), account information (such as your email address and, if you choose to log in through Google or Apple, the associated user ID and email address), transaction information (such as your billing address and mailing address), or user content you choose to upload (such as photos and task lists). Note that all payments are handled by our third-party payment providers who may collect relevant information in order to complete your transaction (such as your payment card, billing address, and phone number). Our current providers are Apple, Google, PayPal, and Stripe. We encourage you to review their respective privacy policies for additional information regarding their privacy practices.
|
||||
</p>
|
||||
<p>
|
||||
We may also ask you to provide the contact information of another individual, such as when you invite another user to the Services. By providing us this information, you represent to us that you do so with the consent of the individual to whom it relates. We will only use this information for the specific reason for which it was provided.
|
||||
</p>
|
||||
<h3 id="section_1_2">
|
||||
1.2 Information We Collect Automatically
|
||||
</h3>
|
||||
<p>
|
||||
We and third-party companies and business partners may use a variety of technologies, including, without limitation, cookies, pixels, embedded scripts, and session events (collectively, “cookies”) that automatically or passively collect certain information whenever you visit our Site, use our Services, or otherwise interact with us or our content (“<strong>Usage Information</strong>”). Usage Information may include the hardware model, browser, and operating system you are using, the URL or advertisement that referred you to the Site you are visiting or Service you are using, all of the areas within the Site that you visit or Services that you use, your time zone, non-precise location information, and mobile network (if applicable), among other information. In addition, we automatically collect your IP address or other unique identifier ("<strong>Device Identifier</strong>") for any computer, mobile phone or other device you use to access our Services. In some cases, we may directly collect location information through your device. You may be able to turn off the collection of location information through the settings on your device. Usage Information is generally non-identifying, but if HabitRPG associates it with you as a specific and identifiable person, HabitRPG treats it as personal information.
|
||||
</p>
|
||||
<h4>Types of Cookies</h4>
|
||||
<ul>
|
||||
<li><u>First and Third-Party Cookies</u>. First party cookies are generally placed on your computer or device by the website you are visiting. For example, we may use a first party cookie to improve Site security. Third-party cookies are placed on your computer or device by a source other than the website you are visiting in order to enable third-party features such as advertising, analytics, videos, or interactive content.</li>
|
||||
<li><u>Essential or Strictly Necessary Cookies</u>. These cookies are necessary for the Site to function and cannot be switched off in our systems. They are usually set in response to actions taken by you which amount to a request for Services, such as setting your privacy preferences, logging in, or filling in forms.</li>
|
||||
<li><u>Performance and Functionality Cookies</u>. Although these are non-essential cookies, they help the Site perform and function as designed. For example, performance and functionality cookies may help the Site display videos, enable chat sessions, or recognize whether you visited the Site before.</li>
|
||||
<li><u>Analytics Cookies</u>. These cookies track your usage of the Site. The information these cookies collect can be used for various purposes such as understanding how visitors use the Site, Site and content customization, or advertising and marketing.</li>
|
||||
<li><u>Advertising Cookies</u>. Advertising and marketing cookies perform functions such as helping customize your Site experience, personalizing ads based on your online activities and interests, measuring the effectiveness of ads, preventing an ad from reappearing, and serving you targeted advertisements. Information from these cookies may be disclosed to third parties or third parties may place these cookies on your computer or device. Advertising and marketing cookies may track your online activities.</li>
|
||||
</ul>
|
||||
<p>
|
||||
The Site uses essential, functional, and performance cookies to function and perform as designed; analytics cookies to understand how you use the Site, improve its functionality, and other related purposes; and advertising cookies to help us with our advertising and marketing activities. We and our third-party partners and service providers may collect and track information about your online activities over time and across different websites, applications, and devices.
|
||||
</p>
|
||||
<h4>Google Analytics</h4>
|
||||
<p>
|
||||
We use Google Analytics, a service which uses cookies to collect and analyze data about the use of the Services and report on activities and trends. This service may also collect data about the use of other websites, apps, and online services. You can <a
|
||||
href="https://policies.google.com/technologies/partner-sites"
|
||||
target="_blank"
|
||||
>learn about</a> Google's practices, and opt out of them, by downloading the <a
|
||||
href="https://tools.google.com/dlpage/gaoptout"
|
||||
target="_blank"
|
||||
>Google Analytics opt-out browser add-on</a>.
|
||||
</p>
|
||||
<h4>Controlling Cookies</h4>
|
||||
<p>
|
||||
You may control cookies, including preventing or stopping the installation and storage of cookies, through your browser settings and other tools. Most browsers will allow you to block or refuse cookies. However, you may need to manually adjust your preferences each time you visit a site. For more information, see the Help section of your browser. Please note that if you block certain cookies, some of the services and functionalities of our Site may not work.
|
||||
</p>
|
||||
<p class="important">
|
||||
IMPORTANT: BY USING THE SITE, YOU CONSENT TO THE PROCESSING OF ANY PERSONAL INFORMATION FOR THE PURPOSES AND FUNCTIONS DESCRIBED ABOVE.
|
||||
</p>
|
||||
<h4>Do Not Track</h4>
|
||||
<p>
|
||||
“Do Not Track” is a privacy preference that you can set in your Internet search browser that sends a signal to a website that you do not want the website operator to track certain browsing information about you. However, because our Site is not configured to detect Do Not Track signals from a user’s computer, we are unable to respond to Do Not Track requests.
|
||||
</p>
|
||||
<h3 id="section_1_3">
|
||||
1.3 Location Data
|
||||
</h3>
|
||||
<p>
|
||||
We do not collect your precise location. However, please note that we may still be able to collect or infer your approximate location through other information we collect, such as IP address. In addition, some mobile service providers may also provide us or our third-party service providers with information regarding the non-precise physical location of the device you use to access our Services.
|
||||
</p>
|
||||
<h3 id="section_1_4">
|
||||
1.4 Information Collected By and/or Disclosed to Third Parties
|
||||
</h3>
|
||||
<p>
|
||||
We may receive information about you from third parties. For example, you may have the opportunity to log in through or otherwise connect your Apple and Google accounts. Additionally, when you interact with us through social media, you will be choosing to share information about your interactions with HabitRPG with that social media service.
|
||||
</p>
|
||||
<p>
|
||||
The following chart sets out by category the personal information we may collect ("<strong>Category</strong>"), the purposes for which we may collect it ("<strong>A. Purposes</strong>"), the categories of third parties to which we may disclose it for business purposes ("<strong>B. Disclosed To</strong>"), and the categories of third parties to which we may sell it for monetary value or other valuable consideration or share it for cross-context behavioral advertising/targeted marketing ("<strong>C. Sold/Shared To</strong>")
|
||||
</p>
|
||||
|
||||
<button
|
||||
for="showThirdParties"
|
||||
class="btn btn-primary"
|
||||
@click="toggleThirdPartyInfo"
|
||||
>
|
||||
{{ showThirdPartyInfo ? "Hide Information from Third Parties" : "Show Information from Third Parties" }}
|
||||
</button>
|
||||
<div v-if="showThirdPartyInfo">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
rowspan="3"
|
||||
class="first-column"
|
||||
>
|
||||
Category of Data
|
||||
</th>
|
||||
<th>A. Purpose for Collection;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>B. Categories of Third Parties to which Personal Information may be Disclosed;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>C. Categories of Third Parties to which the Personal Information may be Sold/Shared for Targeted Advertising</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">
|
||||
<strong>Contact Information</strong> (such as your name, email address, mailing address)
|
||||
</td>
|
||||
<td>
|
||||
<h6>A. Purposes for Collection:</h6>
|
||||
<p>
|
||||
<strong>(1) Provide You the Service</strong> (to process and fulfill your purchases of products; enable you to use the Services and other products or services we offer, including maintaining your account information and verifying information you provide to us, such as that your email address is active and valid; send you transactional messages regarding your use of the Services, your purchases, and other account-related communications; respond to your inquiries and provide customer support or request feedback from you); <strong>(2) Advertising Activities and Marketing Messages</strong> (to customize and optimize content for you, such as to send you marketing communications if you have provided us your email address, as permitted by applicable law); <strong>(3) Administrative</strong> (to verify your identity, recognize you across the Services and your devices; contact you regarding your use of the Services, content, features, or products you use or request, and, in our discretion, changes to our policies); <strong>(4) Internal Business Purposes</strong> (to operate and improve the Services and our products, services, and marketing endeavors; market research; analyze the effectiveness of our marketing efforts through our third-party service providers; detect and troubleshoot problems; monetize our Services); <strong>(5) Security</strong> (to protect integrity of the Services); <strong>(6) Legal</strong> (to comply with the law; resolve disputes; enforce our agreements and policies; cooperate in governmental or other legal inquiries; fulfill regulatory reporting obligations; protect our or others' rights, assets, safety or security); <strong>(7) Business Transitions</strong> (in connection with a merger, acquisition, consolidation, bankruptcy, or other corporate transition, including during due diligence); <strong>(8) Other Purposes</strong> as disclosed at the time of collection, with your consent (where required by law), or as permitted by applicable law.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>B. Categories of Third Parties to which Personal Information may be Disclosed:</h6>
|
||||
<p>
|
||||
Analytics Partners (such as analytics companies); Social Media Platforms; Business Partners; Technology Systems Service Providers (such as webhosts, database hosts, cloud computing providers, software-as-a-service providers, and technology maintenance and repair vendors); Security Vendors; Communications Service Providers (such as email delivery and direct mail vendors); Customer Service Providers; Government Agencies and Law Enforcement/Where Required by Law (including third parties in connection with a court or other legal proceeding); Third Parties in connection with court or other legal actions; Third Parties in connection with business transitions; Third Parties to whom you agree or direct us to share your data; Other Service Providers we engage to provide services to us and/or you.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>C. Categories of Third Parties to which Personal Information may be Sold/Shared for Targeted Advertising:</h6>
|
||||
<p>
|
||||
Analytics Partners.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
rowspan="3"
|
||||
class="first-column"
|
||||
>
|
||||
Category of Data
|
||||
</th>
|
||||
<th>A. Purpose for Collection;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>B. Categories of Third Parties to which Personal Information may be Disclosed;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>C. Categories of Third Parties to which the Personal Information may be Sold/Shared for Targeted Advertising</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">
|
||||
<strong>User Account Information</strong> (such as account name, communication preferences, and account settings)
|
||||
</td>
|
||||
<td>
|
||||
<h6>A. Purposes for Collection:</h6>
|
||||
<p>
|
||||
<strong>(1) Provide You the Service</strong> (to process your purchases; to enable you to use the Services and other products or services we offer, including maintaining your account information and verifying information you provide to us, such as that your email address is active and valid; send you transactional messages regarding your use of the Services and other account-related communications; respond to your inquiries and provide customer support or request feedback from you); <strong>(2) Advertising Activities and Marketing Messages</strong> (to customize and optimize content for you, such as to send you in-app announcements and marketing communications if you have provided us your email address, as permitted by applicable law); <strong>(3) Personalization</strong> (to tailor the content we display to you on the Services, including content in emails we may send to you, to tell you about new products, promotions, opportunities, or other general information about HabitRPG or our products that we believe will be of interest to you); <strong>(4) Administrative</strong> (to verify your identity, recognize you across the Services and your devices; contact you regarding your use of the Services, content, features, or products you use or request, and, in our discretion, changes to our policies); <strong>(5) Internal Business Purposes</strong> (to operate and improve the Services and our products, services, and marketing endeavors; market research; analyze the effectiveness of our marketing efforts; detect and troubleshoot problems; understand how you use the Services including tracking traffic, usage, trends, and navigation patterns); <strong>(6) Security</strong> (to protect integrity of the Services; to investigate, prevent, and detect, and protect against misuse of our systems, abuse, fraud or other crime, or illegal activities or those that violate our policies; to detect and troubleshoot problems); <strong>(7) Legal</strong> (to comply with the law; resolve disputes; enforce our agreements and policies; cooperate in governmental or other legal inquiries; fulfill regulatory reporting obligations; protect our or others' rights, assets, safety or security); <strong>(8) Business Transitions</strong> (in connection with a merger, acquisition, consolidation, bankruptcy, or other corporate transition, including during due diligence); <strong>(9) Other Purposes</strong> as disclosed at the time of collection, with your consent (where required by applicable law), or as permitted by applicable law.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>B. Categories of Third Parties to which Personal Information may be Disclosed:</h6>
|
||||
<p>
|
||||
Technology Systems Service Providers (such as webhosts, database hosts, cloud computing providers, software- as-a-service providers, and technology maintenance and repair vendors); Security Vendors; Communications Service Providers; Customer Service Providers; Government Agencies and Law Enforcement/Where Required by Law (including third parties in connection with a court or other legal proceeding); Third Parties in connection with court or other legal actions; Third Parties in connection with business transitions; Third Parties to whom you agree or direct us to share your data; Other Service Providers we engage to provide services to us and/or you.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>C. Categories of Third Parties to which Personal Information may be Sold/Shared for Targeted Advertising:</h6>
|
||||
<p>
|
||||
This category of data is not sold or shared for targeted advertising.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
rowspan="3"
|
||||
class="first-column"
|
||||
>
|
||||
Category of Data
|
||||
</th>
|
||||
<th>A. Purpose for Collection;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>B. Categories of Third Parties to which Personal Information may be Disclosed;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>C. Categories of Third Parties to which the Personal Information may be Sold/Shared for Targeted Advertising</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">
|
||||
<strong>Demographic Information</strong> (such as your zip code, birth day/month)
|
||||
</td>
|
||||
<td>
|
||||
<h6>A. Purposes for Collection:</h6>
|
||||
<p>
|
||||
<strong>(1) Provide You the Service</strong> (to enable you to use the Services and other products or services we offer, including verifying information you provide to us); <strong>(2) Advertising Activities and Marketing Messages</strong> (to customize and optimize content for you); <strong>(3) Personalization</strong> (to tailor the content and advertising we display to you or others, on the Services or elsewhere, including content in emails we may send to you); <strong>(4) Administrative</strong> (to verify your identity, recognize you across the Services and your devices); <strong>(5) Internal Business Purposes</strong> (to operate and improve the Services and our products, services, and marketing endeavors; market research; analyze the effectiveness of our marketing efforts; detect and troubleshoot problems; understand how you use the Services including tracking traffic, usage, trends, and navigation patterns); <strong>(6) Security</strong> (to protect integrity of the Services; to investigate, prevent, and detect, and protect against misuse of our systems, abuse, fraud or other crime, or illegal activities or those that violate our policies; to detect and troubleshoot problems); <strong>(7) Legal</strong> (to comply with the law; resolve disputes; enforce our agreements and policies; cooperate in governmental or other legal inquiries; fulfill regulatory reporting obligations; protect our or others' rights, assets, safety or security); <strong>(8) Business Transitions</strong> (in connection with a merger, acquisition, consolidation, bankruptcy, or other corporate transition, including during due diligence); <strong>(9) Other Purposes</strong> as disclosed at the time of collection, with your consent (where required by applicable law), or as permitted by applicable law.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>B. Categories of Third Parties to which Personal Information may be Disclosed:</h6>
|
||||
<p>
|
||||
Social Media Platforms and Other Third Party Platforms; Third Party Business Partners; Order Fulfillment Vendors (such as payment processors); Technology Systems Service Providers (such as webhosts, database hosts, cloud computing providers, software-as-a-service providers, and technology maintenance and repair vendors); Security Vendors; Customer Service Providers; Government Agencies and Law Enforcement/Where Required by Law (including third parties in connection with a court or other legal proceeding); Third Parties in connection with court or other legal actions; Third Parties in connection with business transitions; Third Parties to whom you agree or direct us to share your data; Other Service Providers we engage to provide services to us and/or you.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>C. Categories of Third Parties to which Personal Information may be Sold/Shared for Targeted Advertising:</h6>
|
||||
<p>
|
||||
This category of data is not sold or shared for targeted advertising.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
rowspan="3"
|
||||
class="first-column"
|
||||
>
|
||||
Category of Data
|
||||
</th>
|
||||
<th>A. Purpose for Collection;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>B. Categories of Third Parties to which Personal Information may be Disclosed;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>C. Categories of Third Parties to which the Personal Information may be Sold/Shared for Targeted Advertising</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">
|
||||
<strong>Device ID/Interaction Information</strong> (such as IP address or other unique ID for any computer, mobile phone or other device used to access the Services, device information (model, browser, operating system version), URL or advertisement that referred you to the Services, any search terms you entered into a search engine that led you to the Services; areas within Services that you visit, time of day you visited the Services, your time zone, location information, and mobile network (if applicable) information)
|
||||
</td>
|
||||
<td>
|
||||
<h6>A. Purposes for Collection:</h6>
|
||||
<p>
|
||||
<strong>(1) Provide You the Service</strong> (to process and fulfill your purchases of products; to enable you to use the Services and other products or services we offer, including maintaining your account information and verifying information you provide to us, such as that your email address is active and valid; send you transactional messages regarding your use of the Services and other account-related communications); <strong>(2) Advertising Activities and Marketing Messages</strong> (to customize and optimize content for you, such as to send you in-app announcements and marketing communications if you have provided us your email address, as permitted by applicable law); <strong>(3) Personalization</strong> (to tailor the content and advertising we display to you or others, on the Services or elsewhere, including content in emails we may send to you, to tell you about new products, promotions, opportunities, or other general information about HabitRPG or our products that we believe will be of interest to you); <strong>(4) Administrative</strong> (to verify your identity, recognize you across the Services and your devices; contact you regarding your use of the Services, content, features, or products you use or request, and, in our discretion, changes to our policies); <strong>(5) Internal Business Purposes</strong> (to operate and improve the Services and our products, services, and marketing endeavors; market research; analyze the effectiveness of our marketing efforts; detect and troubleshoot problems; monetize our Services; understand how you use the Services including tracking traffic, usage, trends, and navigation patterns); <strong>(6) Security</strong> (to protect integrity of the Services; to investigate, prevent, and detect, and protect against misuse of our systems, abuse, fraud or other crime, or illegal activities or those that violate our policies; to detect and troubleshoot problems); <strong>(7) Legal</strong> (to comply with the law; resolve disputes; enforce our agreements and policies; cooperate in governmental or other legal inquiries; fulfill regulatory reporting obligations; protect our or others' rights, assets, safety or security); <strong>(8) Business Transitions</strong> (in connection with a merger, acquisition, consolidation, bankruptcy, or other corporate transition, including during due diligence); <strong>(9) Other Purposes</strong> as disclosed at the time of collection, with your consent (where required by law), or as permitted by applicable law.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>B. Categories of Third Parties to which Personal Information may be Disclosed:</h6>
|
||||
<p>
|
||||
Analytics Partners; Social Media Platforms and Other Third Party Platforms; Third Party Business Partners; Order Fulfillment Vendors (such as payment processors, fulfillment centers, delivery services, order tracking vendors); Technology Systems Service Providers (such as webhosts, database hosts, cloud computing providers, software-as- a-service providers, and technology maintenance and repair vendors); Security Vendors; Communications Service Providers; Customer Service Providers; Government Agencies and Law Enforcement/Where Required by Law (including third parties in connection with a court or other legal proceeding); Third Parties in connection with court or other legal actions; Third Parties in connection with business transitions; Third Parties to whom you agree or direct us to share your data; Other Service Providers we engage to provide services to us and/or you.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>C. Categories of Third Parties to which Personal Information may be Sold/Shared for Targeted Advertising:</h6>
|
||||
<p>
|
||||
Analytics Partners.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
rowspan="3"
|
||||
class="first-column"
|
||||
>
|
||||
Category of Data
|
||||
</th>
|
||||
<th>A. Purpose for Collection;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>B. Categories of Third Parties to which Personal Information may be Disclosed;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>C. Categories of Third Parties to which the Personal Information may be Sold/Shared for Targeted Advertising</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">
|
||||
<strong>Transaction Information</strong> (such as data about the products you purchase, obtained, or considered, customer service contacts)
|
||||
</td>
|
||||
<td>
|
||||
<h6>A. Purposes for Collection:</h6>
|
||||
<p>
|
||||
<strong>(1) Provide You the Service</strong> (to enable you to use the Services and other products or services we offer, including maintaining your account information and verifying information you provide to us; send you transactional messages regarding your use of the Services, your purchases, and other account-related communications; respond to your inquiries and provide customer support or request feedback from you); <strong>(2) Advertising Activities and Marketing Messages</strong> (to customize and optimize content for you, such as to send you in-app announcements and marketing communications if you have provided us your email address, as permitted by applicable law); <strong>(3) Personalization</strong> (to tailor the content we display to you on the Services, including content in emails we may send to you, to tell you about new products, promotions, opportunities, or other general information about HabitRPG or our products that we believe will be of interest to you); <strong>(4) Administrative</strong> (to verify your identity, recognize you across the Services and your devices; contact you regarding your use of the Services, content, features, or products you use or request, and, in our discretion, changes to our policies); <strong>(5) Internal Business Purposes</strong> (to operate and improve the Services and our products, services, and marketing endeavors; market research; analyze the effectiveness of our marketing efforts; detect and troubleshoot problems; monetize our Services; understand how you use the Services including tracking traffic, usage, trends, and navigation patterns); <strong>(6) Security</strong> (to protect integrity of the Services; to investigate, prevent, and detect, and protect against misuse of our systems, abuse, fraud or other crime, or illegal activities or those that violate our policies; to detect and troubleshoot problems); <strong>(7) Legal</strong> (to comply with the law; resolve disputes; enforce our agreements and policies; cooperate in governmental or other legal inquiries; fulfill regulatory reporting obligations; protect our or others' rights, assets, safety or security); <strong>(8) Business Transitions</strong> (in connection with a merger, acquisition, consolidation, bankruptcy, or other corporate transition, including during due diligence); <strong>(9) Other Purposes</strong> as disclosed at the time of collection, with your consent (where required by applicable law), or as permitted by applicable law.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>B. Categories of Third Parties to which Personal Information may be Disclosed:</h6>
|
||||
<p>
|
||||
Order Fulfillment Vendors (such as payment processors, fulfillment centers, delivery services, order tracking vendors); Technology Systems Service Providers (such as webhosts, database hosts, cloud computing providers, software-as- a-service providers, and technology maintenance and repair vendors); Security Vendors; Communications Service Providers; Customer Service Providers; Government Agencies and Law Enforcement/Where Required by Law (including third parties in connection with a court or other legal proceeding); Third Parties in connection with court or other legal actions; Third Parties in connection with business transitions; Third Parties to whom you agree or direct us to share your data; Other Service Providers we engage to provide services to us and/or you.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>C. Categories of Third Parties to which Personal Information may be Sold/Shared for Targeted Advertising:</h6>
|
||||
<p>
|
||||
This category of data is not sold or shared for targeted advertising.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
rowspan="3"
|
||||
class="first-column"
|
||||
>
|
||||
Category of Data
|
||||
</th>
|
||||
<th>A. Purpose for Collection;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>B. Categories of Third Parties to which Personal Information may be Disclosed;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>C. Categories of Third Parties to which the Personal Information may be Sold/Shared for Targeted Advertising</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">
|
||||
<strong>Information about your Interests and Preferences</strong> (such as information about the products you purchased, obtained, or considered)
|
||||
</td>
|
||||
<td>
|
||||
<h6>A. Purposes for Collection:</h6>
|
||||
<p>
|
||||
<strong>(1) Provide You the Service</strong> (to enable you to use the Services and other products or services we offer, including maintaining your account information and verifying information you provide to us; send you transactional messages regarding your use of the Services and other account-related communications; respond to your inquiries and provide customer support or request feedback from you); <strong>(2) Personalization</strong> (to tailor the content we display to you or others, on the Services or elsewhere, including content in emails we may send to you, to tell you about new products, promotions, opportunities, or other general information about HabitRPG or our products that we believe will be of interest to you); <strong>(3) Internal Business Purposes</strong> (to operate and improve the Services and our products, services, and marketing endeavors; market research; analyze the effectiveness of our marketing efforts; detect and troubleshoot problems; monetize our Services; understand how you use the Services including tracking traffic, usage, trends, and navigation patterns); <strong>(4) Security</strong> (to protect integrity of the Services; to investigate, prevent, and detect, and protect against misuse of our systems, abuse, fraud or other crime, or illegal activities or those that violate our policies; to detect and troubleshoot problems); <strong>(5) Legal</strong> (to comply with the law; resolve disputes; enforce our agreements and policies; cooperate in governmental or other legal inquiries; fulfill regulatory reporting obligations; protect our or others' rights, assets, safety or security); <strong>(6) Business Transitions</strong> (in connection with a merger, acquisition, consolidation, bankruptcy, or other corporate transition, including during due diligence); <strong>(7) Other Purposes</strong> as disclosed at the time of collection, with your consent (where required by applicable law), or as permitted by applicable law.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>B. Categories of Third Parties to which Personal Information may be Disclosed:</h6>
|
||||
<p>
|
||||
Social Media Platforms and Other Third Party Platforms; Third Party Business Partners; Technology Systems Service Providers (such as webhosts, database hosts, cloud computing providers, software-as-a-service providers, and technology maintenance and repair vendors); Security Vendors; Communications Service Providers; Customer Service Providers; Government Agencies and Law Enforcement/Where Required by Law (including third parties in connection with a court or other legal proceeding); Third Parties in connection with court or other legal actions; Third Parties in connection with business transitions; Third Parties to whom you agree or direct us to share your data; Other Service Providers we engage to provide services to us and/or you.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>C. Categories of Third Parties to which Personal Information may be Sold/Shared for Targeted Advertising:</h6>
|
||||
<p>
|
||||
This category of data is not sold or shared for targeted advertising.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
rowspan="3"
|
||||
class="first-column"
|
||||
>
|
||||
Category of Data
|
||||
</th>
|
||||
<th>A. Purpose for Collection;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>B. Categories of Third Parties to which Personal Information may be Disclosed;</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>C. Categories of Third Parties to which the Personal Information may be Sold/Shared for Targeted Advertising</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="3">
|
||||
<strong>Photo/Video Data, and Other User Generated Content</strong> (such as tasks, profile, chat messages)
|
||||
</td>
|
||||
<td>
|
||||
<h6>A. Purposes for Collection:</h6>
|
||||
<p>
|
||||
<strong>(1) Provide You the Service</strong> (to enable you to use the Services and other products or services we offer, including maintaining your account information and permitting you to create to do lists and upload related content; send you transactional messages regarding your use of the Services and other account-related communications; respond to your inquiries and provide customer support or request feedback from you); <strong>(2) Administrative</strong> (to verify your identity, recognize you across the Services and your devices; contact you regarding your use of the Services, content, features, or products you use or request, and, in our discretion, changes to our policies); <strong>(3) Internal Business Purposes</strong> (to operate and improve the Services and our products, services, and marketing endeavors; market research; detect and troubleshoot problems; monetize our Services; understand how you use the Services including tracking traffic, usage, trends, and navigation patterns); <strong>(4) Security</strong> (to protect integrity of the Services; to investigate, prevent, and detect, and protect against misuse of our systems, abuse, fraud or other crime, or illegal activities or those that violate our policies; to detect and troubleshoot problems); <strong>(5) Legal</strong> (to comply with the law; resolve disputes; enforce our agreements and policies; cooperate in governmental or other legal inquiries; fulfill regulatory reporting obligations; protect our or others' rights, assets, safety or security); <strong>(6) Business Transitions</strong> (in connection with a merger, acquisition, consolidation, bankruptcy, or other corporate transition, including during due diligence); <strong>(7) Other Purposes</strong> as disclosed at the time of collection, with your consent (where required by applicable law), or as permitted by applicable law.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>B. Categories of Third Parties to which Personal Information may be Disclosed:</h6>
|
||||
<p>
|
||||
Third Party Business Partners; Technology Systems Service Providers (such as webhosts, database hosts, cloud computing providers, software-as-a-service providers, and technology maintenance and repair vendors); Security Vendors; Communications Service Providers; Customer Service Providers; Government Agencies and Law Enforcement/Where Required by Law (including third parties in connection with a court or other legal proceeding); Third Parties in connection with court or other legal actions; Third Parties in connection with business transitions; Third Parties to whom you agree or direct us to share your data; Other Service Providers we engage to provide services to us and/or you.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6>C. Categories of Third Parties to which Personal Information may be Sold/Shared for Targeted Advertising:</h6>
|
||||
<p>
|
||||
This category of data is not sold or shared for targeted advertising.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2 id="section_2">
|
||||
2. Purpose and Use of Information We Collect
|
||||
</h2>
|
||||
<p>
|
||||
We may use non-personal information for any purpose, including for research and marketing purposes. We also use information that we collect, including personal information and Usage Information, as disclosed in this Privacy Policy and as follows:
|
||||
</p>
|
||||
<ul>
|
||||
<li>to provide the Services to you and allow you to use the features we offer;</li>
|
||||
<li>to verify your identity and to otherwise manage your user account;</li>
|
||||
<li>to tailor and target content, recommendations, and offers we display to you via the Services;</li>
|
||||
<li>to send you communications with information about our products and Services;</li>
|
||||
<li>to fulfill your order, send you an order confirmation, process your payment, and communicate with you about your order;</li>
|
||||
<li>to respond to your inquiries, customer service questions, feedback, or requests;</li>
|
||||
<li>to provide you with technical support;</li>
|
||||
<li>to improve our Services and for legal, regulatory, and internal business purposes; and</li>
|
||||
<li>to fulfill any other purpose consistent with this Privacy Policy.</li>
|
||||
</ul>
|
||||
<p>
|
||||
We may also use your personal information for any other purpose disclosed to you at the time of collection, with your consent (where required by applicable law), or permitted by applicable law.
|
||||
</p>
|
||||
|
||||
<h2 id="section_3">
|
||||
3. Service Providers
|
||||
</h2>
|
||||
<p>
|
||||
Our service providers may collect information on our behalf and at our direction, in order to provide Services on our behalf to help with our business activities.
|
||||
</p>
|
||||
<p>
|
||||
These companies are authorized to use your personal information only as necessary to provide these Services to us and for other purposes permitted by applicable law.
|
||||
</p>
|
||||
<p>
|
||||
Our Service Providers include, without limitation:
|
||||
</p>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<th>
|
||||
Service Provider Name
|
||||
</th>
|
||||
<th>
|
||||
Product(s)
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Google Cloud</td>
|
||||
<td>cloud computing; storage</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MongoDB</td>
|
||||
<td>database</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Heroku</td>
|
||||
<td>cloud-based testing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Amazon Web Services</td>
|
||||
<td>content storage</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hetzner</td>
|
||||
<td>translations and push notifications</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stripe</td>
|
||||
<td>payment processing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PayPal</td>
|
||||
<td>payment processing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Amazon Payments</td>
|
||||
<td>payment processing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Apple App Store</td>
|
||||
<td>app host</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Google Play Store</td>
|
||||
<td>app host</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mailchimp</td>
|
||||
<td>email marketing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Gmail</td>
|
||||
<td>internal communications</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Redislabs</td>
|
||||
<td>rate limiting</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Loggly</td>
|
||||
<td>log management and analytics</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Slack</td>
|
||||
<td>internal communications</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Amplitude</td>
|
||||
<td>analytics</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="section_4">
|
||||
4. Sweepstakes, Contents and Promotions
|
||||
</h2>
|
||||
<p>
|
||||
We may offer sweepstakes, contests, or other promotions (collectively, "<strong>Promotion(s)</strong>") that may require registration. By participating in a Promotion, you agree to the provisions, conditions, or official rules that govern the Promotion, which may contain specific requirements of you (including, except where prohibited by law, allowing the sponsor(s) of the Promotion to use your name, voice, likeness, or other indicia of persona in advertising or marketing materials). If you choose to enter a Promotion, personal information may be disclosed to co-promotion partners, third parties or the public in connection with the administration of such Promotion, including in connection with winner selection, prize fulfillment, as required by law, or as permitted by the Promotion's terms or official rules.
|
||||
</p>
|
||||
|
||||
<h2 id="section_5">
|
||||
5. Security
|
||||
</h2>
|
||||
<p>
|
||||
HabitRPG maintains commercially reasonable administrative, physical, and technical safeguards that are designed to secure your personal information; however, no data transmission over the Internet, wireless transmission, or electronic storage of data can be guaranteed to be 100% secure. HabitRPG cannot ensure or warrant the security of any data we collect. You use the Services and provide us your data at your own risk.
|
||||
</p>
|
||||
|
||||
<h2 id="section_6">
|
||||
6. Data Retention
|
||||
</h2>
|
||||
<p>
|
||||
We retain your personal information for as long as necessary to provide you Services and in accordance with our data retention schedule. We may retain your personal information for longer if it is necessary to comply with our legal or reporting obligations, resolve disputes, enforce contracts, or address other legitimate business needs, or as permitted or required by applicable law. We may also retain your personal information in a deidentified or aggregated form so that it can no longer be associated with you. To determine the appropriate retention period for your personal information, we consider various factors, such as the amount, nature, and sensitivity of your information; the potential risk of unauthorized access, use, or disclosure; the purposes for which we collect or process your personal information; and applicable legal requirements.
|
||||
</p>
|
||||
|
||||
<h2 id="section_7">
|
||||
7. General Audience Services
|
||||
</h2>
|
||||
<p>
|
||||
The Service are intended for users 13 years or older; you are not permitted to access or use the Service if you are younger than 13. We do not knowingly collect personal information from children under the age of 13 through the Service. We encourage parents and legal guardians to monitor their children's Internet usage and to help enforce our Privacy Policy by instructing their children to never provide personal information without their permission. If you have reason to believe that a child under the age of 13 has provided personal information to us, please contact us at <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>, and we will delete that information from our databases.
|
||||
</p>
|
||||
|
||||
<h2 id="section_8">
|
||||
8. Consent to International Transfer
|
||||
</h2>
|
||||
<p>
|
||||
HabitRPG is based in the United States. Please be aware that information we collect will be transferred to and processed in the United States and other countries. HabitRPG makes no representation that this Privacy Policy or the practices described in it comply with the laws of any other jurisdiction. By using the Services, or providing us with any information, you fully understand and unambiguously consent to this transfer, processing, and storage of your information in the United States and other jurisdictions for which the privacy laws may not be as comprehensive as those in the country where you reside and/or are a citizen. As a result, this information may be subject to access requests from governments, courts, or law enforcement in the United States and other countries according to laws in those jurisdictions.
|
||||
</p>
|
||||
|
||||
<h2 id="section_9">
|
||||
9. Your Choices
|
||||
</h2>
|
||||
<p>
|
||||
<em>Edit Your Information</em>: On the website, you can update the information in your user profile at any time by going to the user icon in the upper right, selecting the "Profile" option, then clicking "Edit Profile". You can update your username and email address by going to the user icon in the upper right and selecting the "Settings" option. If you are using the mobile app, you can update your user profile, username, and email by tapping the Settings gear in the menu and then selecting the "My Account" option.
|
||||
</p>
|
||||
<p>
|
||||
<em>Reset Your Account</em>: You can fully delete or reset your account by selecting the user icon in the upper right, selecting the "Settings", and then looking under "General Settings". You can fully delete or reset your account on the mobile apps by tapping the Settings gear in the menu and then selecting the "My Account" submenu. Please note that in order to fully delete all data associated with your account, you will need to email us at <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>. Note that we may be required to retain certain data about you to comply with applicable laws.
|
||||
</p>
|
||||
<p>
|
||||
<em>Newsletter</em>: You may also sign-up to receive our email newsletter. If you would like to discontinue receiving this information, you may update your email preferences by using the "Unsubscribe" link found in emails we send to you, or by contacting us. Please note that we reserve the right to send you certain communications relating to your account or use of the Services, such as administrative and services announcements. These transactional account messages may be unaffected if you choose to opt out from marketing emails.
|
||||
</p>
|
||||
<p>
|
||||
<em>Push Notifications</em>: With your consent, we may send promotional and non-promotional push notifications or alerts to your mobile device. You can elect to stop receiving those messages by changing the notification settings in the app or on your mobile device.
|
||||
</p>
|
||||
<p>
|
||||
<em>Other Privacy Rights</em>: Certain jurisdictions provide additional rights. Please see the "<a href="#section_11">Jurisdiction-Specific Rights</a>" section below for more information.
|
||||
</p>
|
||||
|
||||
<h2 id="section_10">
|
||||
10. Changes to This Privacy Policy
|
||||
</h2>
|
||||
<p>
|
||||
To the extent permitted by applicable law, we reserve the right to change or modify this Privacy Policy at our discretion at any time. We will notify you of any material changes by posting the changed or modified Privacy Policy on our Services. We may also provide notice to you in other ways, such as through contact information you have provided. Any changes will be effective immediately upon the posting of the revised Privacy Policy unless otherwise specified. Your continued use of the Services after the effective date of the revised Privacy Policy (or such other act as specified in the revised Privacy Policy) will, to the fullest extent permitted by applicable law, constitute your consent to those changes. However, we will provide notice and obtain your consent (opt-in or opt-out) if required by law. We encourage you to regularly review this Privacy Policy for the latest information on our privacy practices.
|
||||
</p>
|
||||
|
||||
<h2 id="section_11">
|
||||
11. Jurisdiction-Specific Rights
|
||||
</h2>
|
||||
<p><strong><u>California, Nebraska, and Texas Residents</u></strong></p>
|
||||
<p>
|
||||
This section applies only to California, Nebraska, and Texas residents. It supplements and amends the information contained in the Policy with respect to such individuals. The other provisions of the Policy continue to apply, except as modified in this section.
|
||||
</p>
|
||||
<p>
|
||||
<em>Shine the Light [California residents only]</em>. California Civil Code Section 1798.83 permits you to request information regarding the disclosure of your personal information by us to third parties for the third parties’ direct marketing purposes. Such requests must be submitted to us in accordance with the instructions in the Contact Us section of this Policy. Please mention when contacting us that you are making a “California Shine the Light” inquiry. Within 30 days of receiving such a request, we will provide a list of the categories of personal information disclosed to third parties for third-party direct marketing purposes during the immediately preceding calendar year, along with the names and addresses of these third parties. This request may be made no more than once per calendar year. We reserve our right not to respond to requests submitted other than in accordance with the instructions specified in this paragraph.
|
||||
</p>
|
||||
<p>
|
||||
<em>Eraser Law [California residents only]</em>. If you are a California resident under the age of 18, and a registered user of any site where this policy is posted, California law permits you to request and obtain removal of content or information you have publicly posted. You may submit your request using the contact information at the end of this Policy. Please be aware that such request does not ensure complete or comprehensive removal of the content or information you have posted and that there may be circumstances in which the law does not require or allow removal even if requested.
|
||||
</p>
|
||||
<p>
|
||||
<u><em>Your Rights</em></u>
|
||||
</p>
|
||||
<p>
|
||||
You may have certain rights related to your personal information, subject to certain exceptions (including, as applicable and without limitation, safety, security, and protecting the rights of other users). Specifically:
|
||||
</p>
|
||||
<p>
|
||||
<em>Right to Confirm and Access</em>. You may have the right to request that we confirm whether we process your personal information and, if we do, that we grant you access to that information. If you previously provided us your personal information, and that information is available in a digital format, you may have the right to obtain a copy of the information in a portable and, to the extent technically feasible, readily usable format that allows you to transmit the information to another person without hindrance.
|
||||
</p>
|
||||
<p>
|
||||
<em>Right to Delete</em>. You may have the right to request that we delete your personal information from our records, subject to certain exceptions.
|
||||
</p>
|
||||
<p>
|
||||
<em>Right to Correct</em>. You may have the right, subject to certain limitations, to request that we correct any inaccurate personal information we maintain about you.
|
||||
</p>
|
||||
<p>
|
||||
<em>Opt - Out of the “ Sale” of Personal Information or Use of Such Information for “Targeted Advertising” or “Profiling”</em>. We engage in common marketing and advertising practices to provide more relevant content and ads to users of our Site and Services. Certain of these practices may involve the “selling” of personal information, or the use of such information for “targeted advertising” or “profiling,” as those terms are defined in the Texas Data Privacy and Security Act (“TDPSA”) and the Nebraska Data Privacy Act. We do not sell personal information under the more commonly understood meaning of that word—i.e., providing personal information to third parties in exchange for money. Nor do we have actual knowledge of selling personal information of minors under the age of 16. To opt-out of the selling of your personal information, or use of that information for targeted advertising or profiling, please submit a request to <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>. Note: We also treat Global Privacy Control browser signals as opt-out of sale/disclosure for targeted advertising or profiling requests. To opt-out via the Global Privacy Control, please follow the instructions available <a
|
||||
href="https://globalprivacycontrol.org/"
|
||||
target="_blank"
|
||||
>here</a>.
|
||||
</p>
|
||||
<p>
|
||||
<em>Right to Consent to Use or Disclosure of Sensitive Personal Information</em>. Where required by applicable law, we will process your sensitive personal information only with your consent.
|
||||
</p>
|
||||
<p>
|
||||
<em>Right Against Discrimination</em>. You have the right not to be discriminated against for exercising any of the rights described in this section. For example, we generally will not provide you a different level or quality of goods or services if you exercise these rights.
|
||||
</p>
|
||||
<p>
|
||||
<em>Submitting Data Subject Rights Requests</em>. To submit a data subject rights request, please email us at <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>. We reserve the right to only respond to verifiable requests. To verify your identity, we may ask you to verify personal information we already have on file for you. If we cannot verify your identity from the information we have on file, we may request additional information from you, which we will only use to verify your identity, and for security or fraud-prevention purposes. You will need to describe your request with sufficient detail to allow us to review, understand, assess, and respond to it, and we may not be able to respond to your request, or provide you with personal information, if we cannot verify your identity or authority to make the request and confirm the personal information relates to you. You may authorize another person to act on your behalf with respect to your rights under this section. We reserve the right to deny requests from persons claiming to be authorized agents that do not submit sufficient proof of their authorization.
|
||||
</p>
|
||||
<p>
|
||||
<em>Our Response</em> . You may have the right, subject to applicable law, to submit up to two (2) requests per year free of charge. We reserve the right to charge a fee to process or respond to your request if it is excessive, repetitive, or manifestly unfounded. If we determine that a request warrants a fee, we will attempt to notify you as to why we made that decision and provide a cost estimate before completing your request. We will endeavor to respond to verifiable requests within forty-five (45) calendar days of receipt, but we may require an extension of up to forty-five (45) additional calendar days to respond and we will notify you of the need for the extension.
|
||||
</p>
|
||||
<p>
|
||||
If you have an account with us, we will deliver our written response to that account. If you do not have an account with us, we will deliver our written response by email. In the event we deny your request, in whole or in part, we will explain the bases for that denial.
|
||||
</p>
|
||||
<p>
|
||||
<em>Appeal of Our Response</em>. In the event you believe we have erroneously denied your request, in full or in part, you may, within 60 days of receipt of that denial, submit an appeal to <a href="mailto:privacy@habitica.com">privacy@habitica.com</a>. In your appeal submission, please explain why you believe our decision to deny your request was incorrect and please provide any additional information you believe we should consider in connection with your appeal. Within 60 days of receipt of your appeal, we will advise you in writing of any action we have taken, or refrained from taking, in response to your appeal, along with an explanation of why we have taken, or refrained from taking, such action.
|
||||
</p>
|
||||
|
||||
<p><strong><u>Nevada Residents</u></strong></p>
|
||||
<p>
|
||||
Nevada residents may opt out of the sale of certain “covered information” collected by operators of websites or online services. We currently do not sell covered information, as “sale” is defined by such law, and do not have plans to do so. In accordance with Nevada law, you may submit to us a verified request instructing us not to sell your covered information by sending an email to <a href='mailto:privacy@habitica.com'>privacy@habitica.com</a>.
|
||||
</p>
|
||||
<p><strong><u>Notice to United Kingdom/European/Switzerland Residents.</u></strong></p>
|
||||
<p>
|
||||
If you are a resident of the United Kingdom (UK), European Economic Area (EEA), or of Switzerland, the following information applies.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Purposes of processing and legal basis for processing:</strong> As explained above, we process personal information in various ways depending upon your use of our Services. We process personal information on the following legal bases: (1) with your consent; (2) as necessary to perform our agreement to provide the Services; (3) compliance with our legal obligations; and (4) as necessary for our legitimate interests in providing the Service where those interests do not override your fundamental rights and freedoms related to data privacy such as for:
|
||||
<ul>
|
||||
<li>preventing fraud;</li>
|
||||
<li>ensuring network and information security, including preventing unauthorized access to our computer and electronic communication systems and preventing malicious software distribution;</li>
|
||||
<li>supporting internal administration;</li>
|
||||
<li>improving and developing the Services; and</li>
|
||||
<li>conducting data analytics analyses to review and better understand consumer interaction.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<strong>Right to lodge a complaint:</strong> Users that reside in the UK, EEA, or Switzerland have the right to seek information and assistance or lodge a complaint about our data collection and processing actions with the supervisory authority where they reside. Contact details for data protection authorities are available here. UK: <a
|
||||
href="https://ico.org.uk/"
|
||||
target="_blank"
|
||||
>https://ico.org.uk/</a> EEA: <a
|
||||
href="https://edpb.europa.eu/about-edpb/board/members_en"
|
||||
target="_blank"
|
||||
>https://edpb.europa.eu/about-edpb/board/members_en</a> Switzerland: <a
|
||||
href="https//www.edoeb.admin.ch/edoeb/en/home/deredoeb/kontakt.html"
|
||||
target="_blank"
|
||||
>https//www.edoeb.admin.ch/edoeb/en/home/deredoeb/kontakt.html</a>.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Transfers:</strong> Personal information we collect may be transferred to, and stored and processed in, the United States or any other country in which we or our affiliates or subcontractors maintain facilities. Transfers of personal data to a third country without an adequacy decision (as that term is understood pursuant to Article 45 of GDPR) are required to be subject to appropriate safeguards such as standard contractual clauses. In certain cases, we rely on your consent to facilitate transfer, processing, and storage of your data in the United States and other jurisdictions, where laws regarding processing of personal information may be less stringent than the laws in the EEA, UK, and Switzerland.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Withdraw consent:</strong> If we have collected personal information with your consent, you have the right to withdraw that consent at any time.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Access:</strong> You have the right to request access to personal information we collected about you and information about its sources, purposes, and sharing.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Correction:</strong> You have the right to request that we correct the personal information we hold about you if it is inaccurate or incomplete.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Erasure:</strong> You have the right to request that we erase data we have collected from you. Please note that we may have a reason to deny your deletion request or delete data in a more limited way than you anticipated, e.g., because of a legal obligation to retain it.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Portability:</strong> You have the right, in certain circumstances, to request that we provide your personal information to you in a format that can be transferred to another entity.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Restrict Processing:</strong> You have the right, in certain circumstances, to request that we limit our processing of your personal information if you are (1) contesting the accuracy of your personal information, (2) asserting that our processing is unlawful; (3) asserting that we no longer need to keep the information for reasons related to the establishment, exercise, or defense of legal claims, or you object to our processing. You have the right, in certain circumstances, to request that we limit our processing of your personal information if you are contesting the accuracy of your personal information; asserting that our processing is unlawful; asserting that we no longer need to keep the information for reasons related to the establishment, exercise, or defense of legal claims, or you object to our processing
|
||||
</p>
|
||||
<p>
|
||||
<strong>Objection:</strong> You have the right to object to our processing if we are processing your personal information based on legitimate interests, using your personal information for direct marketing (including profiling), or processing your personal information for purposes of scientific or historical research and statistics.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Verification Procedures:</strong> We must verify your identity for everyone's protection, so we may require you to provide us with verification information prior to accessing any records containing personal information about you. We do this by asking you to provide personal identifiers we can match against information we may have collected from you previously and confirm your request using the email stated in the request.
|
||||
</p>
|
||||
<p>
|
||||
We will use the information you provide for verification only for the purpose of verification. We may have a reason under the law why we do not have to respond to your request or respond to it in a more limited way than you anticipated. If we do, we will explain that to you in our response.
|
||||
</p>
|
||||
|
||||
<h2 id="section_12">
|
||||
12. Contact Us
|
||||
</h2>
|
||||
<p>
|
||||
If you have any questions or concerns about this Privacy Policy, please contact us at <a href="mailto:privacy@habitica.com">privacy@habitica.com</a> with “Privacy Policy” in the subject line. You may also write to us at:
|
||||
</p>
|
||||
<address class="ml-4">
|
||||
HabitRPG, Inc. c/o Workbar<br>
|
||||
120 Washington Street Suite 202<br>
|
||||
Salem, MA 01970-6396
|
||||
</address>
|
||||
</div>
|
||||
<!-- eslint-enable max-len -->
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/colors.scss';
|
||||
h4 {
|
||||
text-decoration: underline;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.important {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.first-column {
|
||||
width: 25%
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PrivacyReview',
|
||||
data () {
|
||||
return {
|
||||
showThirdPartyInfo: true,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toggleThirdPartyInfo () {
|
||||
this.showThirdPartyInfo = !this.showThirdPartyInfo;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
244
website/client/src/components/static/termsReview.vue
Normal file
244
website/client/src/components/static/termsReview.vue
Normal file
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<!-- eslint-disable max-len -->
|
||||
<div class="container-fluid">
|
||||
<h1>Terms of Service</h1>
|
||||
<p class="strong pagemeta">
|
||||
Last Updated September 1, 2025.
|
||||
</p>
|
||||
<p>Thanks for choosing Habitica!</p>
|
||||
<p>
|
||||
Our Service is provided by HabitRPG, Inc. ("HabitRPG"). By accepting these Terms of Service and our Privacy Policy located at: <a
|
||||
href="https://habitica.com/static/privacy"
|
||||
target="_blank"
|
||||
>https://habitica.com/static/privacy</a> (collectively, the "Agreement"), using our website, Habitica.com, or our other features or services (collectively, “the Services”, or otherwise manifesting your assent to the Agreement, you acknowledge that you have read, understood, and agree to be legally bound by the Agreement. If you do not agree to (or cannot comply with) the Agreement, you are not permitted to access or use the Service. By accepting or agreeing to this Agreement on behalf of a company or other legal entity, you represent and warrant that you have the authority to bind that company or other legal entity to the Agreement and, in such event, "you" and "your" will refer and apply to that company or other legal entity. You further represent and warrant that your assent to this Agreement constitutes an electronic signature as defined by the Electronic Signatures in Global and National Commerce Act (“E-Sign”) and the Uniform Electronic Transactions Act (“UETA”) and that you have formed, executed, entered into, and accepted the terms of and otherwise authenticated the Agreement and acknowledged and agreed that the Agreement is an electronic record for purposes of E- Sign, UETA, and the Uniform Computer Information Transactions Act and, as such, is completely valid, has legal effect, is enforceable, and is binding on, and non- refutable by, you and/or any entity on whose behalf you are acting.
|
||||
</p>
|
||||
<p class="strong">
|
||||
THE SECTIONS BELOW TITLED "BINDING ARBITRATION' AND "CLASS ACTION WAIVER" CONTAIN A BINDING ARBITRATION AGREEMENT AND CLASS ACTION WAIVER. THEY AFFECT YOUR LEGAL RIGHTS. PLEASE READ THEM CAREFULLY.
|
||||
</p>
|
||||
<h2>Changes to the Terms of Service</h2>
|
||||
<p>
|
||||
These Terms of Service are effective as of the last updated date stated at the top of this page. We may change these Terms of Service from time to time with or without notice to you. By accessing the Service after we make any such changes to this Terms of Service, you are deemed to have accepted such changes. Please be aware that, to the extent permitted by applicable law, our use of the information collected is governed by the Terms of Service in effect at the time we collect the information. Please refer back to this Terms of Service on a regular basis.
|
||||
</p>
|
||||
<h2>Intellectual Property</h2>
|
||||
<p>
|
||||
Our Services allow you to upload, store, send, download, or receive content, including but not limited to information, text, graphics, artwork, or other material ("Content"). You retain ownership of any intellectual property rights that you had in your Content prior to using it in connection with the Service. You hereby grant HabitRPG a worldwide, perpetual, irrevocable, sublicenseable, transferable, assignable, non-exclusive, and royalty-free right and license to use, reproduce, distribute, adapt, modify, translate, create derivative works of, publicly perform, publicly display, digitally perform, make, have made, sell, offer for sale, and import your Content, including all intellectual property rights therein. You represent, warrant, and agree that your Content does not and will not violate any third-party intellectual property, privacy, or other rights, and that you have all right, title and interest in and to your Content required to grant us the license above. We reserve the right at all times, but have no obligation, to delete or refuse to use or distribute any Content on or through the Service, including your Content.
|
||||
</p>
|
||||
<p>
|
||||
HabitRPG appreciates receiving your ideas, comments, suggestions and requests regarding the Service ("Unsolicited Ideas"). By submitting your Unsolicited Ideas (in any form or medium), you are transferring all your right, title and interest therein exclusively to HabitRPG. As the owner of Unsolicited Ideas, we have unrestricted rights to use, disclose and process the Unsolicited Ideas for any purpose whatsoever without any compensation to you. You also give up any claim that any use, disclosure, and/or processing by us or our licensees of your Unsolicited Ideas violates any of your rights, including moral rights, privacy rights, rights to publicity, proprietary or other rights, and rights to credit for the material or ideas set forth therein.
|
||||
</p>
|
||||
<p>
|
||||
<strong>DMCA Notice</strong>. We respect the intellectual property rights of third parties. We respond to notices of alleged copyright infringement according to the Digital Millennium Copyright Act (“DMCA”) at 17 U.S.C. § 512 et seq. Regardless of whether or not the we believe that we are liable for any copyright infringement for which we are provided notice, our response may include removing or disabling access to material claimed to be the subject of infringing activity and/or terminating an individual’s access to the Service, in our sole discretion and operating within the parameters of the DMCA.
|
||||
</p>
|
||||
<p>
|
||||
If you believe that your work has been copied in a manner that constitutes copyright infringement, please contact us at <a href="mailto:admin@habitica.com">admin@habitica.com</a> with the following information:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Your name, address, telephone number, and email address;</li>
|
||||
<li>A description of the copyrighted work that you claim has been infringed;</li>
|
||||
<li>A description of the allegedly infringing material and where it is located on the Service;</li>
|
||||
<li>A statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agents, or the law;</li>
|
||||
<li>A statement by you under penalty of perjury that your notice is accurate, that you are the copyright owner, or that the copyright holder has authorized you to act on its behalf; and</li>
|
||||
<li>Your written or electronic signature attesting to the above.</li>
|
||||
</ul>
|
||||
<p>
|
||||
If your content has been removed from the Service in response to our receipt of a DMCA Notification as outlined above, and you believe the removal was inappropriate, you may submit a DMCA Counter-Notification by contacting us using the information above with the following information:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Your name, address, telephone number, and email address;</li>
|
||||
<li>A statement that you consent to the jurisdiction of Federal District Court for the judicial district in which your address is located, or if your address is outside of the United States, for any judicial district for which jurisdiction for us would be appropriate, and that you will accept service of process from the person who submitted the DMCA notification or an agent of such person;</li>
|
||||
<li>A description of the material that has been removed or to which access has been disabled and the location at which the material appeared before it was removed or access to it was disabled;</li>
|
||||
<li>A statement by you under penalty of perjury that you have a good faith belief that the material was removed or disabled as a result of mistake or misidentification of the material to be removed or disabled; and</li>
|
||||
<li>Your written or electronic signature attesting to the above.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Software in our Service</h2>
|
||||
<p>
|
||||
When the Service requires or includes downloadable software ("Software"), it may update automatically on your device once a new version or features become available to you. Some platforms may let you adjust your automatic update settings.
|
||||
</p>
|
||||
<p>
|
||||
HabitRPG hereby grants you a non-commercial, worldwide, royalty-free, non-assignable and non-exclusive license to use the Software provided by HabitRPG as part of the Service. You may not copy, modify, distribute, sell, or lease any part of our Service or included Software unless you are explicitly allowed to do so by the GPL-3.0 license, or you have our written permission to do so with respect to those parts not covered by the open-source license.
|
||||
</p>
|
||||
<p>
|
||||
Third party applications may use one of the permitted logos and signifiers in order to represent their compatibility with the Service, but may not claim formal association with and/or impersonate HabitRPG or our staff without prior written consent. Third Party applications, the companies that own or provide them, and their employees and agents, are not authorized to make any promises or representations on our behalf, or change the terms of this Agreement.
|
||||
</p>
|
||||
<p>
|
||||
We allow for personal, non-commercial uses like fanart under Commercial Commons License CC-NC-SA 3.0 terms.
|
||||
</p>
|
||||
<p>
|
||||
Outside the above explicitly allowed use cases, you may not use our trademarks, service marks, trade names, logos, domain names, taglines, or trade dress without a signed written contract with us granting you a license to do so.
|
||||
</p>
|
||||
|
||||
<h2>Modifying and Termination of Service</h2>
|
||||
<p>
|
||||
HabitRPG reserves the right, in its sole discretion, to add, modify, or remove functionalities or features from the Service, and improve, change and/or update the Service. We may also suspend or terminate the Service at any time, with or without notice to you.
|
||||
</p>
|
||||
<p>
|
||||
You can choose to stop using our Service at any time. We may suspend or cease providing the Service to you at any time, including if we determine in our sole discretion, that:
|
||||
</p>
|
||||
<ul>
|
||||
<li>You have violated any part of this Agreement, the Privacy Policy, or the Community Guidelines;</li>
|
||||
<li>We have stopped offering the Service in your region; or</li>
|
||||
<li>Doing so would be in the best interests of our community, the Service, or the rights of a third party.</li>
|
||||
</ul>
|
||||
<p>
|
||||
If your account is terminated, you will no longer have access to it, including to any of the associated data or Content. You will not be entitled to any refunds and we will have no liability to you. We also reserve the right to terminate any other accounts you may have created, as well as access to any other HabitRPG Service (also without refunds or liability to you).
|
||||
You understand and agree that using the Service comes with the risk that your account may be terminated or suspended at our discretion and at any time. Please keep this risk in mind and comport yourself appropriately.
|
||||
</p>
|
||||
|
||||
<h2>API</h2>
|
||||
<p>
|
||||
You may access your Service data via the Application Program Interface ("API"). By using API you are automatically bound by the Agreement.
|
||||
</p>
|
||||
|
||||
<h2>Links to Third-Party Sites</h2>
|
||||
<p>
|
||||
The Service may contain links to other web sites (“Linked Sites”). The Linked Sites are not under our control and we are not responsible for the contents of any Linked Site, including, without limitation, any link contained in a Linked Site, or any changes or updates to a Linked Site.
|
||||
</p>
|
||||
<p>
|
||||
By providing these links, we do not endorse, sponsor, or recommend such sites or the materials disseminated by or services provided by them, and are not responsible for the materials, services, or other situations at or related to or from any other site. We are not responsible for webcasting or any other form of transmission received from any Linked Site. We are providing these links to you only as a convenience, and the inclusion of any link does not imply endorsement by us of the Linked Site or any association with its operators. We reserve the right to disable links from any third-party sites to the Service.
|
||||
</p>
|
||||
<p>
|
||||
Please exercise discretion while using the Service. You should be aware that when you are using the Service, you could be directed to other sites that are beyond our control. There are links to other sites from the Service pages that take you outside of the Service. These other sites may send their own cookies to users, collect data, solicit personal information, or contain information that you may find inappropriate or offensive.
|
||||
</p>
|
||||
|
||||
<h2>Links to Third-Party Integrations</h2>
|
||||
<p>
|
||||
We may provide links to third-party integrations. Third-party integrations are websites or platforms that synchronize with our Service to provide you with additional functionality, tools, or services, such as delivering content based on your location.
|
||||
</p>
|
||||
<p>
|
||||
You acknowledge and agree that we are not responsible for the availability of such sites or resources and do not endorse and are not responsible or liable for any content, advertising, goods, services, or other materials on, available through, or provided by such sites or resources.
|
||||
</p>
|
||||
<p>
|
||||
We are not responsible for the privacy or other practices of such sites and cannot guarantee the security of any personal information that you provide to such sites or that such sites collect. We encourage you to review the privacy policies and terms and conditions on those linked sites.
|
||||
</p>
|
||||
|
||||
<h2>Using Our Service</h2>
|
||||
<p>
|
||||
You must follow any policies made available to you within the Service, including but not limited to the Terms of Service, Privacy Policy, and Community Guidelines. You may only use our Service as permitted by law. HabitRPG may investigate and/or suspend or terminate our Service to you at any time if we find your use of our Service violates the Agreement, applicable law, and/or any of our policies.
|
||||
</p>
|
||||
<p>
|
||||
Using our Service does not grant you ownership of any intellectual property rights in our Service or the content you may have access to. You may not use any copyrighted content in our Service unless you obtain permission from the content owner and/or are otherwise permitted by law. The Agreement does not grant you the right to use any branding or logos used in our Service. Our Service may display some logos, trademarks, or branding materials that are not the property of HabitRPG. Such content is the sole property of the entity that makes it available.
|
||||
</p>
|
||||
<p>
|
||||
You may not abuse and/or misuse our Service, including but not limited to the following actions:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Using the Service for any unlawful purposes or activities;</li>
|
||||
<li>Uploading any content to the Service in violation of any applicable law, including but not limited to intellectual property laws, privacy laws, and publicity laws;</li>
|
||||
<li>Sending unsolicited promotions or advertisements;</li>
|
||||
<li>Accessing or tampering with the Service's server systems;</li>
|
||||
<li>Interfering with or disrupting the access of any user, host, or network;</li>
|
||||
<li>Abusing or submitting excessively frequent requests to the Service via the API</li>
|
||||
<li>Spamming chat, whether for personal or commercial purposes, by disrupting the flow of conversation with repeated postings;</li>
|
||||
<li>Impersonating any person, business, or entity, including an employee of HabitRPG, or member of the Habitica moderation team, or communicating in any way that makes it appear that the communication originates from Habitica staff or HabitRPG;</li>
|
||||
<li>Transmitting or communicating any content which, in the sole and exclusive discretion of HabitRPG, is deemed offensive, including language that is unlawful, harmful, threatening, abusive, harassing, defamatory, vulgar, obscene, sexually explicit, or racially, ethically, or otherwise objectionable,</li>
|
||||
<li>Participating in any action which, in the sole and exclusive judgment of HabitRPG, defrauds any other user of the Service, including by scamming or social engineering; or</li>
|
||||
<li>Inducing or encouraging others to violate the Community Guidelines or the Agreement.</li>
|
||||
</ul>
|
||||
<p>
|
||||
HabitRPG, in its sole discretion, will determine what constitutes abuse and/or misuse of our Service.
|
||||
</p>
|
||||
|
||||
<h2>Premium Service and Payments</h2>
|
||||
<p>
|
||||
You may choose our free Service or paid Service ("Premium") depending on your needs. We do not guarantee when, if ever, Premium features will be available in the free Service. You may upgrade from free Service to Premium at any time by any of the following methods:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Web: Selecting the user icon in the top right corner and selecting "Subscription" from the dropdown menu,</li>
|
||||
<li>Web: Clicking the green gem icon in the navigation bar at the top of the screen and following instructions to Subscribe or Buy Gems,</li>
|
||||
<li>Android: Tap the menu icon in the top left corner of the main screen and select “Purchase Gems” or “Subscription”. Follow the instructions to make a purchase.</li>
|
||||
<li>iOS: Tap the menu icon in the lower right and select “Purchase Gems” or “Subscription”. Follow the instructions to make a purchase.</li>
|
||||
</ul>
|
||||
<p>
|
||||
You will be charged the amount shown on Pricing before you can access Premium Service. All prices shown on Pricing are inclusive of any applicable sales taxes, levies, value-added taxes, or duties imposed by taxing authorities, and you are responsible for payment of all such taxes, levies, or duties. We may revise the Pricing at any time and may, from time to time, modify, amend, or supplement our fees and fee-billing methods. Such changes shall be effective upon posting on the Pricing page or elsewhere in the Service. If there is a dispute regarding payment of fees to us, we reserve the right to terminate or suspend your account at our sole discretion.
|
||||
</p>
|
||||
<p>
|
||||
BY PURCHASING PREMIUM YOU EXPRESSLY UNDERSTAND AND AGREE TO OUR REFUND POLICY:
|
||||
</p>
|
||||
<p>
|
||||
WITHIN THIRTY (30) DAYS OF YOUR PREMIUM PAYMENT DATE AS SHOWN ON YOUR PAYMENT BILL, YOU CAN REQUEST A FULL REFUND BY CONTACTING US AT <a href="mailto:admin@habitica.com">ADMIN@HABITICA.COM</a>. AFTER THIRTY (30) DAYS OF YOUR PREMIUM PAYMENT DATE, ANY PAYMENT REFUND IS SOLELY SUBJECT TO OUR DISCRETION. THE REFUND SHALL BE YOUR SOLE AND EXCLUSIVE REMEDY.
|
||||
</p>
|
||||
<p>
|
||||
FOR ANY CUSTOMER WHO PURCHASED PREMIUM IN APPLE INC.'s APP STORE ("APP STORE"), PLEASE CONTACT APPLE INC.'s SUPPORT TEAM: <a
|
||||
href="https://reportaproblem.apple.com"
|
||||
target="_blank"
|
||||
>https://reportaproblem.apple.com</a>. APPLE'S APP STORE DOES NOT ALLOW DEVELOPERS TO ISSUE REFUNDS FOR APP STORE PURCHASES MADE BY CUSTOMERS.
|
||||
</p>
|
||||
|
||||
<h2>Warranty Disclaimer and Limitation on Liability</h2>
|
||||
<p>
|
||||
THE SERVICE AND ANY CONTENT MADE AVAILABLE BY HABITRPG VIA THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT ANY WARRANTIES OF ANY KIND, INCLUDING, WITHOUT LIMITATION, THAT THE SERVICE OR CONTENT WILL OPERATE ERROR-FREE OR THAT THE SERVICE OR CONTENT OR ITS SERVERS ARE FREE OF COMPUTER VIRUSES OR SIMILAR CONTAMINATION OR DESTRUCTIVE FEATURES.
|
||||
</p>
|
||||
<p>
|
||||
WE DISCLAIM ALL WARRANTIES, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF TITLE, MERCHANTABILITY, NON-INFRINGEMENT OF THIRD PARTIES' RIGHTS, AND FITNESS FOR PARTICULAR PURPOSE AND ANY WARRANTIES ARISING FROM A COURSE OF DEALING, COURSE OF PERFORMANCE, OR USAGE OF TRADE.
|
||||
</p>
|
||||
<p>
|
||||
WE RESERVE THE RIGHT TO MAKE CHANGES, CORRECTIONS, AND/OR IMPROVEMENTS TO THE SERVICE OR THE CONTENT AT ANY TIME WITHOUT NOTICE. IN CONNECTION WITH ANY WARRANTY, CONTRACT, OR COMMON LAW TORT CLAIMS: (I) WE AND OUR LICENSORS SHALL NOT BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST PROFITS, OR DAMAGES RESULTING FROM LOST DATA OR BUSINESS INTERRUPTION RESULTING FROM THE USE OR INABILITY TO ACCESS AND USE THE SERVICE OR CONTENT POSTED BY HABITRPG, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; AND (II) ANY DIRECT DAMAGES THAT YOU MAY SUFFER AS A RESULT OF YOUR USE OF THE PLATFORM SHALL BE LIMITED TO THE GREATER OF (I) MONIES YOU HAVE PAID US IN CONNECTION WITH YOUR USE OF THE PLATFORM DURING THE TWELVE (12) MONTHS IMMEDIATELY PRECEDING THE EVENTS GIVING RISE TO THE CLAIM, OR (II) ONE HUNDRED US DOLLARS ($100).
|
||||
</p>
|
||||
<p>
|
||||
SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES. THEREFORE, SOME OF THE ABOVE LIMITATIONS ON WARRANTIES IN THIS SECTION MAY NOT APPLY TO YOU. NOTHING IN THIS AGREEMENT SHALL AFFECT ANY NON-WAIVABLE STATUTORY RIGHTS THAT APPLY TO YOU.
|
||||
</p>
|
||||
|
||||
<h2>Indemnification</h2>
|
||||
<p>
|
||||
You agree to defend, indemnify, and hold us and our officers, directors, employees, agents, successors, licensees, licensors, and assigns harmless from and against any damages, liabilities, losses, expenses, claims, actions, and/or demands, including, without limitation, reasonable legal and accounting fees, arising or resulting from: (i) your breach of any of your representations, warranties or other obligations under this Agreement; (ii) your use or misuse of the Service or content posted or made available by HabitRPG; and/or (iii) your violation of any third-party rights in connection with your use of the Service, including without limitation any copyright, trademark, property, publicity, or privacy right. We shall provide notice to you of any such claim, suit, or proceeding and shall assist you, at your expense, in defending any such claim, suit, or proceeding. We reserve the right to participate in the defense (at our expense) of any matter that is subject to indemnification under this section. In such case, you agree to cooperate with any reasonable requests assisting our defense of such matter.
|
||||
</p>
|
||||
|
||||
<h2>Electronic Communications Privacy Act Notice (18 U.S.C. 2701-2711)</h2>
|
||||
<p>
|
||||
We make no guaranty of confidentiality or privacy with respect to any communication or information transmitted via the Service. We will not be liable for the privacy of the information, e-mail addresses, registration, and identification information, disk space, communications, confidential or trade-secret information, or any other content transmitted over networks accessed by the Service, or otherwise connected with your use of the Service.
|
||||
</p>
|
||||
|
||||
<h2>Compliance with Applicable Laws</h2>
|
||||
<p>
|
||||
The Service is based in the United States. We make no claims concerning whether the Service or posted content may be downloaded, viewed, or be appropriate for use outside of the United States. If you access the Service or such content from outside of the United States, you do so at your own risk. Whether inside or outside of the United States, you are solely responsible for ensuring compliance with the laws of your specific jurisdiction.
|
||||
</p>
|
||||
|
||||
<h2>Binding Arbitration</h2>
|
||||
<p>
|
||||
In the event of a dispute arising under or relating to this Agreement or the Service (each, a "Dispute"), such dispute will be finally and exclusively resolved by binding arbitration governed by the Federal Arbitration Act ("FAA"). Any election to arbitrate, at any time, shall be final and binding on the other party. NEITHER PARTY SHALL HAVE THE RIGHT TO LITIGATE SUCH CLAIM IN COURT OR TO HAVE A JURY TRIAL, EXCEPT EITHER PARTY MAY BRING ITS CLAIM IN ITS LOCAL SMALL CLAIMS COURT, IF PERMITTED BY THAT SMALL CLAIMS COURT RULES AND IF WITHIN SUCH COURT'S JURISDICTION. ARBITRATION IS DIFFERENT FROM COURT, AND DISCOVERY AND APPEAL RIGHTS MAY ALSO BE LIMITED IN ARBITRATION.
|
||||
</p>
|
||||
<p>
|
||||
All disputes will be resolved before a neutral arbitrator selected jointly by the parties, whose decision will be final, except for a limited right of appeal under the FAA. The arbitration shall be commenced and conducted by JAMS pursuant to its then current Comprehensive Arbitration Rules and Procedures and in accordance with the Expedited Procedures in those rules, or, where appropriate, pursuant to JAMS' Streamlined Arbitration Rules and Procedures. All applicable JAMS rules and procedures are available at the JAMS website <a
|
||||
href="https://www.jamsadr.com"
|
||||
target="_blank"
|
||||
>www.jamsadr.com</a>. Each party will be responsible for paying any JAMS filing, administrative, and arbitrator fees in accordance with JAMS rules. Judgment on the arbitrator's award may be entered in any court having jurisdiction. This clause shall not preclude parties from seeking provisional remedies in aid of arbitration from a court of appropriate jurisdiction. The arbitration may be conducted in person, through the submission of documents, by phone, or online. If conducted in person, the arbitration shall take place in the United States county where you reside. The parties may litigate in court to compel arbitration, to stay a proceeding pending arbitration, or to confirm, modify, vacate, or enter judgment on the award entered by the arbitrator. The parties shall cooperate in good faith in the voluntary and informal exchange of all non-privileged documents and other information (including electronically stored information) relevant to the Dispute immediately after commencement of the arbitration. As set forth below, nothing in this Agreement will prevent us from seeking injunctive relief in any court of competent jurisdiction as necessary to protect our proprietary interests.
|
||||
</p>
|
||||
<p>
|
||||
ANY CLAIMS, ACTIONS OR PROCEEDINGS BY YOU MUST BE COMMENCED WITHIN ONE YEAR AFTER THE EVENT THAT GAVE RISE TO YOUR CLAIM OCCURS. ALL OTHER CLAIMS YOU MAY HAVE ARE PERMANENTLY BARRED.
|
||||
</p>
|
||||
|
||||
<h2>Class Action Waiver</h2>
|
||||
<p>
|
||||
You agree that any arbitration or proceeding shall be limited to the Dispute between us and you individually. To the full extent permitted by law, (i) no arbitration or proceeding shall be joined with any other; (ii) there is no right or authority for any Dispute to be arbitrated or resolved on a class action-basis or to utilize class action procedures; and (iii) there is no right or authority for any Dispute to be brought in a purported representative capacity on behalf of the general public or any other persons. YOU AGREE THAT YOU MAY BRING CLAIMS AGAINST US ONLY IN YOUR INDIVIDUAL CAPACITY AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING.
|
||||
</p>
|
||||
|
||||
<h2>Jury Trial Waiver</h2>
|
||||
<p>
|
||||
IF FOR ANY REASON A DISPUTE OR CLAIM MAY PROCEED IN COURT RATHER THAN IN ARBITRATION, EACH PARTY TO THIS AGREEMENT IRREVOCABLY WAIVES, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, ANY RIGHT IT MAY HAVE TO A TRIAL BY JURY IN ANY LEGAL PROCEEDING DIRECTLY OR INDIRECTLY ARISING OUT OF OR RELATING TO THESE TERMS OR THE SERVICE (WHETHER BASED ON CONTRACT, TORT, OR ANY OTHER THEORY), UNLESS SUCH WAIVERS ARE UNENFORCEABLE.
|
||||
</p>
|
||||
|
||||
<h2>Equitable Relief</h2>
|
||||
<p>
|
||||
You acknowledge and agree that in the event of a breach or threatened violation by you of our intellectual property rights and/or rights related to our confidential and proprietary information, we will suffer irreparable harm and will therefore be entitled to injunctive relief to enforce this Agreement. We may, without waiving any other remedies under this Agreement, seek from any court having jurisdiction any interim, equitable, provisional, or injunctive relief that is necessary to protect our rights and property pending the outcome of the arbitration referenced above.
|
||||
</p>
|
||||
|
||||
<h2>Contact Us</h2>
|
||||
<p>
|
||||
If you have any questions about the Agreement, or want to report a violation, please contact us at <a href="mailto:admin@habitica.com">admin@habitica.com</a>.
|
||||
</p>
|
||||
|
||||
<h2>Miscellaneous</h2>
|
||||
<ul>
|
||||
<li>This Agreement and any action related thereto will be governed by the laws of the State of California without regard to its conflict of laws provisions.</li>
|
||||
<li>Our failure to act on or enforce any provision of this Agreement shall not be construed as a waiver of that provision or any other provision therein. No waiver shall be effective against us unless made in writing, and no such waiver shall be construed as a waiver in any other or subsequent instance.</li>
|
||||
<li>Except as expressly agreed by us and you in writing, this Agreement constitutes the entire agreement between you and us with respect to the subject matter, and supersedes all previous or contemporaneous agreements, whether written or oral, between the parties with respect to the subject matter.</li>
|
||||
<li>The section headings are provided merely for convenience and shall not be given any legal import. This Agreement will inure to the benefit of our successors, assigns, licensees, and sublicensees.</li>
|
||||
<li>You agree that no joint venture, partnership, employment, or agency relationship exists between you and us as a result of the Agreement or your use of the Service.</li>
|
||||
<li>Our performance under the Agreement is subject to existing laws and legal process, and nothing contained in the Agreement is in derogation of our right to comply with governmental, court, and law enforcement requests, or requirements relating to your use of the Service or information provided to or gathered by us with respect to such use.</li>
|
||||
<li>If any part of the Agreement is determined to be invalid or unenforceable pursuant to applicable law, including, without limitation, the warranty disclaimers and liability limitations set forth above, then the invalid or unenforceable provision will be deemed superseded by a valid, enforceable provision that most closely matches the intent of the original provision and the remainder of the Agreement shall continue in effect.</li>
|
||||
<li>A printed version of the Agreement and of any notice given in electronic form shall be admissible in judicial or administrative proceedings based upon or relating to the Agreement to the same extent and subject to the same conditions as other business documents and records originally generated and maintained in printed form.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- eslint-enable max-len -->
|
||||
</template>
|
||||
@@ -1,9 +1,18 @@
|
||||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
|
||||
export const LOCALSTORAGE_AUTH_KEY = 'habit-mobile-settings';
|
||||
|
||||
export function authAsCredentialsState (authObject) {
|
||||
return {
|
||||
API_ID: authObject.auth.apiId,
|
||||
API_TOKEN: authObject.auth.apiToken,
|
||||
};
|
||||
}
|
||||
|
||||
export function setUpAxios (AUTH_SETTINGS) { // eslint-disable-line import/prefer-default-export
|
||||
if (!AUTH_SETTINGS) {
|
||||
AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings'); // eslint-disable-line no-param-reassign, max-len
|
||||
AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY); // eslint-disable-line no-param-reassign, max-len
|
||||
if (!AUTH_SETTINGS) return false;
|
||||
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS); // eslint-disable-line no-param-reassign
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||
|
||||
// @TODO: I have abstracted this in another PR. Use that function when merged
|
||||
function getApiKey () {
|
||||
let AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
||||
let AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||
|
||||
if (AUTH_SETTINGS) {
|
||||
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
class="balance-info"
|
||||
:currency-needed="currencyNeeded"
|
||||
:amount-needed="amountNeeded"
|
||||
:neededCurrencyOnly="true"
|
||||
:needed-currency-only="true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -158,15 +158,19 @@ export default {
|
||||
confirmPassword: this.passwordUpdates.confirmPassword,
|
||||
};
|
||||
|
||||
await axios.put('/api/v4/user/auth/update-password', localAuthData);
|
||||
const updatePasswordResult = await axios.put('/api/v4/user/auth/update-password', localAuthData);
|
||||
|
||||
const newToken = updatePasswordResult.data.data.apiToken;
|
||||
|
||||
this.$store.dispatch('auth:setNewToken', {
|
||||
userId: this.user._id,
|
||||
apiToken: newToken,
|
||||
});
|
||||
|
||||
this.passwordUpdates = {};
|
||||
this.$store.dispatch('snackbars:add', {
|
||||
title: 'Habitica',
|
||||
text: this.$t('passwordSuccess'),
|
||||
type: 'success',
|
||||
timeout: true,
|
||||
});
|
||||
// Store a flag to show success message after reload
|
||||
sessionStorage.setItem('passwordChangeSuccess', 'true');
|
||||
window.location.reload();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -147,8 +147,6 @@ import {
|
||||
const bugReportModal = () => import('@/components/bugReportModal');
|
||||
const bugReportSuccessModal = () => import('@/components/bugReportSuccessModal');
|
||||
|
||||
const COMMUNITY_MANAGER_EMAIL = import.meta.env.EMAILS_COMMUNITY_MANAGER_EMAIL;
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
@@ -325,29 +323,6 @@ export default {
|
||||
if (loadingScreen) document.body.removeChild(loadingScreen);
|
||||
},
|
||||
methods: {
|
||||
checkForBannedUser (error) {
|
||||
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||
const errorMessage = error.response.data.message;
|
||||
|
||||
// Case where user is not logged in
|
||||
if (!parseSettings) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bannedMessage = this.$t('accountSuspended', {
|
||||
communityManagerEmail: COMMUNITY_MANAGER_EMAIL,
|
||||
userId: parseSettings.auth.apiId,
|
||||
});
|
||||
|
||||
if (errorMessage !== bannedMessage) return false;
|
||||
|
||||
this.$store.dispatch('auth:logout', { redirectToLogin: true });
|
||||
return true;
|
||||
},
|
||||
itemSelected (item) {
|
||||
this.selectedItemToBuy = item;
|
||||
},
|
||||
genericPurchase (item) {
|
||||
if (!item) return false;
|
||||
|
||||
|
||||
@@ -19,16 +19,12 @@ const HallPage = () => import(/* webpackChunkName: "hall" */'@/components/hall/i
|
||||
const PatronsPage = () => import(/* webpackChunkName: "hall" */'@/components/hall/patrons');
|
||||
const HeroesPage = () => import(/* webpackChunkName: "hall" */'@/components/hall/heroes');
|
||||
|
||||
// Admin Panel
|
||||
const AdminPanelPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin-panel');
|
||||
const AdminPanelUserPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin-panel/user-support');
|
||||
const AdminPanelSearchPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin-panel/search');
|
||||
|
||||
// Except for tasks that are always loaded all the other main level
|
||||
// All the main level
|
||||
// components are loaded in separate webpack chunks.
|
||||
// See https://webpack.js.org/guides/code-splitting-async/
|
||||
// for docs
|
||||
// Admin Pages
|
||||
const AdminContainerPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/container');
|
||||
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 BlockerPage = () => import(/* webpackChunkName: "admin-panel" */'@/components/admin/blocker');
|
||||
|
||||
// Tasks
|
||||
const UserTasks = () => import(/* webpackChunkName: "userTasks" */'@/components/tasks/user');
|
||||
@@ -184,32 +180,55 @@ const router = new VueRouter({
|
||||
},
|
||||
|
||||
{
|
||||
name: 'adminPanel',
|
||||
path: '/admin-panel',
|
||||
component: AdminPanelPage,
|
||||
name: 'adminSection',
|
||||
path: '/admin',
|
||||
component: AdminContainerPage,
|
||||
meta: {
|
||||
privilegeNeeded: [ // any one of these is enough to give access
|
||||
'userSupport',
|
||||
'accessControl',
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'adminPanelSearch',
|
||||
path: 'search/:userIdentifier',
|
||||
component: AdminPanelSearchPage,
|
||||
name: 'adminPanel',
|
||||
path: 'panel',
|
||||
component: AdminPanelPage,
|
||||
meta: {
|
||||
privilegeNeeded: [
|
||||
privilegeNeeded: [ // any one of these is enough to give access
|
||||
'userSupport',
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'adminPanelSearch',
|
||||
path: 'search/:userIdentifier',
|
||||
component: AdminPanelSearchPage,
|
||||
meta: {
|
||||
privilegeNeeded: [
|
||||
'userSupport',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'adminPanelUser',
|
||||
path: ':userIdentifier',
|
||||
component: AdminPanelUserPage,
|
||||
meta: {
|
||||
privilegeNeeded: [
|
||||
'userSupport',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'adminPanelUser',
|
||||
path: ':userIdentifier',
|
||||
component: AdminPanelUserPage,
|
||||
name: 'blockers',
|
||||
path: 'blockers',
|
||||
component: BlockerPage,
|
||||
meta: {
|
||||
privilegeNeeded: [
|
||||
'userSupport',
|
||||
privilegeNeeded: [ // any one of these is enough to give access
|
||||
'accessControl',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -22,7 +22,9 @@ const NewsPage = () => import('@/components/static/newStuff');
|
||||
const OverviewPage = () => import('@/components/static/overview');
|
||||
const PressKitPage = () => import('@/components/static/pressKit');
|
||||
const PrivacyPage = () => import('@/components/static/privacy');
|
||||
const PrivacyReviewPage = () => import('@/components/static/privacyReview');
|
||||
const TermsPage = () => import('@/components/static/terms');
|
||||
const TermsReviewPage = () => import('@/components/static/termsReview');
|
||||
|
||||
export const STATIC_ROUTES = {
|
||||
path: '/static',
|
||||
@@ -79,9 +81,15 @@ export const STATIC_ROUTES = {
|
||||
{
|
||||
name: 'privacy', path: 'privacy', component: PrivacyPage, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'privacyReview', path: 'privacy-review', component: PrivacyReviewPage, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'terms', path: 'terms', component: TermsPage, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'termsReview', path: 'terms-review', component: TermsReviewPage, meta: { requiresLogin: false },
|
||||
},
|
||||
{
|
||||
name: 'notFound', path: 'not-found', component: NotFoundPage, meta: { requiresLogin: false },
|
||||
},
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
import axios from 'axios';
|
||||
import { authAsCredentialsState, LOCALSTORAGE_AUTH_KEY } from '@/libs/auth';
|
||||
|
||||
const LOCALSTORAGE_AUTH_KEY = 'habit-mobile-settings';
|
||||
function saveLocalDataAuth (store, apiId, apiToken) {
|
||||
const credentialsObj = {
|
||||
auth: {
|
||||
apiId,
|
||||
apiToken,
|
||||
},
|
||||
};
|
||||
|
||||
const userLocalData = JSON.stringify(credentialsObj);
|
||||
|
||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
||||
|
||||
store.state.credentials = authAsCredentialsState(credentialsObj);
|
||||
}
|
||||
|
||||
export async function register (store, params) {
|
||||
let url = '/api/v4/user/auth/local/register';
|
||||
@@ -16,13 +30,7 @@ export async function register (store, params) {
|
||||
|
||||
const user = result.data.data;
|
||||
|
||||
const userLocalData = JSON.stringify({
|
||||
auth: {
|
||||
apiId: user._id,
|
||||
apiToken: user.apiToken,
|
||||
},
|
||||
});
|
||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
||||
saveLocalDataAuth(store, user.id, user.apiToken);
|
||||
}
|
||||
|
||||
export async function login (store, params) {
|
||||
@@ -35,14 +43,7 @@ export async function login (store, params) {
|
||||
|
||||
const user = result.data.data;
|
||||
|
||||
const userLocalData = JSON.stringify({
|
||||
auth: {
|
||||
apiId: user.id,
|
||||
apiToken: user.apiToken,
|
||||
},
|
||||
});
|
||||
|
||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
||||
saveLocalDataAuth(store, user.id, user.apiToken);
|
||||
}
|
||||
|
||||
export async function verifyUsername (store, params) {
|
||||
@@ -72,14 +73,7 @@ export async function socialAuth (store, params) {
|
||||
|
||||
const user = result.data.data;
|
||||
|
||||
const userLocalData = JSON.stringify({
|
||||
auth: {
|
||||
apiId: user.id,
|
||||
apiToken: user.apiToken,
|
||||
},
|
||||
});
|
||||
|
||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
||||
saveLocalDataAuth(store, user.id, user.apiToken);
|
||||
}
|
||||
|
||||
export async function appleAuth (store, params) {
|
||||
@@ -93,14 +87,7 @@ export async function appleAuth (store, params) {
|
||||
|
||||
const user = result.data.data;
|
||||
|
||||
const userLocalData = JSON.stringify({
|
||||
auth: {
|
||||
apiId: user.id,
|
||||
apiToken: user.apiToken,
|
||||
},
|
||||
});
|
||||
|
||||
localStorage.setItem(LOCALSTORAGE_AUTH_KEY, userLocalData);
|
||||
saveLocalDataAuth(store, user.id, user.apiToken);
|
||||
}
|
||||
|
||||
export function logout (store, options = {}) {
|
||||
@@ -108,3 +95,7 @@ export function logout (store, options = {}) {
|
||||
const query = options.redirectToLogin === true ? '?redirectToLogin=true' : '';
|
||||
window.location.href = `/logout-server${query}`;
|
||||
}
|
||||
|
||||
export function setNewToken (store, params) {
|
||||
saveLocalDataAuth(store, params.userId, params.apiToken);
|
||||
}
|
||||
|
||||
19
website/client/src/store/actions/blockers.js
Normal file
19
website/client/src/store/actions/blockers.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export async function getBlockers () {
|
||||
const response = await axios.get('/api/v4/admin/blockers');
|
||||
return response.data.data;
|
||||
}
|
||||
export async function createBlocker (store, payload) {
|
||||
const response = await axios.post('/api/v4/admin/blockers', payload.blocker);
|
||||
return response.data.data;
|
||||
}
|
||||
export async function updateBlocker (store, payload) {
|
||||
const response = await axios.put(`/api/v4/admin/blockers/${payload.blocker._id}`, payload.blocker);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function deleteBlocker (store, payload) {
|
||||
const response = await axios.delete(`/api/v4/admin/blockers/${payload.blockerId}`);
|
||||
return response.data.data;
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import * as worldState from './worldState';
|
||||
import * as news from './news';
|
||||
import * as analytics from './analytics';
|
||||
import * as faq from './faq';
|
||||
import * as blockers from './blockers';
|
||||
|
||||
// Actions should be named as 'actionName' and can be accessed as 'namespace:actionName'
|
||||
// Example: fetch in user.js -> 'user:fetch'
|
||||
@@ -45,6 +46,7 @@ const actions = flattenAndNamespace({
|
||||
news,
|
||||
analytics,
|
||||
faq,
|
||||
blockers,
|
||||
});
|
||||
|
||||
export default actions;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { DAY_MAPPING } from '@/../../common/script/cron';
|
||||
import deepFreeze from '@/libs/deepFreeze';
|
||||
import Store from '@/libs/store';
|
||||
import { asyncResourceFactory } from '@/libs/asyncResource';
|
||||
import { setUpAxios } from '@/libs/auth';
|
||||
import { authAsCredentialsState, LOCALSTORAGE_AUTH_KEY, setUpAxios } from '@/libs/auth';
|
||||
|
||||
import actions from './actions';
|
||||
import getters from './getters';
|
||||
@@ -22,7 +22,7 @@ const browserTimezoneUtcOffset = moment().utcOffset();
|
||||
|
||||
axios.defaults.headers.common['x-client'] = 'habitica-web';
|
||||
|
||||
let AUTH_SETTINGS = window.localStorage.getItem('habit-mobile-settings');
|
||||
let AUTH_SETTINGS = window.localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
|
||||
if (AUTH_SETTINGS) {
|
||||
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS);
|
||||
isUserLoggedIn = setUpAxios(AUTH_SETTINGS);
|
||||
@@ -64,10 +64,7 @@ export default function clientStore () {
|
||||
// see https://github.com/HabitRPG/habitica/issues/9242
|
||||
notificationsRemoved: [],
|
||||
worldState: asyncResourceFactory(),
|
||||
credentials: isUserLoggedIn ? {
|
||||
API_ID: AUTH_SETTINGS.auth.apiId,
|
||||
API_TOKEN: AUTH_SETTINGS.auth.apiToken,
|
||||
} : {},
|
||||
credentials: isUserLoggedIn ? authAsCredentialsState(AUTH_SETTINGS) : {},
|
||||
// store the timezone offset in case it's different than the one in
|
||||
// user.preferences.timezoneOffset and change it after the user is synced
|
||||
// in app.vue
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"marketing2Lead3Title": "Предизвиквайте се взаимно",
|
||||
"marketing2Lead3": "Предизвикателствата Ви дават възможността да се състезавате с приятели и непознати. Който се справи най-добре, получава специални награди.",
|
||||
"marketing3Header": "Приложения и разширения",
|
||||
"marketing3Lead1": "Приложенията за **iPhone и Андроид** Ви позволяват да се грижите за задачите си в движение. Наясно сме, че влизането в уеб сайта и натискането на бутони може би е старомодно.",
|
||||
"marketing3Lead1": "Приложенията за **iPhone и Андроид** Ви позволяват да се грижите за задачите си в движение. Наясно сме, че влизането в уеб сайта и натискането на бутони може би е старомодно.",
|
||||
"marketing3Lead2Title": "Интеграции",
|
||||
"marketing3Lead2": "Други **инструменти от трети страни** свързват Хабитика с различни страни на живота Ви. Нашият ППИ предоставя лесна интеграция с неща като [разширението за Chrome](https://chrome.google.com/webstore/detail/habitica/pidkmpibnnnhneohdgjclfdjpijggmjj?hl=bg-BG), чрез което губите точки живот, ако разглеждате непродуктивни уеб сайтове, и получавате точки, когато посещавате продуктивни такива. [Вижте повече тук](http://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations).",
|
||||
"marketing4Header": "Употреба в институции",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"valentine2": "„Розите са червени,\n\nа този стих е нещо познато.\n\nДано ти харесва,\n\nзащото струва десет злато.“",
|
||||
"valentine3": "„Розите са червени,\n\nледените дракони са сини.\n\nНе искам да сме разделени,\n\nа да бъда с теб още много години!“",
|
||||
"valentineCardAchievementTitle": "Обожаващи приятели",
|
||||
"valentineCardAchievementText": "Ооо, вие и приятелите ви наистина се харесвате! Имате <%= count %> изпратени или получени картички за Св. Валентин.",
|
||||
"valentineCardAchievementText": "Ооо, вие и приятелите ви наистина се харесвате! Имате <%= count %> изпратени или получени картички за Св. Валентин.",
|
||||
"polarBear": "Полярна мечка",
|
||||
"turkey": "Пуйка",
|
||||
"gildedTurkey": "Позлатена пуйка",
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"questOctopusUnlockText": "Отключва възможността за купуване на Яйца на Октопод от пазара",
|
||||
"questHarpyText": "Помощ! Харпия!",
|
||||
"questHarpyNotes": "Смелият приключенец @UncommonCriminal е изчезнал в гората, следвайки следите на крилато чудовище, което било забелязано преди няколко дни. Докато се подготвяш да започнеш търсенето му, един ранен папагал каца на ръката ти; а през красивата му перушина се вижда грозен белег. За крака му има закачена бележка, от която разбираш, че докато защитавал папагалите, @UncommonCriminal бил хванат от зла харпия, и отчаяно се нуждае от помощта ти, за да се измъкне. Ще последваш ли птицата, за да победиш харпията и спасиш @UncommonCriminal?",
|
||||
"questHarpyCompletion": "Последният удар поваля харпията; перата ѝ се разхвърчават във всички посоки. След като бързо се качваш в гнездото ѝ, намираш @UncommonCriminal, обграден с папагалски яйца. Двамата заедно бързо връщате яйцата в близките гнезда. Белязаният папагал, който те извести, изграчва силно и пуска няколко яйца в ръцете ти. „След нападението на харпията няколко яйца имат нужда от нов дом“ — обяснява @UncommonCriminal. — „Изглежда си избран за почетен папагал.“",
|
||||
"questHarpyCompletion": "Последният удар поваля харпията; перата ѝ се разхвърчават във всички посоки. След като бързо се качваш в гнездото ѝ, намираш @UncommonCriminal, обграден с папагалски яйца. Двамата заедно бързо връщате яйцата в близките гнезда. Белязаният папагал, който те извести, изграчва силно и пуска няколко яйца в ръцете ти. „След нападението на харпията няколко яйца имат нужда от нов дом“ — обяснява @UncommonCriminal. — „Изглежда си избран за почетен папагал.“",
|
||||
"questHarpyBoss": "Харпия",
|
||||
"questHarpyDropParrotEgg": "Папагал (яйце)",
|
||||
"questHarpyUnlockText": "Отключва възможността за купуване на Яйца на папагал от Пазара",
|
||||
@@ -88,7 +88,7 @@
|
||||
"questMoonstone2Completion": "Рецидивата залита назад след последния ти удар, и за момент сърцето ти се изпълва с надежда, но тогава тя отмята глава назад и започва да се смее ужасяващо. Какво става?",
|
||||
"questMoonstone2DropMoonstone3Quest": "Рецидивата, част 3: Трансформираната Рецидивата (свитък)",
|
||||
"questMoonstone3Text": "Рецидивата, част 3: Трансформираната Рецидивата",
|
||||
"questMoonstone3Notes": "Смеейки се странно, Рецидивата пада на земята и ти я нападаш с веригата от лунни камъни. За твой ужас, Рецидивата хваща камъните, а очите ѝ горят от задоволство.<br><br>„Глупаво създание от плът!“ — изкрещява тя — „Вярно е, че тези камъни ще възвърнат земната ми форма, но не по начина, който си представяш. С появата на пълната луна в мрака, моята сила нараства, а от сенките аз призовавам призрака на твоя най-голям враг!“<br><br>Лепкава, зелена мъгла се надига от блатото, а тялото на Рецидивата се сгърчва и изкривява във форма, която те изпълва със страх — немъртвото тяло на Порока, преродено.",
|
||||
"questMoonstone3Notes": "Смеейки се странно, Рецидивата пада на земята и ти я нападаш с веригата от лунни камъни. За твой ужас, Рецидивата хваща камъните, а очите ѝ горят от задоволство.<br><br>„Глупаво създание от плът!“ — изкрещява тя — „Вярно е, че тези камъни ще възвърнат земната ми форма, но не по начина, който си представяш. С появата на пълната луна в мрака, моята сила нараства, а от сенките аз призовавам призрака на твоя най-голям враг!“<br><br>Лепкава, зелена мъгла се надига от блатото, а тялото на Рецидивата се сгърчва и изкривява във форма, която те изпълва със страх — немъртвото тяло на Порока, преродено.",
|
||||
"questMoonstone3Completion": "Дъхът ти е учестен и пот щипе очите ти, докато немъртвия змей се сгромолясва на земята. Останките от Рецидивата се разпръскват под формата на рядка, сива мъгла, която бързо се разнася от полъха на свеж вятър. Чуваш отдалечените, възторжени възгласи на хабитиканците, побеждаващи лошите си навици веднъж и завинаги.<br><br>@Baconsaur, господарят на зверовете, се спуска към теб от небето с грифона си: „Видях победата ти от горе и бях впечатлен. Моля те, вземи тази вълшебна туника — смелостта ти показва, че сърцето ти е благородно, и вярвам, че тя трябва да бъде твоя.“",
|
||||
"questMoonstone3Boss": "Некро-порок",
|
||||
"questMoonstone3DropRottenMeat": "Развалено месо (храна)",
|
||||
@@ -211,7 +211,7 @@
|
||||
"questSlimeDropSlimeEgg": "Белоружена слуз (яйце)",
|
||||
"questSlimeUnlockText": "Отключва възможността за купуване на яйца на белоружена слуз от пазара.",
|
||||
"questSheepText": "Гръмотевичният овен",
|
||||
"questSheepNotes": "Докато се разхождаш с няколко приятели из провинцията на Задачия, „поемайки си дъх“ от задълженията, откривате приятен малък магазин за прежди. Толкова сте погълнати от размотаването си, че едва забелязвате застрашителните облаци, събиращи се на хоризонта. „Имам лооошо чувство за времето.“ — промърморва @Misceo и ти поглеждаш нагоре. Буреносните облаци се завихрят и започват да приличат на… „Няма време да зяпаме облаците!“ — крещи @starsystemic — „То ни напада!“ Гръмотевичният овен се втурва напред, хвърляйки светкавици към теб!",
|
||||
"questSheepNotes": "Докато се разхождаш с няколко приятели из провинцията на Задачия, „поемайки си дъх“ от задълженията, откривате приятен малък магазин за прежди. Толкова сте погълнати от размотаването си, че едва забелязвате застрашителните облаци, събиращи се на хоризонта. „Имам лооошо чувство за времето.“ — промърморва @Misceo и ти поглеждаш нагоре. Буреносните облаци се завихрят и започват да приличат на… „Няма време да зяпаме облаците!“ — крещи @starsystemic — „То ни напада!“ Гръмотевичният овен се втурва напред, хвърляйки светкавици към теб!",
|
||||
"questSheepBoss": "Гръмотевичен овен",
|
||||
"questSheepCompletion": "Впечатлен от старанието ти, гръмотевичният овен укротява яростта си. Той насочва три огромни ледени къса към теб, а след това изчезва с приглушен тътен. След като ги оглеждаш внимателно, откриваш, че ледените късове всъщност са три пухкави яйца. Прибираш ги, а след това се отправяш към вкъщи под синьото небе.",
|
||||
"questSheepDropSheepEgg": "Овца (яйце)",
|
||||
@@ -265,7 +265,7 @@
|
||||
"questHorseDropHorseEgg": "Кон (яйце)",
|
||||
"questHorseUnlockText": "Отключва възможността за купуване на яйца на кон от пазара.",
|
||||
"questBurnoutText": "Умората и духовете на изтощението",
|
||||
"questBurnoutNotes": "Минава полунощ, а въздухът е още задушливо горещ и застоял, когато Redphoenix и капитанът на разузнавачите Kiwibot внезапно нахлуват през портите на града: „Трябва да евакуираме всички дървени сгради!“ — крещи Redphoenix — „По-бързо!“<br><br>Kiwibot се подпира на стената, докато се опитва да си поеме дъх: „Тя изсмуква силите на хората и ги превръща в Духове на изтощението! Затова всичко се бави. Ето къде са изчезнали всички . Тя краде енергията им!“<br><br>„Тя?“ — пита Lemoness.<br><br>В този момент жегата придобива физическа форма.<br><br>Тя се надига от земята във вихър от пръст, а въздухът се изпълва с миризма на пушек и сяра. Пламъци се спускат към разтопената земя и се превръщат в крайници, огъващи се във въздуха. Огнени очи се отварят изведнъж и чудовището издава дълбок грачещ звук.<br><br>Kiwibot прошепва само една дума:<br><br><em>„Умората.“</em>",
|
||||
"questBurnoutNotes": "Минава полунощ, а въздухът е още задушливо горещ и застоял, когато Redphoenix и капитанът на разузнавачите Kiwibot внезапно нахлуват през портите на града: „Трябва да евакуираме всички дървени сгради!“ — крещи Redphoenix — „По-бързо!“<br><br>Kiwibot се подпира на стената, докато се опитва да си поеме дъх: „Тя изсмуква силите на хората и ги превръща в Духове на изтощението! Затова всичко се бави. Ето къде са изчезнали всички . Тя краде енергията им!“<br><br>„Тя?“ — пита Lemoness.<br><br>В този момент жегата придобива физическа форма.<br><br>Тя се надига от земята във вихър от пръст, а въздухът се изпълва с миризма на пушек и сяра. Пламъци се спускат към разтопената земя и се превръщат в крайници, огъващи се във въздуха. Огнени очи се отварят изведнъж и чудовището издава дълбок грачещ звук.<br><br>Kiwibot прошепва само една дума:<br><br><em>„Умората.“</em>",
|
||||
"questBurnoutCompletion": "<strong>Умората е ПОБЕДЕНА!</strong><br><br>С дълбока, но мека въздишка, Умората бавно освобождава изгарящата енергия, захранваща пламъците ѝ. Докато чудовището се превръща в пепел и разнася наоколо, откраднатата от него енергия се разпръсква из въздуха, възстановяваща духовете на изтощението и връщайки истинската им форма.<br><br>Иън, Даниел и Сезонната Магьосница се радват на хабитиканците, идващи да ги поздравят, а всички липсващи жители на Цветущите поля се прегръщат с приятелите и семействата си. Последният дух на изтощението се превръща в самата Весела Жетварка!<br><br>„Виж“ — прошепва @Baconsaur, когато пепелта започва да блести. Бавно, от пепелта се появяват стотици светещи феникси!<br><br>Една от блестящите птици кацва на скелетната ръка на Веселата Жетварка, а тя се усмихва към нея: „Мина доста време от последния път, когато имах невероятната чест да държа в ръцете си феникс от Цветущите поля“ — проговаря тя. — „Въпреки че, ако се имат предвид последните събития, бих казала, че това е съвсем нормално!“<br><br>Гласът ѝ става по-сериозен, но усмивката ѝ (очаквано) остава: „Всички ни познават като трудолюбиви, но освен това, ние знаем как да се веселим и празнуваме. Някак иронично, докато усърдно планирахме огромно празненство, забравихме да си позволим малко време за забавление. Определено няма да повторим тази грешка!“<br><br>Тя плясва с ръце — „А сега — да празнуваме!“",
|
||||
"questBurnoutCompletionChat": "`Умората е ПОБЕДЕНА!`\n\nС дълбока, но мека въздишка, Умората бавно освобождава изгарящата енергия, захранваща пламъците ѝ. Докато чудовището се превръща в пепел и разнася наоколо, откраднатата от него енергия се разпръсква из въздуха, възстановяваща духовете на изтощението и връщайки истинската им форма.\n\nИън, Даниел и Сезонната Магьосница се радват на хабитиканците, идващи да ги поздравят, а всички липсващи жители на Цветущите поля се прегръщат с приятелите и семействата си. Последният дух на изтощението се превръща в самата Весела Жетварка!\n\n„Виж“ — прошепва @Baconsaur, когато пепелта започва да блести. Бавно, от пепелта се появяват стотици светещи феникси!\n\nЕдна от блестящите птици кацва на скелетната ръка на Веселата Жетварка, а тя се усмихва към нея: „Мина доста време от последния път, когато имах невероятната чест да държа в ръцете си феникс от Цветущите поля“ — проговаря тя. — „Въпреки че, ако се имат предвид последните събития, бих казала, че това е съвсем нормално!“\n\nГласът ѝ става по-сериозен, но усмивката ѝ (очаквано) остава: „Всички ни познават като трудолюбиви, но освен това, ние знаем как да се веселим и празнуваме. Някак иронично, докато усърдно планирахме огромно празненство, забравихме да си позволим малко време за забавление. Определено няма да повторим тази грешка!“\n\nТя плясва с ръце — „А сега — да празнуваме!“\n\nВсички хабитиканци получават:\n\nЛюбимец феникс\nПревоз феникс\nПостижението: Спасител на Цветущите поля\nОбикновен бонбон\nВанилов бонбон\nПясъчен бонбон\nКанелен бонбон\nШоколадов бонбон\nРазвален бонбон\nКисел розов бонбон\nКисел син бонбон\nМеден бонбон",
|
||||
"questBurnoutBoss": "Умората",
|
||||
@@ -313,7 +313,7 @@
|
||||
"questSnailDropSnailEgg": "Охлюв (яйце)",
|
||||
"questSnailUnlockText": "Отключва възможността за купуване на яйца на охлюв от пазара.",
|
||||
"questBewilderText": "Озадачителят",
|
||||
"questBewilderNotes": "Празненството започва като всяко друго.<br><br>Мезетата са отлични, музиката е прекрасна и дори танцуващите слонове са някак на място. Хабитиканците пеят и се веселят сред пищната растителна украса, наслаждавайки се на кратката почивка от неприятните си задачи, а Първоаприлският шегаджия се мотае между тях, правейки шегички и фокуси.<br><br>Когато часовниковата кула на Мъглоград удря полунощ, Първоъприлският шегаджия скача на сцената и подхваща реч:<br><br>„Приятели! Врагове! Случайни познайници! Дайте ми ушите си.“ — всички се разсмиват, когато на главите им израстват животински уши и започват да се оглеждат един друг.<br><br>„Както знаете“ — продължава шегаджията, — „фокусите ми обикновено траят само ден. Но с радост Ви съобщавам, че открих по-лесен начин да си осигурим постоянно забавление, без да трябва да понасяме тежестта на неспирните си задължения. Скъпи хабитиканци, посрещнете моя вълшебен приятел… Озадачителя!“<br><br>Lemoness внезапно пребледнява и изпуска ордьовъра си. „Чакайте! Не вярвайте…“<br><br>Но изведнъж в стаята започва да навлиза мъгла, светеща и гъста, която се завихря около Първоаприлския шегаджия и започва да формира мъгляви пера и удължен врат. Тълпата е безмълвна; пред погледите на всички се образува чудовищна птица със светещи, призрачни крила, която избухва в ужасяващ, писклив смях:<br><br>„О, от векове не е имало толкова глупав хабитиканец, който да ме призове! Колко прекрасно е чувството най-после да имам истинска форма!“<br><br>Ужасени, вълшебните пчели на Мъглоград напускат летящия град, реещ се в небето. Едно по едно, прекрасните пролетни цветя повяхват и изчезват.<br><br>„Скъпи мои приятели, защо сте толкова уплашени?“ — изграчва Озадачителят, пляскайки с криле — „Вече няма нужда да се трудите за наградите си. Аз мога да ви дам всичко, което пожелаете!“<br><br>От небето се изсипва дъжд от монети, които се удрят в земята със страшна сила, а тълпата започва да пищи и се разбягва, за да намери подслон. „Това някаква шега ли е?“ — изкрещява Baconsaur, когато златота започва да чупи прозорците и да пробива покривите.<br><br>PainterProphet заляга, когато започват да удрят светкавици, а мъгла закрива слънцето. — „Не, този път мисля, че не е!“<br><br>Бързо, хабитиканци, нека не позволяваме на този световен главатар да ни разсее от целите ни! Концентрирайте се върху задачите, които трябва да изпълните, за да можем да спасим Мъглоград… както и себе си.",
|
||||
"questBewilderNotes": "Празненството започва като всяко друго.<br><br>Мезетата са отлични, музиката е прекрасна и дори танцуващите слонове са някак на място. Хабитиканците пеят и се веселят сред пищната растителна украса, наслаждавайки се на кратката почивка от неприятните си задачи, а Първоаприлският шегаджия се мотае между тях, правейки шегички и фокуси.<br><br>Когато часовниковата кула на Мъглоград удря полунощ, Първоъприлският шегаджия скача на сцената и подхваща реч:<br><br>„Приятели! Врагове! Случайни познайници! Дайте ми ушите си.“ — всички се разсмиват, когато на главите им израстват животински уши и започват да се оглеждат един друг.<br><br>„Както знаете“ — продължава шегаджията, — „фокусите ми обикновено траят само ден. Но с радост Ви съобщавам, че открих по-лесен начин да си осигурим постоянно забавление, без да трябва да понасяме тежестта на неспирните си задължения. Скъпи хабитиканци, посрещнете моя вълшебен приятел… Озадачителя!“<br><br>Lemoness внезапно пребледнява и изпуска ордьовъра си. „Чакайте! Не вярвайте…“<br><br>Но изведнъж в стаята започва да навлиза мъгла, светеща и гъста, която се завихря около Първоаприлския шегаджия и започва да формира мъгляви пера и удължен врат. Тълпата е безмълвна; пред погледите на всички се образува чудовищна птица със светещи, призрачни крила, която избухва в ужасяващ, писклив смях:<br><br>„О, от векове не е имало толкова глупав хабитиканец, който да ме призове! Колко прекрасно е чувството най-после да имам истинска форма!“<br><br>Ужасени, вълшебните пчели на Мъглоград напускат летящия град, реещ се в небето. Едно по едно, прекрасните пролетни цветя повяхват и изчезват.<br><br>„Скъпи мои приятели, защо сте толкова уплашени?“ — изграчва Озадачителят, пляскайки с криле — „Вече няма нужда да се трудите за наградите си. Аз мога да ви дам всичко, което пожелаете!“<br><br>От небето се изсипва дъжд от монети, които се удрят в земята със страшна сила, а тълпата започва да пищи и се разбягва, за да намери подслон. „Това някаква шега ли е?“ — изкрещява Baconsaur, когато златота започва да чупи прозорците и да пробива покривите.<br><br>PainterProphet заляга, когато започват да удрят светкавици, а мъгла закрива слънцето. — „Не, този път мисля, че не е!“<br><br>Бързо, хабитиканци, нека не позволяваме на този световен главатар да ни разсее от целите ни! Концентрирайте се върху задачите, които трябва да изпълните, за да можем да спасим Мъглоград… както и себе си.",
|
||||
"questBewilderCompletion": "<strong>Озадачителят е ПОБЕДЕН!</strong><br><br>Успяхме! Озадачителят изревава и се завърта във въздуха, разпръсквайки перата си като силен дъжд. Бавно и постепенно, той се превръща в ефирна, искряща мъгла. Открилото се отново слънце пробива мъглата и прогаря всичко лошо, откривайки кашлящите, човешки форми на Бейли, Мат, Алекс… и самия Първоаприлски шегаджия.<br><br><strong>Мъглоград е спасен!</strong><br><br>Първоаприлският шегаджия е достатъчно засрамен, че да се прави на полу-заспал: „О, хм“ — казва той, — може би малко се… отнесох.“<br><br>Тълпата започва да недоволства. По тротоарите има донесени от водата подгизнали цветя. Някъде в далечината с грандиозен трясък се срутва покрив.<br><br>„Ами, да“ — казва Първоаприлският шегаджия, — „това… което исках да кажа, е че ужасно съжалявам.“ — той въздъхва — „Предполагам, че човек не може само да се забавлява. Не е лошо понякога да се концентрирам. Може би ще започна отрано със шегите за следващата година.“<br><br>Redphoenix се изкашля нарочно.<br><br>„Исках да кажа, че ще започна отрано тазгодишното пролетно почистване!“ — поправя се Първоаприлският шегаджия — „Не се притеснявайте, за нула време ще почистя Хабитград. За щастие никой не е по-добър от мен в размахването на две метли.“<br><br>Окуражени, всички се връщат към нормалния си живот.<br><br>Много скоро всичко в Хабитград отново е нормално. Освен това, след като Озадачителят е унищожен, вълшебните пчели на Мъглоград се връщат на работа и много скоро цветята разцъфват и градът отново се носи над водата.<br><br>Докато хабитиканците прегръщат жужащите вълшебни пчели, очите на Първоаприлския шегаджия светват: „О, дойде ми една идея! Защо не задържите някои от тези пчели като любимци и превози? Това е подарък, който идеално изразява равновесието между усърдната работа и сладките награди, ако трябва да се изразя скучно.“ — намигва той — „Освен това, те нямат жила! Честна шегаджийска дума.“",
|
||||
"questBewilderCompletionChat": "`Озадачителят е ПОБЕДЕН!`\n\nУспяхме! Озадачителят изревава и се завърта във въздуха, разпръсквайки перата си като силен дъжд. Бавно и постепенно, той се превръща в ефирна, искряща мъгла. Открилото се отново слънце пробива мъглата и прогаря всичко лошо, откривайки кашлящите, човешки форми на Бейли, Мат, Алекс… и самия Първоаприлски шегаджия.\n\n`Мъглоград е спасен!`\n\nПървоаприлският шегаджия е достатъчно засрамен, че да се прави на полу-заспал: „О, хм“ — казва той, — може би малко се… отнесох.“\n\nТълпата започва да недоволства. По тротоарите има донесени от водата подгизнали цветя. Някъде в далечината с грандиозен трясък се срутва покрив.\n\n„Ами, да“ — казва Първоаприлският шегаджия, — „това… което исках да кажа, е че ужасно съжалявам.“ — той въздъхва — „Предполагам, че човек не може само да се забавлява. Не е лошо понякога да се концентрирам. Може би ще започна отрано със шегите за следващата година.“\n\nRedphoenix се изкашля нарочно.\n\n„Исках да кажа, че ще започна отрано тазгодишното пролетно почистване!“ — поправя се Първоаприлският шегаджия — „Не се притеснявайте, за нула време ще почистя Хабитград. За щастие никой не е по-добър от мен в размахването на две метли.“\n\nОкуражени, всички се връщат към нормалния си живот.\n\nМного скоро всичко в Хабитград отново е нормално. Освен това, след като Озадачителят е унищожен, вълшебните пчели на Мъглоград се връщат на работа и много скоро цветята разцъфват и градът отново се носи над водата.\n\nДокато хабитиканците прегръщат жужащите вълшебни пчели, очите на Първоаприлския шегаджия светват: „О, дойде ми една идея! Защо не задържите някои от тези пчели като любимци и превози? Това е подарък, който идеално изразява равновесието между усърдната работа и сладките награди, ако трябва да се изразя скучно.“ — намигва той — „Освен това, те нямат жила! Честна шегаджийска дума.“",
|
||||
"questBewilderBossRageTitle": "Разсейващ удар",
|
||||
@@ -442,7 +442,7 @@
|
||||
"questStoikalmCalamity1DropDesertPotion": "Пустинна излюпваща отвара",
|
||||
"questStoikalmCalamity1DropArmor": "Броня на мамутоездач",
|
||||
"questStoikalmCalamity2Text": "Споколандското бедствие, част 2: Търсенето на ледените пещери",
|
||||
"questStoikalmCalamity2Notes": "Величествената зала на ездачите на мамути е неприветлив архитектурен шедьовър, но е също така и съвсем празна. Няма никакви мебели, липсват и оръжията, и дори по колоните няма никакви украси.<br><br>„Черепите пометоха всичко“ — казва лейди Глетчер, а гласът ѝ напомня надигаща се буря. — „Унизително! Да не съм чула някой да казва за това на Първоаприлския шегаджия, защото няма да отговарям за действията си!“<br><br>„Колко загадъчно!“ — казва @Beffymaroo — „Но те къде…“<br><br>„Пещерите на ледения дракон“ — лейди Глетчер посочва някакви блещукащи монети, разпилени по снега отвън. — „Небрежна работа.“<br><br>„Но ледените дракони не са ли честни създания с предостатъчни количества собствени съкровища?“ — пита @Beffymaroo — „Защо биха…“<br><br>„Контрол над съзнанието“ — казва лейди Глетчер, съвсем спокойно, — „или нещо също толкова мелодраматично и неприятно.“ — Тя тръгва към изхода на залата. — „Какво чакате?“<br><br>Бързо, трябва да последвате следата на ледените монети!",
|
||||
"questStoikalmCalamity2Notes": "Величествената зала на ездачите на мамути е неприветлив архитектурен шедьовър, но е също така и съвсем празна. Няма никакви мебели, липсват и оръжията, и дори по колоните няма никакви украси.<br><br>„Черепите пометоха всичко“ — казва лейди Глетчер, а гласът ѝ напомня надигаща се буря. — „Унизително! Да не съм чула някой да казва за това на Първоаприлския шегаджия, защото няма да отговарям за действията си!“<br><br>„Колко загадъчно!“ — казва @Beffymaroo — „Но те къде…“<br><br>„Пещерите на ледения дракон“ — лейди Глетчер посочва някакви блещукащи монети, разпилени по снега отвън. — „Небрежна работа.“<br><br>„Но ледените дракони не са ли честни създания с предостатъчни количества собствени съкровища?“ — пита @Beffymaroo — „Защо биха…“<br><br>„Контрол над съзнанието“ — казва лейди Глетчер, съвсем спокойно, — „или нещо също толкова мелодраматично и неприятно.“ — Тя тръгва към изхода на залата. — „Какво чакате?“<br><br>Бързо, трябва да последвате следата на ледените монети!",
|
||||
"questStoikalmCalamity2Completion": "Ледените монети ви отвеждат до заровения вход на добре прикрита пещера. Въпреки че времето навън е спокойно и приятно, а слънчевите лъчи блестят по снежната покривка, вътре има страшно течение, като пронизващ леден вятър. Лейди Глетчер прави гримаса и ти подава шлем на мамутоездач: „Сложи си това“ — казва тя, — „ще ти трябва.“",
|
||||
"questStoikalmCalamity2CollectIcicleCoins": "Ледени монети",
|
||||
"questStoikalmCalamity2DropHeadgear": "Шлем на мамутоездач (защита за главата)",
|
||||
@@ -460,7 +460,7 @@
|
||||
"questGuineaPigDropGuineaPigEgg": "Морско свинче (яйце)",
|
||||
"questGuineaPigUnlockText": "Отключва възможността за купуване на яйца на морско свинче от пазара.",
|
||||
"questPeacockText": "Паунът Бутни-Дръпни",
|
||||
"questPeacockNotes": "Правейки поредния си тежък преход през Задачев лес, ти се чудиш коя от съблазнителните си нови цели трябва да преследваш първо. Навлизайки все по-навътре в гората, осъзнаваш, че не си сам в нерешителността си. „Мога да изучавам нов език, или да започна да тренирам…“ — мърмори си @Cecily Perez. — „Може да спя повече“ — размишлява на глас @Lilith of Alfheim, — „или да прекарвам повече време с приятелите си…“. Изглежда @PainterProphet, @Pfeffernusse и @Draayder са озадачени от огромния брой възможности.<br><br>Осъзнаваш, че тези все по-натрапчиви чувства не са твои собствени… паднал си право в капана на пагубния паун Бутни-Дръпни! Преди да успееш да избягаш, той изскача от храстите. Всяка от главите му те тегли в различни посоки и започваш да усещаш как те обзема невероятна умора. Не можеш да победиш и двамата противници едновременно, така че имаш само един избор — да се концентрираш върху най-близката задача, за да отвърнеш!",
|
||||
"questPeacockNotes": "Правейки поредния си тежък преход през Задачев лес, ти се чудиш коя от съблазнителните си нови цели трябва да преследваш първо. Навлизайки все по-навътре в гората, осъзнаваш, че не си сам в нерешителността си. „Мога да изучавам нов език, или да започна да тренирам…“ — мърмори си @Cecily Perez. — „Може да спя повече“ — размишлява на глас @Lilith of Alfheim, — „или да прекарвам повече време с приятелите си…“. Изглежда @PainterProphet, @Pfeffernusse и @Draayder са озадачени от огромния брой възможности.<br><br>Осъзнаваш, че тези все по-натрапчиви чувства не са твои собствени… паднал си право в капана на пагубния паун Бутни-Дръпни! Преди да успееш да избягаш, той изскача от храстите. Всяка от главите му те тегли в различни посоки и започваш да усещаш как те обзема невероятна умора. Не можеш да победиш и двамата противници едновременно, така че имаш само един избор — да се концентрираш върху най-близката задача, за да отвърнеш!",
|
||||
"questPeacockCompletion": "Изненадваш пауна Бутни-Дръпни с неочакваната си решителност. Победен от концентрираното си мислене, той слива главите си в една, превръщайки се в най-красивото същество, което някога си виждал. „Благодаря ти“ — казва паунът, — „толкова дълго се разкъсвах в различни посоки, че вече бях забравил какво искам всъщност. Моля, приеми тези яйца като знак за благодарността ми.“",
|
||||
"questPeacockBoss": "Паунът Бутни-Дръпни",
|
||||
"questPeacockDropPeacockEgg": "Паун (яйце)",
|
||||
@@ -488,7 +488,7 @@
|
||||
"questMayhemMistiflying2CollectRedMistiflies": "Червени мъгливи пеперуди",
|
||||
"questMayhemMistiflying2CollectBlueMistiflies": "Сини мъгливи пеперуди",
|
||||
"questMayhemMistiflying2CollectGreenMistiflies": "Зелени мъгливи пеперуди",
|
||||
"questMayhemMistiflying2DropHeadgear": "Качулка на закачливия куриер с цветовете на дъгата (защита за главата)",
|
||||
"questMayhemMistiflying2DropHeadgear": "Качулка на закачливия куриер с цветовете на дъгата (защита за главата)",
|
||||
"questMayhemMistiflying3Text": "Хаос в Мъглоград, част 3: В която един пощальон е много груб",
|
||||
"questMayhemMistiflying3Notes": "Мъгливите пеперуди се въртят толкова изкусно из торнадото, че е много трудно да бъдат забелязани. Присвивайки очи, забелязваш многокрил силует, реещ се в средата на ущасяващия вихър.<br><br>„О!“ — възкликва Първоаприлският шегаджия, който за малко да бъде повален от вятъра. — „Изглежда Вятърчо е бил обладан. Много неприятно. Може да се случи на всекиго.“<br><br>„Майсторът на вятъра!“ — изкрещява към теб @Beffymaroo. — „Той е най-талантливият вълшебник-куриер на Мъглоград, тъй като е много добър в заклинанията, влияещи на времето. Обикновено е много мил пощальон!“<br><br>Сякаш за да опровергае това, майсторът на вятъра изкрещява бясно, при което бурята така ви връхлита, че въпреки вълшебната си мантия, едва успяваш да се задържиш върху превоза си.<br><br>„Тази неприятна маска е нова,“ — отбелязва Първоаприлският шегаджия. — „Може би трябва да му я свалите?““<br><br>Това е добра идея… но разяреният вълшебник няма да я даде без бой.",
|
||||
"questMayhemMistiflying3Completion": "Тъкмо когато си мислиш, че няма да издържиш нито секунда повече на вятъра, успяваш да откачиш маската от лицето на майстора на вятъра. Торнадото изведнъж спира, оставяйки само лек ветрец и слънчеви лъчи след себе си. Майсторът на вятъра се оглежда учуден. — „Къде отиде тя?“<br><br>„Коя?“ — пита приятелят ти @khdarkwolf.<br><br>„Онази приятна жена, която искаше да ми предаде пратка. Тзина.“ — Когато оглежда одуханият град по себе си, лицето му помръква. — „Е, може би не беше толкова приятна.“<br><br>Първоаприлският шегаджия го потупва по гърба, а след това ти подава две блещукащи писма. — „Ето. Защо не оставиш този приятел малко да си почине, и не се погрижиш за пощата? Чух, че магията в тези пликове ще си заслужава усилията.“",
|
||||
@@ -606,7 +606,7 @@
|
||||
"aquaticAmigosText": "Пакет мисии „Водни дружки“",
|
||||
"aquaticAmigosNotes": "Съдържа: „Вълшебният саламандър“, „Кракенът на незавършеността“ и „Зовът на Октотулу“. Наличен до 30 юни.",
|
||||
"questSeaSerpentText": "Опасност в дълбините: Нападението на морския змей!",
|
||||
"questSeaSerpentNotes": "С всичките си серии се чувстваш като късметлия – и сега е идеално време за посещение на хиподрума за морски кончета. Качваш се на подводницата от пристанище Усърдие и се настаняваш удобно за пътуването до Мудноград, но едва се потапяте, когато нещо удря подводницата и запраща всички пътници на пода. „Какво става“ — крещи @AriesFaries?<br><br>Поглеждаш през близкия люк и ужас виждаш как покрай него преминава стена от блестящи люспи. „Морски змей“ — обявява капитан @Witticaster по вътрешното радио! — „Пригответе се, връща се!“ Сграбчвайки подлакътниците на седалката си, виждаш незавършените си задачи да преминават пред погледа ти. „Може би, ако работим заедно и ги завършим“, мислиш си, „ще прогоним чудовището!“",
|
||||
"questSeaSerpentNotes": "С всичките си серии се чувстваш като късметлия – и сега е идеално време за посещение на хиподрума за морски кончета. Качваш се на подводницата от пристанище Усърдие и се настаняваш удобно за пътуването до Мудноград, но едва се потапяте, когато нещо удря подводницата и запраща всички пътници на пода. „Какво става“ — крещи @AriesFaries?<br><br>Поглеждаш през близкия люк и ужас виждаш как покрай него преминава стена от блестящи люспи. „Морски змей“ — обявява капитан @Witticaster по вътрешното радио! — „Пригответе се, връща се!“ Сграбчвайки подлакътниците на седалката си, виждаш незавършените си задачи да преминават пред погледа ти. „Може би, ако работим заедно и ги завършим“, мислиш си, „ще прогоним чудовището!“",
|
||||
"questSeaSerpentCompletion": "Сломен от усърдието ви, морският змей отстъпва и изчезва в дълбините. Когато пристигаш в Мудноград, най-после си отдъхваш, и забелязваш, че @*~Seraphina~ се приближава с три яйца. „Ето, вземи ги“ — казва тя. — „Явно знаеш как да се оправяш с морските змейове!“ Когато вземаш яйцата, отново се заричаш да бъдеш по-сериозен със задачите си, за да не се повтори тази случка.",
|
||||
"questSeaSerpentBoss": "Могъщият морски змей",
|
||||
"questSeaSerpentDropSeaSerpentEgg": "Морски змей (яйце)",
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
"xml": "(XML)",
|
||||
"json": "(JSON)",
|
||||
"customDayStart": "Персонализирано начало на деня",
|
||||
"sureChangeCustomDayStartTime": "Наистина ли искате да промените персонализираното начало на деня си? Ежедневните Ви задачи ще бъдат подновени при първото влизане в Хабитика след <%= time %>. Уверете се, че сте изпълнили ежедневните си задачи преди това време!",
|
||||
"sureChangeCustomDayStartTime": "Наистина ли искате да промените персонализираното начало на деня си? Ежедневните Ви задачи ще бъдат подновени при първото влизане в Хабитика след <%= time %>. Уверете се, че сте изпълнили ежедневните си задачи преди това време!",
|
||||
"customDayStartHasChanged": "Вашето персонализирано начало на деня беше променено.",
|
||||
"nextCron": "Ежедневните Ви задачи ще бъдат подновени при първото влизане в Хабитика след <%= time %>. Уверете се, че сте изпълнили ежедневните си задачи преди това!",
|
||||
"nextCron": "Ежедневните Ви задачи ще бъдат подновени при първото влизане в Хабитика след <%= time %>. Уверете се, че сте изпълнили ежедневните си задачи преди това!",
|
||||
"customDayStartInfo1": "По подразбиране Хабитика проверява и нулира ежедневните Ви задачи в полунощ Ваше време, всеки ден. Можете да промените това време тук.",
|
||||
"misc": "Разни",
|
||||
"showHeader": "Показване на горната част",
|
||||
@@ -55,7 +55,6 @@
|
||||
"APIToken": "Жетон за ППИ (Това е на практика парола — вижте предупреждението по-горе!)",
|
||||
"showAPIToken": "Показване на жетона за ППИ",
|
||||
"hideAPIToken": "Скриване на жетона за ППИ",
|
||||
"APITokenWarning": "Ако Ви трябва нов жетон за ППИ (ако например старият Ви вече не е таен), пишете на <%= hrefTechAssistanceEmail %>, посочвайки потребителския си идентификатор и текущия си жетон. След като той бъде подновен, ще трябва отново да разрешите достъпа на всичко, което сте използвали, като излезете от профила си в уеб сайта и мобилното приложение, и след това въведете новия си жетон във всички инструменти за Хабитика, които използвате.",
|
||||
"thirdPartyApps": "Външни приложения",
|
||||
"resetDo": "Потвърждавам, нулирайте профила ми!",
|
||||
"resetComplete": "Нулирането е завършено!",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"commonQuestions": "Časté otázky",
|
||||
"faqQuestion25": "Jaké různé úkoly existují?",
|
||||
"faqQuestion26": "Jaké úkoly mohu například vytvořit?",
|
||||
"webFaqAnswer28": "Jistě! Tlačítko \"Pozastavit Škody\" je k nalezení v nastavení. Tak můžež zabránit ztrátě bodů za promeškané denní úkoly. To je užitečné např. na dovolené, pokud sipotřebuješ odpočinout nebo musíš z jiného důvodu udělat přestávku v plnění denních úkolů. Pokud se právě nacházíš na výpravě se svou družinou, tvůj zásah proti nepříteli se pozastaví, ale stále můžeš být vystaven zranění, pokud ostatní členové družiny neplní své úkoly. \n\nPokud chceš pozastavit pouze některé úkoly, můžeš je upravit, tak že se opakují v 0 dnech a ponechat je v aplikaci, dokud nebudeš připraven je začít znovu plnit.",
|
||||
"webFaqAnswer28": "Jistě! Tlačítko \"Pozastavit Škody\" je k nalezení v nastavení. Tak můžež zabránit ztrátě bodů za promeškané denní úkoly. To je užitečné např. na dovolené, pokud sipotřebuješ odpočinout nebo musíš z jiného důvodu udělat přestávku v plnění denních úkolů. Pokud se právě nacházíš na výpravě se svou družinou, tvůj zásah proti nepříteli se pozastaví, ale stále můžeš být vystaven zranění, pokud ostatní členové družiny neplní své úkoly. \n\nPokud chceš pozastavit pouze některé úkoly, můžeš je upravit, tak že se opakují v 0 dnech a ponechat je v aplikaci, dokud nebudeš připraven je začít znovu plnit.",
|
||||
"faqQuestion29": "Jak získám zpět Zdraví?",
|
||||
"webFaqAnswer29": "Můžeš získat 15 bodů zdraví zakoupením Lektvaru zdraví ze sloupce Odměny za 25 zlaťáků. Navíc, pokud postoupíš do další úrovně, tak se ti všechno zdraví automaticky obnoví!",
|
||||
"faqQuestion30": "Co se stane, když mi dojde zdraví?",
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"pkQuestion3": "Why did you add social features?",
|
||||
"pkAnswer3": "Social pressure is a huge motivating factor for a lot of people, so we knew that we wanted to have a strong community that would hold each other accountable for their goals and cheer for their successes. Luckily, one of the things that multiplayer video games do best is foster a sense of community among their users! Habitica’s community structure borrows from these types of games; you can form a small Party of close friends, but you can also join a larger, shared-interest groups known as a Guild. Although some users choose to play solo, most decide to form a support network that encourages social accountability through features such as Quests, where Party members pool their productivity to battle monsters together.",
|
||||
"pkQuestion4": "Why does skipping tasks remove your avatar’s health?",
|
||||
"pkAnswer4": "If you skip one of your daily goals, your avatar will lose health the following day. This serves as an important motivating factor to encourage people to follow through with their goals because people really hate hurting their little avatar! Plus, the social accountability is critical for a lot of people: if you’re fighting a monster with your friends, skipping your tasks hurts their avatars, too.",
|
||||
"pkAnswer4": "If you skip one of your daily goals, your avatar will lose health the following day. This serves as an important motivating factor to encourage people to follow through with their goals because people really hate hurting their little avatar! Plus, the social accountability is critical for a lot of people: if you’re fighting a monster with your friends, skipping your tasks hurts their avatars, too.",
|
||||
"pkQuestion5": "What distinguishes Habitica from other gamification programs?",
|
||||
"pkAnswer5": "One of the ways that Habitica has been most successful at using gamification is that we've put a lot of effort into thinking about the game aspects to ensure that they are actually fun. We've also included many social components, because we feel that some of the most motivating games let you play with friends, and because research has shown that it's easier to form habits when you have accountability to other people.",
|
||||
"pkQuestion6": "Who is the typical user of Habitica?",
|
||||
|
||||
@@ -522,7 +522,7 @@
|
||||
"armorSpecialSummer2015MageText": "Věštecké roucho",
|
||||
"armorSpecialSummer2015MageNotes": "Moc se skrývá v nadýchaných rukávech. Zvyšuje Inteligenci o <%= int %>. Limitovaná edice letní výbavy 2015.",
|
||||
"armorSpecialSummer2015HealerText": "Námořníkovo brnění",
|
||||
"armorSpecialSummer2015HealerNotes": "Toto brnění dává všem najevo, že jsi čestný námořní kupec, který by se nikdy nechoval jako křivák. Zvyšuje Obranu o <%= con %>. Limitovaná edice letní výbavy 2015.",
|
||||
"armorSpecialSummer2015HealerNotes": "Toto brnění dává všem najevo, že jsi čestný námořní kupec, který by se nikdy nechoval jako křivák. Zvyšuje Obranu o <%= con %>. Limitovaná edice letní výbavy 2015.",
|
||||
"armorSpecialFall2015RogueText": "Netopýří brnění",
|
||||
"armorSpecialFall2015RogueNotes": "Odleť do bitvy. Zvyšuje Vnímání o <%= per %>. Limitovaná edice podzimní výbavy 2015.",
|
||||
"armorSpecialFall2015WarriorText": "Strašákovo brnění",
|
||||
@@ -538,7 +538,7 @@
|
||||
"armorSpecialWinter2016MageText": "Snowboarďácká větrovka",
|
||||
"armorSpecialWinter2016MageNotes": "Ten nejmoudřejší z čarodějů je v zimě pořádně zachumlaný. Zvyšuje Inteligenci o <%= int %>. Limitovaná edice zimní výbavy 2015-2016.",
|
||||
"armorSpecialWinter2016HealerText": "Sváteční vílí plášť",
|
||||
"armorSpecialWinter2016HealerNotes": "Sváteční víly se halí do svých křídel, aby se chránily, zatímco po zemi Habitica létají pomocí křídel na hlavě rychlostí až 160km/h, doručují dárky a házejí na lidi konfety. Jak vtipné. Zvyšuje Obranu o <%= con %>. Limitovaná edice zimní výbavy 2015-2016.",
|
||||
"armorSpecialWinter2016HealerNotes": "Sváteční víly se halí do svých křídel, aby se chránily, zatímco po zemi Habitica létají pomocí křídel na hlavě rychlostí až 160km/h, doručují dárky a házejí na lidi konfety. Jak vtipné. Zvyšuje Obranu o <%= con %>. Limitovaná edice zimní výbavy 2015-2016.",
|
||||
"armorSpecialSpring2016RogueText": "Maskáčový oblek",
|
||||
"armorSpecialSpring2016RogueNotes": "Chytré štěně ví, že si má vybrat jasnější převlek pro to aby se skryl, když je vše zelené a zvučné. Zvyšuje vnímání o <%= per %>. Limitované edice Jarní výbavy 2016.",
|
||||
"armorSpecialSpring2016WarriorText": "Mocné brnění",
|
||||
@@ -660,7 +660,7 @@
|
||||
"armorMystery201504Text": "Oděv pilné včelky",
|
||||
"armorMystery201504Notes": "V tomto okouzlujícím oděvu budeš produktivní jako pilná včelka! Nepřináší žádný benefit. Předmět pro předplatitele Duben 2015.",
|
||||
"armorMystery201506Text": "Neopren na šnorchlování",
|
||||
"armorMystery201506Notes": "Zašnorchluj si u korálového útesu v tomto zářivě barevném úboru! Nepřináší žádný benefit. Předmět pro předplatitele červen 2015.",
|
||||
"armorMystery201506Notes": "Zašnorchluj si u korálového útesu v tomto zářivě barevném úboru! Nepřináší žádný benefit. Předmět pro předplatitele červen 2015.",
|
||||
"armorMystery201508Text": "Kostým geparda",
|
||||
"armorMystery201508Notes": "Utíkej rychle jako blesk s tímhle huňatým kostýmem geparda! Nepřináší žádný benefit. Předmět pro předplatitele srpen 2015.",
|
||||
"armorMystery201509Text": "Kostým vlkodlaka",
|
||||
@@ -710,7 +710,7 @@
|
||||
"armorMystery201810Text": "Dark Forest Robes",
|
||||
"armorMystery201810Notes": "These robes are extra warm to protect you from the ghastly cold of haunted realms. Confers no benefit. October 2018 Subscriber Item.",
|
||||
"armorMystery301404Text": "Steampunk oblek",
|
||||
"armorMystery301404Notes": "Elegantní a fešácký, joj! Nepřináší žádný benefit. Předmět pro předplatitele únor 3015.",
|
||||
"armorMystery301404Notes": "Elegantní a fešácký, joj! Nepřináší žádný benefit. Předmět pro předplatitele únor 3015.",
|
||||
"armorMystery301703Text": "Steampunk Peacock Gown",
|
||||
"armorMystery301703Notes": "This elegant gown is well-suited for even the most extravagant gala! Confers no benefit. March 3017 Subscriber Item.",
|
||||
"armorMystery301704Text": "Steampunk Pheasant Dress",
|
||||
@@ -724,9 +724,9 @@
|
||||
"armorArmoireGoldenTogaText": "Zlatá tóga",
|
||||
"armorArmoireGoldenTogaNotes": "Tato třpytivá tóga je nošena pouze pravými hrdiny. Zvyšuje Sílu a Obranu o <%= attrs %> každou. Začarovaná almara: Set zlaté tógy (předmět 1 ze 3).",
|
||||
"armorArmoireHornedIronArmorText": "Železné brnění s rohy",
|
||||
"armorArmoireHornedIronArmorNotes": "Zprudka ukuto z oceli, toto brnění je skoro nerozbitné. Zvyšuje Obranu o <%= con %> a Vnímání o <%= per %>. Začarovaná almara: Set helmy s rohy (předmět 2 ze 3).",
|
||||
"armorArmoireHornedIronArmorNotes": "Zprudka ukuto z oceli, toto brnění je skoro nerozbitné. Zvyšuje Obranu o <%= con %> a Vnímání o <%= per %>. Začarovaná almara: Set helmy s rohy (předmět 2 ze 3).",
|
||||
"armorArmoirePlagueDoctorOvercoatText": "Zimník Morového Lékaře",
|
||||
"armorArmoirePlagueDoctorOvercoatNotes": "Autentický zimník nošený doktory, kteří vzdorují Moru Otálení! Zvyšuje Inteligenci o <%= int %>, Sílu o <%= str %> a Obranu o <%= con %>. Začarovaná almara: Set Morových Lékařů (Předmět 3 ze 3).",
|
||||
"armorArmoirePlagueDoctorOvercoatNotes": "Autentický zimník nošený doktory, kteří vzdorují Moru Otálení! Zvyšuje Inteligenci o <%= int %>, Sílu o <%= str %> a Obranu o <%= con %>. Začarovaná almara: Set Morových Lékařů (Předmět 3 ze 3).",
|
||||
"armorArmoireShepherdRobesText": "Oděv pastýře",
|
||||
"armorArmoireShepherdRobesNotes": "Látka je chladivá a prodyšná, perfektní pro horký den pasení gryfů v poušti. Zvyšuje Sílu a Vnímání o <%= attrs %> každé. Začarovaná almara: Set pastýře (předmět 2 ze 3).",
|
||||
"armorArmoireRoyalRobesText": "Královský oděv",
|
||||
@@ -850,17 +850,17 @@
|
||||
"headWizard5Text": "Královský klobouk pro mága",
|
||||
"headWizard5Notes": "Vyzařuje autoritu nad jměním, počasím a nižšími mágy. Zvyšuje Vnímání o <%= per %>.",
|
||||
"headHealer1Text": "Křišťálová čelenka",
|
||||
"headHealer1Notes": "Čelenka zdobená kameny pro soustředění se na úkol. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headHealer1Notes": "Čelenka zdobená kameny pro soustředění se na úkol. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headHealer2Text": "Ametystová čelenka",
|
||||
"headHealer2Notes": "Ochutnávka luxusu pro skromnou profesi. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headHealer2Notes": "Ochutnávka luxusu pro skromnou profesi. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headHealer3Text": "Safírová čelenka",
|
||||
"headHealer3Notes": "Září na znamení toho, že trpící budou brzy spaseni. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headHealer3Notes": "Září na znamení toho, že trpící budou brzy spaseni. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headHealer4Text": "Smaragdová čelenka",
|
||||
"headHealer4Notes": "Vyzařuje auru života a růstu. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headHealer5Text": "Královská čelenka",
|
||||
"headHealer5Notes": "Pro krále, královnu, či konatele zázraků. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headHealer5Notes": "Pro krále, královnu, či konatele zázraků. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headSpecial0Text": "Stínová helma",
|
||||
"headSpecial0Notes": "Krev a popel, láva a obsidián dávají této helmě její kouzlo a sílu. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headSpecial0Notes": "Krev a popel, láva a obsidián dávají této helmě její kouzlo a sílu. Zvyšuje Inteligenci o <%= int %>.",
|
||||
"headSpecial1Text": "Křišťálová přilba",
|
||||
"headSpecial1Notes": "The favored crown of those who lead by example. Increases all Stats by <%= attrs %>.",
|
||||
"headSpecial2Text": "Bezejmenná přilba",
|
||||
@@ -1162,9 +1162,9 @@
|
||||
"headMystery201901Text": "Polaris Helm",
|
||||
"headMystery201901Notes": "The glowing gems on this helm contain light magically captured from winter auroras. Confers no benefit. January 2019 Subscriber Item.",
|
||||
"headMystery301404Text": "Fešný cylindr",
|
||||
"headMystery301404Notes": "Fešný cylindr pro ty největší džentlmeny. Předmět pro předplatitele leden 2015. Nepřináší žádný benefit.",
|
||||
"headMystery301404Notes": "Fešný cylindr pro ty největší džentlmeny. Předmět pro předplatitele leden 2015. Nepřináší žádný benefit.",
|
||||
"headMystery301405Text": "Obyčejný cylindr",
|
||||
"headMystery301405Notes": "Obyčejný cylindr, který si přímo žádá o doplnění nějakým fešáckým ohozem. Nepřináší žádný benefit. Předmět pro předplatitele květen 3015.",
|
||||
"headMystery301405Notes": "Obyčejný cylindr, který si přímo žádá o doplnění nějakým fešáckým ohozem. Nepřináší žádný benefit. Předmět pro předplatitele květen 3015.",
|
||||
"headMystery301703Text": "Fancy Feather Hat",
|
||||
"headMystery301703Notes": "The feathers for this hat were donated by Miss Prue's Finishing School for Fancy Peacocks. Wear them with pride! Confers no benefit. March 3017 Subscriber Item.",
|
||||
"headMystery301704Text": "Pheasant Plume Hat",
|
||||
@@ -1186,7 +1186,7 @@
|
||||
"headArmoireGoldenLaurelsText": "Zlaté vavříny",
|
||||
"headArmoireGoldenLaurelsNotes": "Tyto zlaté vavříny odměňují ty, kteří pokořili zlozvyky. Zvyšuje Vnímání a Obranu o <%= attrs %> každou. Začarovaná almara: Set zlaté tógy (předmět 2 ze 3).",
|
||||
"headArmoireHornedIronHelmText": "Železná helma s rohy",
|
||||
"headArmoireHornedIronHelmNotes": "Zprudka ukuto z oceli, tato helma je skoro nerozbitná. Zvyšuje Obranu o <%= con %> a Sílu o <%= str %>. Začarovaná almara: Set helmy s rohy (předmět 1 ze 3).",
|
||||
"headArmoireHornedIronHelmNotes": "Zprudka ukuto z oceli, tato helma je skoro nerozbitná. Zvyšuje Obranu o <%= con %> a Sílu o <%= str %>. Začarovaná almara: Set helmy s rohy (předmět 1 ze 3).",
|
||||
"headArmoireYellowHairbowText": "Žlutá mašle do vlasů",
|
||||
"headArmoireYellowHairbowNotes": "Become perceptive, strong, and smart while wearing this beautiful Yellow Hairbow! Increases Perception, Strength, and Intelligence by <%= attrs %> each. Enchanted Armoire: Yellow Hairbow Set (Item 1 of 2).",
|
||||
"headArmoireRedFloppyHatText": "Červený měkký klobouk",
|
||||
@@ -1297,7 +1297,7 @@
|
||||
"shieldSpecialTakeThisText": "Take This Shield",
|
||||
"shieldSpecialTakeThisNotes": "This shield was earned by participating in a sponsored Challenge made by Take This. Congratulations! Increases all Stats by <%= attrs %>.",
|
||||
"shieldSpecialGoldenknightText": "Mustainův Milník drtící řemdih",
|
||||
"shieldSpecialGoldenknightNotes": "Meetingy, monstra, neduhy: zvládnuto! Prásk! Zvyšuje Obranu a Vnímání o <%= attrs %> každé.",
|
||||
"shieldSpecialGoldenknightNotes": "Meetingy, monstra, neduhy: zvládnuto! Prásk! Zvyšuje Obranu a Vnímání o <%= attrs %> každé.",
|
||||
"shieldSpecialMoonpearlShieldText": "Štít z měsíční perly",
|
||||
"shieldSpecialMoonpearlShieldNotes": "Zkonstruován k rychlému plavání a také nějaké té obraně. Zvyšuje Obranu o <%= con %>.",
|
||||
"shieldSpecialMammothRiderHornText": "Mammoth Rider's Horn",
|
||||
@@ -1409,7 +1409,7 @@
|
||||
"shieldMystery201802Text": "Love Bug Shield",
|
||||
"shieldMystery201802Notes": "Although it may look like brittle candy, this shield is resistant to even the strongest Shattering Heartbreak attacks! Confers no benefit. February 2018 Subscriber Item.",
|
||||
"shieldMystery301405Text": "Štít z hodin",
|
||||
"shieldMystery301405Notes": "Čas je na tvé straně s tímhle štítem z hodin! Nepřináší žádný benefit. Předmět pro předplatitele červen 3015.",
|
||||
"shieldMystery301405Notes": "Čas je na tvé straně s tímhle štítem z hodin! Nepřináší žádný benefit. Předmět pro předplatitele červen 3015.",
|
||||
"shieldMystery301704Text": "Fluttery Fan",
|
||||
"shieldMystery301704Notes": "This fine fan will keep you feeling cool and looking fancy! Confers no benefit. April 3017 Subscriber Item.",
|
||||
"shieldArmoireGladiatorShieldText": "Štít gladiátora",
|
||||
@@ -1417,7 +1417,7 @@
|
||||
"shieldArmoireMidnightShieldText": "Půlnoční štít",
|
||||
"shieldArmoireMidnightShieldNotes": "Tento štít je nejmocnější úderem půlnoci! Zvyšuje Obranu o <%= con %> a Sílu o <%= str %>. Začarovaná almara: Nezávislý předmět.",
|
||||
"shieldArmoireRoyalCaneText": "Královská hůlka",
|
||||
"shieldArmoireRoyalCaneNotes": "Sláva vládci, oslavovaného v písních! Zvyšuje Obranu, Inteligenci a Vnímání o <%= attrs %> každé. Začarovaná almara: Královský set (předmět 2 ze 3).",
|
||||
"shieldArmoireRoyalCaneNotes": "Sláva vládci, oslavovaného v písních! Zvyšuje Obranu, Inteligenci a Vnímání o <%= attrs %> každé. Začarovaná almara: Královský set (předmět 2 ze 3).",
|
||||
"shieldArmoireDragonTamerShieldText": "Štít krotitele draků",
|
||||
"shieldArmoireDragonTamerShieldNotes": "Znejisti své nepřátele tímto štítem ve tvaru draka. Zvyšuje Vnímání o <%= per %>. Začarovaná almara: Set krotitele draků (předmět 2 ze 3).",
|
||||
"shieldArmoireMysticLampText": "Mystická lampa",
|
||||
@@ -1542,11 +1542,11 @@
|
||||
"bodyBase0Text": "Žádné doplňky",
|
||||
"bodyBase0Notes": "Žádné doplňky.",
|
||||
"bodySpecialWonderconRedText": "Rubínový límec",
|
||||
"bodySpecialWonderconRedNotes": "Atraktivní rubínový límec! Speciální edice běžné zbroje. Nepřináší žádný benefit.",
|
||||
"bodySpecialWonderconRedNotes": "Atraktivní rubínový límec! Speciální edice běžné zbroje. Nepřináší žádný benefit.",
|
||||
"bodySpecialWonderconGoldText": "Zlatý límec",
|
||||
"bodySpecialWonderconGoldNotes": "Atraktivní zlatý límec! Speciální edice běžné zbroje. Nepřináší žádný benefit.",
|
||||
"bodySpecialWonderconGoldNotes": "Atraktivní zlatý límec! Speciální edice běžné zbroje. Nepřináší žádný benefit.",
|
||||
"bodySpecialWonderconBlackText": "Ebenový límec",
|
||||
"bodySpecialWonderconBlackNotes": "Atraktivní ebenový límec! Speciální edice běžné zbroje. Nepřináší žádný benefit.",
|
||||
"bodySpecialWonderconBlackNotes": "Atraktivní ebenový límec! Speciální edice běžné zbroje. Nepřináší žádný benefit.",
|
||||
"bodySpecialTakeThisText": "Take This Pauldrons",
|
||||
"bodySpecialTakeThisNotes": "These pauldrons were earned by participating in a sponsored Challenge made by Take This. Congratulations! Increases all Stats by <%= attrs %>.",
|
||||
"bodySpecialAetherAmuletText": "Aether Amulet",
|
||||
@@ -1659,7 +1659,7 @@
|
||||
"headAccessoryMystery201812Text": "Arctic Fox Ears",
|
||||
"headAccessoryMystery201812Notes": "You hear the subtle sound of snowflakes falling upon the landscape. Confers no benefit. December 2018 Subscriber Item.",
|
||||
"headAccessoryMystery301405Text": "Brýle na čele",
|
||||
"headAccessoryMystery301405Notes": "\"Brýle jsou na oči,\" říkali. \"Nikdo nechce nosit brýle na čele,\" říkali. Ha! Teď jsi jim to natřel! Nepřináší žádný benefit. Předmět pro předplatitele srpen 3015.",
|
||||
"headAccessoryMystery301405Notes": "\"Brýle jsou na oči,\" říkali. \"Nikdo nechce nosit brýle na čele,\" říkali. Ha! Teď jsi jim to natřel! Nepřináší žádný benefit. Předmět pro předplatitele srpen 3015.",
|
||||
"headAccessoryArmoireComicalArrowText": "Komický šíp",
|
||||
"headAccessoryArmoireComicalArrowNotes": "This whimsical item sure is good for a laugh! Increases Strength by <%= str %>. Enchanted Armoire: Independent Item.",
|
||||
"headAccessoryArmoireGogglesOfBookbindingText": "Goggles of Bookbinding",
|
||||
@@ -1692,7 +1692,7 @@
|
||||
"eyewearSpecialWonderconBlackText": "Záludná maska",
|
||||
"eyewearSpecialWonderconBlackNotes": "Tvé motivy jsou bezpochyby legitimní. Nepřináší žádný benefit. Speciální edice běžné zbroje.",
|
||||
"eyewearMystery201503Text": "Akvamarínová maska",
|
||||
"eyewearMystery201503Notes": "Ať ti třpytivé krystaly nevypíchnou oko! Nepřináší žádný benefit. Předmět pro předplatitele březen 2015.",
|
||||
"eyewearMystery201503Notes": "Ať ti třpytivé krystaly nevypíchnou oko! Nepřináší žádný benefit. Předmět pro předplatitele březen 2015.",
|
||||
"eyewearMystery201506Text": "Neonový šnorchl",
|
||||
"eyewearMystery201506Notes": "Tento neonový šnorchl umožňuje svému nositeli vidět pod vodou. Nepřináší žádný benefit. Předmět pro předplatitele červen 2015.",
|
||||
"eyewearMystery201507Text": "Čupr sluneční brýle",
|
||||
@@ -1700,9 +1700,9 @@
|
||||
"eyewearMystery201701Text": "Nadčasové Sluneční Brýle",
|
||||
"eyewearMystery201701Notes": "Tyto sluneční brýle ochrání tvé oči před škodlivými paprsky a budou vypadat skvěle, ať už se objevíš kdekoliv a kdykoliv! Nepřináší žádný benefit. Leden 2017 - Předmět pro předplatitele.",
|
||||
"eyewearMystery301404Text": "Brýle na oči",
|
||||
"eyewearMystery301404Notes": "Nic na oči nemůže být trendovějšího než brýle - možná tedy kromě monoklu. Nepřináší žádný benefit. Předmět pro předplatitele duben 3015.",
|
||||
"eyewearMystery301404Notes": "Nic na oči nemůže být trendovějšího než brýle - možná tedy kromě monoklu. Nepřináší žádný benefit. Předmět pro předplatitele duben 3015.",
|
||||
"eyewearMystery301405Text": "Monokl",
|
||||
"eyewearMystery301405Notes": "Není nic stylovějšího než monokl - možná tedy kromě brýlí. Nepřináší žádný benefit. Předmět pro předplatitele červenec 3015.",
|
||||
"eyewearMystery301405Notes": "Není nic stylovějšího než monokl - možná tedy kromě brýlí. Nepřináší žádný benefit. Předmět pro předplatitele červenec 3015.",
|
||||
"eyewearMystery301703Text": "Peacock Masquerade Mask",
|
||||
"eyewearMystery301703Notes": "Perfect for a fancy masquerade or for stealthily moving through a particularly well-dressed crowd. Confers no benefit. March 3017 Subscriber Item.",
|
||||
"eyewearArmoirePlagueDoctorMaskText": "Maska Morového Lékaře",
|
||||
|
||||
@@ -246,7 +246,7 @@
|
||||
"partyDescriptionPlaceholder": "This is our Party's description. It describes what we do in this Party. If you want to learn more about what we do in this Party, read the description. Party on.",
|
||||
"guildGemCostInfo": "A Gem cost promotes high quality Guilds and is transferred into your Guild's bank.",
|
||||
"noGuildsTitle": "Nejsi členem žádného cechu.",
|
||||
"noGuildsParagraph1": "Guilds are social groups created by other players that can offer you support, accountability, and encouraging chat.",
|
||||
"noGuildsParagraph1": "Guilds are social groups created by other players that can offer you support, accountability, and encouraging chat.",
|
||||
"noGuildsParagraph2": "Click the Discover tab to see recommended Guilds based on your interests, browse Habitica's public Guilds, or create your own Guild.",
|
||||
"noGuildsMatchFilters": "We couldn't find any matching Guilds.",
|
||||
"privateDescription": "A private Guild will not be displayed in Habitica's Guild directory. New members can be added by invitation only.",
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
"mustPurchaseToSet": "Musíte koupit <%= val %> k nastavení na <%= key %>.",
|
||||
"typeRequired": "Je požadován typ",
|
||||
"positiveAmountRequired": "Pozitivní množství je požadováno",
|
||||
"notAccteptedType": "Typ musí být v [vajíčka, líhnoucíLektvary, prémiovéLíhnoucíLektvary, jídlo, výpravy, výbava]",
|
||||
"notAccteptedType": "Typ musí být v [vajíčka, líhnoucíLektvary, prémiovéLíhnoucíLektvary, jídlo, výpravy, výbava]",
|
||||
"contentKeyNotFound": "Klíč nenalezen pro Obsah <%= type %>",
|
||||
"plusGem": "+<%= count %> Drahokam",
|
||||
"typeNotSellable": "Nelze prodat. Lze prodat pouze <%= acceptedTypes %>",
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"mountMasterText": "Zkrotil všech 90 zvířátek ( šíleně obtížné, zaslouží si uznání!)",
|
||||
"mountMasterText2": " a vypustil všech svých 90 zvířat celkem <%= count %>krát",
|
||||
"triadBingoName": "Bingo trojice",
|
||||
"triadBingoText": "Našel všech 90 mazlíčků, zkrotil všech 90 zkrocených zvířat, a našel všech 90 mazlíčků ZNOVU (JAK JSI TO UDĚLAL!)",
|
||||
"triadBingoText": "Našel všech 90 mazlíčků, zkrotil všech 90 zkrocených zvířat, a našel všech 90 mazlíčků ZNOVU (JAK JSI TO UDĚLAL!)",
|
||||
"triadBingoText2": " a vypustil plnou stáj celkem <%= count %>krát",
|
||||
"triadBingoAchievement": "Získal jsi ocenění \"Bingo trojice\" za nalezení všech mazlíčků, zkrocení všech zvířat, a znovunalezení všech mazlíčku ještě jednou!",
|
||||
"hatchedPet": "Vylíhnul jsi nového <%= potion %><%= egg %>!",
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
"questBasilistCompletion": "Bazi-lístek se rozpadl ve změť papírů, které se ve vzduchu blýskají jako duha. \"Ufff!\" říká @Arcosine. \"Dobře, že jste tu byli!\" Nabytí zkušenostmi posbíráte popadané zlato mezi papíry.",
|
||||
"questBasilistBoss": "Bazi-lístek",
|
||||
"questEggHuntText": "Sbírání Vajec",
|
||||
"questEggHuntNotes": "Přes noc se všude objevila podivná obyčejná vejce: v Mattově stáji, za pokladnou v krčme, a dokonce mezi vejci zvířat na tržišti! Jaká to nepříjemnost! \"Nikdo neví odkud pochází, nebo co by se z nich mohlo vylíhnout,\" říká Megan, \"Ale nemůžeme je nechat válet se jen tak kolem! Tvrdě pracuj a pořádně hledej, abys pomohl shromáždit všechna tato záhadný vajíčka. Možná, když jich shromáždíš dostatek, zbudou nějaká i pro tebe...\"",
|
||||
"questEggHuntNotes": "Přes noc se všude objevila podivná obyčejná vejce: v Mattově stáji, za pokladnou v krčme, a dokonce mezi vejci zvířat na tržišti! Jaká to nepříjemnost! \"Nikdo neví odkud pochází, nebo co by se z nich mohlo vylíhnout,\" říká Megan, \"Ale nemůžeme je nechat válet se jen tak kolem! Tvrdě pracuj a pořádně hledej, abys pomohl shromáždit všechna tato záhadný vajíčka. Možná, když jich shromáždíš dostatek, zbudou nějaká i pro tebe...\"",
|
||||
"questEggHuntCompletion": "Zvládli jste to! Z vděčnosti ti <strong>Megan</strong> dá deset vajec. \"Vsadím se, že je líhnoucí lektvary obarví do úžasných barviček! A jsem zvědavá, co se stane, až je vykrmíš...\"",
|
||||
"questEggHuntCollectPlainEgg": "Obyčejná vejce",
|
||||
"questEggHuntDropPlainEgg": "Obyčejné vejce",
|
||||
@@ -201,7 +201,7 @@
|
||||
"questBunnyText": "Zabijácký králíček",
|
||||
"questBunnyNotes": "Po mnoha těžkých dnech konečně staneš na vrcholu Hory Flákání a stojíš před impozantními dveřmi do Pevnosti Zanedbání. Přečteš si nápis na kameni. \"Uvnitř sídlí stvoření, které ztělesňuje tvůj největší strach, důvod tvého nicnedělání. Zaklepej a postav se svým démonům!\" Třeseš se a představuješ si ten horor za dveřmi a cítíš, že bys raději utekl jako tolikrát předtím. @Draayder tě zadrží. \"neboj, příteli! Přišel tvůj čas. Tohle musíš udělat!\"<br><br>Zaklepeš na dveře a ty se otevřou. Zevnitř slyšíš hrůzný řev a vytasíš svou zbraň.",
|
||||
"questBunnyBoss": "Zabijácký králíček",
|
||||
"questBunnyCompletion": "Posledním úderem srážíš zabijáckého králíčka k zemi. Třpytivá mlha se zvedne z jejího těla a smrskne se na obyčejného králíčka... vůbec nevypadá jako ta obluda, se kterou ses bil před chvílí. Její nosík se zaklepe a odhopká pryč zanechávajíc za sebou vejce. @Gully se směje. \"Hora Flákání dokáže z malých výzev udělat skoro neporazitelné. Vezměme tato vejce a pojďme domů.\"",
|
||||
"questBunnyCompletion": "Posledním úderem srážíš zabijáckého králíčka k zemi. Třpytivá mlha se zvedne z jejího těla a smrskne se na obyčejného králíčka... vůbec nevypadá jako ta obluda, se kterou ses bil před chvílí. Její nosík se zaklepe a odhopká pryč zanechávajíc za sebou vejce. @Gully se směje. \"Hora Flákání dokáže z malých výzev udělat skoro neporazitelné. Vezměme tato vejce a pojďme domů.\"",
|
||||
"questBunnyDropBunnyEgg": "Králíček (vejce)",
|
||||
"questBunnyUnlockText": "Odemyká vejce Králíčka na Trhu",
|
||||
"questSlimeText": "Želésprávce",
|
||||
@@ -567,8 +567,8 @@
|
||||
"questPterodactylDropPterodactylEgg": "Pterodactyl (Egg)",
|
||||
"questPterodactylUnlockText": "Unlocks purchasable Pterodactyl eggs in the Market",
|
||||
"questBadgerText": "Stop Badgering Me!",
|
||||
"questBadgerNotes": "Ah, winter in the Taskwoods. The softly falling snow, the branches sparkling with frost, the Flourishing Fairies… still not snoozing?<br><br>“Why are they still awake?” cries @LilithofAlfheim. “If they don't hibernate soon, they'll never have the energy for planting season.”<br><br>As you and @Willow the Witty hurry to investigate, a furry head pops up from the ground. Before you can yell, “It’s the Badgering Bother!” it’s back in its burrow—but not before snatching up the Fairies' “Hibernate” To-Dos and dropping a giant list of pesky tasks in their place!<br><br>“No wonder the fairies aren't resting, if they're constantly being badgered like that!” @plumilla says. Can you chase off this beast and save the Taskwood’s harvest this year?",
|
||||
"questBadgerCompletion": "You finally drive away the the Badgering Bother and hurry into its burrow. At the end of a tunnel, you find its hoard of the faeries’ “Hibernate” To-Dos. The den is otherwise abandoned, except for three eggs that look ready to hatch.",
|
||||
"questBadgerNotes": "Ah, winter in the Taskwoods. The softly falling snow, the branches sparkling with frost, the Flourishing Fairies… still not snoozing?<br><br>“Why are they still awake?” cries @LilithofAlfheim. “If they don't hibernate soon, they'll never have the energy for planting season.”<br><br>As you and @Willow the Witty hurry to investigate, a furry head pops up from the ground. Before you can yell, “It’s the Badgering Bother!” it’s back in its burrow—but not before snatching up the Fairies' “Hibernate” To-Dos and dropping a giant list of pesky tasks in their place!<br><br>“No wonder the fairies aren't resting, if they're constantly being badgered like that!” @plumilla says. Can you chase off this beast and save the Taskwood’s harvest this year?",
|
||||
"questBadgerCompletion": "You finally drive away the the Badgering Bother and hurry into its burrow. At the end of a tunnel, you find its hoard of the faeries’ “Hibernate” To-Dos. The den is otherwise abandoned, except for three eggs that look ready to hatch.",
|
||||
"questBadgerBoss": "The Badgering Bother",
|
||||
"questBadgerDropBadgerEgg": "Badger (Egg)",
|
||||
"questBadgerUnlockText": "Unlocks purchasable Badger eggs in the Market",
|
||||
@@ -651,7 +651,7 @@
|
||||
"questDolphinText": "Delfín Pochyností",
|
||||
"questDolphinNotes": "Procházíš se po březích Zálivu Nedodělků, hlavu plnou náročné práce, která tě očekává. Zaujme tě žblunknutí na vodní hladině. Překrásný delfín přeskočí mezi vlnami. Sluneční svit se odráží na jeho ploutvích. Ale počkej... to není sluneční světlo a delfín se nezanoří zpět do moře. Zahledí se na @khdarkwolf.<br><br>“Já své denní úkoly nikdy nezvládnu” hlesne @khdarkwolf.<br><br>“Asi nejsem dost dobrý, abych dosáhl svých cílů,” fňukne @confusedcicada když delfín přesune svůj přísný pohled na něj.<br><br>“Proč se vůbec namáhat?” zeptá se @mewrose a rozstřese se pod pohledem příšery.<br><br>Pak se delfín podívá na tebea ty cítíš, jak tvé odhodlání mizí pod záplavou pochybností. A vzchopíš se; Někdo musí tu příšeru zastavit a budeš to právě ty!",
|
||||
"questBronzeNotes": "Během osvěžující přestávky mezi výpravami se ty a tví přátelé touláte po lesních stezkách v Taskwoodu. Najednou narazíte na velký padlý vykotlaný strom a z jeho dutiny se něco zaleskne. <br><br>A je to skrýš plná kouzelných líhnoucích lektvarů! Třpytivá bronzová tekutina se převaluje v lahvičkách a @Hachiseiko se po jedné natáhne, aby si ji prohlédl. <br><br> \"Nechej to!\" zasyčí za tebou neznámý hlas. Je to obrovský brouk s krovkami z lesklého bronzu a pozvedá proti tobě klepeta v bojovném postoji. \"To jsou mé lektvary a pokud si je chcete zasloužit, musíte se osvědčit v rytířském souboji!\"",
|
||||
"evilSantaAddlNotes": "Dávej pozor, Pytlačící Ježíšek a Najdi Mládě mají sice na sebe navazující úspěchy z výprav, ale vzácného mazlíčka a jezdecké zvíře dostaneš pouze jednou.",
|
||||
"evilSantaAddlNotes": "Dávej pozor, Pytlačící Ježíšek a Najdi Mládě mají sice na sebe navazující úspěchy z výprav, ale vzácného mazlíčka a jezdecké zvíře dostaneš pouze jednou.",
|
||||
"questDolphinBoss": "Delfín Pochybností",
|
||||
"mythicalMarvelsNotes": "Obsahuje výpravy na získání vajec jednorožce, grifona a mořského hada: Přesvědčení Královny Jednorožců, Ohnivý Grifon a Nebezpečí v Hlubinách: Mořský Had Útočí!"
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
"APIToken": "API token (toto je heslo - přečti si upozornění nahoře!)",
|
||||
"showAPIToken": "Ukázat API Token",
|
||||
"hideAPIToken": "Skrýt API Token",
|
||||
"APITokenWarning": "Jestli potřebuješ nový API Token (např., pokud jsi jej omylem sdílel), napiš email na <%= hrefTechAssistanceEmail %> obsahující tvé Uživatelské ID a aktuální Token. Jakmile se Token resetuje, budeš potřebovat znovu autorizovat vše pomocí odhlášení se ze stránky a mobilní appky, a poté poskytnout nový Token jakémukoliv jinému Habitica nástroji, který používáš.",
|
||||
"thirdPartyApps": "Programy třetí strany",
|
||||
"resetDo": "Udělej to, zresetuj můj účet!",
|
||||
"resetComplete": "Reset dokončen!",
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
"startDate": "Datum začátku",
|
||||
"streaks": "Ocenění za série úspěšnosti",
|
||||
"streakName": "<%= count %> ocenění za sérii úspěšnosti",
|
||||
"streakText": "Získal <%= count %> ocenění za splnění 21-denní série plnění každodenních úkolů",
|
||||
"streakText": "Získal <%= count %> ocenění za splnění 21-denní série plnění každodenních úkolů",
|
||||
"streakSingular": "Sériář",
|
||||
"streakSingularText": "Právě završil 21 dní dlouhou sérii úspěšnosti na denním úkolu",
|
||||
"perfectName": "<%= count %> Perfektních dní",
|
||||
@@ -87,7 +87,7 @@
|
||||
"taskAliasAlreadyUsed": "Alias úkolu byl již použit na jiném úkolu.",
|
||||
"invalidTaskType": "Typ úkolu musí být „zvyk\", „denní úkol\", „úkol\" nebo „odměna\".",
|
||||
"invalidTasksType": "Typ úkolu musí být jeden z „zvyky\", „denní úkoly\", „úkoly\", nebo „odměny\".",
|
||||
"invalidTasksTypeExtra": "Typ úkolu musí být jeden z „zvyky\", „denní úkoly\", „úkoly\", „odměny\", \"dokončené úkoly\".",
|
||||
"invalidTasksTypeExtra": "Typ úkolu musí být jeden z „zvyky\", „denní úkoly\", „úkoly\", „odměny\", \"dokončené úkoly\".",
|
||||
"cantDeleteChallengeTasks": "Úkol náležící výzvě nelze vymazat.",
|
||||
"checklistOnlyDailyTodo": "Seznamy jsou podporovány pouze pro denní úkoly a klasické úkoly",
|
||||
"checklistItemNotFound": "Na seznamu nenalezen žádný předmět s tímto id.",
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
"questEggVelociraptorText": "Velociraptor",
|
||||
"questEggVelociraptorMountText": "Velociraptor",
|
||||
"questEggVelociraptorAdjective": "en vaks",
|
||||
"eggNotes": "Find en udrugningseliksir til at hælde på dit æg, og det vil udklække <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"eggNotes": "Find en udrugningseliksir til at hælde på dit æg, og det vil udklække <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"hatchingPotionBase": "Almindelig",
|
||||
"hatchingPotionWhite": "Hvid",
|
||||
"hatchingPotionDesert": "Ørken",
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
"battleMonstersDesc": "Kæmp monstre med andre Habiticanere! Brug det Guld du tjener i spillet ved at købe spilgenstande eller personlige belønninger, som fx at se en episode af din yndlingsserie.",
|
||||
"playersUseToImprove": "Spillere bruger Habitica til at forbedre sig",
|
||||
"healthAndFitness": "Sundhed og velvære",
|
||||
"healthAndFitnessDesc": "Er du aldrig motiveret til at bruge tandtråd? Har du svært ved at komme til fitness? Habitica gør det endelig sjovt at være sund.",
|
||||
"healthAndFitnessDesc": "Er du aldrig motiveret til at bruge tandtråd? Har du svært ved at komme til fitness? Habitica gør det endelig sjovt at være sund.",
|
||||
"schoolAndWork": "Skole og arbejde",
|
||||
"schoolAndWorkDesc": "Uanset om du forbereder en rapport til din lærer eller din chef, er det let at holde styr på dine fremskridt mens du tackler dine sværeste opgaver.",
|
||||
"muchmuchMore": "Og meget, meget mere!",
|
||||
|
||||
@@ -82,9 +82,9 @@
|
||||
"weaponSpecial1Text": "Krystalklinge",
|
||||
"weaponSpecial1Notes": "Dets glitrende facetter fortæller historien om en helt. Forøger alle Egenskaber med <%= attrs %>.",
|
||||
"weaponSpecial2Text": "Stephen Webers Dragestav",
|
||||
"weaponSpecial2Notes": "Mærk dragens kraft strømme indeni! Øger Styrke og Opfattelse med <%= attrs %> hver.",
|
||||
"weaponSpecial2Notes": "Mærk dragens kraft strømme indeni! Øger Styrke og Opfattelse med <%= attrs %> hver.",
|
||||
"weaponSpecial3Text": "Mustaines Milepæls-masende Morgenstjerne",
|
||||
"weaponSpecial3Notes": "Møder, monstre, modløshed: håndteret! Mast! Øger Styrke, Intelligens og Konstitution med <%= attrs %> hver.",
|
||||
"weaponSpecial3Notes": "Møder, monstre, modløshed: håndteret! Mast! Øger Styrke, Intelligens og Konstitution med <%= attrs %> hver.",
|
||||
"weaponSpecialCriticalText": "Kritisk Kryb-Hammer",
|
||||
"weaponSpecialCriticalNotes": "Denne mægtige kriger slog en særlig stædig fjende fra GitHub, hvor mange andre måtte give fortabt. Denne hammer, skabt af knoglerne fra bugs, rammer plet hver gang. Forøger Styrke og Opfattelse med <%= attrs %> hver.",
|
||||
"weaponSpecialTakeThisText": "Tag dette sværd",
|
||||
@@ -92,7 +92,7 @@
|
||||
"weaponSpecialTridentOfCrashingTidesText": "Trefork af Brydende Bølger",
|
||||
"weaponSpecialTridentOfCrashingTidesNotes": "Giver dig evnen til at herske over fiskene og giver også dine opgaver nogle mægtige hug. Øger Intelligens med <%= int %>.",
|
||||
"weaponSpecialTaskwoodsLanternText": "Taskwoods Lanterne",
|
||||
"weaponSpecialTaskwoodsLanternNotes": "Givet i tidernes morgen til Taskwood Plantagens vogtende spøgelse, denne lanterne kan oplyse det dybeste mørke og væve kraftfulde besværgelser. Øger Opfattelse og Intelligens med <%= attrs %> hver.",
|
||||
"weaponSpecialTaskwoodsLanternNotes": "Givet i tidernes morgen til Taskwood Plantagens vogtende spøgelse, denne lanterne kan oplyse det dybeste mørke og væve kraftfulde besværgelser. Øger Opfattelse og Intelligens med <%= attrs %> hver.",
|
||||
"weaponSpecialBardInstrumentText": "Skjaldens Lute",
|
||||
"weaponSpecialBardInstrumentNotes": "Slå en munter tone an på denne magiske lute! øger Intelligens og Opfattelse med hver <%= attrs %>.",
|
||||
"weaponSpecialLunarScytheText": "Måne Le",
|
||||
@@ -200,7 +200,7 @@
|
||||
"weaponSpecialSummer2016MageText": "Havskum Stav",
|
||||
"weaponSpecialSummer2016MageNotes": "Alle havenes kræfter filtrerer gennem denne stav. Øger Intelligens med <%= int %> og Opfattelse med <%= per %>. Specielt 2016 Sommerudstyr.",
|
||||
"weaponSpecialSummer2016HealerText": "Helende Trefork",
|
||||
"weaponSpecialSummer2016HealerNotes": "Én pik skader, den anden helbreder. Øger Intelligens med <%= int %>. Specielt 2016 Sommerudstyr.",
|
||||
"weaponSpecialSummer2016HealerNotes": "Én pik skader, den anden helbreder. Øger Intelligens med <%= int %>. Specielt 2016 Sommerudstyr.",
|
||||
"weaponSpecialFall2016RogueText": "Edderkoppebidskniv",
|
||||
"weaponSpecialFall2016RogueNotes": "Mærk den stikkende smerte af et edderkoppebid! Forøger Styrke med <%= str %>. Begrænset udstyr fra efteråret 2016.",
|
||||
"weaponSpecialFall2016WarriorText": "Angribende Rødder",
|
||||
@@ -572,13 +572,13 @@
|
||||
"armorSpecialWinter2017HealerText": "Skinnende kronbladsrustning",
|
||||
"armorSpecialWinter2017HealerNotes": "Selvom den er blød, har denne rustning af kronblade fantastiske beskyttende kræfter. Forøger Konstitution med <%= con %>. Begrænset udstyr fra vinteren 2016-2017.",
|
||||
"armorSpecialSpring2017RogueText": "Knivskarp kanindragt",
|
||||
"armorSpecialSpring2017RogueNotes": "Blød men stærk, denne dragt lader dig snige dig gennem haver med ekstra list. Øger Opfattelse med <%= per %>. Specielt 2017 Forårsudstyr.",
|
||||
"armorSpecialSpring2017RogueNotes": "Blød men stærk, denne dragt lader dig snige dig gennem haver med ekstra list. Øger Opfattelse med <%= per %>. Specielt 2017 Forårsudstyr.",
|
||||
"armorSpecialSpring2017WarriorText": "Hundeharnisk",
|
||||
"armorSpecialSpring2017WarriorNotes": "Denne lækre rustning er så skinnende som din fint behandlede pels, men med øget modstand mod angreb. Øger Konstitution med <%= con %>. Specielt 2017 Forårsudstyr.",
|
||||
"armorSpecialSpring2017WarriorNotes": "Denne lækre rustning er så skinnende som din fint behandlede pels, men med øget modstand mod angreb. Øger Konstitution med <%= con %>. Specielt 2017 Forårsudstyr.",
|
||||
"armorSpecialSpring2017MageText": "Hundeheksers Rober",
|
||||
"armorSpecialSpring2017MageNotes": "Magisk med vilje, blød som bonus. Forøger Intelligens med <%= int %>. Begrænset udstyr fra foråret 2017.",
|
||||
"armorSpecialSpring2017HealerText": "Roens rober",
|
||||
"armorSpecialSpring2017HealerNotes": "Blødheden af disse rober giver komfort til dig og trøst til alle der har brug for din helbredende hjælp! Øger Konstitution med <%= con %>. Specielt 2017 Forårsudstyr.",
|
||||
"armorSpecialSpring2017HealerNotes": "Blødheden af disse rober giver komfort til dig og trøst til alle der har brug for din helbredende hjælp! Øger Konstitution med <%= con %>. Specielt 2017 Forårsudstyr.",
|
||||
"armorSpecialSummer2017RogueText": "Sødragehale",
|
||||
"armorSpecialSummer2017RogueNotes": "Disse farvestrålende klæder forvandler bæreren til en ægte Sødrage! Forøger Opfattelse med <%= per %>. Begrænset udstyr fra sommeren 2017.",
|
||||
"armorSpecialSummer2017WarriorText": "Sandpanser",
|
||||
@@ -1297,7 +1297,7 @@
|
||||
"shieldSpecialTakeThisText": "Tag Dette Skjold",
|
||||
"shieldSpecialTakeThisNotes": "This shield was earned by participating in a sponsored Challenge made by Take This. Congratulations! Increases all Stats by <%= attrs %>.",
|
||||
"shieldSpecialGoldenknightText": "Mustaines Milepæls-masende Morgenstjerne",
|
||||
"shieldSpecialGoldenknightNotes": "Møder, monstre, modløshed: håndteret! Mast! Øger Konstitution og Opfattelse med <%= attrs %> hver.",
|
||||
"shieldSpecialGoldenknightNotes": "Møder, monstre, modløshed: håndteret! Mast! Øger Konstitution og Opfattelse med <%= attrs %> hver.",
|
||||
"shieldSpecialMoonpearlShieldText": "Måneperleskjold",
|
||||
"shieldSpecialMoonpearlShieldNotes": "Designet til at svømme hurtigt i, men har også indbygget forsvar. Øger Konstitution med <%= con %>.",
|
||||
"shieldSpecialMammothRiderHornText": "Mammut-riders horn",
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
"emailsMustBeAnArray": "Invitationer med e-mailadresse skal indtastes korrekt i tabellen.",
|
||||
"usernamesMustBeAnArray": "Invitationer med brugernavn skal indtastes korrekt i tabellen.",
|
||||
"canOnlyInviteMaxInvites": "Du kan kun invitere \"<%= maxInvites %>\" ad gangen",
|
||||
"partyExceedsMembersLimit": "Holdets størrelse er begrænset til <%= maxMembersParty %> medlemmer",
|
||||
"partyExceedsMembersLimit": "Holdets størrelse er begrænset til <%= maxMembersParty %> medlemmer",
|
||||
"onlyCreatorOrAdminCanDeleteChat": "Du har ikke rettigheder til at slette denne besked!",
|
||||
"onlyGroupLeaderCanEditTasks": "Du har ikke rettigheder til at administrere opgaver!",
|
||||
"onlyGroupTasksCanBeAssigned": "Kun gruppeopgaver kan blive tildelt",
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"noFoodAvailable": "Du har ikke noget Dyrefoder.",
|
||||
"noSaddlesAvailable": "Du har ikke nogle sadler.",
|
||||
"dropsExplanation": "Du kan få fat i disse ting hurtigere med ædelsten, hvis du ikke længere vil vente på at finde dem når du gennemfører en opgave. <a href=\"https://habitica.fandom.com/wiki/Drops\">Lær mere om drop-systemet.</a>",
|
||||
"dropsExplanationEggs": "Brug Ædelsten for hurtigere at få æg, hvis du ikke vil vente på at få standard-æg som drops, eller gentage Quests for at vinde Quest-æg. <a href=\"https://habitica.fandom.com/wiki/Drops\">Læs mere om dropsystemet her.</a>",
|
||||
"dropsExplanationEggs": "Brug Ædelsten for hurtigere at få æg, hvis du ikke vil vente på at få standard-æg som drops, eller gentage Quests for at vinde Quest-æg. <a href=\"https://habitica.fandom.com/wiki/Drops\">Læs mere om dropsystemet her.</a>",
|
||||
"premiumPotionNoDropExplanation": "Magiske udrugningseliksirer kan ikke blive brugt på æg, der er modtaget fra quests. Den eneste måde at få en magisk udrugningseliksir på, er ved at købe dem nedenfor, ikke fra tilfældige drop.",
|
||||
"beastMasterProgress": "Dyretæmmerfremskridt",
|
||||
"beastAchievement": "Du har opnået \"Dyretæmmer\"-præstationen ved at samle alle kæledyr!",
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
"questDilatoryDropMantisShrimpMount": "Knælerreje (Ridedyr)",
|
||||
"questDilatoryBossRageTavern": "Den Frygtelige Drag'e af Forhaling slår sit FORSØMMELSESSLAG!\n\nÅh nej! På trods af vores indsats lod vi nogle Daglige slippe fra os, og deres mørkerøde farve har tiltrukket Drag'ens vrede! Med dens frygtelige Forsømmelsesslag har den ødelagt Værtshuset! Heldigvis har vi bygget en Kro i en by tæt på, og du kan blive ved med at chatte på stranden... men stakkels Kroejer Daniel så lige sin elskede bygning falde sammen!\n\nJeg håber ikke, at monstret angriber igen!",
|
||||
"questDilatoryBossRageStables": "Den Frygtelige Drag'e af Forhaling slår sit FORSØMMELSESSLAG!\n\nUps! Igen har vi ladet for mange Daglige slippe fra os. Drag'en har sendt sit Forsømmelsesslag mod Matt og staldene! Kæledyr er flygtet i alle retninger. Heldigvis ser det ud til, at dine er i sikkerhed!\n\nStakkels Habitica! Jeg håber ikke, at det sker igen. Skynd dig at udføre alle dine opgaver!",
|
||||
"questDilatoryBossRageMarket": "Den Frygtelige Drag'e af Forhaling slår sit FORSØMMELSESSLAG!\n\nÅh nej! Købmanden Alex har lige fået sin butik slået til plukfisk af Drag'ens Forsømmelsesslag! Men det ser ud til, at vi virkelig er ved at få has på dette bæst. Jeg tvivler på, at det har energi nok til et slag til.\n\nSå fortvivl ikke, Habitica! Lad os fordrive dette bæst fra vores kyster!",
|
||||
"questDilatoryBossRageMarket": "Den Frygtelige Drag'e af Forhaling slår sit FORSØMMELSESSLAG!\n\nÅh nej! Købmanden Alex har lige fået sin butik slået til plukfisk af Drag'ens Forsømmelsesslag! Men det ser ud til, at vi virkelig er ved at få has på dette bæst. Jeg tvivler på, at det har energi nok til et slag til.\n\nSå fortvivl ikke, Habitica! Lad os fordrive dette bæst fra vores kyster!",
|
||||
"questDilatoryCompletion": "Sejren Over Den Frygtelige Drag'e af Forhaling\n\nVi klarede det! Med et sidste brøl kollapser Den Frygtelige Drag'e og svømmer langt, langt væk. Grupper af jublende Habitikanere fylder strandene! Vi har hjulpet Matt, Daniel og Alex genopbygge deres bygninger. Men hvad er dette?\n\n`Beboerne Vender Tilbage!`\n\nNu da Drag'en er flygtet bevæger tusindvis af glinsende farver sig gennem havet. Det er en regnbuesværm af Knælerrejer... og mellem dem, hundredevis af havfolk!\n\n\"Vi er de fortable beboere fra Forhaling!\" forklarer deres leder, Manta. \"Da Forhaling sank brugte Knælerrejerne, der boede i havet, en fortryllelse, der gjorde os til havfolk så vi kunne overleve. Men i sin vrede fangede Den Frygtelige Drag'e os i den mørke sprække. Vi har været fanget dér i hundredevis af år - men nu er vi endelig frie til at genopbygge vores by!\"\n\n\"Som tak,\" siger hans ven @Ottl, \"giver vi jer dette Knælerreje-kæledyr og dette Knælerreje-ridedyr, samt XP, Guld og vores evige taknemmelighed.\"\n\n`Belønning`\n* Knælerreje-kæledyr\n* Knælerreje-ridedyr\n* Chokolade, Blå Candyfloss, Lyserød Candyfloss, Fisk, Honning, Kød, Mælk, Kartoffel, Råddent Kød, Jordbær",
|
||||
"questSeahorseText": "Forhalings-Derby",
|
||||
"questSeahorseNotes": "Det er Derby-dag, og Habitikanere fra hele kontinentet er rejst til Forhaling for at få deres kælesøheste til at svømme væddeløb. Pludselig er der en masse plask, og en snerren kan høres over hele væddeløbsbanen, og du kan høre Søhestepasseren @Kiwibot råbe over bølgernes brusen. \"Samlingen af søheste har tiltrukket en bidsk Søhingst!\" råber hun. \"Han ødelægger alle staldende og den ældgamle bane! Kan nogen berolige ham?\"",
|
||||
@@ -259,7 +259,7 @@
|
||||
"questCheetahDropCheetahEgg": "Gepard (Æg)",
|
||||
"questCheetahUnlockText": "Åbner for køb af Gepardæg på Markedet",
|
||||
"questHorseText": "Tag på Mare-Ridt",
|
||||
"questHorseNotes": "Mens du slapper af i Værtshuset med @beffymaroo og @JessicaChase falder snakken over i godhjertet pralen om dine eventyrlige bedrifter. Stolt af dine handlinger, og måske en smule over gevind, du siger, at du kan løse enhver opgave det skulle være. En fremmed ved et bord tæt ved vender sig mod dig og smiler. Det ene øje glimter, da han beder dig om at bevise din påstand ved at ride hans hest. \nMens I alle går mod stalden, @UncommonCriminal hvisker: \"Du har måske taget munden lidt for fuld. Det er ikke nogen almindelig hest - det bliver et Mare-Ridt!\" Da du ser dyrets stampende hove begynder du at fortryde dine ord...",
|
||||
"questHorseNotes": "Mens du slapper af i Værtshuset med @beffymaroo og @JessicaChase falder snakken over i godhjertet pralen om dine eventyrlige bedrifter. Stolt af dine handlinger, og måske en smule over gevind, du siger, at du kan løse enhver opgave det skulle være. En fremmed ved et bord tæt ved vender sig mod dig og smiler. Det ene øje glimter, da han beder dig om at bevise din påstand ved at ride hans hest. \nMens I alle går mod stalden, @UncommonCriminal hvisker: \"Du har måske taget munden lidt for fuld. Det er ikke nogen almindelig hest - det bliver et Mare-Ridt!\" Da du ser dyrets stampende hove begynder du at fortryde dine ord...",
|
||||
"questHorseCompletion": "Det kræver alle dine færdigheder, men til slut stamper hesten med sine hove, og sætter mulen mod din skulder, før den giver dig lov til at sætte dig op. Du rider kortvarigt, men stolt rundt i Værtshuset mens dine venner råber opmuntrende. Den fremmede bryder ud i et bredt smil.\n\"Jeg kan se, det ikke var tom pralen! Din beslutsomhed er i sandhed imponerende. Tag disse æg og opdræt dine gene heste, og en dag vil vi måske mødes igen.\" Du tage æggene. Den fremmede kipper med hatten... og forsvinder.",
|
||||
"questHorseBoss": "Ride-Mare",
|
||||
"questHorseDropHorseEgg": "Hest (Æg)",
|
||||
@@ -567,8 +567,8 @@
|
||||
"questPterodactylDropPterodactylEgg": "Pterodactyl (Egg)",
|
||||
"questPterodactylUnlockText": "Unlocks purchasable Pterodactyl eggs in the Market",
|
||||
"questBadgerText": "Stop Badgering Me!",
|
||||
"questBadgerNotes": "Ah, winter in the Taskwoods. The softly falling snow, the branches sparkling with frost, the Flourishing Fairies… still not snoozing?<br><br>“Why are they still awake?” cries @LilithofAlfheim. “If they don't hibernate soon, they'll never have the energy for planting season.”<br><br>As you and @Willow the Witty hurry to investigate, a furry head pops up from the ground. Before you can yell, “It’s the Badgering Bother!” it’s back in its burrow—but not before snatching up the Fairies' “Hibernate” To-Dos and dropping a giant list of pesky tasks in their place!<br><br>“No wonder the fairies aren't resting, if they're constantly being badgered like that!” @plumilla says. Can you chase off this beast and save the Taskwood’s harvest this year?",
|
||||
"questBadgerCompletion": "You finally drive away the the Badgering Bother and hurry into its burrow. At the end of a tunnel, you find its hoard of the faeries’ “Hibernate” To-Dos. The den is otherwise abandoned, except for three eggs that look ready to hatch.",
|
||||
"questBadgerNotes": "Ah, winter in the Taskwoods. The softly falling snow, the branches sparkling with frost, the Flourishing Fairies… still not snoozing?<br><br>“Why are they still awake?” cries @LilithofAlfheim. “If they don't hibernate soon, they'll never have the energy for planting season.”<br><br>As you and @Willow the Witty hurry to investigate, a furry head pops up from the ground. Before you can yell, “It’s the Badgering Bother!” it’s back in its burrow—but not before snatching up the Fairies' “Hibernate” To-Dos and dropping a giant list of pesky tasks in their place!<br><br>“No wonder the fairies aren't resting, if they're constantly being badgered like that!” @plumilla says. Can you chase off this beast and save the Taskwood’s harvest this year?",
|
||||
"questBadgerCompletion": "You finally drive away the the Badgering Bother and hurry into its burrow. At the end of a tunnel, you find its hoard of the faeries’ “Hibernate” To-Dos. The den is otherwise abandoned, except for three eggs that look ready to hatch.",
|
||||
"questBadgerBoss": "The Badgering Bother",
|
||||
"questBadgerDropBadgerEgg": "Badger (Egg)",
|
||||
"questBadgerUnlockText": "Unlocks purchasable Badger eggs in the Market",
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
"APIToken": "API-nøgle (det er et kodeord - se advarsel ovenfor!)",
|
||||
"showAPIToken": "Vis API-nøgle",
|
||||
"hideAPIToken": "Skjul API-nøgle",
|
||||
"APITokenWarning": "Hvis du har brug for en ny API-nøgle (f.eks. hvis du har delt den ved et uheld), så send en e-mail til <%= hrefTechAssistanceEmail %> med dit Bruger-ID og din nuværende Nøgle. Når den er nulstillet, skal du godkende alt på ny ved at logge ud af hjemmesiden og mobil-appen, og forsyne alle dine andre Habitica-værktøjer med den nye nøgle.",
|
||||
"thirdPartyApps": "Tredjeparts-apps",
|
||||
"resetDo": "Gør det, nulstil min konto!",
|
||||
"resetComplete": "Nulstilling gennemført!",
|
||||
@@ -89,7 +88,7 @@
|
||||
"invitedGuild": "Du fik en Klaninvitation",
|
||||
"importantAnnouncements": "Påmindelser om check-in for at fuldføre opgaver og modtage belønninger",
|
||||
"weeklyRecaps": "Oversigt over aktiviteter på din konto den sidste uge (Bemærk: dette er midlertidigt slået fra grundet ydelsesproblemer, men vi håber snarest at have det oppe at køre og sende e-mails igen!)",
|
||||
"onboarding": "Hjælp til opsætning af din Habitica-konto",
|
||||
"onboarding": "Hjælp til opsætning af din Habitica-konto",
|
||||
"majorUpdates": "Vigtige meddelelser",
|
||||
"questStarted": "Din Quest er begyndt",
|
||||
"invitedQuest": "Questinvitation",
|
||||
|
||||
@@ -906,5 +906,11 @@
|
||||
"backgroundTrailThroughAForestNotes": "Wandere einen Weg Durch Einen Wald entlang.",
|
||||
"backgrounds062025": "SET 133: Veröffentlicht im Juni 2025",
|
||||
"backgroundSummerSeashoreText": "Sommer Meeresstrand",
|
||||
"backgroundSummerSeashoreNotes": "Erwisch eine Welle an einem Sommer Meeresstrand."
|
||||
"backgroundSummerSeashoreNotes": "Erwisch eine Welle an einem Sommer Meeresstrand.",
|
||||
"backgrounds072025": "SET 134: Veröffentlicht im Juli 2025",
|
||||
"backgroundSirensLairText": "Höhle der Sirene",
|
||||
"backgroundSirensLairNotes": "Wage es, in die Höhle einer Sirene zu tauchen.",
|
||||
"backgrounds082025": "SET 135: Veröffentlicht im August 2025",
|
||||
"backgroundSunnyStreetWithShopsText": "Sonnige Straße mit Läden",
|
||||
"backgroundSunnyStreetWithShopsNotes": "Genieße den Anblick und die Geräusche einer sonnigen Straße mit Läden."
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
"allocatePerPop": "Erhöhe Wahrnehmung um einen Punkt",
|
||||
"allocateInt": "Zugewiesene Intelligenzpunkte:",
|
||||
"allocateIntPop": "Erhöhe Intelligenz um einen Punkt",
|
||||
"noMoreAllocate": "Jetzt, nach dem Erreichen von Level 100, wirst Du keine weiteren Attributpunkte erhalten. Du kannst weiterspielen, oder ein neues Abenteuer auf Level 1 anfangen, in dem Du die <a href='http://habitica.fandom.com/wiki/Orb_of_Rebirth' target='_blank'>Sphäre der Wiedergeburt</a> benutzt!",
|
||||
"noMoreAllocate": "Jetzt, nach dem Erreichen von Level 100, wirst Du keine weiteren Attributpunkte erhalten. Du kannst weiter aufsteigen oder ein neues Abenteuer auf Level 1 anfangen, indem Du die <a href='/shops/market'>Sphäre der Wiedergeburt</a> benutzt!",
|
||||
"stats": "Attributwerte",
|
||||
"strength": "Stärke",
|
||||
"strText": "Stärke erhöht die Wahrscheinlichkeit zufälliger \"kritischer Treffer\" und die Rate mit der durch sie Gold, Beute und Erfahrung gewonnen wird. Und hilft auch dabei, Boss-Monstern Schaden zuzufügen.",
|
||||
@@ -129,8 +129,8 @@
|
||||
"healerText": "Heiler stehen Schaden unbeeindruckt gegenüber und erweitern diesen Schutz auf Andere. Verpasste Tagesaufgaben und schlechte Angewohnheiten schaden ihnen nicht viel und sie haben Mittel und Wege Lebenspunkte wiederherzustellen. Spiele einen Heiler, wenn Du gerne Anderen in einer Party hilfst, oder wenn es Dich besonders reizt, dem Tod durch harte Arbeit zu entkommen!",
|
||||
"optOutOfClasses": "Später entscheiden",
|
||||
"chooseClass": "Wähle Deine Klasse",
|
||||
"chooseClassLearnMarkdown": "[Erfahre mehr über Habiticas Klassensystem](https://habitica.fandom.com/de/wiki/Klassen)",
|
||||
"optOutOfClassesText": "Keine Lust auf Klassen oder Du möchtest Dich später entscheiden? Brich jetzt ab und werde ein Krieger ohne Spezialfähigkeiten. Du kannst Dich im Wiki über das Klassensystem informieren und Deine Klasse jederzeit unter Benutzer Icon -> Statuswerte aktivieren.",
|
||||
"chooseClassLearnMarkdown": "[Erfahre mehr über Habiticas Klassensystem](/static/faq#what-classes)",
|
||||
"optOutOfClassesText": "Noch nicht bereit zu wählen? Keine Eile! Wenn du ablehnst, kannst du zu jeder Klasse in <a href='/static/faq#what-classes' target='_blank'>unseren FAQ</a> nachlesen und in den Einstellungen das Klassen-System aktivieren, wenn du bereit bist.",
|
||||
"selectClass": "Wähle <%= heroClass %>",
|
||||
"select": "Auswählen",
|
||||
"stealth": "Schleichen",
|
||||
@@ -184,8 +184,8 @@
|
||||
"chatCastSpellUser": "<%= username %> wendet <%= spell %> auf <%= target %> an.",
|
||||
"purchasePetItemConfirm": "Dieser Einkauf würde die Anzahl der Gegenstände überschreiten, die Du zum Schlüpfen aller möglichen <%= itemText %>-Tiere benötigst. Bist du sicher?",
|
||||
"notEnoughGold": "Nicht genügend Gold.",
|
||||
"chatCastSpellPartyTimes": "<%= username %> verwendet <%= spell %> <%= times %> Male für Deine Party <%= times %>.",
|
||||
"chatCastSpellUserTimes": "<%= username %> spricht <%= times %> mal <%= spell %> auf <%= target %>.",
|
||||
"chatCastSpellPartyTimes": "<%= username %> wendet <%= spell %> <%= times %> mal für Deine Party an.",
|
||||
"chatCastSpellUserTimes": "<%= username %> wendet <%= times %> mal <%= spell %> auf <%= target %> an.",
|
||||
"nextReward": "Nächste Anmelde-Belohnung",
|
||||
"skins": "Hautfarben",
|
||||
"titleHaircolor": "Haarfarben",
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
"backerTier": "Trägerstufe",
|
||||
"playerTiers": "Spielerstufen",
|
||||
"tier": "Level",
|
||||
"conRewardsURL": "https://habitica.fandom.com/wiki/Contributor_Rewards",
|
||||
"conRewardsURL": "https://github.com/HabitRPG/habitica/wiki/Contributing-to-Habitica#contributor-tier-rewards",
|
||||
"surveysSingle": "Half Habitica zu wachsen, entweder durch das Ausfüllen einer Umfrage oder durch große Hilfe beim Testen. Danke!",
|
||||
"surveysMultiple": "Hat Habitica an <%= count %> Gelegenheiten geholfen zu wachsen, entweder durch Ausfüllen eines Fragebogens oder durch große Hilfe beim Testen. Danke!",
|
||||
"blurbHallPatrons": "Dies ist die Halle der Schirmherren, in der wir die edlen Abenteurer ehren, die Habiticas ursprüngliche Kickstarter-Kampagne unterstützt haben. Wir danken ihnen für die Hilfe Habitica zum Leben zu erwecken!",
|
||||
"blurbHallContributors": "Dies ist die Halle der Mitwirkenden, in der Open-Source-Unterstützer von Habitica geehrt werden. Durch Code, Kunst, Musik, Schreiben, oder auch nur Hilfsbereitschaft haben sie <a href='https://habitica.fandom.com/wiki/Contributor_Rewards' target='_blank'> Edelsteine, exklusive Ausrüstung</a> und <a href='https://habitica.fandom.com/wiki/Contributor_Titles' target='_blank'>angesehene Titel</a> verdient. Auch Du kannst Habitica unterstützen! <a href='https://habitica.fandom.com/wiki/Contributing_to_Habitica' target='_blank'> Hier erfährst Du mehr dazu.</a>",
|
||||
"blurbHallContributors": "Dies ist die Halle der Mitwirkenden, in der Open-Source-Unterstützer von Habitica geehrt werden. Durch Code, Kunst, Musik, Schreiben, oder auch nur Hilfsbereitschaft haben sie <a href='https://github.com/HabitRPG/habitica/wiki/Contributing-to-Habitica#contributor-tier-rewards' target='_blank'> Edelsteine, exklusive Ausrüstung</a> und <a href='https://github.com/HabitRPG/habitica/wiki/Contributing-to-Habitica#contributor-tiers' target='_blank'>angesehene Titel</a> verdient. Auch Du kannst Habitica unterstützen! <a href='https://github.com/HabitRPG/habitica/wiki/Contributing-to-Habitica' target='_blank'> Hier erfährst Du mehr dazu.</a>",
|
||||
"noPrivAccess": "Du besitzt nicht die erforderlichen Berechtigungen."
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"webFaqAnswer31": "Wenn du eine Aufgabe erfüllst und HP verlierst, obwohl du das nicht hättest tun sollen, kam es zu einer Verzögerung, während der Server die auf anderen Plattformen vorgenommenen Änderungen synchronisiert hat. Wenn du zum Beispiel Gold oder Mana verwendest oder HP in der mobilen App verlierst und dann eine Aufgabe auf der Website erledigst, bestätigt der Server lediglich, dass alles synchronisiert ist.",
|
||||
"webFaqAnswer49": "Wenn Du Habitica mit anderen erleben möchtest, aber keine anderen Spieler kennst, ist die Suche nach einer Party die beste Option! Wenn Du bereits andere Spieler kennst, die eine Party haben, kannst Du deinen @Benutzernamen mit ihnen teilen, um eingeladen zu werden. Alternativ kannst Du auch eine neue Gruppe erstellen und sie mit ihrem @Nutzernamen oder ihrer E-Mail-Adresse einladen.\n\nUm eine Party zu erstellen oder zu suchen, wähle \"Party\" im Navigationsmenü und wähle dann die Option, die Dir am besten gefällt.",
|
||||
"webFaqAnswer62": "Gruppenpläne bieten dir die einzigartige Möglichkeit, anderen Mitgliedern deines Gruppenplans gemeinsame Aufgaben zuzuweisen. Wenn eine gemeinsame Aufgabe einem Mitglied zugewiesen wird, können andere Mitglieder sie nicht mehr erledigen.\n\nDu kannst eine Aufgabe auch mehreren Mitgliedern zuweisen. Wenn sich zum Beispiel alle Mitglieder die Zähne putzen müssen, erstellst du eine Aufgabe und weist sie jedem Mitglied zu. Jedes Mitglied kann die Aufgabe erledigen und sich seine individuelle Belohnung verdienen. Die Hauptaufgabe wird als erledigt angezeigt, sobald alle Mitglieder sie erledigt haben.",
|
||||
"webFaqAnswer32": "Alle Spieler beginnen in der Klasse des Kriegers, bis sie Stufe 10 erreicht haben. Sobald du Stufe 10 erreichst, hast du die Wahl, eine neue Klasse zu wählen oder als Krieger weiterzuspielen.\n\nJede Klasse verfügt über unterschiedliche Ausrüstungen und Fertigkeiten. Wenn du dich nicht für eine Klasse entscheiden möchtest, kannst du \"Abbrechen\" wählen. Wenn du dich später doch entscheidest, kannst du das Klassensystem in den Einstellungen wieder aktivieren.\n\nWenn Du Deine Klasse nach Level 10 noch einmal ändern möchtest, kannst Du die Sphäre der Wiedergeburt hierfür nutzen. Die Sphäre der Wiedergeburt ist mit Level 50 auf demMarktplatz für 6 Edelsteine verfügbar und mit Level 100 bekommst Du sie umsonst.\n\nAlternativ kannst Du Deine Klasse jederzeit in den Einstellungen für 3 Edelsteine ändern. Dies wird Dein Level nicht wie die Sphäre der Wiedergeburt zurücksetzen, aber es erlaubt Dir, die Fertigkeits-Punkte, die Du beim Leveln gesammelt hast, Deiner neuen Klasse zuzuordnen.",
|
||||
"webFaqAnswer32": "Alle Spieler beginnen in der Klasse des Kriegers, bis sie Stufe 10 erreicht haben. Sobald du Stufe 10 erreichst, hast du die Wahl, eine neue Klasse zu wählen oder als Krieger weiterzuspielen.\n\nJede Klasse verfügt über unterschiedliche Ausrüstungen und Fertigkeiten. Wenn du dich nicht für eine Klasse entscheiden möchtest, kannst du \"Abbrechen\" wählen. Du kannst das Klassensystem in den Einstellungen jederzeit wieder aktivieren.\n\nWenn du deine Klasse nach Level 10 noch einmal ändern möchtest, kannst du die Sphäre der Wiedergeburt hierfür nutzen. Die Sphäre der Wiedergeburt ist mit Level 50 auf dem Marktplatz für 6 Edelsteine verfügbar und mit Level 100 bekommst du sie umsonst.\n\nAlternativ kannst du deine Klasse jederzeit in den Einstellungen für 3 Edelsteine ändern. Dies wird dein Level nicht wie die Sphäre der Wiedergeburt zurücksetzen, aber es erlaubt dir, die Fähigkeitspunkte, die du beim Leveln gesammelt hast, deiner neuen Klasse zuzuordnen.",
|
||||
"sunsetFaqPara14": "<strong>Linguists</strong><br />Wir freuen uns auch weiterhin über Hilfe bei der Übersetzung der Apps und der Website und werden für qualifizierte Beiträge nach wie vor Beitragsstufen vergeben. Die Methode, mit der wir Übersetzungen annehmen, wird sich jedoch ändern. Wir möchten unsere Ressourcen auf die Unterstützung einer bestimmten Auswahl von Sprachen für alle Plattformen konzentrieren. Um dies zu erreichen, werden wir die Anzahl der für Übersetzungen verfügbaren Sprachen reduzieren. Zuvor nicht fertiggestellte Sprachen werden in Github archiviert. Wir hoffen, dass diese Änderung das plattformübergreifende Habitica-Erlebnis konsistenter macht. Sie können unsere aktuellsten Richtlinien für das Übersetzungsverfahren auf unserer Website lesen <a href='https://translate.habitica.com/projects/habitica/#information'>Übersetzungswebsite</a>.",
|
||||
"webFaqAnswer34": "Haustiere mögen Futter, das zu ihrer Farbe passt. Basis-Tiere sind die Ausnahme, aber alle Basis-Tiere mögen den gleichen Gegenstand. Im Folgenden siehst du, welche Nahrungsmittel jedes Haustier mag:\n\n * Basistiere mögen Fleisch\n * Weiße Haustiere mögen Milch\n * Wüstenhaustiere mögen Kartoffeln\n * Rote Haustiere mögen Erdbeeren\n * Schattentiere mögen Schokolade\n * Skelett-Tiere mögen Fisch\n * Zombie-Tiere mögen verdorbenes Fleisch\n * Zuckerwatte rosa Haustiere mögen rosa Zuckerwatte\n * Zuckerwatte blaue Haustiere mögen blaue Zuckerwatte\n * Goldene Haustiere mögen Honig",
|
||||
"webFaqAnswer35": "Sobald du dein Haustier genug gefüttert hast, um es zu einem Reittier zu machen, musst du diese Art von Haustier erneut ausbrüten, um es in deinem Stall zu haben.\n\nUm Reittiere in den mobilen Apps zu sehen:\n\n * Wähle im Menü \"Haustiere & Reittiere\" und wechseln zur Registerkarte \"Reittiere\".\n\nSo zeigst du Reittiere auf der Website an:\n\n * Wähle im Menü \"Inventar\" die Option \"Haustiere und Reittiere\" und scrollen nach unten zum Abschnitt \"Reittiere\"",
|
||||
@@ -102,7 +102,7 @@
|
||||
"sunsetFaqPara4": "Um die Zeit zu feiern, die wir erlebt haben, werden wir jedem ein Veteranen-Haustier schenken, während wir uns in diese neue Ära begeben. Für unsere großartigen Mitwirkenden werden wir außerdem ein spezielles Ausrüstungsset verschicken, um ihre harte Arbeit in den Habitica-Communities zu würdigen.",
|
||||
"sunsetFaqPara6": "Der Service für Tavernen sowie öffentliche und private Gilden endet und diese Räume werden am <strong>August 8, 2023</strong> aus Habitica entfernt.",
|
||||
"sunsetFaqList1": "Der Hauptzweck von Habitica ist es, Motivation durch ein gamifiziertes Aufgabenmanagement zu schaffen. Gilden und Tavernen werden von einem unverhältnismäßig kleinen Prozentsatz unserer Spielerbasis genutzt. Die Mehrheit der Spieler nutzt externe Dienste, die in erster Linie für soziale Interaktion gedacht sind und absichtlich mit Blick auf diese Anwendungsfälle entwickelt und gepflegt werden.",
|
||||
"sunsetFaqList2": "Die neuen Online-Sicherheitsgesetze erfordern ein Maß an aktiver Inhaltskontrolle für öffentliche Bereiche, das Habitica in der Vergangenheit nicht geboten hat. Die Investition in die Funktionen, die diese neuen Vorschriften erfordern würden, würde dazu führen, dass unsere begrenzten Ressourcen in Teile von Habitica umgeleitet werden, die die große Mehrheit der Spieler nie berührt.",
|
||||
"sunsetFaqList2": "Die neuen Online-Sicherheitsgesetze erfordern ein Maß an aktiver Inhaltskontrolle für öffentliche Bereiche, das Habitica in der Vergangenheit nicht geboten hat. Die Investition in die Funktionen, die diese neuen Vorschriften erfordern würden, würde dazu führen, dass unsere begrenzten Ressourcen in Teile von Habitica umgeleitet werden, welche die große Mehrheit der Spieler nie berührt.",
|
||||
"sunsetFaqList3": "Es ist uns wichtig, der ständig wachsenden internationalen Spielerbasis von Habitica weiterhin einen weltweiten Zugang zu bieten. Die Entfernung dieser Dienste ermöglicht es uns, dieses Ziel weiter zu verfolgen, ohne den Zugang in Regionen einschränken zu müssen, in denen eine aktivere Kontrolle der Inhalte erforderlich ist, als wir sie bieten können.",
|
||||
"sunsetFaqPara7": "Partys und Gruppenpläne werden beibehalten und behalten ihre Chatbereiche. Du wirst auch weiterhin private Nachrichten senden können.",
|
||||
"sunsetFaqPara12": "Als Open-Source-Projekt begrüßen und fördern wir viele Arten von Beiträgen. Um unsere Wertschätzung zu zeigen, werden wir das heroische Ausrüstungsset an alle Spieler schicken, die vor dem <strong>1. August 2023</strong>eine Beitragsstufe haben. Wenn die Tavernen- und Gilden-Dienste enden, wird es auch bei den Beiträgen einige Änderungen geben. Im Folgenden erfährst du mehr über den jeweiligen Plan für die einzelnen Typen.",
|
||||
@@ -243,5 +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* 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 Party Kameraden.\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* Heiler haben eine starke Verteidigung und können sich selbst, sowie die Party Kameraden, 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 Party Kameraden.\n* Erwäge, einen Heiler zu spielen, wenn du oft Aufgaben versäumst, und die Fähigkeit benötigst, dich selbst und deine Party Kameraden zu heilen. Heiler erreichen schnell neue Level.\n#### **Magier**\n* 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 Party Kameraden 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* 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 Party Kameraden zu erhöhen.\n* Erwäge, einen Schurken zu spielen, wenn du durch Belohnungen sehr motiviert wirst."
|
||||
"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."
|
||||
}
|
||||
|
||||
@@ -25,32 +25,32 @@
|
||||
"invalidEmail": "Um das Passwort zurückzusetzen, ist eine gültige E-Mail-Adresse notwendig.",
|
||||
"login": "Anmelden",
|
||||
"logout": "Abmelden",
|
||||
"marketing1Header": "Verbessere spielerisch Deinen Lebensstil mit Habitica",
|
||||
"marketing1Lead1Title": "Dein Leben, das Rollenspiel",
|
||||
"marketing1Lead1": "Habitica ist ein Computerspiel, welches Dir dabei hilft, Deine Gewohnheiten im realen Leben zu verbessern. Es \"gamifiziert\" Dein Leben, indem es all Deine Aufgaben (Gewohnheiten, Tagesaufgaben und To-Dos) in kleine Monster verwandelt, die Du besiegen musst. Je besser Du Dich dabei anstellst, umso weiter kommst Du im Spiel. Wenn Du in Deinem realen Leben nachlässt, beginnt Dein Charakter im Spiel zurückzufallen.",
|
||||
"marketing1Lead2Title": "Bekomme coole Ausrüstung",
|
||||
"marketing1Lead2": "Verbessere Deine Gewohnheiten, um Deinen Avatar aufzubauen. Gib' ordentlich an mit all der Ausrüstung, die Du verdient hast!",
|
||||
"marketing1Lead3Title": "Finde zufällige Preise",
|
||||
"marketing1Lead3": "Für manche ist es das Glücksspiel, was sie motiviert: das System der \"zufälligen Belohnungen\". Habitica kombiniert alle Stile des bestärkenden Lernens: positiv, negativ, erwartet oder zufällig.",
|
||||
"marketing2Header": "Messe Dich mit Freunden",
|
||||
"marketing1Header": "Verbessere deine Gewohnheiten mit jedem Level!",
|
||||
"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 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": "Schließe dich mit Freunden zusammen",
|
||||
"marketing2Lead1Title": "Soziale Produktivität",
|
||||
"marketing2Lead1": "Obwohl Du Habitica im Alleingang spielen kannst, wird es erst richtig spaßig, wenn Du anfängst, mit anderen zusammenzuarbeiten, zu wetteifern und einander zur Verantwortung zu ziehen. Der effektivste Teil von allen Persönlichkeitsentwicklungsprogrammen ist die soziale Verantwortlichkeit - und wo gibt es eine bessere Umgebung für Verantwortung und Wettkampf als in einem Videospiel?",
|
||||
"marketing2Lead2Title": "Bezwinge Monster",
|
||||
"marketing2Lead2": "Was ist schon ein Rollenspiel ohne Kämpfe? Bezwinge Monster mit Deiner Party. Monster sind der \"super Verantwortlichkeitsmodus\": wenn Du an einem Tag nicht ins Fitnessstudio gehst, dann verletzt das Monster *alle!*",
|
||||
"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": "Bei Herausforderungen kannst Du Dich mit Freunden und Unbekannten messen. Wer sich bis zum Ende der Herausforderung am besten schlägt, gewinnt besondere Preise.",
|
||||
"marketing3Header": "Apps und Erweiterungen",
|
||||
"marketing3Lead1": "Mit den **iPhone & Android** Apps kannst Du alles von Unterwegs erledigen. Wir wissen, dass sich auf einer Webseite einzuloggen, um Knöpfe zu drücken, manchmal anstrengend sein kann.",
|
||||
"marketing3Lead2Title": "Einbindungen",
|
||||
"marketing3Lead2": "Andere **Tools von Drittanbietern** binden Habitica in unterschiedlichen Bereichen Deines Lebens ein. Unser API stellt eine einfache Verknüpfung z.B. mit [Chrome Extension](https://chrome.google.com/webstore/detail/habitica/pidkmpibnnnhneohdgjclfdjpijggmjj?hl=en-US) her, die es ermöglicht, für das Besuchen unproduktiver Webseiten Punkte zu verlieren oder für das Besuchen produktiver Webseiten Punkte zu erhalten. [Mehr dazu hier](https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations).",
|
||||
"marketing4Header": "Verwendung für Organisationen",
|
||||
"marketing4Lead1": "Bildung ist einer der besten Bereiche für Gamifizierung. Wir wissen alle, wie sehr Schüler*innen dieser Tage an ihren Handys und Spielen hängen; nutze diese Macht! Lasse sie in freundlichen Wettbewerben gegeneinander antreten und belohne gutes Verhalten mit seltenen Preisen. Schaue zu, wie sich ihre Noten und ihr Verhalten verbessern.",
|
||||
"marketing4Lead1Title": "Betrachtungswinkel Ausbildung",
|
||||
"marketing4Lead2": "Die Kosten für medizinische Versorgung steigen und irgendjemand muss sie tragen. Zahlreiche Pläne wurden entwickelt, um Kosten zu reduzieren und das Wohlbefinden zu verbessern. Wir glauben, dass Habitica einen wesentlichen Beitrag zu gesünderen Lebensstilen leisten kann.",
|
||||
"marketing4Lead2Title": "Betrachtungswinkel Gesundheit und Erholung",
|
||||
"marketing4Lead3-1": "Willst Du Dein Leben einmal als Spiel betrachten?",
|
||||
"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",
|
||||
"marketing3Lead2": "Wir sind stolz darauf, ein Open-Source-Projekt zu sein, das Beiträge von unserer engagierten Community begrüßt. Passe Habitica deinen eigenen Bedürfnissen an oder trage dazu bei, die Erfahrung aller Spieler auf der ganzen Welt zu verbessern. Besuche uns auf [GitHub](https://github.com/HabitRPG/habitica/wiki/Contributing-to-Habitica), um mehr zu erfahren!",
|
||||
"marketing4Header": "Mehr als nur Hausarbeit",
|
||||
"marketing4Lead1": "Unterricht ist einer der besten Bereiche für ein wenig Gamification! Durchbrich die Monotonie der täglichen Klassenarbeit, indem du ein paar Spiele in einbaust. Mit Habitica kannst du auf unterhaltsame Weise die Hausaufgaben verfolgen, Herausforderungen im Klassenzimmer schaffen und deine SchülerInnen mit ihren Erfolgen angeben lassen.",
|
||||
"marketing4Lead1Title": "Gamification in der Bildung",
|
||||
"marketing4Lead2": "Der Aufbau eines gesünderen Lebensstils kann leicht zu einem überwältigenden Unterfangen werden. Habitica hilft dir dabei, alle Aspekte deiner Fitnessziele zu verfolgen, mit flexibler Zeitplanung und Intensität, um dich dort abzuholen, wo du gerade bist. Habe also etwas Spaß, während du auf deine Gesundheit hinarbeitest!",
|
||||
"marketing4Lead2Title": "Gamification von Gesundheit und Erholung",
|
||||
"marketing4Lead3-1": "Bereit Spaß zu haben beim Erledigen von Aufgaben?",
|
||||
"marketing4Lead3-2": "Willst Du eine Gruppe für Ausbildung, Wohlbefinden usw. leiten?",
|
||||
"marketing4Lead3Title": "Mache Alles zum Spiel",
|
||||
"marketing4Lead3Title": "Starte deine Reise!",
|
||||
"mobileAndroid": "Android App",
|
||||
"mobileIOS": "iOS App",
|
||||
"oldNews": "Neuigkeiten",
|
||||
@@ -87,7 +87,7 @@
|
||||
"sync": "Synchronisieren",
|
||||
"tasks": "Aufgaben",
|
||||
"teams": "Teams",
|
||||
"terms": "AGB",
|
||||
"terms": "Nutzungsbedingungen",
|
||||
"tumblr": "Tumblr",
|
||||
"localStorageTryFirst": "Wenn Du Probleme mit Habitica hast, drücke den untenstehenden Knopf um lokale Browserdaten und die meisten Cookies zu löschen (andere Internetseiten sind davon nicht betroffen). Du wirst Dich danach neu einloggen müssen, damit das funktioniert, also halte Deine Anmeldedaten bereit. Du kannst sie unter Einstellungen -> <%= linkStart %>Seite<%= linkEnd %> einsehen.",
|
||||
"localStorageTryNext": "Wenn das Problem weiterhin besteht, <%= linkStart %>melde bitte einen Fehler<%= linkEnd %>, falls Du das noch nicht getan hast.",
|
||||
@@ -111,7 +111,7 @@
|
||||
"missingPassword": "Fehlendes Passwort.",
|
||||
"missingNewPassword": "Fehlendes neues Passwort.",
|
||||
"invalidEmailDomain": "Du kannst E-Mails mit den folgenden Domains nicht registrieren: <%= domains %>",
|
||||
"wrongPassword": "Das Passwort ist falsch. Wenn Du Dein Passwort vergessen hast, klicke auf „Passwort vergessen“.",
|
||||
"wrongPassword": "Das Passwort ist falsch. Wenn Du Dein Passwort vergessen hast, klicke auf „Passwort vergessen“",
|
||||
"incorrectDeletePhrase": "Bitte gebe <%= magicWord %> in Großbuchstaben ein, um Dein Konto zu löschen.",
|
||||
"notAnEmail": "Ungültige E-Mail-Adresse.",
|
||||
"emailTaken": "Diese E-Mail-Adresse wird bereits von einem Konto verwendet.",
|
||||
@@ -182,5 +182,7 @@
|
||||
"incorrectResetPhrase": "Bitte tippe <%= magicWord %> in Großbuchstaben um deinen Account zurückzusetzen.",
|
||||
"translateHabitica": "Habitica übersetzen",
|
||||
"marketing3Lead1Title": "Android & iOS Apps",
|
||||
"marketing4Lead3Button": "Starte noch heute"
|
||||
"marketing4Lead3Button": "Starte noch heute",
|
||||
"emailBlockedRegistration": "Diese E-Mail ist für die Registrierung blockiert. Wenn du denkst, dass das ein Fehler ist, kontaktiere uns bitte unter admin@habitica.com.",
|
||||
"missingClientHeader": "Fehlende X-Client Header."
|
||||
}
|
||||
|
||||
@@ -2485,7 +2485,7 @@
|
||||
"weaponSpecialWinter2022HealerText": "Kristallklarer Zauberstab aus Eis",
|
||||
"weaponSpecialWinter2022HealerNotes": "Berühre einen Freund mit diesem Werkzeug aus festgefrorenem Wasser am Nacken, und er wird aus dem Sessel springen! Aber sich danach auch besser fühlen. Hoffentlich. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2021–2022 Winterausrüstung.",
|
||||
"armorSpecialWinter2022RogueText": "Strahlende Explosion",
|
||||
"armorSpecialWinter2022WarriorText": "Samtiger Strumpf",
|
||||
"armorSpecialWinter2022WarriorText": "Flauschiger Strumpf",
|
||||
"armorSpecialWinter2022MageText": "Granatapfel-Schutzrüstung",
|
||||
"armorSpecialWinter2022HealerText": "Kristallklare Rüstung aus Eis",
|
||||
"armorSpecialWinter2022HealerNotes": "Gleite wie auf Schlittschuhen knapp über dem Boden – eine ätherisch-glitzernde Gestalt, gekommen, um Geduld und Gelassenheit zu verbreiten. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2021–2022 Winterausrüstung.",
|
||||
@@ -2494,7 +2494,7 @@
|
||||
"headSpecialWinter2022MageText": "Granatapfelhelm",
|
||||
"headSpecialWinter2022HealerText": "Kristallklare Krone aus Eis",
|
||||
"weaponSpecialWinter2022RogueText": "Sternschnuppenfeuerwerk",
|
||||
"armorSpecialWinter2022RogueNotes": "Wenn sie Sterne sehen, sehen sie Dich nicht! Ja, lass uns das so sagen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2021–2022 Winterausrüstung.",
|
||||
"armorSpecialWinter2022RogueNotes": "Wenn sie Sterne sehen, dann werden sie dich nicht sehen! Ja, lass es uns so machen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2021–2022 Winterausrüstung.",
|
||||
"armorSpecialWinter2022WarriorNotes": "Wer sagt, dass Du es nicht geborgen und gemütlich haben kannst, während Du mit alltäglichen Aufgaben kämpfst? Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2021–2022 Winterausrüstung.",
|
||||
"armorSpecialWinter2022MageNotes": "Wenn Du Dich näherst, müssen sich Deine Feinde sich vor Fruchtsaft-Flecken in Acht nehmen! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2021–2022 Winterausrüstung.",
|
||||
"headSpecialWinter2022RogueText": "Donnerndes Finale",
|
||||
@@ -2708,7 +2708,7 @@
|
||||
"weaponSpecialWinter2023RogueText": "Grüne Satin Schärpe",
|
||||
"weaponSpecialWinter2023WarriorText": "Stoßzahn Speer",
|
||||
"weaponSpecialSpring2023MageText": "Mondstein Magie",
|
||||
"weaponSpecialSpring2023MageNotes": "Je stärker ihr Glühen, desto größer ist ihre Macht. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
|
||||
"weaponSpecialSpring2023MageNotes": "Je stärker ihr Glühen, desto größer ist ihre Macht. Erhöht Intelligenz um <%= int %> und Wahrnehmung um <%= per %>. Limitierte Ausgabe 2023 Frühlingsausrüstung.",
|
||||
"weaponSpecialSpring2023HealerText": "Lilien Pollen",
|
||||
"weaponSpecialSummer2023WarriorText": "Wasserelementar-Schwert",
|
||||
"weaponSpecialSummer2023MageText": "Fisch",
|
||||
@@ -2945,8 +2945,8 @@
|
||||
"armorArmoireHattersSuitNotes": "Dein Outfit ist nicht vollständig ohne deine grüne Glücks-Fliege. Trage dies zu deinem nächsten verrückten Teekränzchen. Oder angenehmen Teekränzchen. Oder begeisterten Teekränzchen. Oder... Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Hutmacher-Set (Gegenstand 2 von 4).",
|
||||
"armorArmoireBlueStripedSwimsuitNotes": "Was könnte spannender sein als Seemonster am Strand zu bekämpfen? Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Strand-Set (Gegenstand 2 von 4).",
|
||||
"armorArmoireSchoolUniformPantsNotes": "Ob du nun eine Schule für magische Zauberer, Drachenreiter, Ballsportspieler, kreative Künstler oder Mitglieder einer Organisation, die zu geheim ist, um sie hier aufzuzählen, besuchst, du wirst mit dieser Uniform gut dazu passen. Erhöht Intelligenz um <%= int %>.Verzauberter Schrank: Schuluniform-Set (Gegenstand 2 von 4).",
|
||||
"armorArmoireGreenFluffTrimmedCoatNotes": "Sagen erzählen, dass einmal in einer Generation ein Mantel daherkommt, der der wärmste und bequemste von allen ist. Sein Flausch ist außergewöhnlich und seine Knöpfe sind sogar von fäustlingsumhüllten Händen handhabbar. Das ist dieser Mantel hier. Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Fallenstellerhut-Set (Gegenstand 2 von 2).",
|
||||
"armorArmoireSoftWhiteSuitNotes": "Weiß ist eine friedvolle Farbe. Ob du nun ein strahlend weißes Bettlaken oder eine Decke aus frischgefallenem Schnee betrachtest, du wirst einen klaren und vorbereiteten Geist haben. Erhöht Ausdauer um <% con %> und Wahrnehmung um <%= per %>. Verzauberter Schrank: Weiße Lounge-Kleidung (Gegenstand 2 von 3).",
|
||||
"armorArmoireGreenFluffTrimmedCoatNotes": "Sagen erzählen, dass einmal in einer Generation ein Mantel daherkommt, welcher der wärmste und bequemste von allen ist. Sein Flausch ist außergewöhnlich und seine Knöpfe sind sogar von fäustlingsumhüllten Händen handhabbar. Das ist dieser Mantel hier. Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Fallenstellerhut-Set (Gegenstand 2 von 2).",
|
||||
"armorArmoireSoftWhiteSuitNotes": "Weiß ist eine friedvolle Farbe. Ob du nun ein strahlend weißes Bettlaken oder eine Decke aus frischgefallenem Schnee betrachtest, du wirst einen klaren und vorbereiteten Geist haben. Erhöht Ausdauer um <%= con %> und Wahrnehmung um <%= per %>. Verzauberter Schrank: Weißes Lounge-Kleidungsset (Gegenstand 2 von 3).",
|
||||
"armorArmoireCorsairsCoatAndCapeText": "Mantel und Umhang des Korsaren",
|
||||
"armorArmoireSmileyShirtNotes": "Weil du glücklich bist! Zeig der Welt, dass du heute den ganzen Tag lächelst. Erhöht Intelligenz und Wahrnehmung um jeweils <%= attrs %>. Verzauberter Schrank: Optimisten-Set (Gegenstand 1 von 4).",
|
||||
"armorArmoireYellowStripedSwimsuitText": "Gelb gestreifter Badeanzug",
|
||||
@@ -2954,7 +2954,7 @@
|
||||
"armorArmoireGreenFluffTrimmedCoatText": "Mantel mit grünem Flauschband",
|
||||
"armorArmoireSchoolUniformSkirtText": "Schuluniform mit Rock",
|
||||
"armorArmoireHattersSuitText": "Anzug des Hutmachers",
|
||||
"armorArmoireKarateGiText": "Karate Gi",
|
||||
"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)",
|
||||
@@ -3084,7 +3084,7 @@
|
||||
"headSpecialWinter2025HealerText": "Lichterketten-Wirrwarr",
|
||||
"headMystery202402Notes": "Diese hübsche rosa Mähne ist das perfekte Accessoire für den Februar und darüber hinaus. Gewährt keinen Attributbonus. Februar 2024 Abonnentengegenstand.",
|
||||
"headMystery202402Text": "Paradiesisches Rosa Haar",
|
||||
"headMystery202301Notes": "Dein Gehör wird so scharf sein, dass du das Hereinbrechen des Morgens und das Glitzern des Taus hören wirst. Gewährt keinen Attributbonus. Jänner 2023 Abonnentengegenstand.",
|
||||
"headMystery202301Notes": "Dein Gehör wird so scharf sein, dass du das Hereinbrechen des Morgens und das Glitzern des Taus hören wirst. Gewährt keinen Attributbonus. Januar 2023 Abonnentengegenstand.",
|
||||
"headMystery202304Text": "Tiptop Teekannen-Deckel",
|
||||
"headMystery202304Notes": "Dieser Helm gewährt dir Immuni-Tee-t. April 2023 Abonnentengegenstand.",
|
||||
"headMystery202310Text": "Narrenkappe",
|
||||
@@ -3295,7 +3295,7 @@
|
||||
"shieldSpecialSpring2025RogueText": "Kristallspitzen-Flegel",
|
||||
"shieldSpecialSpring2025RogueNotes": "Du kannst den Kristall nutzen, um eine produktive Zukunft für dich weiszusagen. Nutze die Gelegenheit und spring vorwärts! Erhöht Stärke um <%= str %>. Limitierte Ausgabe 2025 Frühlingsausrüstung.",
|
||||
"shieldSpecialSpring2025HealerText": "Plumeria Schild",
|
||||
"shieldSpecialSpring2025HealerNotes": "Du kannst dieses spezielle Blütenblatt verwenden, um Güte zu sammeln oder um negative Gedanken wegzuschnipsen. Nutze die Gelegenheit und spring vorwärts! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2025 Ausrüstung.",
|
||||
"shieldSpecialSpring2025HealerNotes": "Du kannst dieses spezielle Blütenblatt verwenden, um Güte zu sammeln oder um negative Gedanken wegzuschnipsen. Nutze die Gelegenheit und spring vorwärts! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2025 Frühlingsausrüstung.",
|
||||
"shieldSpecialSpring2025WarriorText": "Sonnenstrahl Schild",
|
||||
"shieldSpecialSpring2025WarriorNotes": "Du kannst deine Gegner für den Moment blenden, wenn die Sonne diesen Schild genau richtig trifft. Nutze den Vorteil und spring vorwärts! Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2025 Frühlingsausrüstung.",
|
||||
"shieldArmoireSpringPetalUchiwaNotes": "Dieser tragbare Fächer mit schönem Blütenmuster bewirkt eine leichte Brise nur für dich, wenn das Wetter wärmer wird. Erhöht Intelligenz und Wahrnehmung um jeweils <%= attrs %>. Verzauberter Schrank: Frühlingsblüten Set (Gegenstand 2 von 2).",
|
||||
@@ -3341,5 +3341,38 @@
|
||||
"armorSpecialSummer2025MageText": "Zwerglippfisch Anzug",
|
||||
"armorSpecialSummer2025MageNotes": "Dieser Anzug hat nicht nur atemberaubende Farben, sondern ermöglicht dir auch, anmutig durch's Wasser zu gleiten. Schwimmen oder Tanzen - du hast die Wahl! Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Sommerausrüstung 2025.",
|
||||
"armorArmoireBeekeepersSuitText": "Imkeranzug",
|
||||
"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)"
|
||||
"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",
|
||||
"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",
|
||||
"headSpecialSummer2025HealerText": "Ruderschnecken Helm",
|
||||
"headSpecialSummer2025HealerNotes": "Glückwunsch, jetzt bist du ein Seeschmetterling. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe Sommerausrüstung 2025.",
|
||||
"headSpecialSummer2025MageText": "Feenlippfisch Kopfschmuck",
|
||||
"headSpecialSummer2025MageNotes": "Alle werden davon hypnotisiert sein, wie sich deine Flossen mit der Strömung bewegen. Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe Sommerausrüstung 2025.",
|
||||
"headMystery202507Notes": "Umgedrehte Mützen sind immer noch cool, oder? Gewährt keinen Attributbonus. Juli 2025 Abonnentengegenstand.",
|
||||
"headMystery202507Text": "Draufgängerische Skater Mütze",
|
||||
"armorArmoireFlyFishingWadersText": "Fliegenfischerhose",
|
||||
"armorArmoireFlyFishingWadersNotes": "Halte dich vollkommen warm und trocken, wenn du in einen Bach, Teich, See oder Fluß watest. Erhöht Stärke und Ausdauer um jeweils <%= attrs %>. Verzauberter Schrank: Fliegenfischer Set (Gegenstand 2 von 3)",
|
||||
"headArmoireBeekeepersHatText": "Imkerhut und Schleier",
|
||||
"headArmoireBeekeepersHatNotes": "Schützt dein Gesicht, während Du dich um Deine brummenden Kumpels kümmerst. Erhöht Wahrnehmung um <%= per %>. Verzauberter Schrank: Bienenzüchter-Set (Gegenstand 1 von 4)",
|
||||
"shieldSpecialSummer2025WarriorText": "Jakobsmuschelschild",
|
||||
"shieldSpecialSummer2025WarriorNotes": "Die Farben sind schön, aber der Kamm ist gefährlich. Feinde, nehmt euch in Acht! Erhöht die Konstitution um <%= con %>. Limitierte Edition Sommer 2025 Ausrüstung.",
|
||||
"headArmoireFlyFishingHatText": "Fliegenfischerhut",
|
||||
"headArmoireFlyFishingHatNotes": "Mit breiter Krempe und Platz für einen Ersatzköder. Du solltest nicht ohne diese Schönheit zum Fliegenfischen gehen. Erhöht Stärke und Wahrnehmung jeweils um <%= attrs %>. Verzauberter Schrank: Fliegenfischer-Set (Gegenstand 1 von 3)",
|
||||
"shieldArmoireFlyFishingRodNotes": "Hänge einen Köder an diese lange, flexible Rute und Fische werden ihn jedes Mal mit einem Insekt verwechseln. Erhöht Stärke und Intelligenz um jeweils <%= attrs %>. Verzauberter Schrank: Fliegenfischer-Set (Gegenstand 3 von 3)",
|
||||
"backMystery202506Text": "Sonnenschein-Aureole",
|
||||
"shieldSpecialSummer2025RogueNotes": "Dieser Tentakel sieht biegsam aus, aber seine Saugnäpfe greifen fest zu. Feinde, passt auf! Erhöht die Stärke um <%= str %>. Limitierte Edition Sommer 2025 Ausrüstung.",
|
||||
"shieldSpecialSummer2025HealerText": "Ruderschnecken-Schild",
|
||||
"shieldSpecialSummer2025HealerNotes": "Dieser Schild sieht einfach aus, aber er hat gesundheitsschädliche Eigenschaften. Feinde, passt auf! Erhöht die Konstitution um <%= con %>. Limitierte Edition Sommer 2025 Ausrüstung.",
|
||||
"shieldArmoireBeekeepersHiveText": "Bienenstock",
|
||||
"shieldArmoireBeekeepersHiveNotes": "Bienenstöcke dienen sowohl als Zuhause als auch als Arbeitsplatz. Vielleicht solltet ihr mit euren Bienen über eine gute Work-Life-Balance sprechen. Erhöht die Stärke um <%= str %>. Verzauberter Schrank: Imker-Set (Gegenstand 4 von 4)",
|
||||
"shieldArmoireFlyFishingRodText": "Fliegenfischer-Rute",
|
||||
"backMystery202507Text": "Draufgängerisches Skateboard",
|
||||
"backMystery202507Notes": "Dein Ross für Bürgersteige und Halfpipes. Gewährt keinen Attributbonus. Juli 2025 Abonnentengegenstand.",
|
||||
"shieldMystery202506Text": "Sonnenschein-Schild",
|
||||
"shieldMystery202506Notes": "Vertreibe die Dunkelheit und lasse deiner Umgebung warme und herzliche Strahlen zuteilwerden wo immer du auch bist. Gewährt keinen Attributbonus. Juni 2025 Abonnentengegenstand.",
|
||||
"backMystery202506Notes": "Trage ein warmes Leuchten mit dir, wenn du deinen täglichen Aufgaben nachgehst. Gewährt keinen Attributbonus. Juni 2025 Abonnentengegenstand."
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
"dismissAll": "Alle entfernen",
|
||||
"messages": "Nachrichten",
|
||||
"emptyMessagesLine1": "Du hast im Moment keine Nachrichten",
|
||||
"emptyMessagesLine2": "Du kannst anderen eine neue Nachricht schicken, indem Du ihr Profil aufrufst und auf den \"Nachrichten\"-Knopf drückst.",
|
||||
"emptyMessagesLine2": "Sende eine Nachricht, um eine Konversation mit Mitgliedern deiner Gruppe oder anderen Habitica Spielern zu beginnen",
|
||||
"userSentMessage": "<span class=\"notification-bold\"><%- user %></span> hat Dir eine Nachricht gesendet",
|
||||
"letsgo": "Auf geht's!",
|
||||
"selected": "Ausgewählt",
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
"newBaileyUpdate": "Neues Update von Bailey!",
|
||||
"tellMeLater": "Erzähl es mir später",
|
||||
"dismissAlert": "Als gelesen markieren",
|
||||
"donateText3": "Als Open-Source-Projekt ist Habitica auf die Hilfe unserer Benutzer angewiesen. Das Geld, was Du für Edelsteine ausgibst, hilft uns dabei unsere Server am Laufen zu halten, ein paar Mitarbeiter zu bezahlen, neue Features zu entwickeln und unseren ehrenamtlichen Helferlein Anreize zu bieten",
|
||||
"donateText3": "Als Open-Source-Projekt ist Habitica auf die Hilfe unserer Benutzer angewiesen. Das Geld, das Du für Edelsteine ausgibst, hilft uns dabei unsere Server am Laufen zu halten, ein paar Mitarbeiter zu bezahlen, neue Features zu entwickeln und unseren ehrenamtlichen Helferlein Anreize zu bieten",
|
||||
"card": "Kreditkarte",
|
||||
"paymentMethods": "Kauf mit",
|
||||
"paymentSuccessful": "Die Zahlung war erfolgreich!",
|
||||
@@ -125,7 +125,7 @@
|
||||
"limitedAvailabilityMinutes": "Für <%= minutes %>min <%= seconds %>sek verfügbar",
|
||||
"limitedAvailabilityHours": "Für t <%= hours %>std und <%= minutes %>min verfügbar",
|
||||
"limitedAvailabilityDays": "Für <%= days %>t <%= hours %>std und <%= minutes %>min verfügbar",
|
||||
"amountExp": "<%= amount %> Exp",
|
||||
"amountExp": "<%= amount %> XP",
|
||||
"helpSupportHabitica": "Hilf dabei, Habitica zu unterstützen",
|
||||
"groupsPaymentSubBilling": "Dein nächstes Rechnungsdatum ist <strong><%= renewalDate %></strong>.",
|
||||
"groupsPaymentAutoRenew": "Dieses Abonnement läuft automatisch weiter, bis es gekündigt wird. Du kannst es im Gruppen-Abrechnungs-Tab kündigen.",
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
"questOwlDropOwlEgg": "Eule (Ei)",
|
||||
"questOwlUnlockText": "Schaltet den Kauf von Euleneiern auf dem Marktplatz frei",
|
||||
"questPenguinText": "Der Federvieh-Frost",
|
||||
"questPenguinNotes": "Obwohl es auf der Südspitze von Habitica ein heißer Sommertag ist, hat eine unnatürliche Kälte den Lively Lake befallen. Man hört das Heulen von starken, eisigen Winden und das Ufer fängt an zuzufrieren. Eisspitzen brechen aus dem Boden und verdrängen Gras und Dreck. @Melynnrose und @Breadstrings rennen zu Dir hinüber.<br><br>\"Hilfe!\" sagt @Melynnrose. \"Wir haben einen riesigen Pinguin hergebracht, um den See zuzufrieren damit wir alle schlittschuhlaufen können, aber uns sind die Fische ausgegangen, mit denen wir ihn gefüttert haben!\"<br><br>\"Er wurde wütend und friert mit seinem Eis-Atem alles zu, was er sieht!\" sagt @Breadstrings. \"Bitte, Du musst ihn überwältigen bevor wir alle von Eis bedeckt sind!\" Sieht aus, als ob Du das Gemüt dieses Pinguins ... etwas <em>abkühlen</em> musst.",
|
||||
"questPenguinNotes": "Obwohl es auf der Südspitze von Habitica ein heißer Sommertag ist, hat eine unnatürliche Kälte den Lively Lake befallen. Man hört das Heulen von starken, eisigen Winden und das Ufer fängt an zuzufrieren. Eisspitzen brechen aus dem Boden und verdrängen Gras und Dreck. @Melynnrose und @Breadstrings rennen zu Dir hinüber.<br><br>\"Hilfe!\" sagt @Melynnrose. \"Wir haben einen riesigen Pinguin hergebracht, um den See zuzufrieren damit wir alle schlittschuhlaufen können, aber uns sind die Fische ausgegangen, mit denen wir ihn gefüttert haben!\"<br><br>\"Er wurde wütend und friert mit seinem Eis-Atem alles zu, was er sieht!\" sagt @Breadstrings. \"Bitte, Du musst ihn überwältigen bevor wir alle von Eis bedeckt sind!\" Sieht aus, als müsstest Du das Gemüt dieses Pinguins ... etwas <em>abkühlen.</em>",
|
||||
"questPenguinCompletion": "Mit der Niederlage des Pinguins beginnt das Eis zu schmelzen. Der riesige Pinguin setzt sich im Sonnenschein auf den Boden und schlürft einen Eimer Fische herunter. Er gleitet über den See und lässt dabei mit einem leichten Pusten nach unten glattes, glitzerndes Eis entstehen. Was für ein komischer Vogel! \"Es scheint so, als hätte er einige Eier hinterlassen,\" sagt @Painter de Cluster. <br><br>@Rattify lacht. \"Vielleicht werden diese Pinguine ein bisschen ... gechillter sein?\"",
|
||||
"questPenguinBoss": "Frostpinguin",
|
||||
"questPenguinDropPenguinEgg": "Pinguin (Ei)",
|
||||
@@ -289,7 +289,7 @@
|
||||
"questSnakeDropSnakeEgg": "Schlange (Ei)",
|
||||
"questSnakeUnlockText": "Schaltet den Kauf von Schlangeneiern auf dem Marktplatz frei",
|
||||
"questUnicornText": "Überzeuge die Einhornkönigin",
|
||||
"questUnicornNotes": "Conquest Creek ist völlig verschlammt und zerstört so Habit Citys Frischwasser-Vorräte! Glücklicherweise kennt @Lukreja eine alte Legende, laut welcher das Horn eines Einhorns in der Lage ist selbst das fauleste aller Wasser zu reinigen. Gemeinsam mit Deinem unerschrockenen Führer @UncommonCriminal machst Du Dich auf die Reise durch die, im ewigen Eis verborgenen, Gipfel der Mäandergebirge.\nLetztendlich, auf der eisigen Spitze von Mount Habitica erblickst Du inmitten des funkelnden Schneetreibens die Einhornkönigin höchstselbst.\n\"Dein Gesuch ist überzeugend\", spricht sie. \"Aber zuerst musst Du Dich meiner Hilfe als würdig erweisen!\"",
|
||||
"questUnicornNotes": "Conquest Creek ist völlig verschlammt und zerstört so Habit Citys Frischwasser-Vorräte! Glücklicherweise kennt @Lukreja eine alte Legende, laut welcher das Horn eines Einhorns in der Lage ist selbst das dreckigste Wasser zu reinigen. Gemeinsam mit Deinem unerschrockenen Führer @UncommonCriminal machst Du Dich auf die Reise durch die, im ewigen Eis verborgenen, Gipfel der Mäandergebirge. Schließlich erblickst Du auf der eisigen Spitze von Mount Habitica inmitten des funkelnden Schneetreibens die Einhornkönigin höchstselbst. \"Dein Gesuch ist überzeugend\", spricht sie. \"Aber zuerst musst Du Dich meiner Hilfe als würdig erweisen!\"",
|
||||
"questUnicornCompletion": "Von Deiner Aufrichtigkeit und Stärke beeindruckt stimmt die Einhornkönigin schließlich Deinem Anliegen zu. Auf Ihrem Rücken reitend fliegt ihr zum Ursprung des Conquest Creek. In dem Moment, als das güldene Horn der Königin das faulige Wasser berührt beginnt ein grell-blaues Licht aus dem Wasser zu steigen. Es blendet so sehr, dass Du nicht anders kannst als Deine Augen zu schließen. Als Du sie einen Augenblick später wieder öffnest ist die Königin verschwunden. Ehe Du darüber nachdenken kannst hörst Du @rosiesullys Freudenschrei: Das Wasser ist nun klar und am Ufer des Flusses erblickst Du drei glänzende Eier.",
|
||||
"questUnicornBoss": "Die Einhornkönigin",
|
||||
"questUnicornDropUnicornEgg": "Einhorn (Ei)",
|
||||
@@ -314,8 +314,8 @@
|
||||
"questSnailUnlockText": "Schaltet den Kauf von Schneckeneiern auf dem Marktplatz frei",
|
||||
"questBewilderText": "Der Verwirrer",
|
||||
"questBewilderNotes": "Die Party beginnt wie jede Andere.<br><br>Die Appetithäppchen sind exzellent, die Musik sorgt für lockere Stimmung und sogar an die tanzenden Elefanten hat man sich gewöhnt. Habiticaner lachen ausgelassen zwischen den ausladenden Blumengestecken, froh um eine Ablenkung von Ihren meist-gehassten Aufgaben, und der April-Scherzkeks wirbelt zwischen ihnen herum, eifrig Scherze und Schabernack treibend.<br><br>Als die Uhr des Mistiflying Uhrturms Mitternacht schlägt, springt der April-Scherzkeks auf die Bühne um eine Rede zu halten.<br><br>\"Freunde! Feinde! Tolerante Bekannte! Leiht mir euer Ohr!\" Als aus ihren Köpfen Tierohren sprießen, kichert die Schar und posiert mit ihren neuen Verkleidungen.<br><br>\"Wie ihr alle wisst,\" fährt der April-Scherzkeks weiter, \"dauern meine verwirrenden Illusionen normalerweise nur einen Tag. Deshalb freue ich mich besonders euch mitzuteilen, dass ich eine Abkürzung gefunden habe, die uns Spaß ohne Ende verspricht, ohne dass wir uns um die mühsame Last unserer Pflichten sorgen müssen. Liebe Habiticaner, ich stelle euch hiermit meinen neuen, magischen Freund vor: den Verwirrer!\"<br><br>Lemoness wird plötzlich bleich und lässt ihre Häppchen fallen. \"Wartet! Traut ihm ni--\"<br><br>Doch schon stürzen Nebelschwaden in den Saal, dick und glitzernd. Sie wirbeln um den April-Scherzkeks und vereinen sich zu verschwommenen Federn und einem langen Hals. The Menge ist sprachlos, während sich vor ihr ein monströser Vogel entfaltet, seine Flügel schimmernd vor lauter Illusionen. Er gibt ein fürchterliches, kreischendes Lachen von sich.<br><br>\"Oh, es ist schon Ewigkeiten her, seit ein Habiticaner töricht genug war, mich herbeizurufen! Wie wundervoll es ist, endlich eine greifbare Form zu haben!\"<br><br>Erschreckt summend fliehen die magischen Bienen von Mistiflying aus der fliegenden Stadt, die aus dem Himmel sackt. Eine nach der anderen verwelken die leuchtenden Frühlingsblumen und schrumpfen weg.<br><br>\"Meine liebsten Freunde, warum so beunruhigt?\" krächzt der Verwirrer, während er mit den Flügeln schlägt. \"Es gibt keinen Grund mehr, euch für eure Belohnungen abzurackern. Ich werde euch alles geben, was ihr euch wünscht!\"<br><br>Ein Münzenschauer stürzt aus dem Himmel und hämmert sich mit brutaler Kraft in den Boden. Die Menge schreit und sucht Deckung. \"Soll das ein Scherz sein?\" ruft Baconsaur, während das Gold Fenster einschlägt und die Schindeln auf den Dächern zerschmettert.<br><br>PainterProphet duckt sich, als Blitze über den Himmel schießen und Nebel die Sonne verdunkelt. \"Nein! Diesmal ist es glaube ich kein Scherz!\"<br><br>Schnell, Habiticaner, lasst diesen Weltboss euch nicht von euren Zielen ablenken! Konzentriert euch auf das, was ihr zu erledigen habt, um Mistiflying zu retten -- und hoffentlich euch selbst.",
|
||||
"questBewilderCompletion": "<strong>Der Verwirrer ist BESIEGT!</strong><br><br>Wir haben es geschafft! Der Verwirrer stößt einen heulenden Schrei aus, windet sich in der Luft und verliert büschelweise Federn. Langsam, nach und nach wickelt er sich zu einer funkelnden Nebelwoke auf. Die enthüllte Sonne durchdingt den Nebel, vertreibt ihn und enthüllt die hustenden, glücklicherweise menschlichen Formen von Matt, Bailey, Alex ... und dem April-Scherzkeks persönlich.<br><br><strong>Mistiflying ist gerettet!</strong><br><br>Der April-Scherzkeks schämt sich immerhin genug, um etwas verlegen dazustehen. \"Oh, ähm,\" sagt er. \"Vielleicht habe ich mich ein wenig ... gehen lassen.\"”<br><br>Die Menschenmenge murrt. Durchnässte Blumen werden auf Gehsteigen angeschwemmt. Irgendwo in der Ferne stürzt ein Dach mit spektakulärem Krachen ein.<br><br>\"Ähm, ja,\" sagt der April-Scherzkeks. \"Also, was ich sagen wollte, es tut mir schrecklich leid.\" Er seufzt schwer. \"Ich vermute mal, es kann doch nicht nur Spaß und Spiel geben. Es kann wohl nicht schaden, sich ab und zu mal auf etwas zu konzentrieren. Vielleicht kann ich ja schon mal den nächsten Aprilscherz vorbereiten.\"<br><br>Redphoenix räuspert sich vielsagend.<br><br>\"Ich meine, den nächsten Frühjahrsputz!\" korrigiert sich der April-Scherzkeks. \"Habt keine Angst, ich werde Habit City rasch wieder blitzblank haben. Niemand ist besser als ich mit dem Doppelmopp.\"<br><br>Ermuntert beginnt die Kapelle zu spielen.<br><br>Es dauert nicht lange bis alles in Habit City wieder seinen normalen Lauf nimmt. Außerdem, jetzt wo der Verwirrer pulverisiert ist, sind die magischen Bienen von Mistiflying wieder eifrig am Werk und schon bald blühen die Blumen und die Stadt schwebt von Neuem.<br><br>Wie die Habiticaner die magischen, flaumigen Bienen knuddeln, beginnen die Augen des April-Scherzkeks zu leuchten. \"Oho, mir kommt eine Idee! Warum haltet ihr euch eigentlich keine dieser flaumigen Bienen als Haustiere und Reittiere? Das ist ein Geschenk, das das Gleichgewicht zwischen harter Arbeit und süßer Belohnung symbolisiert, wenn ich das mal so langweilig und sinnbildlich sagen darf.\" Er zwinkert. \"Und außerdem haben sie keinen Stachel! Narrenehrenwort.\"",
|
||||
"questBewilderCompletionChat": "`Der Verwirrer is BESIEGT!`\n\nWir haben es geschafft! Der Verwirrer stößt einen heulenden Schrei aus, windet sich in der Luft und verliert büschelweise Federn. Langsam, nach und nach wickelt er sich zu einer funkelnden Nebelwoke auf. Die enthüllte Sonne durchdingt den Nebel, vertreibt ihn und enthüllt die hustenden, glücklicherweise menschlichen Formen von Matt, Bailey, Alex ... und dem April-Scherzkeks persönlich.\n\n`Mistiflying ist gerettet!`\n\nDer April-Scherzkeks schämt sich immerhin genug, um etwas verlegen dazustehen. \"Oh, ähm,\" sagt er. \"Vielleicht habe ich mich ein wenig ... gehen lassen.\"\n\nDie Menschenmenge murrt. Durchnässte Blumen werden auf Gehsteigen angeschwemmt. Irgendwo in der Ferne stürzt ein Dach mit spektakulärem Krachen ein.\n\n\"Ähm, ja,\" sagt der April-Scherzkeks. \"Also, was ich sagen wollte, es tut mir schrecklich leid.\" Er seufzt schwer. \"Ich vermute mal, es kann doch nicht nur Spaß und Spiel geben. Es kann wohl nicht schaden, sich ab und zu mal auf etwas zu konzentrieren. Vielleicht kann ich ja schon mal den nächsten Aprilscherz vorbereiten.\"\n\nRedphoenix räuspert sich vielsagend.\n\n\"Ich meine, den nächsten Frühjahrsputz!\" korrigiert sich der April-Scherzkeks. \"Habt keine Angst, ich werde Habit City rasch wieder blitzblank haben. Niemand ist besser als ich mit dem Doppelmopp.\"\n\nErmuntert beginnt die Kapelle zu spielen\n\nEs dauert nicht lange bis alles in Habit City wieder seinen normalen Lauf nimmt. Außerdem, jetzt wo der Verwirrer pulverisiert ist, sind die magischen Bienen von Mistiflying wieder eifrig am Werk und schon bald blühen die Blumen und schwebt die Stadt von Neuem.\n\nWie die Habiticaner die magischen, flaumigen Bienen knuddeln, beginnen die Augen des April-Scherzkeks zu leuchten. \"Oho, mir kommt eine Idee! Warum haltet ihr euch eigentlich keine dieser flaumigen Bienen als Haustiere und Reittiere? Das ist ein Geschenk, das das Gleichgewicht zwischen harter Arbeit und süßer Belohnung symbolisiert, wenn ich das mal so langweilig und sinnbildlich sagen darf.\" Er zwinkert. \"Und außerdem haben sie keinen Stachel! Narrenehrenwort.\"",
|
||||
"questBewilderCompletion": "<strong>Der Verwirrer ist BESIEGT!</strong><br><br>Wir haben es geschafft! Der Verwirrer stößt einen heulenden Schrei aus, windet sich in der Luft und verliert büschelweise Federn. Langsam, nach und nach wickelt er sich zu einer funkelnden Nebelwoke auf. Die enthüllte Sonne durchdingt den Nebel, vertreibt ihn und enthüllt die hustenden, glücklicherweise menschlichen Formen von Matt, Bailey, Alex ... und dem April-Scherzkeks persönlich.<br><br><strong>Mistiflying ist gerettet!</strong><br><br>Der April-Scherzkeks schämt sich immerhin genug, um etwas verlegen dazustehen. \"Oh, ähm,\" sagt er. \"Vielleicht habe ich mich ein wenig ... gehen lassen.\"”<br><br>Die Menschenmenge murrt. Durchnässte Blumen werden auf Gehsteigen angeschwemmt. Irgendwo in der Ferne stürzt ein Dach mit spektakulärem Krachen ein.<br><br>\"Ähm, ja,\" sagt der April-Scherzkeks. \"Also, was ich sagen wollte, es tut mir schrecklich leid.\" Er seufzt schwer. \"Ich vermute mal, es kann doch nicht nur Spaß und Spiel geben. Es kann wohl nicht schaden, sich ab und zu mal auf etwas zu konzentrieren. Vielleicht kann ich ja schon mal den nächsten Aprilscherz vorbereiten.\"<br><br>Redphoenix räuspert sich vielsagend.<br><br>\"Ich meine, den nächsten Frühjahrsputz!\" korrigiert sich der April-Scherzkeks. \"Habt keine Angst, ich werde Habit City rasch wieder blitzblank haben. Niemand ist besser als ich mit dem Doppelmopp.\"<br><br>Ermuntert beginnt die Kapelle zu spielen.<br><br>Es dauert nicht lange bis alles in Habit City wieder seinen normalen Lauf nimmt. Außerdem, jetzt wo der Verwirrer pulverisiert ist, sind die magischen Bienen von Mistiflying wieder eifrig am Werk und schon bald blühen die Blumen und die Stadt schwebt von Neuem.<br><br>Als die Habiticaner die magischen, flaumigen Bienen knuddeln, beginnen die Augen des April-Scherzkeks zu leuchten. \"Oho, mir kommt eine Idee! Warum haltet ihr euch eigentlich keine dieser flaumigen Bienen als Haustiere und Reittiere? Das ist ein Geschenk, welches das Gleichgewicht zwischen harter Arbeit und süßer Belohnung symbolisiert, wenn ich das mal so langweilig und sinnbildlich sagen darf.\" Er zwinkert. \"Und außerdem haben sie keinen Stachel! Narrenehrenwort.\"",
|
||||
"questBewilderCompletionChat": "`Der Verwirrer is BESIEGT!`\n\nWir haben es geschafft! Der Verwirrer stößt einen heulenden Schrei aus, windet sich in der Luft und verliert büschelweise Federn. Langsam, nach und nach wickelt er sich zu einer funkelnden Nebelwoke auf. Die enthüllte Sonne durchdingt den Nebel, vertreibt ihn und enthüllt die hustenden, glücklicherweise menschlichen Formen von Matt, Bailey, Alex ... und dem April-Scherzkeks persönlich.\n\n`Mistiflying ist gerettet!`\n\nDer April-Scherzkeks schämt sich immerhin genug, um etwas verlegen dazustehen. \"Oh, ähm,\" sagt er. \"Vielleicht habe ich mich ein wenig ... gehen lassen.\"\n\nDie Menschenmenge murrt. Durchnässte Blumen werden auf Gehsteigen angeschwemmt. Irgendwo in der Ferne stürzt ein Dach mit spektakulärem Krachen ein.\n\n\"Ähm, ja,\" sagt der April-Scherzkeks. \"Also, was ich sagen wollte, es tut mir schrecklich leid.\" Er seufzt schwer. \"Ich vermute mal, es kann doch nicht nur Spaß und Spiel geben. Es kann wohl nicht schaden, sich ab und zu mal auf etwas zu konzentrieren. Vielleicht kann ich ja schon mal den nächsten Aprilscherz vorbereiten.\"\n\nRedphoenix räuspert sich vielsagend.\n\n\"Ich meine, den nächsten Frühjahrsputz!\" korrigiert sich der April-Scherzkeks. \"Habt keine Angst, ich werde Habit City rasch wieder blitzblank haben. Niemand ist besser als ich mit dem Doppelmopp.\"\n\nErmuntert beginnt die Kapelle zu spielen\n\nEs dauert nicht lange bis alles in Habit City wieder seinen normalen Lauf nimmt. Außerdem, jetzt wo der Verwirrer pulverisiert ist, sind die magischen Bienen von Mistiflying wieder eifrig am Werk und schon bald blühen die Blumen und schwebt die Stadt von Neuem.\n\nAls die Habiticaner die magischen, flaumigen Bienen knuddeln, beginnen die Augen des April-Scherzkeks zu leuchten. \"Oho, mir kommt eine Idee! Warum haltet ihr euch eigentlich keine dieser flaumigen Bienen als Haustiere und Reittiere? Das ist ein Geschenk, welches das Gleichgewicht zwischen harter Arbeit und süßer Belohnung symbolisiert, wenn ich das mal so langweilig und sinnbildlich sagen darf.\" Er zwinkert. \"Und außerdem haben sie keinen Stachel! Narrenehrenwort.\"",
|
||||
"questBewilderBossRageTitle": "Betörungsschlag",
|
||||
"questBewilderBossRageDescription": "Wenn dieser Balken voll ist, wird der Verwirrer seinen Wirrschlag über Habitica entfesseln!",
|
||||
"questBewilderDropBumblebeePet": "Magische Biene (Haustier)",
|
||||
@@ -409,7 +409,7 @@
|
||||
"questMoon1CollectShards": "Mondscherben",
|
||||
"questMoon1DropHeadgear": "Mondkriegerhelm (Kopfbedeckung)",
|
||||
"questMoon2Text": "Mondkampf, Teil 2: Stoppt den Überschattenden Stress",
|
||||
"questMoon2Notes": "Nachdem Sie die Splitter untersucht hat, hat @Starsystemic die Seherin schlechte Neuigkeiten: \"Ein altes Monster nähert sich Habitica und überfällt deren Einwohner dabei mit schrecklichem Stress. Ich kann den Schatten aus den Herzen der Leute abziehen und hierherbringen. Dabei wird es seine physische Form annehmen. Ihr müsst es dann besiegen, bevor es sich befreien und erneut ausbreiten kann.\" Du nickst und Sie beginnt ihre Zauberformeln zu sprechen. Tanzende Schatten erfüllen den Raum und schmiegen sich dicht aneinander. Kalte Winde kommen auf und die Dunkelheit verdichtet sich. Der Düsterschatten-Stress erhebt sich vom Boden, grinst wie ein wahrgewordener Albtraum ... und greift an!",
|
||||
"questMoon2Notes": "Nachdem der Untersuchung der Splitter, hat @Starsystemic die Seherin schlechte Neuigkeiten: \"Ein altes Monster nähert sich Habitica und überfällt deren Einwohner dabei mit schrecklichem Stress. Ich kann den Schatten aus den Herzen der Leute abziehen und hierherbringen. Dabei wird es seine physische Form annehmen. Ihr müsst es dann besiegen, bevor es sich befreien und erneut ausbreiten kann.\" Du nickst und Sie beginnt ihre Zauberformeln zu sprechen. Tanzende Schatten erfüllen den Raum und schmiegen sich dicht aneinander. Kalte Winde kommen auf und die Dunkelheit verdichtet sich. Der Düsterschatten-Stress erhebt sich vom Boden, grinst wie ein wahrgewordener Albtraum ... und greift an!",
|
||||
"questMoon2Completion": "Der Schatten zerbirst in einem dunklen Windstoß, und hinterlässt den Raum heller und Eure Herzen strahlender. Der Stress, der Habitica überdeckte hat nachgelassen, und Ihr könnt alle erleichtert durchatment. Und dennoch, als Ihr nach oben in den Himmel seht, könnt Ihr fühlen, dass es noch nicht vorüber ist: Das Monster weiß, dass jemand seinen Schatten zerstört hat. \"Wir werden in den kommenden Wochen sorgfältig Ausschau halten,\" sagt @Starsystemic, \"und ich werde Euch eine Questschriftrolle schicken, sobald es sich manifestiert.\"",
|
||||
"questMoon2Boss": "Überschattender Stress",
|
||||
"questMoon2DropArmor": "Mondkriegerrüstung (Rüstung)",
|
||||
@@ -473,7 +473,7 @@
|
||||
"questButterflyUnlockText": "Schaltet den Kauf von Raupeneiern auf dem Marktplatz frei",
|
||||
"questGroupMayhemMistiflying": "Chaos in Mistiflying",
|
||||
"questMayhemMistiflying1Text": "Chaos in Mistiflying, Teil 1: In welchem Mistiflying unter einer schrecklichen Plage leidet",
|
||||
"questMayhemMistiflying1Notes": "Obwohl die hiesigen Wahrsager angenehmes Wetter vorhersagten, ist der Wind am Nachmittag extrem böig, so dass Du Deiner Freundin @Kiwibot nur zu gerne in ihr Haus folgst, um dem stürmischen Treiben zu entkommen.<br><br>Keiner von euch hat den April-Scherzkeks erwartet, der am Küchentisch lehnt.<br><br>“Oh, hallo”, sagt er. “Wie schön, euch zu sehen. Darf ich euch etwas von diesem köstlichen Tee anbieten?”<br><br>“Das...” setzt @Kiwibot an. “Das ist MEIN—”<br><br>“Ja, ja, selbstverständlich”, sagt der April-Scherzkeks, und nimmt sich einige Kekse. “Ich dachte nur, ich spring' mal kurz rein, für eine kleine Verschnaufpause vor all den Tornado-beschwörenden Schädeln.” Er nimmt einen beiläufigen Schluck aus seiner Teetasse. “Mistiflying wird übrigens angegriffen.”<br><br>Entsetzt rennst Du mit Deinen Freunden zu den Ställen, um eure schnellsten geflügelten Reittiere zu satteln. Als ihr zu der schwebenden Stadt aufsteigt, könnt ihr einen Schwarm klappernder, fliegender Schädel ausmachen, die die Stadt belagern... und einige haben euch entdeckt!",
|
||||
"questMayhemMistiflying1Notes": "Obwohl die hiesigen Wahrsager angenehmes Wetter vorhersagten, ist der Wind am Nachmittag extrem böig, so dass Du Deiner Freundin @Kiwibot nur zu gerne in ihr Haus folgst, um dem stürmischen Treiben zu entkommen.<br><br>Keiner von euch hat den April-Scherzkeks erwartet, der am Küchentisch lehnt.<br><br>“Oh, hallo”, sagt er. “Wie schön, euch zu sehen. Darf ich euch etwas von diesem köstlichen Tee anbieten?”<br><br>“Das...” setzt @Kiwibot an. “Das ist MEIN—”<br><br>“Ja, ja, selbstverständlich”, sagt der April-Scherzkeks, und nimmt sich einige Kekse. “Ich dachte nur, ich spring' mal kurz rein, für eine kleine Verschnaufpause vor all den Tornado-beschwörenden Schädeln.” Er nimmt einen beiläufigen Schluck aus seiner Teetasse. “Mistiflying wird übrigens angegriffen.”<br><br>Entsetzt rennst Du mit Deinen Freunden zu den Ställen, um eure schnellsten geflügelten Reittiere zu satteln. Als ihr zu der schwebenden Stadt aufsteigt, könnt ihr einen Schwarm klappernder, fliegender Schädel ausmachen, welche die Stadt belagern... und einige haben euch entdeckt!",
|
||||
"questMayhemMistiflying1Completion": "Der letzte Schädel fällt vom Himmel, ein schimmerndes Bündel aus Regenbogenroben zwischen seinen Kiefern, aber der stetige Wind hat nicht nachgelassen. Hier scheint noch etwas anderes vorzugehen. Und wo ist eigentlich dieser Drückeberger von April-Scherzkeks? Du hebst die Roben auf und fliegst in die Stadt.",
|
||||
"questMayhemMistiflying1Boss": "Luftschädelschwarm",
|
||||
"questMayhemMistiflying1RageTitle": "Schwarmnachwuchs",
|
||||
@@ -578,7 +578,7 @@
|
||||
"questDysheartenerCompletionChat": "`Der Entmutiger wurde BESIEGT!'`\n\nGemeinsam holen alle in Habitica zu einem letzten Schlag mit ihren Aufgaben aus, und der Entmutiger weicht mit einem bestürzten Kreischen zurück. “Stimmt etwas nicht, Entmutiger?” ruft AnnDeLune mit funkelnden Augen. “Fühlst Du Dich entmutigt?”\n\nGlühend pinke Risse zeigen sich auf dem Panzer des Entmutigers, und er zerbricht mit einer verpuffenden rosa Rauchwolke. Eine Flut von köstlichen Süßigkeiten regnet auf alle hernieder, während sich im ganzen Land ein erneuertes Gefühl von Kraft und Entschlossenheit ausbreitet.\n\nDie Menge jubelt wild, Umarmungen werden ausgetauscht, und die Haustiere kauen glücklich auf ihren verspäteten Valentinsleckerli. Plötzlich liegt Gesang in der Luft, ein fröhlicher Chor ertönt, und funkelnde Silhouetten ziehen über den Himmel.\n\nUnser neu-gewonnener Optimismus hat eine Herde Hippogreifen angelockt! Die anmutigen Kreaturen setzen auf dem Boden auf, sträuben interessiert ihre Federn und tänzeln auf der Stelle. “Wie es aussieht, haben wir neue Freunde gefunden, die uns helfen, nicht zu verzagen, selbst wenn unsere Aufgaben noch so beängstigend sind”, sagt Lemoness.\n\nBeffymaroo hat bereits ihre Arme voll mit gefiederten Plüschbällen. “Vielleicht helfen sie uns, die zerstörten Gebiete Habitica's wieder aufzubauen!”\n\nSummend und singend ziehen die Hippogreifen voran, während alle Habiticaner zusammenarbeiten, um unsere geliebte Heimat wieder aufzubauen.",
|
||||
"questDysheartenerBossRageTitle": "Niederschmetternder Herzschmerz",
|
||||
"questDysheartenerBossRageDescription": "Die Anzeige für den Raserei-Angriff füllt sich, wenn Habiticaner ihre Tagesaufgaben nicht abhaken. Sobald sie gefüllt ist, wird der Entmutiger seine Niederschmetternde Herzschmerz-Attacke über einem von Habitica's Ladenbesitzern entfesseln, also strengt Euch an und erledigt Eure Aufgaben!",
|
||||
"questDysheartenerBossRageSeasonal": "`Der Entmutiger entfesselt NIEDERSCHMETTERNDEN HERZSCHMERZ!`\n\nOh nein! Nachdem er sich an unseren unerledigten Tagesaufgaben gelabt hat, hat der Entmutiger genügend Stärke gesammelt, um seine Niederschmetternde Herzschmerz-Attacke einzusetzen. Mit einem schrillen Aufschrei treffen seine stacheligen Vorderbeine den Pavillon, unter dem der Jahreszeitenmarkt liegt! Die markerschütternde Explosion aus Magie lässt das Holz zersplittern, und die Jahreszeitenzauberin wird bei dem Anblick von Trauer überwältigt.\n\nRasch, lasst uns unsere Tagesaufgaben erledigen, damit das Biest kein weiteres Mal zuschlagen kann!",
|
||||
"questDysheartenerBossRageSeasonal": "`Der Entmutiger entfesselt NIEDERSCHMETTERNDEN HERZSCHMERZ!`\n\nOh nein! Nachdem er sich an unseren unerledigten Tagesaufgaben labte, hat der Entmutiger genügend Stärke gesammelt, um seine Niederschmetternde Herzschmerz-Attacke einzusetzen. Mit einem schrillen Aufschrei treffen seine stacheligen Vorderbeine den Pavillon, unter dem der Jahreszeitenmarkt liegt! Die markerschütternde Explosion aus Magie lässt das Holz zersplittern, und die Jahreszeitenzauberin wird bei dem Anblick von Trauer überwältigt.\n\nRasch, lasst uns unsere Tagesaufgaben erledigen, damit das Biest kein weiteres Mal zuschlagen kann!",
|
||||
"seasonalShopRageStrikeHeader": "Der Jahreszeitenmarkt wurde angegriffen!",
|
||||
"seasonalShopRageStrikeLead": "Leslie wurde das Herz gebrochen!",
|
||||
"seasonalShopRageStrikeRecap": "Am 21. Februar war unsere geschätzte Leslie, die Jahreszeitenzauberin, am Boden zerstört, als der Entmutiger den Jahreszeitenmarkt zerstörte. Schnell, erledigt Eure Aufgaben, um das Monster zu bekämpfen und beim Wiederaufbau zu helfen!",
|
||||
@@ -588,7 +588,7 @@
|
||||
"questsRageStrikeHeader": "Der Questladen wurde angegriffen!",
|
||||
"questsRageStrikeLead": "Ian wurde das Herz gebrochen!",
|
||||
"questsRageStrikeRecap": "Am 6. März war unser wundervoller Ian, der Questmeister, tief erschüttert, als der Entmutiger den Boden rund um den Questladen zerstörte. Schnell, erledigt Eure Aufgaben, um das Monster zu bekämpfen und beim Wiederaufbau zu helfen!",
|
||||
"questDysheartenerBossRageMarket": "`Der Entmutiger entfesselt NIEDERSCHMETTERNDEN HERZSCHMERZ!`\n\nHilfe! Nachdem er sich an unseren unerledigten Tagesaufgaben gelabt hat, lässt der Entmutiger eine weitere Niederschmetternde Herzschmerz-Attacke los, die die Wände des Markts zerbersten lässt und ihn dem Erboden gleich macht! Unter den herabfallenden Steinen weint Alex der Händler um seine von der Zerstörung betroffenen Waren.\n\nWir dürfen nicht zulassen, dass dies noch einmal passiert! Sorgt dafür, dass alle Eure Tagesaufgaben erledigt werden, bevor der Entmutiger zu seinem letzten Schlag ansetzt.",
|
||||
"questDysheartenerBossRageMarket": "`Der Entmutiger entfesselt NIEDERSCHMETTERNDEN HERZSCHMERZ!`\n\nHilfe! Nachdem er sich an unseren unerledigten Tagesaufgaben gelabt hat, lässt der Entmutiger eine weitere Niederschmetternde Herzschmerz-Attacke los, welche die Wände des Markts zerbersten lässt und ihn dem Erboden gleich macht! Unter den herabfallenden Steinen weint Alex der Händler um seine von der Zerstörung betroffenen Waren.\n\nWir dürfen nicht zulassen, dass dies noch einmal passiert! Sorgt dafür, dass alle Eure Tagesaufgaben erledigt werden, bevor der Entmutiger zu seinem letzten Schlag ansetzt.",
|
||||
"questDysheartenerBossRageQuests": "`Der Entmutiger entfesselt NIEDERSCHMETTERNDEN HERZSCHMERZ!`\n\nAaaah! Wir haben schon wieder nicht alle Tagesaufgaben erledigt, und der Entmutiger hat genügend Energie für einen letzten Schlag gegen unsere geliebten Ladenbesitzer gesammelt. Die Landschaft um Ian den Questmeister wurde von seiner Niederschmetternden Herzschmerz-Attacke förmlich zerrissen, und Ian bis ins Mark erschüttert von dem schrecklichen Anblick. Wir sind so nah dran, dieses Monster zu besiegen... Beeilt Euch! Gebt jetzt nicht auf!",
|
||||
"questDysheartenerDropHippogriffPet": "Hoffnungsfroher Hippogreif (Haustier)",
|
||||
"questDysheartenerDropHippogriffMount": "Hoffnungsfroher Hippogreif (Reittier)",
|
||||
@@ -706,7 +706,7 @@
|
||||
"questWindupText": "Zähme die zankenden Zahnräder",
|
||||
"questWindupBoss": "Klangton",
|
||||
"questWindupCompletion": "Während Du den Attacken ausweichst, fällt Dir etwas seltsames auf: ein gestreifter Messingschwanz ragt aus dem Fahrgestell des Roboters. Du greifst mit einer raschen Hand inmitten des laufenden Robotergetriebes und ziehst... ein zitterndes, aufziehbares Tiger-Junges heraus. Es schmiegt sich an deine Kleidung.<br><br>Der Uhrwerk-Roboter hört umgehend auf um sich zu schlagen und lächelt, seine Zahnräder klicken zurück an ihren Platz. \"Kä-Kä-Kätzchen! Kätzchen in meinem Getriebe!\"<br><br>\"Großartig\", sagt Großmächtig errötend. \"Ich habe hart an diesen Aufzieh-Haustier-Tränken gearbeitet. Ich habe wohl etwas die Übersicht über meine Neuerfindungen verloren. Wisst Ihr, ich habe mein tägliches \"Werkstatt aufräumen\" in letzter Zeit öfter verpasst...\"<br><br>Du folgst dem Bastler und Klangton nach drinnen. Teile, Werkzeug und Tränke bedecken jede Oberfläche. Großmächtig nimmt deine Uhr, doch gibt dir einige Tränke.<br><br>\"Hier, nimm diese. Offensichtlich werden sie bei Dir besser aufgehoben sein!\"",
|
||||
"questWindupNotes": "*Habit City* ist selten ruhig, doch auf diese missgestimmte Katzenmusik warst Du nicht vorbereitet: Eine Kakophonie aus Knarzen, Quietschen und Kreischen, drang aus dem Laden *Good Timekeeping*, Habiticas bestem Uhrmacher. Du seufzt--Du wolltest doch nur Deine Uhr reparieren lassen. \"Great and Powerful\", oder \"Großmächtig\", wie der Uhrmacher genannt wird, kommt Dir bereits entgegen gestolpert, direkt gefolgt von einem klirrenden Kupfergiganten. <br><br> \"Kä-! Kä-! Kä-!\" klingelt er, die Arme umher werfend. Sein Getriebe malt und quietscht unter Protest.<br><br>\"Mein Roboter \"Klangton\" ist verrückt geworden! Er will mich umbringen!\" kreischt der angeblich mächtige Uhrmacher.<br><br>Sogar mit einer kaputten Uhr weißt Du wann die Zeit reif ist, zu kämpfen. Du stürzt voran, um den panischen Uhrmacher zu beschützen. @Vikte und @a_diamond kommen ebenfalls zur Hilfe!<br><br>\"Kä-! Kä-! Kä-!\", singt Klangton bei jedem Schlag. \"Miau!\"<br><br>Moment mal, war das ein mechanischen Miauen inmitten der mörderischen Monotonie?",
|
||||
"questWindupNotes": "*Habit City* ist selten ruhig, doch auf diese missgestimmte Katzenmusik warst Du nicht vorbereitet: Eine Kakophonie aus Knarzen, Quietschen und Kreischen, drang aus dem Laden *Good Timekeeping*, Habiticas bestem Uhrmacher. Du seufzt--Du wolltest doch nur Deine Uhr reparieren lassen. \"Great and Powerful\", oder \"Der Großmächtige\", wie der Uhrmacher genannt wird, kommt Dir bereits entgegen gestolpert, direkt gefolgt von einem klirrenden Kupfergiganten. <br><br> \"Ki-! Ki-! Ki!\" klingelt er, die Arme umher werfend. Sein Getriebe malt und quietscht unter Protest.<br><br>\"Mein Roboter \"Klangton\" ist verrückt geworden! Er will mich umbringen!\" kreischt der angeblich mächtige Uhrmacher.<br><br>Sogar mit einer kaputten Uhr weißt Du wann die Zeit reif ist, zu kämpfen. Du stürzt voran, um den panischen Uhrmacher zu beschützen. @Vikte und @a_diamond kommen ebenfalls zu Hilfe!<br><br>\"Ki-! Ki-! Ki!\", singt Klangton bei jedem Schlag. \"Miau!\"<br><br>Moment mal, war das ein mechanisches Miauen inmitten der mörderischen Monotonie?",
|
||||
"questTurquoiseText": "Türkisgrüne Schatzsuchtortur",
|
||||
"questTurquoiseUnlockText": "Schaltet den Kauf von Türkisen Schlüpfelixieren auf dem Marktplatz frei",
|
||||
"questTurquoiseDropTurquoisePotion": "Türkises Schlüpfelixier",
|
||||
@@ -846,5 +846,19 @@
|
||||
"questPlatypusRageDescription": "Diese Leiste füllt sich, wenn Du Deine Tagesaufgaben nicht erfüllst. Wenn sie voll ist, nimmt Das Perfektionisten Schnabeltier deiner Party einige ihrer MP weg!",
|
||||
"questPlatypusRageEffect": "Das Perfektionisten Schnabeltier taucht unter Wasser und spritzt dich naß! Die MP deiner Party sind reduziert!",
|
||||
"questPlatypusDropPlatypusEgg": "Schnabeltier (Ei)",
|
||||
"questPlatypusUnlockText": "Schält Schnabeltier Eier zum Kauf im Marktplatz frei"
|
||||
"questPlatypusUnlockText": "Schält Schnabeltier Eier zum Kauf im Marktplatz frei",
|
||||
"questOtterNotes": "To-Do-Listen sind großartig! Man kann Stunden damit verbringen, jeden Schritt, den man tun muss, akribisch zu dokumentieren und sich produktiv zu fühlen, ohne diese Dinge tatsächlich zu tun. Deine dreiseitige Liste wird in die Tasche gesteckt. Zeit für einen erfrischenden Spaziergang!<br><br>Du machst dich auf den Weg zum Routinen-Fluss, um einen Spaziergang am Ufer zu machen. Das ist genau das, was Du brauchst, um endlich loszulegen! Zeit, Deine To-Do-Liste hervorzuholen und - ach! Ein Windstoß lässt Dir die Liste aus der Hand und direkt in Richtung Wasser fliegen!<br><br>Kurz bevor das Papier ins Wasser fällt, taucht ein Otterkopf auf und fängt das Blatt ab. Puh! Er hält die Liste in seinen Pfoten und ein schelmisches Grinsen breitet sich auf seinem Gesicht aus... Uh-oh.<br><br>„Hmmm“, summt er und wendet das Papier, um Deine Liste zu lesen. „Sieht aus, als bräuchtest Du Hilfe beim Setzen von Prioritäten.“ Ritsch.<br><br>Der Otter hat gerade Deine sorgfältig erstellte Liste in Stücke gerissen! „Wenn Du das alles erledigen willst, musst Du Dich zuerst entscheiden, was das Wichtigste ist“, sagt er und wirft die Punkte auf Deiner Liste Stück für Stück in den Wind.",
|
||||
"questOtterCompletion": "Als Du es geschafft hast, die Teile Deiner Liste einzufangen, begannst du, sie danach zu sortieren, welche Aufgaben am wichtigsten sind, und hast am Ende einen recht handhabbaren Startpunkt gefunden!<br><br>„Jetzt verstehe ich!“, sagst Du dem Otter, „dieser Quatsch hat mir tatsächlich geholfen, darüber nachzudenken, welche Aufgaben ich priorisieren muss.“<br><br>Der Otter spritzt herum und reibt sich vergnügt die Wangen: „Ich bin froh, dass mein kleiner Plan Dich dazu gebracht hat, anders über Deine Aufgaben nachzudenken.“ Er taucht unter und in der Nähe wieder auf. \"Denke daran, deine Listen machbar zu halten. Belohnungen helfen auch, also nimm die hier!\"",
|
||||
"questPlatypusCompletion": "Nach einem erschöpfenden hin und her von Wasserstrahlen und einigen aufmunternden Worten deinerseits hält das Schnabeltier endlich inne und kommt seufzend an die Oberfläche.<br><br>„Da hast du vielleicht recht. Wenn ich Perfektion verlange, werde ich nie fertig! Ich kann ja immer noch Anpassungen vornehmen. Du scheinst dich mit Perfektionismus auszukennen.“<br><br>Du siehst auf dein durchnässtes Arbeitsblatt. „Ja …“<br><br>„Tut mir leid“, sagt das Schnabeltier. „Als Entschuldigung dafür, dass dein Aufsatz nass geworden ist, nimm bitte ein paar Eier, die ich im Schlamm gefunden habe.“",
|
||||
"questOpalNotes": "Habiticas Gelehrte haben lange nach dem sagenumwobenen magischen Opal-Schlüpfelixier gesucht. Ein Trank, so machtvoll, dass er Haustieren und deren Reittieren eine feurige Farbe und Glanz verleiht wie kein anderer Edelstein oder Edelmetall. Gerüchten zufolge soll die Magie der Opale sogar Planung, Einsicht und Kreativität verbessern. Welchen Auftrieb dir das bei deinen Aufgaben geben würde!<br><br>Nach langem Suchen haben Sie vielleicht endlich die Antwort gefunden. Opalelixiere erfordern rohe Opale, auf welche die magischen Runen von Waage und Merkur geschmiedet werden. Diese antiken Gegenstände können nur an einem Ort gefunden werden … den gefährlichen Ruinen der verlorenen Stadt am Rande der Zeitwüste.<br><br>Du erreichst die Ruinen, nachdem du tagelang auf deinen stärksten Reittier durch das raue und abgelegene Gelände geritten bist. Zwischen den sonnengebleichten und zerbrochenen Steinen siehst du einen hellen Schimmer. Die Suche beginnt!",
|
||||
"questJadeCompletion": "Nach unzähligen Rückschlägen hast du es irgendwie geschafft, den Jadebrocken auf den Gipfel des Berges zu rollen! Die Steinfigur holt dich ein und lächelt. Sie gibt dem Brocken einen leichten Schubs, und du siehst entsetzt zu, wie er wieder nach unten rollt.<br><br>„Warum hast du das gemacht? Jetzt muss das jemand nochmal machen!“, beklagst du dich.<br><br>„Nur weil du etwas mehr als einmal tun musst, heißt das nicht, dass deine Leistungen bedeutungslos sind“, sagt die Steinfigur. „Konzentriere dich jetzt auf das Erreichte und erfreue dich an einer Belohnung!“<br><br>Du schreckst von deiner Couch hoch, als dein Handy auf den Boden fällt. Neben ihm stehen drei Flaschen flüssige Jade! Vielleicht ist es Zeit, das Geschirr von heute abzuwaschen und dann eine Pause einzulegen, um zu sehen, wie diese Tränke bei ein paar Haustier-Eiern wirken …",
|
||||
"questAlpacaNotes": "Die Sonne brennt auf dich hernieder, während du die felsigen Pfade des Mäandergebirges hinaufwanderst. Seit Monaten planst du diese Expedition für deine Freunde und hast jeden Aspekt der Reise recherchiert. Das Gewicht der Vorräte auf deinem Rücken ist so schwer zu tragen, dass sich jeder Schritt eher wie eine Strafe als ein Abenteuer anfühlt.<br><br>Du hörst ein leises Knirschen von Hufen auf dem Pfad hinter dir. Ein flauschiges Alpaka nähert sich mit einem gigantischen Stapel Gepäck auf dem Rücken.<br><br>„Sieht aus, als würdest du dich ganz schön abschleppen, Kumpel, und du trägst nur einen kleinen Rucksack!“, sagt es, als es vorbeigeht.<br><br>„Bei dir sieht es so einfach aus“, seufzst du. „Ich habe diese Reise so lange geplant, aber jetzt, wo wir hier sind, macht es mir nicht mal mehr Spaß …“<br><br>„Lass dich nicht unterkriegen“, schnaubt das Alpaka. „Ich werde dir eine Lektion erteilen, die ich vor langer Zeit gelernt habe!“ Es bockt und plötzlich fliegt ein zusammengerollter Schlafsack auf dich zu! Wie hilft das nochmal?!",
|
||||
"questPlatypusNotes": "Es ist ein wundervoller Tag am Conquest Creek, der durch das Arbeitsblatt in deiner Hand nun doch ziemlich mies wird. Warum werden tolle Abenteuer immer durch Hausaufgaben ruiniert? Nach fünf Fragen zu Fluss-Ökosystemen, musst du dich auch noch mit einem Aufsatz herumschlagen.<br><br>„Beschreiben Sie, wie sich ein Tier an das Leben im Fluss anpassen könnte? Puh, keine Ahnung…“<br><br>Nachdem du 30 Minuten lang hoffnungslos festsitzt und nicht einmal weißt, wie du überhaupt anfangen sollst, hättest du eine Menge frustriert klingendes Platschen am Ufer entlang.<br><br>„Auuh“, blubbert eine Stimme direkt unter der Oberfläche. Ein erschöpft aussehendes Schnabeltier taucht auf. „Dieser Bau will einfach nicht zusammenpassen! Jedes Mal, wenn ich anfange, sieht es einfach falsch aus.“ Es taucht wieder unter die Oberfläche und sein breiter, flacher Schwanz spritzt dir mächtig ins Gesicht.<br><br>„Warte, mach nicht alles kaputt –“, rufst du, als dich ein weiterer Schwall Wasser aus dem Bach trifft. Vielleicht kannst du helfen und dich dabei inspirieren lassen!",
|
||||
"questOpalText": "Die Legende der Obskuren Opale",
|
||||
"questOpalCompletion": "Schließlich findest du, müde und staubig, die letzten Runen und den Opalstein, die du brauchst, um das magische Schlüpfelixier zu schmieden.<br><br>Du beginnst mit dem Schmieden, sobald du wieder in Habiticas Hauptstadt bist. Die Kraft der Runen und Opale erfüllt dein Labor mit Licht in den Farben des Regenbogens! Im Handumdrehen hast du drei Elixiere geschmiedet und freust dich darauf, neue, farbenfrohe Freunde auszubrüten.",
|
||||
"questOpalCollectLibraRunes": "Waage-Rune",
|
||||
"questOpalCollectMercuryRunes": "Merkur-Rune",
|
||||
"questOpalCollectOpalGems": "Opal-Edelstein",
|
||||
"questOpalDropOpalPotion": "Opal-Schlüpfelixier",
|
||||
"questOpalUnlockText": "Schaltet im Markt das Opal-Schlüpfelixier zum Kauf frei"
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
"APIToken": "API-Token (Das ist ein Passwort – die obige Warnung gilt auch hier!)",
|
||||
"showAPIToken": "API-Token anzeigen",
|
||||
"hideAPIToken": "API-Token verbergen",
|
||||
"APITokenWarning": "Wenn Du einen neuen API-Token brauchst (z.B. weil Du ihn versehentlich geteilt hast), schreibe eine E-Mail an <%= hrefTechAssistanceEmail %> mit Deiner Benutzer ID und dem aktuellen Schlüssel. Sobald er zurückgesetzt ist, wirst Du Dich auf der Webseite und der mobilen App aus- und neu einloggen müssen und den Schlüssel in jedem anderen Habitica Tool, das Du nutzt, einstellen müssen.",
|
||||
"thirdPartyApps": "Apps von Drittanbietern",
|
||||
"resetDo": "Ja, setzt mein Konto jetzt zurück!",
|
||||
"resetComplete": "Zurückgesetzt!",
|
||||
@@ -117,7 +116,7 @@
|
||||
"generate": "Erstelle",
|
||||
"getCodes": "Codes erhalten",
|
||||
"webhooks": "WebHooks",
|
||||
"webhooksInfo": "WebHooks bieten Entwicklern die Möglichkeit, Benachrichtigngen zu erhalten, wenn eine bestimmte Aktion durchgeführt wird, z. B. das Bewerten oder Aktualisieren einer Aufgabe oder das Senden einer Nachricht in einer Gruppe. Indem du einen WebHook erstellst, kannst du Änderungen in Habitica wahrnehmen und Anwendungen entwickeln, die auf diese Änderungen reagieren. <br><br> Weitere Informationen und Beispiele findest Du bei den <a target=\"_blank\" href=\"https://habitica.fandom.com/wiki/Webhooks\">API Docs</a>.",
|
||||
"webhooksInfo": "WebHooks bieten Entwicklern die Möglichkeit, Benachrichtigungen zu erhalten, wenn eine bestimmte Aktion durchgeführt wird, z. B. das Bewerten oder Aktualisieren einer Aufgabe oder das Senden einer Nachricht in einer Gruppe. Indem du einen WebHook erstellst, kannst du Änderungen in Habitica wahrnehmen und Anwendungen entwickeln, die auf diese Änderungen reagieren. <br><br> Weitere Informationen und Beispiele findest Du bei den <a target=\"_blank\" href=\"https://habitica.com/apidoc/#api-Webhook-AddWebhook\">API Docs</a>.",
|
||||
"enabled": "Aktiviert",
|
||||
"webhookURL": "WebHook-URL",
|
||||
"invalidUrl": "Ungültige URL",
|
||||
@@ -197,7 +196,7 @@
|
||||
"giftSubscriptionRateText": "<strong>$<%= price %> $(USD)</strong> für <strong><%= months %> Monate</strong>",
|
||||
"transaction_admin_update_balance": "<b>Admin</b> gegeben",
|
||||
"transaction_admin_update_hourglasses": "<b>Admin</b> aktualisiert",
|
||||
"transaction_create_bank_challenge": "Bankherausforderung <b>erstellt</b>",
|
||||
"transaction_create_bank_challenge": "Bank-Herausforderung <b>erstellt</b>",
|
||||
"passwordIssueLength": "Passwörter müssen zwischen 8 und 64 Zeichen lang sein.",
|
||||
"timestamp": "Zeitstempel",
|
||||
"amount": "Menge",
|
||||
@@ -242,7 +241,7 @@
|
||||
"addWebhook": "Webhook hinzufügen",
|
||||
"changeEmailDisclaimer": "Dies ist die Email Adresse, die du benutzt, um dich bei Habitica anzumelden und um Benachrichtigungen zu erhalten.",
|
||||
"changeDisplayNameDisclaimer": "Dies ist der Name, der für deinen Avatar in Habitica angezeigt wird.",
|
||||
"changePasswordDisclaimer": "Passwort muß 8 Zeichen oder länger sein. Wir empfehlen ein starkes Passwort, das du sonst nirgends verwendest.",
|
||||
"changePasswordDisclaimer": "Das Ändern deines Passwortes wird dich von all deinen Geräten und Drittanbieter-Anwendungen abmelden.",
|
||||
"dateFormatDisclaimer": "Passe die Datumsformatierung in Habitica an.",
|
||||
"enableAudio": "Aktiviere Audio",
|
||||
"playDemoAudio": "Spiele Demo ab",
|
||||
@@ -256,7 +255,7 @@
|
||||
"connected": "Verbunden",
|
||||
"connect": "Verbinden",
|
||||
"changeClassDisclaimer": "Bei Änderung deiner Klasse bekommst du alle deine vorhandenen Attributspunkte erstattet. Passe deine Attributspunkte im Attributwerte-Abschnitt deines Profils an, sobald du eine neue Klasse gewählt hast.",
|
||||
"APITokenDisclaimer": "<b>Dein API Token ist wie ein Passwort. Teile es nicht öffentlich.</b>Es kann sein, daß du gelegentlich nach deiner User ID gefragt wirst, aber poste niemals dein API Token, wo andere es sehen können, einschließlich Github.<br><br><b>Hinweis:</b> Wenn du ein neues API Token brauchst (z.B., wenn du es aus Versehen geteilt hast), schreib eine Email an <a href='mailto:admin@habitica.com' target='_blank'>admin@habitica.com</a> mit deiner User ID und deinem aktuellen Token. Wenn es dann zurückgesetzt ist, musst du alles wieder neu authorisieren, indem du dich auf der Website und der mobilen App abmeldest und das neue Token bei allen anderen Habitica Tools, die du nutzt, angibst.",
|
||||
"APITokenDisclaimer": "<b>Dein API-Schlüssel ist wie ein Passwort. Teile ihn niemals öffentlich.</b> Du wirst ggf. nach deiner Benutzer-ID gefragt, aber schreibe deinen API-Schlüssel niemals dort, wo andere ihn sehen könnten bspw. Github.<br><br><b>Hinweis:</b> Falls du ein neues API-Schlüssel brauchst (z.B., weil du ihn versehentlich geteilt hast), kannst du dein Passwort ändern, um ihn zurückzusetzen. Einmal zurückgesetzt, musst du dich auf all deinen Geräten, auf denen du Habitica verwendest, erneut anmelden und deinen neuen API-Schlüssel in Drittanbieter-Anwendungen angeben, die du verwendest.",
|
||||
"thirdPartyTools": "Drittanbieter Apps, Erweiterungen, und alle möglichen anderen Tools, die du mit deinem Account nutzen kannst, findest du im <a href='https://habitica.fandom.com/wiki/Extensions,_Add-Ons,_and_Customizations' target='_blank'>Habitica Wiki</a>.",
|
||||
"transaction_subscription_bonus": "<b>Abonnement</b>-Bonus"
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"subGemName": "Abonnenten-Edelsteine",
|
||||
"maxBuyGems": "Du hast diesen Monat schon die erlaubte Menge Edelsteine gekauft. Innerhalb der ersten drei Tage des folgenden Monats werden neue verfügbar sein. Danke für Dein Abonnement!",
|
||||
"timeTravelers": "Mysteriöse Zeitreisende",
|
||||
"timeTravelersPopoverNoSubMobile": "Sieht aus als bräuchtest Du eine Mystische Sanduhr um das Zeitportal zu öffnen und die Mysteriösen Zeitreisenden herbei zu rufen.",
|
||||
"timeTravelersPopoverNoSubMobile": "Abonnenten erhalten jeden Monat eine Mystische Sanduhr für den Laden der Zeitreisenden!",
|
||||
"timeTravelersPopover": "Deine Mystische Sanduhr hat unser Zeitportal geöffnet! Wähle etwas aus, was wir für Dich aus der Vergangenheit oder Zukunft holen sollen.",
|
||||
"mysterySetNotFound": "Überraschungsset nicht gefunden, oder Set wurde bereits erworben.",
|
||||
"mysteryItemIsEmpty": "Mysteriöse Gegenstände sind leer",
|
||||
@@ -264,5 +264,7 @@
|
||||
"mysterySet202503": "Jade Juggernaut Set",
|
||||
"mysterySet202504": "Scheues Yeti Set",
|
||||
"mysterySet202505": "Hochfliegender Schwalbenschwanz Set",
|
||||
"mysterySet202506": "Sonnenschein Set"
|
||||
"mysterySet202506": "Sonnenschein Set",
|
||||
"mysterySet202507": "Draufgängerisches Skater Set",
|
||||
"mysterySet202508": "Strahlendes Klingen Set"
|
||||
}
|
||||
|
||||
7
website/common/locales/en/admin.json
Normal file
7
website/common/locales/en/admin.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"adminPanel": "Admin Panel",
|
||||
"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."
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user