mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
180 lines
6.1 KiB
JavaScript
180 lines
6.1 KiB
JavaScript
import Vue from 'vue';
|
|
|
|
import notifications from './notifications';
|
|
import scoreTask from '@/../../common/script/ops/scoreTask';
|
|
import { mapState } from '@/libs/store';
|
|
import * as Analytics from '@/libs/analytics';
|
|
import { CONSTANTS, getLocalSetting, setLocalSetting } from '@/libs/userlocalManager';
|
|
|
|
export default {
|
|
mixins: [notifications],
|
|
computed: {
|
|
...mapState({
|
|
castingSpell: 'spellOptions.castingSpell',
|
|
user: 'user.data',
|
|
}),
|
|
},
|
|
methods: {
|
|
async beforeTaskScore (task) {
|
|
const { user } = this;
|
|
if (this.castingSpell) return false;
|
|
|
|
if (task.group.approval.required && !task.group.approval.approved) {
|
|
task.group.approval.requested = true;
|
|
const { data: groupPlans } = await this.$store.dispatch('guilds:getGroupPlans');
|
|
const groupPlan = groupPlans.find(g => g.id === task.group.id);
|
|
if (groupPlan) {
|
|
const managers = Object.keys(groupPlan.managers);
|
|
managers.push(groupPlan.leader);
|
|
if (managers.indexOf(user._id) !== -1) {
|
|
task.group.approval.approved = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
},
|
|
playTaskScoreSound (task, direction) {
|
|
switch (task.type) { // eslint-disable-line default-case
|
|
case 'habit':
|
|
this.$root.$emit('playSound', direction === 'up' ? 'Plus_Habit' : 'Minus_Habit');
|
|
break;
|
|
case 'todo':
|
|
this.$root.$emit('playSound', 'Todo');
|
|
break;
|
|
case 'daily':
|
|
this.$root.$emit('playSound', 'Daily');
|
|
break;
|
|
case 'reward':
|
|
this.$root.$emit('playSound', 'Reward');
|
|
break;
|
|
}
|
|
},
|
|
async taskScore (task, direction) {
|
|
const { user } = this;
|
|
|
|
const canScoreTask = await this.beforeTaskScore(task);
|
|
if (!canScoreTask) return;
|
|
|
|
try {
|
|
scoreTask({ task, user, direction });
|
|
} catch (err) {
|
|
this.text(err.message);
|
|
return;
|
|
}
|
|
|
|
this.playTaskScoreSound(task, direction);
|
|
|
|
const response = await this.$store.dispatch('tasks:score', {
|
|
taskId: task._id,
|
|
direction,
|
|
});
|
|
|
|
this.handleTaskScoreNotifications(response.data.data._tmp || {});
|
|
|
|
const tasksScoredCount = getLocalSetting(CONSTANTS.keyConstants.TASKS_SCORED_COUNT);
|
|
if (!tasksScoredCount || tasksScoredCount < 2) {
|
|
Analytics.track({
|
|
eventName: 'task scored',
|
|
eventAction: 'click',
|
|
eventCategory: 'behavior',
|
|
hitType: 'event',
|
|
uuid: user._id,
|
|
taskType: task.type,
|
|
direction,
|
|
}, { trackOnClient: true });
|
|
if (!tasksScoredCount) {
|
|
setLocalSetting(CONSTANTS.keyConstants.TASKS_SCORED_COUNT, 1);
|
|
} else {
|
|
setLocalSetting(CONSTANTS.keyConstants.TASKS_SCORED_COUNT, Number(tasksScoredCount) + 1);
|
|
}
|
|
}
|
|
},
|
|
async handleTaskScoreNotifications (tmpObject = {}) {
|
|
const { user } = this;
|
|
const Content = this.$store.state.content;
|
|
|
|
// _tmp is used to notify drops, critical hits and other bonuses
|
|
const {
|
|
crit,
|
|
drop,
|
|
firstDrops,
|
|
quest,
|
|
} = tmpObject;
|
|
|
|
if (crit) {
|
|
const critBonus = crit * 100 - 100;
|
|
this.crit(critBonus);
|
|
}
|
|
|
|
if (quest && user.party.quest && user.party.quest.key) {
|
|
const userQuest = Content.quests[user.party.quest.key];
|
|
if (quest.progressDelta && userQuest.boss) {
|
|
this.damage(quest.progressDelta.toFixed(1));
|
|
} else if (quest.collection && userQuest.collect) {
|
|
user.party.quest.progress.collectedItems += 1;
|
|
this.quest('questCollection', quest.collection);
|
|
}
|
|
}
|
|
|
|
if (firstDrops) {
|
|
if (!user.items.eggs[firstDrops.egg]) Vue.set(user.items.eggs, firstDrops.egg, 0);
|
|
if (!user.items.hatchingPotions[firstDrops.hatchingPotion]) {
|
|
Vue.set(user.items.hatchingPotions, firstDrops.hatchingPotion, 0);
|
|
}
|
|
user.items.eggs[firstDrops.egg] += 1;
|
|
user.items.hatchingPotions[firstDrops.hatchingPotion] += 1;
|
|
}
|
|
|
|
if (drop) {
|
|
let dropText;
|
|
let dropNotes;
|
|
let type;
|
|
|
|
this.$root.$emit('playSound', 'Item_Drop');
|
|
|
|
// Note: For Mystery Item gear, drop.type will be 'head', 'armor', etc
|
|
// so we use drop.notificationType below.
|
|
|
|
if (drop.type !== 'gear' && drop.type !== 'Quest' && drop.notificationType !== 'Mystery') {
|
|
if (drop.type === 'Food') {
|
|
type = 'food';
|
|
} else if (drop.type === 'HatchingPotion') {
|
|
type = 'hatchingPotions';
|
|
} else {
|
|
type = `${drop.type.toLowerCase()}s`;
|
|
}
|
|
|
|
if (!user.items[type][drop.key]) {
|
|
Vue.set(user.items[type], drop.key, 0);
|
|
}
|
|
user.items[type][drop.key] += 1;
|
|
}
|
|
|
|
if (drop.type === 'HatchingPotion') {
|
|
dropText = Content.hatchingPotions[drop.key].text();
|
|
dropNotes = Content.hatchingPotions[drop.key].notes();
|
|
this.drop(this.$t('messageDropPotion', { dropText, dropNotes }), drop);
|
|
} else if (drop.type === 'Egg') {
|
|
dropText = Content.eggs[drop.key].text();
|
|
dropNotes = Content.eggs[drop.key].notes();
|
|
this.drop(this.$t('messageDropEgg', { dropText, dropNotes }), drop);
|
|
} else if (drop.type === 'Food') {
|
|
dropText = Content.food[drop.key].textA();
|
|
dropNotes = Content.food[drop.key].notes();
|
|
this.drop(this.$t('messageDropFood', { dropText, dropNotes }), drop);
|
|
} else if (drop.type === 'Quest') {
|
|
// TODO $rootScope.selectedQuest = Content.quests[drop.key];
|
|
// $rootScope.openModal('questDrop', {controller:'PartyCtrl', size:'sm'});
|
|
// NOTE if a modal is shown again for quest drops
|
|
// this code will likely need changes, see the NOTE
|
|
// https://github.com/HabitRPG/habitica/blob/develop/website/client/src/components/notifications.vue#L640-L646
|
|
} else {
|
|
// Keep support for another type of drops that might be added
|
|
this.drop(drop.dialog);
|
|
}
|
|
}
|
|
},
|
|
},
|
|
};
|