Merge branch 'develop' of https://github.com/HabitRPG/habitica into negue/modal-notifications
# Conflicts: # website/client/components/notifications.vue
@@ -39,6 +39,7 @@ dist-client
|
||||
test/client/unit/coverage
|
||||
test/client/e2e/reports
|
||||
test/client-old/spec/mocks/translations.js
|
||||
yarn.lock
|
||||
|
||||
# Elastic Beanstalk Files
|
||||
.elasticbeanstalk/*
|
||||
|
||||
@@ -2,9 +2,13 @@ version: "3"
|
||||
services:
|
||||
|
||||
client:
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
volumes:
|
||||
- '.:/usr/src/habitrpg'
|
||||
|
||||
server:
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
volumes:
|
||||
- '.:/usr/src/habitrpg'
|
||||
|
||||
@@ -17,5 +17,5 @@ function setUpServer () {
|
||||
setUpServer();
|
||||
|
||||
// Replace this with your migration
|
||||
const processUsers = require('./tasks/habits-one-history-entry-per-day-challenges.js');
|
||||
const processUsers = require('./users/takeThis.js');
|
||||
processUsers();
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
let migrationName = '20180731_naming-day.js'; // Update when running in future years
|
||||
let authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Award Naming Day ladder items to participants in this month's Naming Day festivities
|
||||
*/
|
||||
|
||||
import monk from 'monk';
|
||||
import nconf from 'nconf';
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING'); // FOR TEST DATABASE
|
||||
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
|
||||
function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
migration: {$ne: migrationName},
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
query._id = {
|
||||
$gt: lastId,
|
||||
};
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
limit: 250,
|
||||
fields: [
|
||||
'items.gear.owned',
|
||||
'items.mounts',
|
||||
'items.pets',
|
||||
], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||
})
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
}
|
||||
|
||||
let userPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(userPromises)
|
||||
.then(() => {
|
||||
processUsers(lastUser._id);
|
||||
});
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
|
||||
let set = {};
|
||||
let push;
|
||||
|
||||
const inc = {
|
||||
'items.food.Cake_Base': 1,
|
||||
'items.food.Cake_CottonCandyBlue': 1,
|
||||
'items.food.Cake_CottonCandyPink': 1,
|
||||
'items.food.Cake_Desert': 1,
|
||||
'items.food.Cake_Golden': 1,
|
||||
'items.food.Cake_Red': 1,
|
||||
'items.food.Cake_Shade': 1,
|
||||
'items.food.Cake_Skeleton': 1,
|
||||
'items.food.Cake_White': 1,
|
||||
'items.food.Cake_Zombie': 1,
|
||||
'achievements.habiticaDays': 1,
|
||||
};
|
||||
|
||||
if (user && user.items && user.items.gear && user.items.gear.owned && typeof user.items.gear.owned.head_special_namingDay2017 !== 'undefined') {
|
||||
set = {migration: migrationName, 'items.gear.owned.body_special_namingDay2018': false};
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.body_special_namingDay2018', _id: monk.id()}};
|
||||
} else if (user && user.items && user.items.pets && typeof user.items.pets['Gryphon-RoyalPurple'] !== 'undefined') {
|
||||
set = {migration: migrationName, 'items.gear.owned.head_special_namingDay2017': false};
|
||||
push = {pinnedItems: {type: 'marketGear', path: 'gear.flat.head_special_namingDay2017', _id: monk.id()}};
|
||||
} else if (user && user.items && user.items.mounts && typeof user.items.mounts['Gryphon-RoyalPurple'] !== 'undefined') {
|
||||
set = {migration: migrationName, 'items.pets.Gryphon-RoyalPurple': 5};
|
||||
} else {
|
||||
set = {migration: migrationName, 'items.mounts.Gryphon-RoyalPurple': true};
|
||||
}
|
||||
|
||||
if (push) {
|
||||
dbUsers.update({_id: user._id}, {$set: set, $push: push, $inc: inc});
|
||||
} else {
|
||||
dbUsers.update({_id: user._id}, {$set: set, $inc: inc});
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count } ${ user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName } processed`);
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${ count } users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = processUsers;
|
||||
@@ -1,4 +1,4 @@
|
||||
let migrationName = '20180702_takeThis.js'; // Update per month
|
||||
let migrationName = '20180801_takeThis.js'; // Update per month
|
||||
let authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
@@ -15,7 +15,7 @@ function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
migration: {$ne: migrationName},
|
||||
challenges: {$in: ['f0481f95-1dde-4ae7-a876-d19502a45d61']}, // Update per month
|
||||
challenges: {$in: ['081f8912-3526-47d5-984f-f71bbeec77fc']}, // Update per month
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.54.0",
|
||||
"version": "4.57.1",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@slack/client": "^3.8.1",
|
||||
@@ -26,7 +26,7 @@
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"babel-register": "^6.6.0",
|
||||
"babel-runtime": "^6.11.6",
|
||||
"bcrypt": "^2.0.0",
|
||||
"bcrypt": "^3.0.0",
|
||||
"body-parser": "^1.18.3",
|
||||
"bootstrap": "^4.1.1",
|
||||
"bootstrap-vue": "^2.0.0-rc.9",
|
||||
@@ -35,7 +35,7 @@
|
||||
"coupon-code": "^0.4.5",
|
||||
"cross-env": "^5.1.5",
|
||||
"css-loader": "^0.28.11",
|
||||
"csv-stringify": "^2.1.0",
|
||||
"csv-stringify": "^3.0.0",
|
||||
"cwait": "^1.1.1",
|
||||
"domain-middleware": "~0.1.0",
|
||||
"express": "^4.16.3",
|
||||
@@ -43,7 +43,7 @@
|
||||
"express-validator": "^5.2.0",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"glob": "^7.1.2",
|
||||
"got": "^8.3.1",
|
||||
"got": "^9.0.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-babel": "^7.0.1",
|
||||
"gulp-imagemin": "^4.1.0",
|
||||
@@ -95,7 +95,7 @@
|
||||
"url-loader": "^1.0.0",
|
||||
"useragent": "^2.1.9",
|
||||
"uuid": "^3.0.1",
|
||||
"validator": "^9.4.1",
|
||||
"validator": "^10.5.0",
|
||||
"vinyl-buffer": "^1.0.1",
|
||||
"vue": "^2.5.16",
|
||||
"vue-loader": "^14.2.2",
|
||||
@@ -163,19 +163,19 @@
|
||||
"expect.js": "^0.3.1",
|
||||
"http-proxy-middleware": "^0.18.0",
|
||||
"istanbul": "^1.1.0-alpha.1",
|
||||
"karma": "^2.0.2",
|
||||
"karma": "^3.0.0",
|
||||
"karma-babel-preprocessor": "^7.0.0",
|
||||
"karma-chai-plugins": "^0.9.0",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-coverage": "^1.1.2",
|
||||
"karma-mocha": "^1.3.0",
|
||||
"karma-mocha-reporter": "^2.2.5",
|
||||
"karma-sinon-chai": "^1.3.4",
|
||||
"karma-sinon-chai": "^2.0.0",
|
||||
"karma-sinon-stub-promise": "^1.0.0",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-spec-reporter": "0.0.32",
|
||||
"karma-webpack": "^3.0.0",
|
||||
"lcov-result-merger": "^2.0.0",
|
||||
"lcov-result-merger": "^3.0.0",
|
||||
"mocha": "^5.1.1",
|
||||
"monk": "^6.0.6",
|
||||
"nightwatch": "^0.9.21",
|
||||
|
||||
@@ -65,6 +65,12 @@ describe('cron', () => {
|
||||
expect(analytics.track.callCount).to.equal(1);
|
||||
});
|
||||
|
||||
it('calls analytics when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(analytics.track.callCount).to.equal(1);
|
||||
});
|
||||
|
||||
describe('end of the month perks', () => {
|
||||
beforeEach(() => {
|
||||
user.purchased.plan.customerId = 'subscribedId';
|
||||
@@ -655,76 +661,6 @@ describe('cron', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('user is sleeping', () => {
|
||||
beforeEach(() => {
|
||||
user.preferences.sleep = true;
|
||||
});
|
||||
|
||||
it('calls analytics', () => {
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(analytics.track.callCount).to.equal(1);
|
||||
});
|
||||
|
||||
it('clears user buffs', () => {
|
||||
user.stats.buffs = {
|
||||
str: 1,
|
||||
int: 1,
|
||||
per: 1,
|
||||
con: 1,
|
||||
stealth: 1,
|
||||
streaks: true,
|
||||
};
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.buffs.str).to.equal(0);
|
||||
expect(user.stats.buffs.int).to.equal(0);
|
||||
expect(user.stats.buffs.per).to.equal(0);
|
||||
expect(user.stats.buffs.con).to.equal(0);
|
||||
expect(user.stats.buffs.stealth).to.equal(0);
|
||||
expect(user.stats.buffs.streaks).to.be.false;
|
||||
});
|
||||
|
||||
it('resets all dailies without damaging user', () => {
|
||||
let daily = {
|
||||
text: 'test daily',
|
||||
type: 'daily',
|
||||
frequency: 'daily',
|
||||
everyX: 5,
|
||||
startDate: new Date(),
|
||||
};
|
||||
|
||||
let task = new Tasks.daily(Tasks.Task.sanitize(daily)); // eslint-disable-line new-cap
|
||||
tasksByType.dailys.push(task);
|
||||
tasksByType.dailys[0].completed = true;
|
||||
|
||||
let healthBefore = user.stats.hp;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(tasksByType.dailys[0].completed).to.be.false;
|
||||
expect(user.stats.hp).to.equal(healthBefore);
|
||||
});
|
||||
|
||||
it('sets isDue for daily', () => {
|
||||
let daily = {
|
||||
text: 'test daily',
|
||||
type: 'daily',
|
||||
frequency: 'daily',
|
||||
everyX: 5,
|
||||
startDate: new Date(),
|
||||
};
|
||||
|
||||
let task = new Tasks.daily(Tasks.Task.sanitize(daily)); // eslint-disable-line new-cap
|
||||
tasksByType.dailys.push(task);
|
||||
tasksByType.dailys[0].completed = true;
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(tasksByType.dailys[0].isDue).to.be.exist;
|
||||
});
|
||||
});
|
||||
|
||||
describe('todos', () => {
|
||||
beforeEach(() => {
|
||||
let todo = {
|
||||
@@ -846,6 +782,15 @@ describe('cron', () => {
|
||||
expect(tasksByType.dailys[0].isDue).to.be.false;
|
||||
});
|
||||
|
||||
it('computes isDue when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
tasksByType.dailys[0].frequency = 'daily';
|
||||
tasksByType.dailys[0].everyX = 5;
|
||||
tasksByType.dailys[0].startDate = moment().toDate();
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(tasksByType.dailys[0].isDue).to.exist;
|
||||
});
|
||||
|
||||
it('computes nextDue', () => {
|
||||
tasksByType.dailys[0].frequency = 'daily';
|
||||
tasksByType.dailys[0].everyX = 5;
|
||||
@@ -865,6 +810,13 @@ describe('cron', () => {
|
||||
expect(tasksByType.dailys[0].completed).to.be.false;
|
||||
});
|
||||
|
||||
it('should set tasks completed to false when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
tasksByType.dailys[0].completed = true;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(tasksByType.dailys[0].completed).to.be.false;
|
||||
});
|
||||
|
||||
it('should reset task checklist for completed dailys', () => {
|
||||
tasksByType.dailys[0].checklist.push({title: 'test', completed: false});
|
||||
tasksByType.dailys[0].completed = true;
|
||||
@@ -872,6 +824,14 @@ describe('cron', () => {
|
||||
expect(tasksByType.dailys[0].checklist[0].completed).to.be.false;
|
||||
});
|
||||
|
||||
it('should reset task checklist for completed dailys when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
tasksByType.dailys[0].checklist.push({title: 'test', completed: false});
|
||||
tasksByType.dailys[0].completed = true;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(tasksByType.dailys[0].checklist[0].completed).to.be.false;
|
||||
});
|
||||
|
||||
it('should reset task checklist for dailys with scheduled misses', () => {
|
||||
daysMissed = 10;
|
||||
tasksByType.dailys[0].checklist.push({title: 'test', completed: false});
|
||||
@@ -884,12 +844,19 @@ describe('cron', () => {
|
||||
daysMissed = 1;
|
||||
let hpBefore = user.stats.hp;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.hp).to.be.lessThan(hpBefore);
|
||||
});
|
||||
|
||||
it('should not do damage for missing a daily when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
daysMissed = 1;
|
||||
let hpBefore = user.stats.hp;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.stats.hp).to.equal(hpBefore);
|
||||
});
|
||||
|
||||
it('should not do damage for missing a daily when CRON_SAFE_MODE is set', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('CRON_SAFE_MODE').returns('true');
|
||||
let cronOverride = requireAgain(pathToCronLib).cron;
|
||||
@@ -930,7 +897,7 @@ describe('cron', () => {
|
||||
expect(hpDifferenceOfPartiallyIncompleteDaily).to.be.lessThan(hpDifferenceOfFullyIncompleteDaily);
|
||||
});
|
||||
|
||||
it('should decrement quest progress down for missing a daily', () => {
|
||||
it('should decrement quest.progress.down for missing a daily', () => {
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
@@ -939,6 +906,16 @@ describe('cron', () => {
|
||||
expect(progress.down).to.equal(-1);
|
||||
});
|
||||
|
||||
it('should not decrement quest.progress.down for missing a daily when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
let progress = cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(progress.down).to.equal(0);
|
||||
});
|
||||
|
||||
it('should do damage for only yesterday\'s dailies', () => {
|
||||
daysMissed = 3;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
@@ -1017,7 +994,7 @@ describe('cron', () => {
|
||||
expect(tasksByType.habits[0].counterDown).to.equal(0);
|
||||
});
|
||||
|
||||
it('should reset habit counters even if user is resting in the Inn', () => {
|
||||
it('should reset habit counters even if user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
tasksByType.habits[0].counterUp = 1;
|
||||
tasksByType.habits[0].counterDown = 1;
|
||||
@@ -1278,7 +1255,23 @@ describe('cron', () => {
|
||||
expect(user.achievements.perfect).to.equal(0);
|
||||
});
|
||||
|
||||
it('increments user buffs if all (at least 1) due dailies were completed', () => {
|
||||
it('gives perfect day buff if all (at least 1) due dailies were completed', () => {
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].completed = true;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
let previousBuffs = user.stats.buffs.toObject();
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.buffs.str).to.be.greaterThan(previousBuffs.str);
|
||||
expect(user.stats.buffs.int).to.be.greaterThan(previousBuffs.int);
|
||||
expect(user.stats.buffs.per).to.be.greaterThan(previousBuffs.per);
|
||||
expect(user.stats.buffs.con).to.be.greaterThan(previousBuffs.con);
|
||||
});
|
||||
|
||||
it('gives perfect day buff if all (at least 1) due dailies were completed when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].completed = true;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
@@ -1317,6 +1310,31 @@ describe('cron', () => {
|
||||
expect(user.stats.buffs.streaks).to.be.false;
|
||||
});
|
||||
|
||||
it('clears buffs if user does not have a perfect day (no due dailys) when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].completed = true;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).add({days: 1});
|
||||
|
||||
user.stats.buffs = {
|
||||
str: 1,
|
||||
int: 1,
|
||||
per: 1,
|
||||
con: 1,
|
||||
stealth: 0,
|
||||
streaks: true,
|
||||
};
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.buffs.str).to.equal(0);
|
||||
expect(user.stats.buffs.int).to.equal(0);
|
||||
expect(user.stats.buffs.per).to.equal(0);
|
||||
expect(user.stats.buffs.con).to.equal(0);
|
||||
expect(user.stats.buffs.stealth).to.equal(0);
|
||||
expect(user.stats.buffs.streaks).to.be.false;
|
||||
});
|
||||
|
||||
it('clears buffs if user does not have a perfect day (at least one due daily not completed)', () => {
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].completed = false;
|
||||
@@ -1341,7 +1359,50 @@ describe('cron', () => {
|
||||
expect(user.stats.buffs.streaks).to.be.false;
|
||||
});
|
||||
|
||||
it('still grants a perfect day when CRON_SAFE_MODE is set', () => {
|
||||
it('clears buffs if user does not have a perfect day (at least one due daily not completed) when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].completed = false;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
user.stats.buffs = {
|
||||
str: 1,
|
||||
int: 1,
|
||||
per: 1,
|
||||
con: 1,
|
||||
stealth: 0,
|
||||
streaks: true,
|
||||
};
|
||||
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.buffs.str).to.equal(0);
|
||||
expect(user.stats.buffs.int).to.equal(0);
|
||||
expect(user.stats.buffs.per).to.equal(0);
|
||||
expect(user.stats.buffs.con).to.equal(0);
|
||||
expect(user.stats.buffs.stealth).to.equal(0);
|
||||
expect(user.stats.buffs.streaks).to.be.false;
|
||||
});
|
||||
|
||||
it('always grants a perfect day buff when CRON_SAFE_MODE is set', () => {
|
||||
sandbox.stub(nconf, 'get').withArgs('CRON_SAFE_MODE').returns('true');
|
||||
let cronOverride = requireAgain(pathToCronLib).cron;
|
||||
daysMissed = 1;
|
||||
tasksByType.dailys[0].completed = false;
|
||||
tasksByType.dailys[0].startDate = moment(new Date()).subtract({days: 1});
|
||||
|
||||
let previousBuffs = user.stats.buffs.toObject();
|
||||
|
||||
cronOverride({user, tasksByType, daysMissed, analytics});
|
||||
|
||||
expect(user.stats.buffs.str).to.be.greaterThan(previousBuffs.str);
|
||||
expect(user.stats.buffs.int).to.be.greaterThan(previousBuffs.int);
|
||||
expect(user.stats.buffs.per).to.be.greaterThan(previousBuffs.per);
|
||||
expect(user.stats.buffs.con).to.be.greaterThan(previousBuffs.con);
|
||||
});
|
||||
|
||||
it('always grants a perfect day buff when CRON_SAFE_MODE is set when user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
sandbox.stub(nconf, 'get').withArgs('CRON_SAFE_MODE').returns('true');
|
||||
let cronOverride = requireAgain(pathToCronLib).cron;
|
||||
daysMissed = 1;
|
||||
@@ -1373,6 +1434,20 @@ describe('cron', () => {
|
||||
common.statsComputed.restore();
|
||||
});
|
||||
|
||||
it('should not add mp to user when user is sleeping', () => {
|
||||
const statsComputedRes = common.statsComputed(user);
|
||||
const stubbedStatsComputed = sinon.stub(common, 'statsComputed');
|
||||
|
||||
user.preferences.sleep = true;
|
||||
let mpBefore = user.stats.mp;
|
||||
tasksByType.dailys[0].completed = true;
|
||||
stubbedStatsComputed.returns(Object.assign(statsComputedRes, {maxMP: 100}));
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.stats.mp).to.equal(mpBefore);
|
||||
|
||||
common.statsComputed.restore();
|
||||
});
|
||||
|
||||
it('set user\'s mp to statsComputed.maxMP when user.stats.mp is greater', () => {
|
||||
const statsComputedRes = common.statsComputed(user);
|
||||
const stubbedStatsComputed = sinon.stub(common, 'statsComputed');
|
||||
@@ -1568,7 +1643,7 @@ describe('cron', () => {
|
||||
expect(user.loginIncentives).to.eql(1);
|
||||
});
|
||||
|
||||
it('increments loginIncentives by 1 even if user has Dailies paused', () => {
|
||||
it('increments loginIncentives by 1 even if user is sleeping', () => {
|
||||
user.preferences.sleep = true;
|
||||
cron({user, tasksByType, daysMissed, analytics});
|
||||
expect(user.loginIncentives).to.eql(1);
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('slack', () => {
|
||||
title: 'Flag in Some group - (private guild)',
|
||||
title_link: undefined,
|
||||
text: 'some text',
|
||||
footer: sandbox.match(/<.*?groupId=group-id&chatId=chat-id\|Flag this message>/),
|
||||
footer: sandbox.match(/<.*?groupId=group-id&chatId=chat-id\|Flag this message.>/),
|
||||
mrkdwn_in: [
|
||||
'text',
|
||||
],
|
||||
|
||||
@@ -304,14 +304,14 @@ describe('POST /challenges', () => {
|
||||
expect(groupLeader.challenges.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('awards achievement if this is creator\'s first challenge', async () => {
|
||||
it('does not award joinedChallenge achievement for creating a challenge', async () => {
|
||||
await groupLeader.post('/challenges', {
|
||||
group: group._id,
|
||||
name: 'Test Challenge',
|
||||
shortName: 'TC Label',
|
||||
});
|
||||
groupLeader = await groupLeader.sync();
|
||||
expect(groupLeader.achievements.joinedChallenge).to.be.true;
|
||||
expect(groupLeader.achievements.joinedChallenge).to.not.be.true;
|
||||
});
|
||||
|
||||
it('sets summary to challenges name when not supplied', async () => {
|
||||
|
||||
@@ -3,15 +3,23 @@ import {
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
import { find } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import nconf from 'nconf';
|
||||
import { IncomingWebhook } from '@slack/client';
|
||||
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
|
||||
describe('POST /chat/:chatId/flag', () => {
|
||||
let user, admin, anotherUser, group;
|
||||
let user, admin, anotherUser, newUser, group;
|
||||
const TEST_MESSAGE = 'Test Message';
|
||||
const USER_AGE_FOR_FLAGGING = 3;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser({balance: 1});
|
||||
user = await generateUser({balance: 1, 'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate()});
|
||||
admin = await generateUser({balance: 1, 'contributor.admin': true});
|
||||
anotherUser = await generateUser();
|
||||
anotherUser = await generateUser({'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate()});
|
||||
newUser = await generateUser({'auth.timestamps.created': moment().subtract(1, 'days').toDate()});
|
||||
sandbox.stub(IncomingWebhook.prototype, 'send');
|
||||
|
||||
group = await user.post('/groups', {
|
||||
name: 'Test Guild',
|
||||
@@ -20,6 +28,10 @@ describe('POST /chat/:chatId/flag', () => {
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Returns an error when chat message is not found', async () => {
|
||||
await expect(user.post(`/groups/${group._id}/chat/incorrectMessage/flag`))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
@@ -34,7 +46,7 @@ describe('POST /chat/:chatId/flag', () => {
|
||||
await expect(user.post(`/groups/${group._id}/chat/${message.message.id}/flag`)).to.eventually.be.ok;
|
||||
});
|
||||
|
||||
it('Flags a chat', async () => {
|
||||
it('Flags a chat and sends normal message to moderator Slack when user is not new', async () => {
|
||||
let { message } = await anotherUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE});
|
||||
|
||||
let flagResult = await user.post(`/groups/${group._id}/chat/${message.id}/flag`);
|
||||
@@ -45,6 +57,62 @@ describe('POST /chat/:chatId/flag', () => {
|
||||
|
||||
let messageToCheck = find(groupWithFlags.chat, {id: message.id});
|
||||
expect(messageToCheck.flags[user._id]).to.equal(true);
|
||||
|
||||
// Slack message to mods
|
||||
const timestamp = `${moment(message.timestamp).utc().format('YYYY-MM-DD HH:mm')} UTC`;
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||
text: `${user.profile.name} (${user.id}; language: en) flagged a message`,
|
||||
attachments: [{
|
||||
fallback: 'Flag Message',
|
||||
color: 'danger',
|
||||
author_name: `${anotherUser.profile.name} - ${anotherUser.auth.local.email} - ${anotherUser._id}\n${timestamp}`,
|
||||
title: 'Flag in Test Guild',
|
||||
title_link: `${BASE_URL}/groups/guild/${group._id}`,
|
||||
text: TEST_MESSAGE,
|
||||
footer: `<https://habitrpg.github.io/flag-o-rama/?groupId=${group._id}&chatId=${message.id}|Flag this message.>`,
|
||||
mrkdwn_in: [
|
||||
'text',
|
||||
],
|
||||
}],
|
||||
});
|
||||
/* eslint-ensable camelcase */
|
||||
});
|
||||
|
||||
it('Does not increment message flag count and sends different message to moderator Slack when user is new', async () => {
|
||||
let automatedComment = `The post's flag count has not been increased because the flagger's account is less than ${USER_AGE_FOR_FLAGGING} days old.`;
|
||||
let { message } = await newUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE});
|
||||
|
||||
let flagResult = await newUser.post(`/groups/${group._id}/chat/${message.id}/flag`);
|
||||
expect(flagResult.flags[newUser._id]).to.equal(true);
|
||||
expect(flagResult.flagCount).to.equal(0);
|
||||
|
||||
let groupWithFlags = await admin.get(`/groups/${group._id}`);
|
||||
|
||||
let messageToCheck = find(groupWithFlags.chat, {id: message.id});
|
||||
expect(messageToCheck.flags[newUser._id]).to.equal(true);
|
||||
|
||||
// Slack message to mods
|
||||
const timestamp = `${moment(message.timestamp).utc().format('YYYY-MM-DD HH:mm')} UTC`;
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||
text: `${newUser.profile.name} (${newUser.id}; language: en) flagged a message`,
|
||||
attachments: [{
|
||||
fallback: 'Flag Message',
|
||||
color: 'danger',
|
||||
author_name: `${newUser.profile.name} - ${newUser.auth.local.email} - ${newUser._id}\n${timestamp}`,
|
||||
title: 'Flag in Test Guild',
|
||||
title_link: `${BASE_URL}/groups/guild/${group._id}`,
|
||||
text: TEST_MESSAGE,
|
||||
footer: `<https://habitrpg.github.io/flag-o-rama/?groupId=${group._id}&chatId=${message.id}|Flag this message.> ${automatedComment}`,
|
||||
mrkdwn_in: [
|
||||
'text',
|
||||
],
|
||||
}],
|
||||
});
|
||||
/* eslint-ensable camelcase */
|
||||
});
|
||||
|
||||
it('Flags a chat when the author\'s account was deleted', async () => {
|
||||
@@ -117,7 +185,7 @@ describe('POST /chat/:chatId/flag', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Returns an error when user tries to flag a message that is already flagged', async () => {
|
||||
it('Returns an error when user tries to flag a message that they already flagged', async () => {
|
||||
let { message } = await anotherUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE});
|
||||
|
||||
await user.post(`/groups/${group._id}/chat/${message.id}/flag`);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { IncomingWebhook } from '@slack/client';
|
||||
import nconf from 'nconf';
|
||||
import {
|
||||
createAndPopulateGroup,
|
||||
generateUser,
|
||||
@@ -15,8 +17,6 @@ import { getMatchesByWordArray } from '../../../../../website/server/libs/string
|
||||
import bannedWords from '../../../../../website/server/libs/bannedWords';
|
||||
import guildsAllowingBannedWords from '../../../../../website/server/libs/guildsAllowingBannedWords';
|
||||
import * as email from '../../../../../website/server/libs/email';
|
||||
import { IncomingWebhook } from '@slack/client';
|
||||
import nconf from 'nconf';
|
||||
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
|
||||
@@ -80,12 +80,14 @@ describe('POST /chat', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error when chat privileges are revoked when sending a message to a public guild', async () => {
|
||||
let userWithChatRevoked = await member.update({'flags.chatRevoked': true});
|
||||
await expect(userWithChatRevoked.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('chatPrivilegesRevoked'),
|
||||
describe('mute user', () => {
|
||||
it('returns an error when chat privileges are revoked when sending a message to a public guild', async () => {
|
||||
const userWithChatRevoked = await member.update({'flags.chatRevoked': true});
|
||||
await expect(userWithChatRevoked.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('chatPrivilegesRevoked'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -259,7 +261,6 @@ describe('POST /chat', () => {
|
||||
title: 'Slur in Test Guild',
|
||||
title_link: `${BASE_URL}/groups/guild/${groupWithChat.id}`,
|
||||
text: testSlurMessage,
|
||||
// footer: sandbox.match(/<.*?groupId=group-id&chatId=chat-id\|Flag this message>/),
|
||||
mrkdwn_in: [
|
||||
'text',
|
||||
],
|
||||
@@ -274,6 +275,7 @@ describe('POST /chat', () => {
|
||||
message: t('chatPrivilegesRevoked'),
|
||||
});
|
||||
|
||||
// @TODO: The next test should not depend on this. We should reset the user test in a beforeEach
|
||||
// Restore chat privileges to continue testing
|
||||
user.flags.chatRevoked = false;
|
||||
await user.update({'flags.chatRevoked': false});
|
||||
@@ -312,7 +314,6 @@ describe('POST /chat', () => {
|
||||
title: 'Slur in Party - (private party)',
|
||||
title_link: undefined,
|
||||
text: testSlurMessage,
|
||||
// footer: sandbox.match(/<.*?groupId=group-id&chatId=chat-id\|Flag this message>/),
|
||||
mrkdwn_in: [
|
||||
'text',
|
||||
],
|
||||
|
||||
@@ -4,23 +4,24 @@ import {
|
||||
translate as t,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
import config from '../../../../../config.json';
|
||||
import moment from 'moment';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
|
||||
describe('POST /groups/:id/chat/:id/clearflags', () => {
|
||||
const USER_AGE_FOR_FLAGGING = 3;
|
||||
let groupWithChat, message, author, nonAdmin, admin;
|
||||
|
||||
before(async () => {
|
||||
let { group, groupLeader, members } = await createAndPopulateGroup({
|
||||
let { group, groupLeader } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
|
||||
groupWithChat = group;
|
||||
author = groupLeader;
|
||||
nonAdmin = members[0];
|
||||
nonAdmin = await generateUser({'auth.timestamps.created': moment().subtract(USER_AGE_FOR_FLAGGING + 1, 'days').toDate()});
|
||||
admin = await generateUser({'contributor.admin': true});
|
||||
|
||||
message = await author.post(`/groups/${groupWithChat._id}/chat`, { message: 'Some message' });
|
||||
@@ -69,9 +70,14 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
|
||||
privateMessage = privateMessage.message;
|
||||
|
||||
await admin.post(`/groups/${group._id}/chat/${privateMessage.id}/flag`);
|
||||
|
||||
// first test that the flag was actually successful
|
||||
let messages = await members[0].get(`/groups/${group._id}/chat`);
|
||||
expect(messages[0].flagCount).to.eql(5);
|
||||
|
||||
await admin.post(`/groups/${group._id}/chat/${privateMessage.id}/clearflags`);
|
||||
|
||||
let messages = await members[0].get(`/groups/${group._id}/chat`);
|
||||
messages = await members[0].get(`/groups/${group._id}/chat`);
|
||||
expect(messages[0].flagCount).to.eql(0);
|
||||
});
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('GET /groups/:groupId/members', () => {
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
|
||||
expect(Object.keys(memberRes.preferences).sort()).to.eql([
|
||||
'size', 'hair', 'skin', 'shirt',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
|
||||
].sort());
|
||||
|
||||
expect(memberRes.stats.maxMP).to.exist;
|
||||
@@ -98,7 +98,7 @@ describe('GET /groups/:groupId/members', () => {
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
|
||||
expect(Object.keys(memberRes.preferences).sort()).to.eql([
|
||||
'size', 'hair', 'skin', 'shirt',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
|
||||
].sort());
|
||||
|
||||
expect(memberRes.stats.maxMP).to.exist;
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('GET /members/:memberId', () => {
|
||||
expect(Object.keys(memberRes.auth)).to.eql(['timestamps']);
|
||||
expect(Object.keys(memberRes.preferences).sort()).to.eql([
|
||||
'size', 'hair', 'skin', 'shirt',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks',
|
||||
'chair', 'costume', 'sleep', 'background', 'tasks', 'disableClasses',
|
||||
].sort());
|
||||
|
||||
expect(memberRes.stats.maxMP).to.exist;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
createAndPopulateGroup,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
|
||||
describe('Prevent multiple notifications', () => {
|
||||
let partyLeader, partyMembers, party;
|
||||
|
||||
before(async () => {
|
||||
let { group, groupLeader, members } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
type: 'party',
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 4,
|
||||
});
|
||||
|
||||
party = group;
|
||||
partyLeader = groupLeader;
|
||||
partyMembers = members;
|
||||
});
|
||||
|
||||
it('does not add the same notification twice', async () => {
|
||||
const multipleChatMessages = [];
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
for (let memberIndex = 0; memberIndex < partyMembers.length; memberIndex++) {
|
||||
multipleChatMessages.push(
|
||||
partyMembers[memberIndex].post(`/groups/${party._id}/chat`, { message: `Message ${i}_${memberIndex}`}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(multipleChatMessages);
|
||||
|
||||
const userWithNotification = await partyLeader.get('/user');
|
||||
|
||||
expect(userWithNotification.notifications.length).to.be.eq(1);
|
||||
});
|
||||
});
|
||||
@@ -58,6 +58,21 @@ describe('POST /user/class/cast/:spellId', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if use Healing Light spell with full health', async () => {
|
||||
await user.update({
|
||||
'stats.class': 'healer',
|
||||
'stats.lvl': 11,
|
||||
'stats.hp': 50,
|
||||
'stats.mp': 200,
|
||||
});
|
||||
await expect(user.post('/user/class/cast/heal'))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('messageHealthAlreadyMax'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if spell.lvl > user.level', async () => {
|
||||
await user.update({'stats.mp': 200, 'stats.class': 'wizard'});
|
||||
await expect(user.post('/user/class/cast/earth'))
|
||||
|
||||
@@ -50,11 +50,24 @@ describe('POST /user/push-devices', () => {
|
||||
});
|
||||
|
||||
it('adds a push device to the user', async () => {
|
||||
let response = await user.post('/user/push-devices', {type, regId});
|
||||
const response = await user.post('/user/push-devices', {type, regId});
|
||||
await user.sync();
|
||||
|
||||
expect(response.message).to.equal(t('pushDeviceAdded'));
|
||||
expect(response.data[0].type).to.equal(type);
|
||||
expect(response.data[0].regId).to.equal(regId);
|
||||
expect(user.pushDevices[0].type).to.equal(type);
|
||||
expect(user.pushDevices[0].regId).to.equal(regId);
|
||||
});
|
||||
|
||||
it('removes a push device to the user', async () => {
|
||||
await user.post('/user/push-devices', {type, regId});
|
||||
|
||||
const response = await user.del(`/user/push-devices/${regId}`);
|
||||
await user.sync();
|
||||
|
||||
expect(response.message).to.equal(t('pushDeviceRemoved'));
|
||||
expect(response.data[0]).to.not.exist;
|
||||
expect(user.pushDevices[0]).to.not.exist;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
generateUser,
|
||||
} from '../../helpers/common.helper';
|
||||
import spells from '../../../website/common/script/content/spells';
|
||||
import {
|
||||
NotAuthorized,
|
||||
} from '../../../website/common/script/libs/errors';
|
||||
import i18n from '../../../website/common/script/i18n';
|
||||
|
||||
// TODO complete the test suite...
|
||||
|
||||
describe('shared.ops.spells', () => {
|
||||
let user;
|
||||
|
||||
beforeEach(() => {
|
||||
user = generateUser();
|
||||
});
|
||||
|
||||
it('returns an error when healer tries to cast Healing Light with full health', (done) => {
|
||||
user.stats.class = 'healer';
|
||||
user.stats.lvl = 11;
|
||||
user.stats.hp = 50;
|
||||
user.stats.mp = 200;
|
||||
|
||||
let spell = spells.healer.heal;
|
||||
|
||||
try {
|
||||
spell.cast(user);
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||
expect(err.message).to.equal(i18n.t('messageHealthAlreadyMax'));
|
||||
expect(user.stats.hp).to.eql(50);
|
||||
expect(user.stats.mp).to.eql(200);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,90 +1,42 @@
|
||||
.promo_aquatic_glass_potions {
|
||||
.promo_armoire_backgrounds_201808 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -853px 0px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_armoire_backgrounds_201807 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -995px 0px;
|
||||
background-position: -817px 0px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_ios {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -477px 0px;
|
||||
background-position: -441px 0px;
|
||||
width: 375px;
|
||||
height: 361px;
|
||||
}
|
||||
.promo_kangaroo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -327px;
|
||||
width: 420px;
|
||||
height: 336px;
|
||||
}
|
||||
.promo_mystery_201807 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -995px -442px;
|
||||
background-position: -817px -442px;
|
||||
width: 114px;
|
||||
height: 120px;
|
||||
}
|
||||
.promo_orcas {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -954px;
|
||||
width: 219px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_seafoam {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -853px -442px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_seaserpent {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px 0px;
|
||||
width: 476px;
|
||||
height: 364px;
|
||||
}
|
||||
.promo_seasonal_shop_summer {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -642px -552px;
|
||||
width: 162px;
|
||||
height: 138px;
|
||||
}
|
||||
.promo_splashy_skins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -142px -365px;
|
||||
width: 375px;
|
||||
height: 186px;
|
||||
}
|
||||
.customize-option.promo_splashy_skins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -167px -380px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.promo_summer_splash_2018 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -365px;
|
||||
width: 141px;
|
||||
height: 588px;
|
||||
}
|
||||
.promo_take_this {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -995px -563px;
|
||||
background-position: -817px -563px;
|
||||
width: 96px;
|
||||
height: 69px;
|
||||
}
|
||||
.promo_unconventional_armor {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -518px -365px;
|
||||
background-position: -441px -362px;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
}
|
||||
.scene_pomodoro {
|
||||
.scene_tavern {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -142px -552px;
|
||||
width: 258px;
|
||||
height: 258px;
|
||||
}
|
||||
.scene_todos {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -401px -552px;
|
||||
width: 240px;
|
||||
height: 195px;
|
||||
background-position: 0px 0px;
|
||||
width: 440px;
|
||||
height: 326px;
|
||||
}
|
||||
|
||||
@@ -354,13 +354,13 @@
|
||||
}
|
||||
.background_at_the_docks {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px 0px;
|
||||
background-position: -710px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_aurora {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -148px;
|
||||
background-position: -710px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -372,19 +372,19 @@
|
||||
}
|
||||
.background_back_of_giant_beast {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -296px;
|
||||
background-position: -710px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_bamboo_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -444px;
|
||||
background-position: 0px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_beach {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -592px;
|
||||
background-position: -142px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -424,375 +424,387 @@
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_bug_covered_log {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1128px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_buried_treasure {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_champions_colosseum {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -148px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cherry_trees {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -296px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_chessboard_land {
|
||||
.background_bridge {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_clouds {
|
||||
.background_bug_covered_log {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -592px;
|
||||
background-position: -1277px 0px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_coral_reef {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -740px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cornfields {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cozy_library {
|
||||
.background_buried_treasure {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_crosscountry_ski_trail {
|
||||
.background_champions_colosseum {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -296px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cherry_trees {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -444px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_chessboard_land {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_crystal_cave {
|
||||
.background_clouds {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -141px -1184px;
|
||||
background-position: -1277px -740px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dark_deep {
|
||||
.background_coral_reef {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cornfields {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_cozy_library {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_deep_mine {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -423px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_deep_sea {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -564px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_desert_dunes {
|
||||
.background_crosscountry_ski_trail {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dilatory_castle {
|
||||
.background_crystal_cave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -846px -1184px;
|
||||
background-position: -282px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dilatory_city {
|
||||
.background_dark_deep {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dilatory_ruins {
|
||||
.background_deep_mine {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1128px -1184px;
|
||||
background-position: -564px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_distant_castle {
|
||||
.background_deep_sea {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1269px -1184px;
|
||||
background-position: -705px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_drifting_raft {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px 0px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_driving_a_coach {
|
||||
.background_desert_dunes {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_driving_a_sleigh {
|
||||
.background_dilatory_castle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dusty_canyons {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -444px;
|
||||
background-position: -987px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_elegant_balcony {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fairy_ring {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -740px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fantastical_shoe_store {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_farmhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fiber_arts_room {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_floating_islands {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_floral_meadow {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -141px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_a_field_of_wildflowers {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.customize-option.background_flying_over_a_field_of_wildflowers {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -309px -755px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.background_flying_over_an_ancient_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_icy_steppes {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -705px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_frigid_peak {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -846px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_frozen_lake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -987px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_garden_shed {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gazebo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1269px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_birdhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1410px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_florals {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_seashell {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_wave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gorgeous_greenhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_grand_staircase {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_graveyard {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -740px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_green {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_guardian_statues {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gumdrop_land {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_habit_city_streets {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_feast {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_fields {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_moon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_haunted_house {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -423px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_ice_cave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_iceberg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -705px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_idyllic_cabin {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -846px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_island_waterfalls {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -987px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_kelp_forest {
|
||||
.background_dilatory_city {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dilatory_ruins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1269px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_distant_castle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px 0px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_drifting_raft {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -148px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_driving_a_coach {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_driving_a_sleigh {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_dusty_canyons {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -592px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_elegant_balcony {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fairy_ring {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fantastical_shoe_store {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_farmhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_fiber_arts_room {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_floating_islands {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -141px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_floral_meadow {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -282px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_a_field_of_wildflowers {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.customize-option.background_flying_over_a_field_of_wildflowers {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -451px -755px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.background_flying_over_an_ancient_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_icy_steppes {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_flying_over_rocky_canyon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -852px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -987px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_frigid_peak {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1128px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_frozen_lake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1269px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_garden_shed {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gazebo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px 0px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_birdhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -148px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_florals {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -148px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_seashell {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -296px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_giant_wave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -444px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gorgeous_greenhouse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_grand_staircase {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -994px -740px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_graveyard {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_green {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_guardian_statues {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_gumdrop_land {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_habit_city_streets {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_feast {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -282px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_fields {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -284px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_harvest_moon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_haunted_house {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -705px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_ice_cave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -568px -888px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_iceberg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -987px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_idyllic_cabin {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -296px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_island_waterfalls {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -992px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_kelp_forest {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -710px 0px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_lighthouse_shore {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -990px -888px;
|
||||
background-position: -710px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_lilypad {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -849px -888px;
|
||||
background-position: -846px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_magic_beanstalk {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -708px -888px;
|
||||
background-position: -564px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -816,13 +828,13 @@
|
||||
}
|
||||
.background_market {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -282px -1480px;
|
||||
background-position: -1559px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_meandering_cave {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -141px -1480px;
|
||||
background-position: -1559px -740px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -834,7 +846,7 @@
|
||||
}
|
||||
.background_midnight_clouds {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -1036px;
|
||||
background-position: -1559px -444px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -846,31 +858,31 @@
|
||||
}
|
||||
.background_mist_shrouded_mountain {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -444px;
|
||||
background-position: -1410px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_mistiflying_circus {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -296px;
|
||||
background-position: -846px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_mountain_lake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -148px;
|
||||
background-position: -705px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_mountain_pyramid {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px 0px;
|
||||
background-position: -564px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_night_dunes {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1128px -1332px;
|
||||
background-position: -423px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -894,13 +906,13 @@
|
||||
}
|
||||
.background_orchard {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -1184px;
|
||||
background-position: -1128px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_pagodas {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -592px;
|
||||
background-position: -846px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -918,13 +930,13 @@
|
||||
}
|
||||
.background_pumpkin_patch {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -987px -1184px;
|
||||
background-position: 0px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_purple {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -705px -1184px;
|
||||
background-position: -1277px -592px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -948,13 +960,13 @@
|
||||
}
|
||||
.background_rainy_city {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -444px;
|
||||
background-position: -141px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_red {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px 0px;
|
||||
background-position: 0px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -984,61 +996,61 @@
|
||||
}
|
||||
.background_seafarer_ship {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -592px;
|
||||
background-position: -423px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_shimmering_ice_prism {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -444px;
|
||||
background-position: -141px -1480px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_shimmery_bubbles {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -567px -888px;
|
||||
background-position: -1559px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_slimy_swamp {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -426px -888px;
|
||||
background-position: -1559px -592px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_snowman_army {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -564px -1480px;
|
||||
background-position: -1559px -296px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_snowy_pines {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -1332px;
|
||||
background-position: 0px -1332px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_snowy_sunrise {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1559px -592px;
|
||||
background-position: -1418px -740px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_south_pole {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -564px -1332px;
|
||||
background-position: -1418px -444px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_sparkling_snowflake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -423px -1332px;
|
||||
background-position: -423px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_spider_web {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -282px -1332px;
|
||||
background-position: -141px -1184px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
@@ -1050,61 +1062,49 @@
|
||||
}
|
||||
.background_spring_rain {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -148px;
|
||||
background-position: -1128px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_stable {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -282px -1184px;
|
||||
background-position: -564px -1036px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_stained_glass {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1184px;
|
||||
background-position: -1136px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_starry_skies {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1277px -1036px;
|
||||
background-position: -1136px -592px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_starry_winter_night {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -142px -592px;
|
||||
background-position: -284px -592px;
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_stoikalm_volcanoes {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -141px -1036px;
|
||||
background-position: -851px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_stone_circle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: 0px -1036px;
|
||||
background-position: -1277px -148px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_stormy_rooftops {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1136px -888px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_stormy_ship {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -1418px -296px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_strange_sewers {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-0.png');
|
||||
background-position: -564px -1036px;
|
||||
background-position: -1136px -444px;
|
||||
width: 140px;
|
||||
height: 147px;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 553 KiB After Width: | Height: | Size: 549 KiB |
|
Before Width: | Height: | Size: 432 KiB After Width: | Height: | Size: 449 KiB |
|
Before Width: | Height: | Size: 340 KiB After Width: | Height: | Size: 315 KiB |
|
Before Width: | Height: | Size: 328 KiB After Width: | Height: | Size: 343 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 162 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 112 KiB |
@@ -2,8 +2,8 @@
|
||||
// possible values are: normal, fall, habitoween, thanksgiving, winter, nye, birthday, valentines, spring, summer
|
||||
// more to be added on future seasons
|
||||
|
||||
$npc_market_flavor: 'summer';
|
||||
$npc_quests_flavor: 'summer';
|
||||
$npc_seasonal_flavor: 'summer';
|
||||
$npc_timetravelers_flavor: 'summer';
|
||||
$npc_tavern_flavor: 'summer';
|
||||
$npc_market_flavor: 'normal';
|
||||
$npc_quests_flavor: 'normal';
|
||||
$npc_seasonal_flavor: 'normal';
|
||||
$npc_timetravelers_flavor: 'normal';
|
||||
$npc_tavern_flavor: 'normal';
|
||||
|
||||
@@ -164,30 +164,30 @@ export default {
|
||||
classGear (heroClass) {
|
||||
if (heroClass === 'rogue') {
|
||||
return {
|
||||
armor: 'armor_special_summer2018Rogue',
|
||||
head: 'head_special_summer2018Rogue',
|
||||
shield: 'shield_special_summer2018Rogue',
|
||||
weapon: 'weapon_special_summer2018Rogue',
|
||||
armor: 'armor_rogue_5',
|
||||
head: 'head_rogue_5',
|
||||
shield: 'shield_rogue_6',
|
||||
weapon: 'weapon_rogue_6',
|
||||
};
|
||||
} else if (heroClass === 'wizard') {
|
||||
return {
|
||||
armor: 'armor_special_summer2018Mage',
|
||||
head: 'head_special_summer2018Mage',
|
||||
weapon: 'weapon_special_summer2018Mage',
|
||||
armor: 'armor_wizard_5',
|
||||
head: 'head_wizard_5',
|
||||
weapon: 'weapon_wizard_6',
|
||||
};
|
||||
} else if (heroClass === 'healer') {
|
||||
return {
|
||||
armor: 'armor_special_summer2018Healer',
|
||||
head: 'head_special_summer2018Healer',
|
||||
shield: 'shield_special_summer2018Healer',
|
||||
weapon: 'weapon_special_summer2018Healer',
|
||||
armor: 'armor_healer_5',
|
||||
head: 'head_healer_5',
|
||||
shield: 'shield_healer_5',
|
||||
weapon: 'weapon_healer_6',
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
armor: 'armor_special_summer2018Warrior',
|
||||
head: 'head_special_summer2018Warrior',
|
||||
shield: 'shield_special_summer2018Warrior',
|
||||
weapon: 'weapon_special_summer2018Warrior',
|
||||
armor: 'armor_warrior_5',
|
||||
head: 'head_warrior_5',
|
||||
shield: 'shield_warrior_5',
|
||||
weapon: 'weapon_warrior_6',
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -6,21 +6,21 @@ b-modal#login-incentives(:title="data.message", size='md', :hide-footer="true")
|
||||
.row.reward-row
|
||||
.col-12
|
||||
avatar.avatar(:member='user', :avatarOnly='true', :withBackground='true')
|
||||
.text-center.col-12
|
||||
.text-center.col-12(v-if='nextReward')
|
||||
.reward-wrap(v-if="!data.rewardText")
|
||||
div(v-if="nextReward.rewardKey.length === 1", :class="nextReward.rewardKey[0]")
|
||||
.reward(v-for="reward in nextReward.rewardKey", v-if="nextReward.rewardKey.length > 1", :class='reward')
|
||||
.reward-wrap(v-if="data.rewardText")
|
||||
div(v-if="data.rewardKey.length === 1", :class="data.rewardKey[0]")
|
||||
.reward(v-for="reward in data.rewardKey", v-if="data.rewardKey.length > 1", :class='reward')
|
||||
.col-12.text-center(v-if="data.nextRewardAt")
|
||||
.col-12.text-center(v-if="data && data.nextRewardAt")
|
||||
h4 {{ $t('countLeft', {count: data.nextRewardAt - user.loginIncentives}) }}
|
||||
.row
|
||||
.col-12.text-center(v-if='data.rewardText')
|
||||
p {{ $t('earnedRewardForDevotion', {reward: data.rewardText}) }}
|
||||
.col-12.text-center
|
||||
p {{ $t('incentivesDescription') }}
|
||||
.col-12.text-center(v-if="data.nextRewardAt")
|
||||
.col-12.text-center(v-if="data && data.nextRewardAt")
|
||||
h3 {{ $t('nextRewardUnlocksIn', {numberOfCheckinsLeft: data.nextRewardAt - user.loginIncentives}) }}
|
||||
.modal-footer
|
||||
.col-12.text-center
|
||||
@@ -70,8 +70,9 @@ export default {
|
||||
user: 'user.data',
|
||||
}),
|
||||
nextReward () {
|
||||
let nextRewardKey = this.loginIncentives[this.user.loginIncentives].nextRewardAt;
|
||||
let nextReward = this.loginIncentives[nextRewardKey];
|
||||
if (!this.loginIncentives[this.user.loginIncentives]) return;
|
||||
const nextRewardKey = this.loginIncentives[this.user.loginIncentives].nextRewardAt;
|
||||
const nextReward = this.loginIncentives[nextRewardKey];
|
||||
return nextReward;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -15,22 +15,22 @@
|
||||
|
||||
// Show avatar only if not currently affected by visual buff
|
||||
template(v-if="showAvatar()")
|
||||
span(:class="'chair_' + member.preferences.chair")
|
||||
span(:class="getGearClass('back')")
|
||||
span(:class="skinClass")
|
||||
span(:class="member.preferences.size + '_shirt_' + member.preferences.shirt")
|
||||
span.head_0
|
||||
span(:class="member.preferences.size + '_' + getGearClass('armor')")
|
||||
span(:class="getGearClass('back_collar')")
|
||||
span(:class="['chair_' + member.preferences.chair, specialMountClass]")
|
||||
span(:class="[getGearClass('back'), specialMountClass]")
|
||||
span(:class="[skinClass, specialMountClass]")
|
||||
span(:class="[member.preferences.size + '_shirt_' + member.preferences.shirt, specialMountClass]")
|
||||
span(:class="['head_0', specialMountClass]")
|
||||
span(:class="[member.preferences.size + '_' + getGearClass('armor'), specialMountClass]")
|
||||
span(:class="[getGearClass('back_collar'), specialMountClass]")
|
||||
template(v-for="type in ['bangs', 'base', 'mustache', 'beard']")
|
||||
span(:class="'hair_' + type + '_' + member.preferences.hair[type] + '_' + member.preferences.hair.color")
|
||||
span(:class="getGearClass('body')")
|
||||
span(:class="getGearClass('eyewear')")
|
||||
span(:class="getGearClass('head')")
|
||||
span(:class="getGearClass('headAccessory')")
|
||||
span(:class="'hair_flower_' + member.preferences.hair.flower")
|
||||
span(v-if="!hideGear('shield')", :class="getGearClass('shield')")
|
||||
span(v-if="!hideGear('weapon')", :class="getGearClass('weapon')")
|
||||
span(:class="['hair_' + type + '_' + member.preferences.hair[type] + '_' + member.preferences.hair.color, specialMountClass]")
|
||||
span(:class="[getGearClass('body'), specialMountClass]")
|
||||
span(:class="[getGearClass('eyewear'), specialMountClass]")
|
||||
span(:class="[getGearClass('head'), specialMountClass]")
|
||||
span(:class="[getGearClass('headAccessory'), specialMountClass]")
|
||||
span(:class="['hair_flower_' + member.preferences.hair.flower, specialMountClass]")
|
||||
span(v-if="!hideGear('shield')", :class="[getGearClass('shield'), specialMountClass]")
|
||||
span(v-if="!hideGear('weapon')", :class="[getGearClass('weapon'), specialMountClass]")
|
||||
|
||||
// Resting
|
||||
span.zzz(v-if="member.preferences.sleep")
|
||||
@@ -67,6 +67,10 @@
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.offset-kangaroo {
|
||||
margin-top: 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -172,6 +176,11 @@ export default {
|
||||
costumeClass () {
|
||||
return this.member.preferences.costume ? 'costume' : 'equipped';
|
||||
},
|
||||
specialMountClass () {
|
||||
if (!this.avatarOnly && this.member.items.currentMount && this.member.items.currentMount.indexOf('Kangaroo') !== -1) {
|
||||
return 'offset-kangaroo';
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getGearClass (gearType) {
|
||||
|
||||
@@ -344,14 +344,14 @@ export default {
|
||||
this.tasksByType[task.type].splice(index, 1);
|
||||
},
|
||||
showMemberModal () {
|
||||
// @TODO: Change these to options and add a custom event to members modal
|
||||
this.$store.state.memberModalOptions.challengeId = this.challenge._id;
|
||||
this.$store.state.memberModalOptions.groupId = 'challenge'; // @TODO: change these terrible settings
|
||||
this.$store.state.memberModalOptions.group = this.group;
|
||||
this.$store.state.memberModalOptions.memberCount = this.challenge.memberCount;
|
||||
this.$store.state.memberModalOptions.viewingMembers = this.members;
|
||||
this.$store.state.memberModalOptions.fetchMoreMembers = this.loadMembers;
|
||||
this.$root.$emit('bv::show::modal', 'members-modal');
|
||||
this.$root.$emit('habitica:show-member-modal', {
|
||||
challengeId: this.challenge._id,
|
||||
groupId: 'challenge', // @TODO: change these terrible settings
|
||||
group: this.group,
|
||||
memberCount: this.challenge.memberCount,
|
||||
viewingMembers: this.members,
|
||||
fetchMoreMembers: this.loadMembers,
|
||||
});
|
||||
},
|
||||
async joinChallenge () {
|
||||
this.user.challenges.push(this.searchId);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
.container
|
||||
.row
|
||||
.col-12
|
||||
copy-as-todo-modal(:group-name='groupName', :group-id='groupId')
|
||||
copy-as-todo-modal(:group-type='groupType', :group-name='groupName', :group-id='groupId')
|
||||
report-flag-modal
|
||||
div(v-for="(msg, index) in messages", v-if='chat && canViewFlag(msg)')
|
||||
// @TODO: is there a different way to do these conditionals? This creates an infinite loop
|
||||
@@ -87,7 +87,7 @@ import reportFlagModal from './reportFlagModal';
|
||||
import chatCard from './chatCard';
|
||||
|
||||
export default {
|
||||
props: ['chat', 'groupId', 'groupName', 'inbox'],
|
||||
props: ['chat', 'groupType', 'groupId', 'groupName', 'inbox'],
|
||||
components: {
|
||||
copyAsTodoModal,
|
||||
reportFlagModal,
|
||||
@@ -202,8 +202,17 @@ export default {
|
||||
|
||||
if (!profile._id) {
|
||||
const result = await this.$store.dispatch('members:fetchMember', { memberId });
|
||||
this.cachedProfileData[memberId] = result.data.data;
|
||||
profile = result.data.data;
|
||||
if (result.response && result.response.status === 404) {
|
||||
return this.$store.dispatch('snackbars:add', {
|
||||
title: 'Habitica',
|
||||
text: this.$t('messageDeletedUser'),
|
||||
type: 'error',
|
||||
timeout: false,
|
||||
});
|
||||
} else {
|
||||
this.cachedProfileData[memberId] = result.data.data;
|
||||
profile = result.data.data;
|
||||
}
|
||||
}
|
||||
|
||||
// Open the modal only if the data is available
|
||||
|
||||
@@ -18,6 +18,7 @@ import notificationsMixin from 'client/mixins/notifications';
|
||||
import Task from 'client/components/tasks/task';
|
||||
|
||||
import taskDefaults from 'common/script/libs/taskDefaults';
|
||||
import { TAVERN_ID } from '../../../common/script/constants';
|
||||
|
||||
const baseUrl = 'https://habitica.com';
|
||||
|
||||
@@ -29,7 +30,7 @@ export default {
|
||||
Task,
|
||||
},
|
||||
mixins: [notificationsMixin],
|
||||
props: ['copyingMessage', 'groupName', 'groupId'],
|
||||
props: ['copyingMessage', 'groupType', 'groupName', 'groupId'],
|
||||
data () {
|
||||
return {
|
||||
isUser: true,
|
||||
@@ -38,7 +39,7 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica::copy-as-todo', message => {
|
||||
const notes = `${message.user || 'system message'}${message.user ? ' wrote' : ''} in [${this.groupName}](${baseUrl}/groups/guild/${this.groupId})`;
|
||||
const notes = `${message.user || 'system message'}${message.user ? ' wrote' : ''} in [${this.groupName}](${this.groupPath()})`;
|
||||
const newTask = {
|
||||
text: message.text,
|
||||
type: 'todo',
|
||||
@@ -55,6 +56,15 @@ export default {
|
||||
...mapActions({
|
||||
createTask: 'tasks:create',
|
||||
}),
|
||||
groupPath () {
|
||||
if (this.groupId === TAVERN_ID) {
|
||||
return `${baseUrl}/groups/tavern`;
|
||||
} else if (this.groupType === 'party') {
|
||||
return `${baseUrl}/party`;
|
||||
} else {
|
||||
return `${baseUrl}/groups/guild/${this.groupId}`;
|
||||
}
|
||||
},
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
|
||||
},
|
||||
|
||||
@@ -222,7 +222,7 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
||||
.col-12.customize-options
|
||||
.option(@click='set({"preferences.chair": "none"})', :class='{active: user.preferences.chair === "none"}')
|
||||
| None
|
||||
.option(v-for='option in ["black", "blue", "green", "pink", "red", "yellow"]',
|
||||
.option(v-for='option in chairKeys',
|
||||
:class='{active: user.preferences.chair === option}')
|
||||
.chair.sprite.customize-option(:class="`button_chair_${option}`", @click='set({"preferences.chair": option})')
|
||||
#flowers.row(v-if='activeSubPage === "flower"')
|
||||
@@ -856,7 +856,7 @@ import isPinned from 'common/script/libs/isPinned';
|
||||
const skinsBySet = groupBy(appearance.skin, 'set.key');
|
||||
const hairColorBySet = groupBy(appearance.hair.color, 'set.key');
|
||||
|
||||
let tasksByCategory = {
|
||||
const tasksByCategory = {
|
||||
work: [
|
||||
{
|
||||
type: 'habit',
|
||||
@@ -1014,6 +1014,7 @@ export default {
|
||||
baseHair5Keys: [1, 2],
|
||||
baseHair6Keys: [1, 2, 3],
|
||||
animalEarsKeys: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
|
||||
chairKeys: ['black', 'blue', 'green', 'pink', 'red', 'yellow', 'handleless_black', 'handleless_blue', 'handleless_green', 'handleless_pink', 'handleless_red', 'handleless_yellow'],
|
||||
icons: Object.freeze({
|
||||
logoPurple,
|
||||
bodyIcon,
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
.row
|
||||
.hr.col-12
|
||||
chat-message(:chat.sync='group.chat', :group-id='group._id', :group-name='group.name')
|
||||
chat-message(:chat.sync='group.chat', :group-type='group.type', :group-id='group._id', :group-name='group.name')
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
group-form-modal(v-if='isParty')
|
||||
start-quest-modal(:group='this.group')
|
||||
quest-details-modal(:group='this.group')
|
||||
participant-list-modal(:group='this.group')
|
||||
group-gems-modal
|
||||
.col-12.col-sm-8.standard-page
|
||||
.row
|
||||
@@ -126,7 +127,7 @@
|
||||
.sidebar {
|
||||
background-color: $gray-600;
|
||||
padding-bottom: 2em;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.buttons-wrapper {
|
||||
@@ -262,6 +263,7 @@ import * as Analytics from 'client/libs/analytics';
|
||||
import membersModal from './membersModal';
|
||||
import startQuestModal from './startQuestModal';
|
||||
import questDetailsModal from './questDetailsModal';
|
||||
import participantListModal from './participantListModal';
|
||||
import groupFormModal from './groupFormModal';
|
||||
import groupChallenges from '../challenges/groupChallenges';
|
||||
import groupGemsModal from 'client/components/groups/groupGemsModal';
|
||||
@@ -292,6 +294,7 @@ export default {
|
||||
groupFormModal,
|
||||
groupChallenges,
|
||||
questDetailsModal,
|
||||
participantListModal,
|
||||
groupGemsModal,
|
||||
questSidebarSection,
|
||||
sidebarSection,
|
||||
@@ -426,12 +429,13 @@ export default {
|
||||
return this.$store.dispatch('members:getGroupMembers', payload);
|
||||
},
|
||||
showMemberModal () {
|
||||
this.$store.state.memberModalOptions.groupId = this.group._id;
|
||||
this.$store.state.memberModalOptions.group = this.group;
|
||||
this.$store.state.memberModalOptions.memberCount = this.group.memberCount;
|
||||
this.$store.state.memberModalOptions.viewingMembers = this.members;
|
||||
this.$store.state.memberModalOptions.fetchMoreMembers = this.loadMembers;
|
||||
this.$root.$emit('bv::show::modal', 'members-modal');
|
||||
this.$root.$emit('habitica:show-member-modal', {
|
||||
groupId: this.group._id,
|
||||
group: this.group,
|
||||
memberCount: this.group.memberCount,
|
||||
viewingMembers: this.members,
|
||||
fetchMoreMembers: this.loadMembers,
|
||||
});
|
||||
},
|
||||
fetchRecentMessages () {
|
||||
this.fetchGuild();
|
||||
@@ -538,24 +542,6 @@ export default {
|
||||
this.$store.state.upgradingGroup = this.group;
|
||||
this.$router.push('/group-plans');
|
||||
},
|
||||
clickStartQuest () {
|
||||
Analytics.track({
|
||||
hitType: 'event',
|
||||
eventCategory: 'button',
|
||||
eventAction: 'click',
|
||||
eventLabel: 'Start a Quest',
|
||||
});
|
||||
|
||||
let hasQuests = find(this.user.items.quests, (quest) => {
|
||||
return quest > 0;
|
||||
});
|
||||
|
||||
if (hasQuests) {
|
||||
this.$root.$emit('bv::show::modal', 'start-quest-modal');
|
||||
return;
|
||||
}
|
||||
// $rootScope.$state.go('options.inventory.quests');
|
||||
},
|
||||
showGroupGems () {
|
||||
this.$root.$emit('bv::show::modal', 'group-gems-modal');
|
||||
},
|
||||
|
||||
@@ -53,7 +53,7 @@ div
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon")
|
||||
span.text {{$t('removeManager2')}}
|
||||
b-dropdown-item(@click='viewProgress(member)')
|
||||
b-dropdown-item(@click='viewProgress(member)', v-if='challengeId')
|
||||
span.dropdown-icon-item
|
||||
span.text {{ $t('viewProgress') }}
|
||||
.row(v-if='isLoadMoreAvailable')
|
||||
@@ -278,7 +278,20 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.getMembers();
|
||||
this.$root.$on('habitica:show-member-modal', (data) => {
|
||||
// @TODO: Remove store
|
||||
this.$store.state.memberModalOptions.challengeId = data.challengeId;
|
||||
this.$store.state.memberModalOptions.groupId = data.groupId;
|
||||
this.$store.state.memberModalOptions.group = data.group;
|
||||
this.$store.state.memberModalOptions.memberCount = data.memberCount;
|
||||
this.$store.state.memberModalOptions.viewingMembers = data.viewingMembers;
|
||||
this.$store.state.memberModalOptions.fetchMoreMembers = data.fetchMoreMembers;
|
||||
this.$root.$emit('bv::show::modal', 'members-modal');
|
||||
this.getMembers();
|
||||
});
|
||||
},
|
||||
destroyed () {
|
||||
this.$root.$off('habitica:show-member-modal');
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
@@ -363,6 +376,7 @@ export default {
|
||||
});
|
||||
this.invites = invites;
|
||||
}
|
||||
|
||||
if (this.$store.state.memberModalOptions.viewingMembers.length > 0) {
|
||||
this.members = this.$store.state.memberModalOptions.viewingMembers;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<template lang="pug">
|
||||
b-modal#participant-list(size='md', :hide-footer='true')
|
||||
.header-wrap(slot="modal-header")
|
||||
.row
|
||||
.col-6
|
||||
h1(v-once) {{ $t('participantsTitle') }}
|
||||
.col-6
|
||||
button(type="button" aria-label="Close" class="close", @click='close()')
|
||||
span(aria-hidden="true") ×
|
||||
.row(v-for='member in participants')
|
||||
.col-12.no-padding-left
|
||||
member-details(:member='member')
|
||||
.modal-footer
|
||||
button.btn.btn-primary(@click='close()') {{ $t('close') }}
|
||||
</template>
|
||||
|
||||
<style lang='scss'>
|
||||
#participant-list {
|
||||
.modal-header {
|
||||
background-color: #edecee;
|
||||
border-radius: 8px 8px 0 0;
|
||||
box-shadow: 0 1px 2px 0 rgba(26, 24, 29, 0.24);
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
background-color: #edecee;
|
||||
border-radius: 0 0 8px 8px;
|
||||
}
|
||||
|
||||
.small-text, .character-name {
|
||||
color: #878190;
|
||||
}
|
||||
|
||||
.no-padding-left {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.member-details {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.header-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #4f2a93;
|
||||
}
|
||||
|
||||
#participant-list_modal_body {
|
||||
padding: 0;
|
||||
max-height: 450px;
|
||||
|
||||
.member-details {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'client/libs/store';
|
||||
|
||||
import MemberDetails from '../memberDetails';
|
||||
|
||||
export default {
|
||||
props: ['group'],
|
||||
components: {
|
||||
MemberDetails,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
partyMembers: 'party:members',
|
||||
}),
|
||||
participants () {
|
||||
let partyMembers = this.partyMembers || [];
|
||||
return partyMembers.filter(member => this.group.quest.members[member._id] === true);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'participant-list');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -24,6 +24,9 @@ sidebar-section(:title="$t('questDetailsTitle')")
|
||||
h3(v-once) {{ questData.text() }}
|
||||
.quest-box
|
||||
.collect-info(v-if='questData.collect')
|
||||
.row
|
||||
.col-12
|
||||
a.float-right(@click="openParticipantList()") {{ $t('participantsTitle') }}
|
||||
.row(v-for='(value, key) in questData.collect')
|
||||
.col-2
|
||||
div(:class="'quest_' + questData.key + '_' + key")
|
||||
@@ -38,7 +41,7 @@ sidebar-section(:title="$t('questDetailsTitle')")
|
||||
.col-6
|
||||
h4.float-left(v-once) {{ questData.boss.name() }}
|
||||
.col-6
|
||||
span.float-right(v-once) {{ $t('participantsTitle') }}
|
||||
a.float-right(@click="openParticipantList()") {{ $t('participantsTitle') }}
|
||||
.row
|
||||
.col-12
|
||||
.grey-progress-bar
|
||||
@@ -134,6 +137,12 @@ sidebar-section(:title="$t('questDetailsTitle')")
|
||||
padding: .5em;
|
||||
margin-bottom: 1em;
|
||||
|
||||
a {
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
font-weight: bold;
|
||||
color: $gray-10;
|
||||
}
|
||||
|
||||
svg: {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -258,6 +267,9 @@ export default {
|
||||
openQuestDetails () {
|
||||
this.$root.$emit('bv::show::modal', 'quest-details');
|
||||
},
|
||||
openParticipantList () {
|
||||
this.$root.$emit('bv::show::modal', 'participant-list');
|
||||
},
|
||||
async questAbort () {
|
||||
if (!confirm(this.$t('sureAbort'))) return;
|
||||
if (!confirm(this.$t('doubleSureAbort'))) return;
|
||||
|
||||
@@ -148,8 +148,13 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
let questKeys = Object.keys(this.user.items.quests);
|
||||
this.selectedQuest = questKeys[0];
|
||||
const userQuests = this.user.items.quests;
|
||||
for (const key in userQuests) {
|
||||
if (userQuests[key] > 0) {
|
||||
this.selectedQuest = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.$root.$on('selectQuest', this.selectQuest);
|
||||
},
|
||||
@@ -177,13 +182,14 @@ export default {
|
||||
let groupId = this.group._id || this.user.party._id;
|
||||
|
||||
const key = this.selectedQuest;
|
||||
const response = await this.$store.dispatch('guilds:inviteToQuest', {groupId, key});
|
||||
const quest = response.data.data;
|
||||
|
||||
if (this.$store.state.party.data) this.$store.state.party.data.quest = quest;
|
||||
|
||||
this.loading = false;
|
||||
try {
|
||||
const response = await this.$store.dispatch('guilds:inviteToQuest', {groupId, key});
|
||||
const quest = response.data.data;
|
||||
|
||||
if (this.$store.state.party.data) this.$store.state.party.data.quest = quest;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
this.$root.$emit('bv::hide::modal', 'start-quest-modal');
|
||||
},
|
||||
},
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
.checkbox
|
||||
label
|
||||
input(type='checkbox', v-if='hero.flags', v-model='hero.flags.chatRevoked')
|
||||
| Chat Privileges Revoked
|
||||
strong Chat Privileges Revoked
|
||||
.form-group
|
||||
.checkbox
|
||||
label
|
||||
@@ -103,10 +103,10 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// import keys from 'lodash/keys';
|
||||
import each from 'lodash/each';
|
||||
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
import styleHelper from 'client/mixins/styleHelper';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import quests from 'common/script/content/quests';
|
||||
import { mountInfo, petInfo } from 'common/script/content/stable';
|
||||
@@ -115,7 +115,7 @@ import gear from 'common/script/content/gear';
|
||||
import notifications from 'client/mixins/notifications';
|
||||
|
||||
export default {
|
||||
mixins: [notifications],
|
||||
mixins: [notifications, styleHelper],
|
||||
data () {
|
||||
return {
|
||||
heroes: [],
|
||||
@@ -174,7 +174,7 @@ export default {
|
||||
async loadHero (uuid, heroIndex) {
|
||||
this.currentHeroIndex = heroIndex;
|
||||
let hero = await this.$store.dispatch('hall:getHero', { uuid });
|
||||
this.hero = Object.assign({}, this.hero, hero);
|
||||
this.hero = Object.assign({}, hero);
|
||||
if (!this.hero.flags) {
|
||||
this.hero.flags = {
|
||||
chatRevoked: false,
|
||||
@@ -204,9 +204,6 @@ export default {
|
||||
startingPage: 'profile',
|
||||
});
|
||||
},
|
||||
userLevelStyle () {
|
||||
// @TODO: implement
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -176,11 +176,11 @@ export default {
|
||||
}
|
||||
},
|
||||
showPartyMembers () {
|
||||
// Set the party details for the members-modal component
|
||||
this.$store.state.memberModalOptions.groupId = this.user.party._id;
|
||||
this.$store.state.memberModalOptions.viewingMembers = this.partyMembers;
|
||||
this.$store.state.memberModalOptions.group = this.user.party;
|
||||
this.$root.$emit('bv::show::modal', 'members-modal');
|
||||
this.$root.$emit('habitica:show-member-modal', {
|
||||
groupId: this.user.party._id,
|
||||
viewingMembers: this.partyMembers,
|
||||
group: this.user.party,
|
||||
});
|
||||
},
|
||||
setPartyMembersWidth ($event) {
|
||||
if (this.currentWidth !== $event.width) {
|
||||
|
||||
@@ -27,8 +27,8 @@ menu-dropdown.item-notifications(:right="true", @toggled="handleOpenStatusChange
|
||||
v-if="notificationsCount === 0"
|
||||
)
|
||||
.svg-icon(v-html="icons.success")
|
||||
h2 You're all caught up!
|
||||
p The notification fairies give you a raucous round of applause! Well done!
|
||||
h2 {{ $t('noNotifications') }}
|
||||
p {{ $t('noNotificationsText') }}
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<template lang="pug">
|
||||
b-modal#hatching-modal(@change="resetHatchablePet($event)")
|
||||
div.content(v-if="hatchablePet")
|
||||
div.potionEggGroup
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_HatchingPotion_'+hatchablePet.potionKey")
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_Egg_'+hatchablePet.eggKey")
|
||||
h4.title {{ hatchablePet.name }}
|
||||
div.text(v-html="$t('hatchDialogText', { potionName: hatchablePet.potionName, eggName: hatchablePet.eggName, petName: hatchablePet.name })")
|
||||
span.svg-icon.icon-10(v-html="icons.close", slot="modal-header", @click="closeHatchPetDialog()")
|
||||
div(slot="modal-footer")
|
||||
button.btn.btn-primary(@click="hatchPet(hatchablePet)") {{ $t('hatch') }}
|
||||
button.btn.btn-secondary.btn-flat(@click="closeHatchPetDialog()") {{ $t('cancel') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/modal.scss';
|
||||
|
||||
#hatching-modal {
|
||||
@include centeredModal();
|
||||
|
||||
.modal-dialog {
|
||||
width: 310px;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
margin: 9px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 24px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
color: #4e4a57;
|
||||
}
|
||||
|
||||
.text {
|
||||
height: 60px;
|
||||
font-size: 14px;
|
||||
line-height: 1.43;
|
||||
text-align: center;
|
||||
color: #686274;
|
||||
}
|
||||
|
||||
span.svg-icon.icon-10 {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import svgClose from 'assets/svg/close.svg';
|
||||
|
||||
import petMixin from 'client/mixins/petMixin';
|
||||
|
||||
export default {
|
||||
props: ['hatchablePet'],
|
||||
mixins: [petMixin],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
close: svgClose,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
resetHatchablePet ($event) {
|
||||
if (!$event) {
|
||||
this.hatchablePet = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,245 +1,205 @@
|
||||
<template lang="pug">
|
||||
// @TODO: breakdown to componentes and use some SOLID
|
||||
.row.stable(v-mousePosition="30", @mouseMoved="mouseMoved($event)")
|
||||
.standard-sidebar.d-none.d-sm-block
|
||||
div
|
||||
#npmMattStable.npc_matt
|
||||
b-popover(
|
||||
triggers="hover",
|
||||
placement="right",
|
||||
target="npmMattStable"
|
||||
)
|
||||
h4.popover-content-title(v-once) {{ $t('mattBoch') }}
|
||||
.popover-content-text(v-once) {{ $t('mattBochText1') }}
|
||||
|
||||
.row.stable(v-mousePosition="30", @mouseMoved="mouseMoved($event)")
|
||||
.standard-sidebar.d-none.d-sm-block
|
||||
div
|
||||
#npmMattStable.npc_matt
|
||||
b-popover(
|
||||
triggers="hover",
|
||||
placement="right",
|
||||
target="npmMattStable"
|
||||
)
|
||||
h4.popover-content-title(v-once) {{ $t('mattBoch') }}
|
||||
.popover-content-text(v-once) {{ $t('mattBochText1') }}
|
||||
.form-group
|
||||
input.form-control.input-search(type="text", v-model="searchText", :placeholder="$t('search')")
|
||||
.form
|
||||
h2(v-once) {{ $t('filter') }}
|
||||
h3(v-once) {{ $t('pets') }}
|
||||
.form-group
|
||||
input.form-control.input-search(type="text", v-model="searchText", :placeholder="$t('search')")
|
||||
|
||||
.form
|
||||
h2(v-once) {{ $t('filter') }}
|
||||
h3(v-once) {{ $t('pets') }}
|
||||
.form-group
|
||||
.form-check(
|
||||
v-for="petGroup in petGroups",
|
||||
:key="petGroup.key"
|
||||
)
|
||||
.custom-control.custom-checkbox
|
||||
input.custom-control-input(
|
||||
type="checkbox",
|
||||
v-model="viewOptions[petGroup.key].selected",
|
||||
:disabled="viewOptions[petGroup.key].animalCount == 0",
|
||||
:id="petGroup.key",
|
||||
)
|
||||
label.custom-control-label(v-once, :for="petGroup.key") {{ petGroup.label }}
|
||||
h3(v-once) {{ $t('mounts') }}
|
||||
.form-group
|
||||
.form-check(
|
||||
v-for="mountGroup in mountGroups",
|
||||
:key="mountGroup.key"
|
||||
)
|
||||
.custom-control.custom-checkbox
|
||||
input.custom-control-input(
|
||||
type="checkbox",
|
||||
v-model="viewOptions[mountGroup.key].selected",
|
||||
:disabled="viewOptions[mountGroup.key].animalCount == 0",
|
||||
:id="mountGroup.key",
|
||||
)
|
||||
label.custom-control-label(v-once, :for="mountGroup.key") {{ mountGroup.label }}
|
||||
|
||||
div.form-group.clearfix
|
||||
h3.float-left {{ $t('hideMissing') }}
|
||||
toggle-switch.float-right(
|
||||
:checked="hideMissing",
|
||||
@change="updateHideMissing"
|
||||
)
|
||||
.standard-page
|
||||
.clearfix
|
||||
h1.float-left.mb-4.page-header(v-once) {{ $t('stable') }}
|
||||
|
||||
div.float-right
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t(selectedSortBy)", right=true)
|
||||
b-dropdown-item(
|
||||
v-for="sort in sortByItems",
|
||||
@click="selectedSortBy = sort",
|
||||
:active="selectedSortBy === sort",
|
||||
:key="sort"
|
||||
) {{ $t(sort) }}
|
||||
|
||||
h2.mb-3
|
||||
| {{ $t('pets') }}
|
||||
|
|
||||
span.badge.badge-pill.badge-default {{countOwnedAnimals(petGroups[0], 'pet')}}
|
||||
|
||||
div(
|
||||
v-for="(petGroup, index) in petGroups",
|
||||
v-if="viewOptions[petGroup.key].selected",
|
||||
:key="petGroup.key"
|
||||
)
|
||||
h4(v-if="viewOptions[petGroup.key].animalCount !== 0") {{ petGroup.label }}
|
||||
|
||||
.pet-row.d-flex(
|
||||
v-for="(group, key, index) in pets(petGroup, hideMissing, selectedSortBy, searchTextThrottled)",
|
||||
v-if='index === 0 || $_openedItemRows_isToggled(petGroup.key)')
|
||||
.pet-group(
|
||||
v-for='item in group'
|
||||
v-drag.drop.food="item.key",
|
||||
@itemDragOver="onDragOver($event, item)",
|
||||
@itemDropped="onDrop($event, item)",
|
||||
@itemDragLeave="onDragLeave()",
|
||||
:class="{'last': item.isLastInRow}"
|
||||
)
|
||||
petItem(
|
||||
:item="item",
|
||||
:itemContentClass="getPetItemClass(item)",
|
||||
:popoverPosition="'top'",
|
||||
:progress="item.progress",
|
||||
:emptyItem="!item.isOwned()",
|
||||
:showPopover="currentDraggingFood == null",
|
||||
:highlightBorder="highlightPet == item.key",
|
||||
@click="petClicked(item)"
|
||||
)
|
||||
span(slot="popoverContent")
|
||||
div.hatchablePopover(v-if="item.isHatchable()")
|
||||
h4.popover-content-title {{ item.name }}
|
||||
div.popover-content-text(v-html="$t('haveHatchablePet', { potion: item.potionName, egg: item.eggName })")
|
||||
div.potionEggGroup
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_HatchingPotion_'+item.potionKey")
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_Egg_'+item.eggKey")
|
||||
div(v-else)
|
||||
h4.popover-content-title {{ item.name }}
|
||||
template(slot="itemBadge", slot-scope="context")
|
||||
starBadge(:selected="item.key === currentPet", :show="item.isOwned()", @click="selectPet(item)")
|
||||
|
||||
.btn.btn-flat.btn-show-more(@click="setShowMore(petGroup.key)", v-if='petGroup.key !== "specialPets"')
|
||||
| {{ $_openedItemRows_isToggled(petGroup.key) ? $t('showLess') : $t('showMore') }}
|
||||
|
||||
h2
|
||||
| {{ $t('mounts') }}
|
||||
|
|
||||
span.badge.badge-pill.badge-default {{countOwnedAnimals(mountGroups[0], 'mount')}}
|
||||
|
||||
div(
|
||||
v-for="mountGroup in mountGroups",
|
||||
v-if="viewOptions[mountGroup.key].selected",
|
||||
:key="mountGroup.key"
|
||||
)
|
||||
h4(v-if="viewOptions[mountGroup.key].animalCount != 0") {{ mountGroup.label }}
|
||||
|
||||
.pet-row.d-flex(v-for="(group, key, index) in mounts(mountGroup, hideMissing, selectedSortBy, searchTextThrottled)"
|
||||
v-if='index === 0 || $_openedItemRows_isToggled(mountGroup.key)')
|
||||
.pet-group(v-for='item in group')
|
||||
mountItem(
|
||||
:item="item",
|
||||
:itemContentClass="item.isOwned() ? ('Mount_Icon_' + item.key) : 'PixelPaw GreyedOut'",
|
||||
:key="item.key",
|
||||
:popoverPosition="'top'",
|
||||
:emptyItem="!item.isOwned()",
|
||||
:showPopover="true",
|
||||
@click="selectMount(item)"
|
||||
)
|
||||
span(slot="popoverContent")
|
||||
h4.popover-content-title {{ item.name }}
|
||||
template(slot="itemBadge", slot-scope="context")
|
||||
starBadge(
|
||||
:selected="item.key === currentMount",
|
||||
:show="item.isOwned()",
|
||||
@click="selectMount(item)",
|
||||
)
|
||||
|
||||
.btn.btn-flat.btn-show-more(@click="setShowMore(mountGroup.key)", v-if='mountGroup.key !== "specialMounts"')
|
||||
| {{ $_openedItemRows_isToggled(mountGroup.key) ? $t('showLess') : $t('showMore') }}
|
||||
|
||||
drawer(
|
||||
:title="$t('quickInventory')",
|
||||
:errorMessage="(!hasDrawerTabItems(selectedDrawerTab)) ? ((selectedDrawerTab === 0) ? $t('noFoodAvailable') : $t('noSaddlesAvailable')) : null"
|
||||
)
|
||||
div(slot="drawer-header")
|
||||
.drawer-tab-container
|
||||
.drawer-tab.text-right
|
||||
a.drawer-tab-text(
|
||||
@click="selectedDrawerTab = 0",
|
||||
:class="{'drawer-tab-text-active': selectedDrawerTab === 0}",
|
||||
) {{ drawerTabs[0].label }}
|
||||
.clearfix
|
||||
.drawer-tab.float-left
|
||||
a.drawer-tab-text(
|
||||
@click="selectedDrawerTab = 1",
|
||||
:class="{ 'drawer-tab-text-active': selectedDrawerTab === 1 }",
|
||||
) {{ drawerTabs[1].label }}
|
||||
|
||||
#petLikeToEatStable.drawer-help-text(v-once)
|
||||
| {{ $t('petLikeToEat') + ' ' }}
|
||||
span.svg-icon.inline.icon-16(v-html="icons.information")
|
||||
b-popover(
|
||||
target="petLikeToEatStable"
|
||||
placement="top"
|
||||
)
|
||||
.popover-content-text(v-html="$t('petLikeToEatText')", v-once)
|
||||
drawer-slider(
|
||||
:items="drawerTabs[selectedDrawerTab].items",
|
||||
:scrollButtonsVisible="hasDrawerTabItems(selectedDrawerTab)",
|
||||
slot="drawer-slider",
|
||||
:itemWidth=94,
|
||||
:itemMargin=24,
|
||||
:itemType="selectedDrawerTab"
|
||||
.form-check(
|
||||
v-for="petGroup in petGroups",
|
||||
:key="petGroup.key"
|
||||
)
|
||||
template(slot="item", slot-scope="context")
|
||||
foodItem(
|
||||
:item="context.item",
|
||||
:itemCount="userItems.food[context.item.key]",
|
||||
:active="currentDraggingFood == context.item",
|
||||
@itemDragEnd="onDragEnd()",
|
||||
@itemDragStart="onDragStart($event, context.item)",
|
||||
@itemClick="onFoodClicked($event, context.item)"
|
||||
.custom-control.custom-checkbox
|
||||
input.custom-control-input(
|
||||
type="checkbox",
|
||||
v-model="viewOptions[petGroup.key].selected",
|
||||
:disabled="viewOptions[petGroup.key].animalCount == 0",
|
||||
:id="petGroup.key",
|
||||
)
|
||||
b-modal#welcome-modal(
|
||||
:ok-only="true",
|
||||
:ok-title="$t('gotIt')",
|
||||
:visible="!hideDialog",
|
||||
:hide-header="true",
|
||||
@hide="hideFlag()"
|
||||
)
|
||||
div.content
|
||||
div.npc_matt
|
||||
h1.page-header(v-once) {{ $t('welcomeStable') }}
|
||||
div.content-text(v-once) {{ $t('welcomeStableText') }}
|
||||
b-modal#hatching-modal(
|
||||
@change="resetHatchablePet($event)"
|
||||
)
|
||||
div.content(v-if="hatchablePet")
|
||||
div.potionEggGroup
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_HatchingPotion_'+hatchablePet.potionKey")
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_Egg_'+hatchablePet.eggKey")
|
||||
h4.title {{ hatchablePet.name }}
|
||||
div.text(v-html="$t('hatchDialogText', { potionName: hatchablePet.potionName, eggName: hatchablePet.eggName, petName: hatchablePet.name })")
|
||||
label.custom-control-label(v-once, :for="petGroup.key") {{ petGroup.label }}
|
||||
h3(v-once) {{ $t('mounts') }}
|
||||
.form-group
|
||||
.form-check(
|
||||
v-for="mountGroup in mountGroups",
|
||||
:key="mountGroup.key"
|
||||
)
|
||||
.custom-control.custom-checkbox
|
||||
input.custom-control-input(
|
||||
type="checkbox",
|
||||
v-model="viewOptions[mountGroup.key].selected",
|
||||
:disabled="viewOptions[mountGroup.key].animalCount == 0",
|
||||
:id="mountGroup.key",
|
||||
)
|
||||
label.custom-control-label(v-once, :for="mountGroup.key") {{ mountGroup.label }}
|
||||
|
||||
span.svg-icon.icon-10(v-html="icons.close", slot="modal-header", @click="closeHatchPetDialog()")
|
||||
div.form-group.clearfix
|
||||
h3.float-left {{ $t('hideMissing') }}
|
||||
toggle-switch.float-right(
|
||||
:checked="hideMissing",
|
||||
@change="updateHideMissing"
|
||||
)
|
||||
.standard-page
|
||||
.clearfix
|
||||
h1.float-left.mb-4.page-header(v-once) {{ $t('stable') }}
|
||||
|
||||
div(slot="modal-footer")
|
||||
button.btn.btn-primary(@click="hatchPet(hatchablePet)") {{ $t('hatch') }}
|
||||
button.btn.btn-secondary.btn-flat(@click="closeHatchPetDialog()") {{ $t('cancel') }}
|
||||
div.float-right
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t(selectedSortBy)", right=true)
|
||||
b-dropdown-item(
|
||||
v-for="sort in sortByItems",
|
||||
@click="selectedSortBy = sort",
|
||||
:active="selectedSortBy === sort",
|
||||
:key="sort"
|
||||
) {{ $t(sort) }}
|
||||
|
||||
hatchedPetDialog(
|
||||
:hideText="true",
|
||||
)
|
||||
h2.mb-3
|
||||
| {{ $t('pets') }}
|
||||
|
|
||||
span.badge.badge-pill.badge-default {{countOwnedAnimals(petGroups[0], 'pet')}}
|
||||
|
||||
div.foodInfo(ref="dragginFoodInfo")
|
||||
div(v-if="currentDraggingFood != null")
|
||||
div.food-icon(:class="'Pet_Food_'+currentDraggingFood.key")
|
||||
div.popover
|
||||
div.popover-content {{ $t('dragThisFood', {foodName: currentDraggingFood.text() }) }}
|
||||
div(v-for="(petGroup, index) in petGroups",
|
||||
v-if="viewOptions[petGroup.key].selected",
|
||||
:key="petGroup.key")
|
||||
h4(v-if="viewOptions[petGroup.key].animalCount !== 0") {{ petGroup.label }}
|
||||
|
||||
div.foodInfo.mouse(ref="clickFoodInfo", v-if="foodClickMode")
|
||||
div(v-if="currentDraggingFood != null")
|
||||
div.food-icon(:class="'Pet_Food_'+currentDraggingFood.key")
|
||||
div.popover
|
||||
div.popover-content {{ $t('clickOnPetToFeed', {foodName: currentDraggingFood.text() }) }}
|
||||
mount-raised-modal
|
||||
.pet-row.d-flex(
|
||||
v-for="(group, key, index) in pets(petGroup, hideMissing, selectedSortBy, searchTextThrottled)",
|
||||
v-if='index === 0 || $_openedItemRows_isToggled(petGroup.key)')
|
||||
.pet-group(
|
||||
v-for='item in group'
|
||||
v-drag.drop.food="item.key",
|
||||
@itemDragOver="onDragOver($event, item)",
|
||||
@itemDropped="onDrop($event, item)",
|
||||
@itemDragLeave="onDragLeave()",
|
||||
:class="{'last': item.isLastInRow}"
|
||||
)
|
||||
petItem(
|
||||
:item="item",
|
||||
:itemContentClass="getPetItemClass(item)",
|
||||
:popoverPosition="'top'",
|
||||
:progress="item.progress",
|
||||
:emptyItem="!item.isOwned()",
|
||||
:showPopover="currentDraggingFood == null",
|
||||
:highlightBorder="highlightPet == item.key",
|
||||
@click="petClicked(item)"
|
||||
)
|
||||
span(slot="popoverContent")
|
||||
div.hatchablePopover(v-if="item.isHatchable()")
|
||||
h4.popover-content-title {{ item.name }}
|
||||
div.popover-content-text(v-html="$t('haveHatchablePet', { potion: item.potionName, egg: item.eggName })")
|
||||
div.potionEggGroup
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_HatchingPotion_'+item.potionKey")
|
||||
div.potionEggBackground
|
||||
div(:class="'Pet_Egg_'+item.eggKey")
|
||||
div(v-else)
|
||||
h4.popover-content-title {{ item.name }}
|
||||
template(slot="itemBadge", slot-scope="context")
|
||||
starBadge(:selected="item.key === currentPet", :show="item.isOwned()", @click="selectPet(item)")
|
||||
|
||||
.btn.btn-flat.btn-show-more(@click="setShowMore(petGroup.key)", v-if='petGroup.key !== "specialPets"')
|
||||
| {{ $_openedItemRows_isToggled(petGroup.key) ? $t('showLess') : $t('showMore') }}
|
||||
|
||||
h2
|
||||
| {{ $t('mounts') }}
|
||||
|
|
||||
span.badge.badge-pill.badge-default {{countOwnedAnimals(mountGroups[0], 'mount')}}
|
||||
|
||||
div(v-for="mountGroup in mountGroups",
|
||||
v-if="viewOptions[mountGroup.key].selected",
|
||||
:key="mountGroup.key")
|
||||
h4(v-if="viewOptions[mountGroup.key].animalCount != 0") {{ mountGroup.label }}
|
||||
|
||||
.pet-row.d-flex(v-for="(group, key, index) in mounts(mountGroup, hideMissing, selectedSortBy, searchTextThrottled)"
|
||||
v-if='index === 0 || $_openedItemRows_isToggled(mountGroup.key)')
|
||||
.pet-group(v-for='item in group')
|
||||
mountItem(
|
||||
:item="item",
|
||||
:itemContentClass="item.isOwned() ? ('Mount_Icon_' + item.key) : 'PixelPaw GreyedOut'",
|
||||
:key="item.key",
|
||||
:popoverPosition="'top'",
|
||||
:emptyItem="!item.isOwned()",
|
||||
:showPopover="true",
|
||||
@click="selectMount(item)"
|
||||
)
|
||||
span(slot="popoverContent")
|
||||
h4.popover-content-title {{ item.name }}
|
||||
template(slot="itemBadge", slot-scope="context")
|
||||
starBadge(
|
||||
:selected="item.key === currentMount",
|
||||
:show="item.isOwned()",
|
||||
@click="selectMount(item)",
|
||||
)
|
||||
|
||||
.btn.btn-flat.btn-show-more(@click="setShowMore(mountGroup.key)", v-if='mountGroup.key !== "specialMounts"')
|
||||
| {{ $_openedItemRows_isToggled(mountGroup.key) ? $t('showLess') : $t('showMore') }}
|
||||
|
||||
drawer(:title="$t('quickInventory')",
|
||||
:errorMessage="(!hasDrawerTabItems(selectedDrawerTab)) ? ((selectedDrawerTab === 0) ? $t('noFoodAvailable') : $t('noSaddlesAvailable')) : null")
|
||||
div(slot="drawer-header")
|
||||
.drawer-tab-container
|
||||
.drawer-tab.text-right
|
||||
a.drawer-tab-text(
|
||||
@click="selectedDrawerTab = 0",
|
||||
:class="{'drawer-tab-text-active': selectedDrawerTab === 0}",
|
||||
) {{ drawerTabs[0].label }}
|
||||
.clearfix
|
||||
.drawer-tab.float-left
|
||||
a.drawer-tab-text(
|
||||
@click="selectedDrawerTab = 1",
|
||||
:class="{ 'drawer-tab-text-active': selectedDrawerTab === 1 }",
|
||||
) {{ drawerTabs[1].label }}
|
||||
|
||||
#petLikeToEatStable.drawer-help-text(v-once)
|
||||
| {{ $t('petLikeToEat') + ' ' }}
|
||||
span.svg-icon.inline.icon-16(v-html="icons.information")
|
||||
b-popover(
|
||||
target="petLikeToEatStable"
|
||||
placement="top"
|
||||
)
|
||||
.popover-content-text(v-html="$t('petLikeToEatText')", v-once)
|
||||
drawer-slider(
|
||||
:items="drawerTabs[selectedDrawerTab].items",
|
||||
:scrollButtonsVisible="hasDrawerTabItems(selectedDrawerTab)",
|
||||
slot="drawer-slider",
|
||||
:itemWidth=94,
|
||||
:itemMargin=24,
|
||||
:itemType="selectedDrawerTab"
|
||||
)
|
||||
template(slot="item", slot-scope="context")
|
||||
foodItem(
|
||||
:item="context.item",
|
||||
:itemCount="userItems.food[context.item.key]",
|
||||
:active="currentDraggingFood == context.item",
|
||||
@itemDragEnd="onDragEnd()",
|
||||
@itemDragStart="onDragStart($event, context.item)",
|
||||
@itemClick="onFoodClicked($event, context.item)"
|
||||
)
|
||||
hatchedPetDialog(:hideText="true")
|
||||
div.foodInfo(ref="dragginFoodInfo")
|
||||
div(v-if="currentDraggingFood != null")
|
||||
div.food-icon(:class="'Pet_Food_'+currentDraggingFood.key")
|
||||
div.popover
|
||||
div.popover-content {{ $t('dragThisFood', {foodName: currentDraggingFood.text() }) }}
|
||||
div.foodInfo.mouse(ref="clickFoodInfo", v-if="foodClickMode")
|
||||
div(v-if="currentDraggingFood != null")
|
||||
div.food-icon(:class="'Pet_Food_'+currentDraggingFood.key")
|
||||
div.popover
|
||||
div.popover-content {{ $t('clickOnPetToFeed', {foodName: currentDraggingFood.text() }) }}
|
||||
mount-raised-modal
|
||||
welcome-modal
|
||||
hatching-modal(:hatchablePet.sync='hatchablePet')
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@@ -328,79 +288,6 @@
|
||||
height: 114px;
|
||||
}
|
||||
|
||||
#welcome-modal {
|
||||
@include centeredModal();
|
||||
|
||||
.npc_matt {
|
||||
margin: 0 auto 21px auto;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
|
||||
// the modal already has 15px padding
|
||||
margin-left: 33px;
|
||||
margin-right: 33px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: 1.43;
|
||||
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
#hatching-modal {
|
||||
@include centeredModal();
|
||||
|
||||
.modal-dialog {
|
||||
width: 310px;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
margin: 9px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 24px;
|
||||
font-family: Roboto;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
font-stretch: condensed;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
color: #4e4a57;
|
||||
}
|
||||
|
||||
.text {
|
||||
height: 60px;
|
||||
font-family: Roboto;
|
||||
font-size: 14px;
|
||||
line-height: 1.43;
|
||||
text-align: center;
|
||||
color: #686274;
|
||||
}
|
||||
|
||||
span.svg-icon.icon-10 {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-backdrop.fade.show {
|
||||
background-color: $purple-50;
|
||||
opacity: 0.9;
|
||||
@@ -476,7 +363,7 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'client/libs/store';
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
import _each from 'lodash/each';
|
||||
import _sortBy from 'lodash/sortBy';
|
||||
@@ -492,6 +379,8 @@
|
||||
import FoodItem from './foodItem';
|
||||
import HatchedPetDialog from './hatchedPetDialog';
|
||||
import MountRaisedModal from './mountRaisedModal';
|
||||
import WelcomeModal from './welcomeModal';
|
||||
import HatchingModal from './hatchingModal';
|
||||
import Drawer from 'client/components/ui/drawer';
|
||||
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
||||
import StarBadge from 'client/components/ui/starBadge';
|
||||
@@ -505,10 +394,10 @@
|
||||
import createAnimal from 'client/libs/createAnimal';
|
||||
|
||||
import svgInformation from 'assets/svg/information.svg';
|
||||
import svgClose from 'assets/svg/close.svg';
|
||||
|
||||
import notifications from 'client/mixins/notifications';
|
||||
import openedItemRowsMixin from 'client/mixins/openedItemRows';
|
||||
import petMixin from 'client/mixins/petMixin';
|
||||
|
||||
// TODO Normalize special pets and mounts
|
||||
// import Store from 'client/store';
|
||||
@@ -518,7 +407,7 @@
|
||||
let lastMouseMoveEvent = {};
|
||||
|
||||
export default {
|
||||
mixins: [notifications, openedItemRowsMixin],
|
||||
mixins: [notifications, openedItemRowsMixin, petMixin],
|
||||
components: {
|
||||
PetItem,
|
||||
Item,
|
||||
@@ -532,6 +421,8 @@
|
||||
DrawerSlider,
|
||||
HatchedPetDialog,
|
||||
MountRaisedModal,
|
||||
WelcomeModal,
|
||||
HatchingModal,
|
||||
},
|
||||
directives: {
|
||||
resize: ResizeDirective,
|
||||
@@ -554,7 +445,6 @@
|
||||
],
|
||||
icons: Object.freeze({
|
||||
information: svgInformation,
|
||||
close: svgClose,
|
||||
}),
|
||||
|
||||
highlightPet: '',
|
||||
@@ -578,7 +468,6 @@
|
||||
currentPet: 'user.data.items.currentPet',
|
||||
currentMount: 'user.data.items.currentMount',
|
||||
userItems: 'user.data.items',
|
||||
hideDialog: 'user.data.flags.tutorial.common.mounts',
|
||||
user: 'user.data',
|
||||
}),
|
||||
petGroups () {
|
||||
@@ -871,12 +760,6 @@
|
||||
selectMount (item) {
|
||||
this.$store.dispatch('common:equip', {key: item.key, type: 'mount'});
|
||||
},
|
||||
hatchPet (pet) {
|
||||
this.closeHatchPetDialog();
|
||||
|
||||
this.$store.dispatch('common:hatch', {egg: pet.eggKey, hatchingPotion: pet.potionKey});
|
||||
this.text(this.$t('hatchedPet', {egg: pet.eggName, potion: pet.potionName}));
|
||||
},
|
||||
onDragStart (ev, food) {
|
||||
this.currentDraggingFood = food;
|
||||
|
||||
@@ -952,14 +835,6 @@
|
||||
});
|
||||
}
|
||||
},
|
||||
closeHatchPetDialog () {
|
||||
this.$root.$emit('bv::hide::modal', 'hatching-modal');
|
||||
},
|
||||
resetHatchablePet ($event) {
|
||||
if (!$event) {
|
||||
this.hatchablePet = null;
|
||||
}
|
||||
},
|
||||
onFoodClicked ($event, food) {
|
||||
if (this.currentDraggingFood === null || this.currentDraggingFood !== food) {
|
||||
this.currentDraggingFood = food;
|
||||
@@ -981,11 +856,6 @@
|
||||
lastMouseMoveEvent = $event;
|
||||
}
|
||||
},
|
||||
hideFlag () {
|
||||
this.$store.dispatch('user:set', {
|
||||
'flags.tutorial.common.mounts': true,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<template lang="pug">
|
||||
b-modal#welcome-modal(:ok-only="true",
|
||||
:ok-title="$t('gotIt')",
|
||||
:visible="!hideDialog",
|
||||
:hide-header="true",
|
||||
@hide="hideFlag()")
|
||||
div.content
|
||||
div.npc_matt
|
||||
h1.page-header(v-once) {{ $t('welcomeStable') }}
|
||||
div.content-text(v-once) {{ $t('welcomeStableText') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/modal.scss';
|
||||
|
||||
#welcome-modal {
|
||||
@include centeredModal();
|
||||
|
||||
.npc_matt {
|
||||
margin: 0 auto 21px auto;
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
|
||||
// the modal already has 15px padding
|
||||
margin-left: 33px;
|
||||
margin-right: 33px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: 1.43;
|
||||
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
hideDialog: 'user.data.flags.tutorial.common.mounts',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
hideFlag () {
|
||||
this.$store.dispatch('user:set', {
|
||||
'flags.tutorial.common.mounts': true,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -89,6 +89,7 @@ import moment from 'moment';
|
||||
import throttle from 'lodash/throttle';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
import { toNextLevel } from '../../common/script/statHelpers';
|
||||
import { shouldDo } from '../../common/script/cron';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import notifications from 'client/mixins/notifications';
|
||||
@@ -255,7 +256,12 @@ export default {
|
||||
userExp (after, before) {
|
||||
if (after === before) return;
|
||||
if (this.user.stats.lvl === 0) return;
|
||||
this.exp(after - before);
|
||||
|
||||
let exp = after - before;
|
||||
if (exp < -50) { // recalculate exp if user level up
|
||||
exp = toNextLevel(this.user.stats.lvl - 1) - before + after;
|
||||
}
|
||||
this.exp(exp);
|
||||
},
|
||||
userGp (after, before) {
|
||||
if (after === before) return;
|
||||
@@ -525,7 +531,7 @@ export default {
|
||||
this.$root.$emit('bv::show::modal', 'won-challenge');
|
||||
break;
|
||||
case 'STREAK_ACHIEVEMENT':
|
||||
this.text(this.user.achievements.streak, () => {
|
||||
this.text(`${this.$t('streaks')}: ${this.user.achievements.streak}`, () => {
|
||||
if (!this.user.preferences.suppressModals.streak) {
|
||||
this.$root.$emit('bv::show::modal', 'streak');
|
||||
}
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
|
||||
<style scoped>
|
||||
#AmazonPayButton {
|
||||
margin: 0 auto;
|
||||
width: 150px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
#AmazonPayButton, #AmazonPayWallet, #AmazonPayRecurring {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#AmazonPayRecurring {
|
||||
|
||||
@@ -83,6 +83,7 @@ export default {
|
||||
removeTask () {
|
||||
if (!confirm('Are you sure you want to delete this task?')) return;
|
||||
this.destroyTask(this.brokenChallengeTask);
|
||||
this.close();
|
||||
},
|
||||
close () {
|
||||
this.$store.state.brokenChallengeTask = {};
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
draggable.sortable-tasks(
|
||||
ref="tasksList",
|
||||
@update='taskSorted',
|
||||
:options='{disabled: activeFilter.label === "scheduled"}',
|
||||
:options='{disabled: activeFilter.label === "scheduled", scrollSensitivity: 64}',
|
||||
class="sortable-tasks"
|
||||
)
|
||||
task(
|
||||
@@ -362,7 +362,7 @@ export default {
|
||||
type: this.type,
|
||||
filterType: this.activeFilter.label,
|
||||
}) :
|
||||
this.filterByCompleted(this.taskListOverride, this.activeFilter.label);
|
||||
this.filterByLabel(this.taskListOverride, this.activeFilter.label);
|
||||
|
||||
let taggedList = this.filterByTagList(filteredTaskList, this.selectedTags);
|
||||
let searchedList = this.filterBySearchText(taggedList, this.searchText);
|
||||
@@ -598,10 +598,12 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
filterByCompleted (taskList, filter) {
|
||||
filterByLabel (taskList, filter) {
|
||||
if (!taskList) return [];
|
||||
return taskList.filter(task => {
|
||||
if (filter === 'complete2') return task.completed;
|
||||
if (filter === 'due') return task.isDue;
|
||||
if (filter === 'notDue') return !task.isDue;
|
||||
return !task.completed;
|
||||
});
|
||||
},
|
||||
|
||||
@@ -9,36 +9,50 @@ div(v-if='user.stats.lvl > 10')
|
||||
.col-4.mana
|
||||
.img(:class='`shop_${spell.key} shop-sprite item-img`')
|
||||
|
||||
drawer(
|
||||
:title="$t('skillsTitle')",
|
||||
v-if='user.stats.class && !user.preferences.disableClasses',
|
||||
v-mousePosition="30",
|
||||
@mouseMoved="mouseMoved($event)",
|
||||
:openStatus='openStatus',
|
||||
@toggled='drawerToggled'
|
||||
)
|
||||
div(slot="drawer-slider")
|
||||
.container.spell-container
|
||||
.row
|
||||
.col-3(
|
||||
@click='castStart(skill)',
|
||||
v-for='(skill, key) in spells[user.stats.class]',
|
||||
v-if='user.stats.lvl >= skill.lvl',
|
||||
v-b-popover.hover.auto='skill.notes()')
|
||||
.spell.col-12.row
|
||||
.col-8.details
|
||||
a(:class='{"disabled": spellDisabled(key)}')
|
||||
div.img(:class='`shop_${skill.key} shop-sprite item-img`')
|
||||
span.title {{skill.text()}}
|
||||
.col-4.mana
|
||||
.mana-text
|
||||
.svg-icon(v-html="icons.mana")
|
||||
div {{skill.mana}}
|
||||
.drawer-wrapper.d-flex.justify-content-center
|
||||
drawer(
|
||||
:title="$t('skillsTitle')",
|
||||
v-if='user.stats.class && !user.preferences.disableClasses',
|
||||
v-mousePosition="30",
|
||||
@mouseMoved="mouseMoved($event)",
|
||||
:openStatus='openStatus',
|
||||
@toggled='drawerToggled'
|
||||
)
|
||||
div(slot="drawer-slider")
|
||||
.container.spell-container
|
||||
.row
|
||||
.col-12.col-md-3(
|
||||
@click='castStart(skill)',
|
||||
v-for='(skill, key) in spells[user.stats.class]',
|
||||
v-if='user.stats.lvl >= skill.lvl',
|
||||
v-b-popover.hover.auto='skill.notes()')
|
||||
.spell.col-12.row
|
||||
.col-8.details
|
||||
a(:class='{"disabled": spellDisabled(key)}')
|
||||
div.img(:class='`shop_${skill.key} shop-sprite item-img`')
|
||||
span.title {{skill.text()}}
|
||||
.col-4.mana
|
||||
.mana-text
|
||||
.svg-icon(v-html="icons.mana")
|
||||
div {{skill.mana}}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.drawer-wrapper {
|
||||
width: 100vw;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 19;
|
||||
|
||||
.drawer-container {
|
||||
left: auto !important;
|
||||
right: auto !important;
|
||||
min-width: 60%;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-container {
|
||||
left: calc((100% - 978px) / 2);
|
||||
}
|
||||
|
||||
.drawer-slider {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template lang="pug">
|
||||
form(v-if="task", @submit.stop.prevent="submit()")
|
||||
b-modal#task-modal(size="sm", @hidden="onClose()", @show="handleOpen()", @shown="focusInput()")
|
||||
.task-modal-header(slot="modal-header", :class="cssClass('bg')")
|
||||
form(v-if="task", @submit.stop.prevent="submit()", @click="handleClick($event)")
|
||||
b-modal#task-modal(v-bind:no-close-on-esc="showTagsSelect", v-bind:no-close-on-backdrop="showTagsSelect", size="sm", @hidden="onClose()", @show="handleOpen()", @shown="focusInput()")
|
||||
.task-modal-header(slot="modal-header", :class="cssClass('bg')", @click="handleClick($event)")
|
||||
.clearfix
|
||||
h1.float-left {{ title }}
|
||||
.float-right.d-flex.align-items-center
|
||||
@@ -23,7 +23,7 @@
|
||||
a(target="_blank", href="http://habitica.wikia.com/wiki/Markdown_Cheat_Sheet") {{ $t('markdownHelpLink') }}
|
||||
|
||||
textarea.form-control(v-model="task.notes", rows="3")
|
||||
.task-modal-content
|
||||
.task-modal-content(@click="handleClick($event)")
|
||||
.option.mt-0(v-if="task.type === 'reward'")
|
||||
.form-group
|
||||
label(v-once) {{ $t('cost') }}
|
||||
@@ -147,7 +147,7 @@
|
||||
.category-label(v-for='tagName in truncatedSelectedTags', :title="tagName", v-markdown='tagName')
|
||||
.tags-more(v-if='remainingSelectedTags.length > 0') +{{ $t('more', { count: remainingSelectedTags.length }) }}
|
||||
.dropdown-toggle
|
||||
tags-popup(v-if="showTagsSelect", :tags="user.tags", v-model="task.tags", @close='closeTagsPopup()')
|
||||
tags-popup(ref="popup", v-if="showTagsSelect", :tags="user.tags", v-model="task.tags", @close='closeTagsPopup()')
|
||||
|
||||
.option(v-if="task.type === 'habit'")
|
||||
.form-group
|
||||
@@ -242,7 +242,7 @@
|
||||
.svg-icon.d-inline-b(v-html="icons.destroy")
|
||||
span {{ $t('deleteTask') }}
|
||||
|
||||
.task-modal-footer.d-flex.justify-content-center.align-items-center(slot="modal-footer")
|
||||
.task-modal-footer.d-flex.justify-content-center.align-items-center(slot="modal-footer", @click="handleClick($event)")
|
||||
.cancel-task-btn(v-once, @click="cancel()") {{ $t('cancel') }}
|
||||
button.btn.btn-primary(type="submit", v-once) {{ $t('save') }}
|
||||
</template>
|
||||
@@ -714,6 +714,9 @@ export default {
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.showAdvancedOptions = !this.user.preferences.advancedCollapsed;
|
||||
},
|
||||
watch: {
|
||||
task () {
|
||||
this.syncTask();
|
||||
@@ -803,6 +806,12 @@ export default {
|
||||
return this.selectedTags.slice(this.maxTags);
|
||||
},
|
||||
},
|
||||
created () {
|
||||
document.addEventListener('keyup', this.handleEsc);
|
||||
},
|
||||
destroyed () {
|
||||
document.removeEventListener('keyup', this.handleEsc);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({saveTask: 'tasks:save', destroyTask: 'tasks:destroy', createTask: 'tasks:create'}),
|
||||
async syncTask () {
|
||||
@@ -914,17 +923,18 @@ export default {
|
||||
|
||||
if (this.purpose === 'create') {
|
||||
if (this.challengeId) {
|
||||
this.$store.dispatch('tasks:createChallengeTasks', {
|
||||
const response = await this.$store.dispatch('tasks:createChallengeTasks', {
|
||||
challengeId: this.challengeId,
|
||||
tasks: [this.task],
|
||||
});
|
||||
Object.assign(this.task, response);
|
||||
this.$emit('taskCreated', this.task);
|
||||
} else if (this.groupId) {
|
||||
await this.$store.dispatch('tasks:createGroupTasks', {
|
||||
const response = await this.$store.dispatch('tasks:createGroupTasks', {
|
||||
groupId: this.groupId,
|
||||
tasks: [this.task],
|
||||
});
|
||||
|
||||
Object.assign(this.task, response);
|
||||
let promises = this.assignedMembers.map(memberId => {
|
||||
return this.$store.dispatch('tasks:assignTask', {
|
||||
taskId: this.task._id,
|
||||
@@ -988,6 +998,16 @@ export default {
|
||||
focusInput () {
|
||||
this.$refs.inputToFocus.focus();
|
||||
},
|
||||
handleEsc (e) {
|
||||
if (e.keyCode === 27 && this.showTagsSelect) {
|
||||
this.closeTagsPopup();
|
||||
}
|
||||
},
|
||||
handleClick (e) {
|
||||
if (this.$refs.popup && !this.$refs.popup.$el.contains(e.target)) {
|
||||
this.closeTagsPopup();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -52,8 +52,14 @@
|
||||
// @TODO: Implement new message header here when we fix the above
|
||||
|
||||
.new-message-row(v-if='selectedConversation.key && !user.flags.chatRevoked')
|
||||
textarea(v-model='newMessage', @keyup.ctrl.enter='sendPrivateMessage()')
|
||||
button.btn.btn-secondary(@click='sendPrivateMessage()') Send
|
||||
textarea(
|
||||
v-model='newMessage',
|
||||
@keyup.ctrl.enter='sendPrivateMessage()',
|
||||
maxlength='3000'
|
||||
)
|
||||
button.btn.btn-secondary(@click='sendPrivateMessage()') {{$t('send')}}
|
||||
.row
|
||||
span.ml-3 {{ currentLength }} / 3000
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -322,6 +328,9 @@ export default {
|
||||
return conversation.name.toLowerCase().indexOf(this.search.toLowerCase()) !== -1;
|
||||
});
|
||||
},
|
||||
currentLength () {
|
||||
return this.newMessage.length;
|
||||
},
|
||||
placeholderTexts () {
|
||||
if (this.user.flags.chatRevoked) {
|
||||
return {
|
||||
|
||||
@@ -47,6 +47,6 @@ export function round (number, nDigits) {
|
||||
}
|
||||
|
||||
export function getXPMessage (val) {
|
||||
if (val < -50) return; // don't show when they level up (resetting their exp)
|
||||
if (val < -50) return; // don't show when they multi-level up (resetting their exp)
|
||||
return `${getSign(val)} ${round(val)}`;
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import times from 'lodash/times';
|
||||
import Intro from 'intro.js/';
|
||||
import introjs from 'intro.js';
|
||||
import * as Analytics from 'client/libs/analytics';
|
||||
|
||||
let showingTour = false;
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
@@ -13,6 +15,8 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
$route () {
|
||||
if (showingTour) return;
|
||||
showingTour = true;
|
||||
this.routeChange();
|
||||
},
|
||||
},
|
||||
@@ -168,13 +172,15 @@ export default {
|
||||
});
|
||||
|
||||
// @TODO: Do we always need to initialize here?
|
||||
let intro = Intro.introJs();
|
||||
const intro = introjs();
|
||||
intro.setOptions({
|
||||
exitOnOverlayClick: false,
|
||||
steps: opts.steps,
|
||||
doneLabel: this.$t('letsgo'),
|
||||
});
|
||||
intro.start();
|
||||
intro.oncomplete(() => {
|
||||
showingTour = false;
|
||||
this.markTourComplete(chapter);
|
||||
});
|
||||
},
|
||||
@@ -187,19 +193,6 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
// if (true) { // -2 indicates complete
|
||||
// if (chapter === 'intro') {
|
||||
// // Manually show bunny scroll reward
|
||||
// // let rewardData = {
|
||||
// // reward: [Shared.content.quests.dustbunnies],
|
||||
// // rewardKey: ['inventory_quest_scroll_dustbunnies'],
|
||||
// // rewardText: Shared.content.quests.dustbunnies.text(),
|
||||
// // message: this.$t('checkinEarned'),
|
||||
// // nextRewardAt: 1,
|
||||
// // };
|
||||
// // @TODO: Notification.showLoginIncentive(this.user, rewardData, Social.loadWidgets);
|
||||
// }
|
||||
|
||||
// Mark tour complete
|
||||
ups[`flags.tour.${chapter}`] = -2; // @TODO: Move magic numbers to enum
|
||||
|
||||
@@ -211,7 +204,6 @@ export default {
|
||||
eventValue: lastKnownStep,
|
||||
complete: true,
|
||||
});
|
||||
// }
|
||||
|
||||
this.$store.dispatch('user:set', ups);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
export default {
|
||||
methods: {
|
||||
closeHatchPetDialog () {
|
||||
this.$root.$emit('bv::hide::modal', 'hatching-modal');
|
||||
},
|
||||
hatchPet (pet) {
|
||||
this.closeHatchPetDialog();
|
||||
|
||||
this.$store.dispatch('common:hatch', {egg: pet.eggKey, hatchingPotion: pet.potionKey});
|
||||
this.text(this.$t('hatchedPet', {egg: pet.eggName, potion: pet.potionName}));
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -85,7 +85,20 @@ export default {
|
||||
|
||||
// the selected member doesn't have the flags property which sets `cardReceived`
|
||||
if (spell.pinType !== 'card') {
|
||||
spell.cast(this.user, target);
|
||||
try {
|
||||
spell.cast(this.user, target);
|
||||
} catch (e) {
|
||||
if (!e.request) {
|
||||
this.$store.dispatch('snackbars:add', {
|
||||
title: '',
|
||||
text: e.message,
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let targetId = target ? target._id : null;
|
||||
|
||||
@@ -64,6 +64,12 @@ async function buyArmoire (store, params) {
|
||||
if (item.type === 'gear') {
|
||||
store.state.user.data.items.gear.owned[item.dropKey] = true;
|
||||
}
|
||||
|
||||
if (item.type === 'food') {
|
||||
if (!store.state.user.data.items.food[item.dropKey]) store.state.user.data.items.food[item.dropKey] = 0;
|
||||
store.state.user.data.items.food[item.dropKey] += 1;
|
||||
}
|
||||
|
||||
store.state.user.data.stats.gp -= armoire.value;
|
||||
|
||||
// @TODO: We might need to abstract notifications to library rather than mixin
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
module.exports = {
|
||||
invalidAttribute: '"<%= attr %>" is not a valid Stat.',
|
||||
|
||||
statsObjectRequired: '"stats" update is required',
|
||||
statsObjectRequired: '"stats" object is required',
|
||||
|
||||
missingTypeParam: '"req.params.type" is required.',
|
||||
missingKeyParam: '"req.params.key" is required.',
|
||||
|
||||