Casting Chilling Frost and Stealth skill again will not be processed and return an error instead. Fixes #12361. (#12404)

* Added logic for a repeating Chilling Frost skill. Added test case for redundant chilling frost skill cast. Added comments for the logic of repeating Stealth skill because of an error.

* Added logic for a repeating Stealth skill. Avoiding MP reduction still pending because of console error. Test cases pending.

* Completed the logic for a repeated Stealth skill. Added repeated frost skill cast check in common. Removed exclusive test. Test cases are pending.

* Added test case for Stealth skill recast. Fixed lint errors. Fixed a flaw in if statement which led to test case failure.

* Fixed lint errors in test case.

* Added a common JSON entry for skil recasts in three files. Other files remaining. Added Chilling Frost recast check in common code. Modified test cases.

* Added spellDisabled condition in client code.

* Reverted JSON messages for three languages. Added spellAlreadyCast attribute to JSON file in locales/en. Made changes for showing appropriate message in client code.

* Added an import for throwing BadRequest in common code. Modified test case accordingly.

* Update website/common/script/content/spells.js

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>

* Added target and req attributes in cast() method arguments.

* Changed common code test case because of increased function parameters. Moved chilling frost test casse to common tests instead of server tests.

* Changed the test case format in common tests.

* Added a missing done statement.

* Fixed a minor error which led to failing test case. Removed the exclusive test which led to lint error.

* Fixed lint errors.

* Added a class named 'disabled' for the frontend change.

* fix(skills): style cleanup

* fix(skills): unfix

Co-authored-by: Matteo Pagliazzi <matteopagliazzi@gmail.com>
Co-authored-by: Sabe Jones <sabrecat@gmail.com>
This commit is contained in:
Jalansh 2020-08-09 21:55:59 +05:30 committed by GitHub
parent d7d7f82723
commit c0bf2cffea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 17 deletions

View file

@ -161,6 +161,23 @@ describe('POST /user/class/cast/:spellId', () => {
});
});
it('Issue #12361: returns an error if stealth has already been cast', async () => {
await user.update({
'stats.class': 'rogue',
'stats.lvl': 15,
'stats.mp': 400,
'stats.buffs.stealth': 1,
});
await user.sync();
await expect(user.post('/user/class/cast/stealth'))
.to.eventually.be.rejected.and.eql({
code: 400,
error: 'BadRequest',
message: t('spellAlreadyCast'),
});
expect(user.stats.mp).to.equal(400);
});
it('returns an error if targeted party member doesn\'t exist', async () => {
const { groupLeader } = await createAndPopulateGroup({
groupDetails: { type: 'party', privacy: 'private' },

View file

@ -4,6 +4,7 @@ import {
import spells from '../../../website/common/script/content/spells';
import {
NotAuthorized,
BadRequest,
} from '../../../website/common/script/libs/errors';
import i18n from '../../../website/common/script/i18n';
@ -25,7 +26,7 @@ describe('shared.ops.spells', () => {
const spell = spells.healer.heal;
try {
spell.cast(user);
spell.cast(user, null, { language: 'en' });
} catch (err) {
expect(err).to.be.an.instanceof(NotAuthorized);
expect(err.message).to.equal(i18n.t('messageHealthAlreadyMax'));
@ -35,4 +36,22 @@ describe('shared.ops.spells', () => {
done();
}
});
it('Issue #12361: returns an error if chilling frost has already been cast', done => {
user.stats.class = 'wizard';
user.stats.lvl = 15;
user.stats.mp = 400;
user.stats.buffs.streaks = true;
const spell = spells.wizard.frost;
try {
spell.cast(user, null, { language: 'en' });
} catch (err) {
expect(err).to.be.an.instanceof(BadRequest);
expect(err.message).to.equal(i18n.t('spellAlreadyCast'));
expect(user.stats.mp).to.eql(400);
done();
}
});
});

View file

@ -42,12 +42,14 @@
:key="key"
v-b-popover.hover.auto="skillNotes(skill)"
class="col-12 col-md-3"
@click="castStart(skill)"
@click="!spellDisabled(key) ? castStart(skill) : null"
>
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
<div class="spell col-12 row">
<div
class="spell col-12 row"
:class="{'disabled': spellDisabled(key)}"
>
<div class="col-8 details">
<a :class="{'disabled': spellDisabled(key)}"></a>
<div
class="img"
:class="`shop_${skill.key} shop-sprite item-img`"
@ -88,9 +90,6 @@
}
}
.drawer-container {
}
.drawer-slider {
margin-top: 1em;
}
@ -100,7 +99,7 @@
white-space: initial;
}
.spell:hover {
.spell:hover:not(.disabled) {
cursor: pointer;
border: solid 2px #50b5e9;
}
@ -116,6 +115,10 @@
padding-left: 0;
overflow: hidden;
&.disabled {
opacity: 0.5;
}
.details {
text-align: left;
padding-top: .5em;
@ -280,9 +283,9 @@ export default {
let notes = skill.notes();
if (skill.key === 'frost' && this.spellDisabled(skill.key)) {
notes = this.$t('spellWizardFrostAlreadyCast');
notes = this.$t('spellAlreadyCast');
} else if (skill.key === 'stealth' && this.spellDisabled(skill.key)) {
notes = this.$t('spellRogueStealthMaxedOut');
notes = this.$t('spellAlreadyCast');
} else if (skill.key === 'stealth') {
notes = this.$t('spellRogueStealthDaliesAvoided', {
originalText: notes,

View file

@ -10,7 +10,6 @@
"spellWizardFrostText": "Chilling Frost",
"spellWizardFrostNotes": "With one cast, ice freezes all your streaks so they won't reset to zero tomorrow! ",
"spellWizardFrostAlreadyCast": "You have already cast this today. Your streaks are frozen, and there's no need to cast this again.",
"spellWarriorSmashText": "Brutal Smash",
@ -37,7 +36,6 @@
"spellRogueStealthText": "Stealth",
"spellRogueStealthNotes": "With each cast, a few of your undone Dailies won't cause damage tonight. Their streaks and colors won't change. (Based on: PER)",
"spellRogueStealthDaliesAvoided": "<%= originalText %> Number of dailies that will be avoided: <%= number %>.",
"spellRogueStealthMaxedOut": "You have already avoided all your dailies; there's no need to cast this again.",
"spellHealerHealText": "Healing Light",
"spellHealerHealNotes": "Shining light restores your health! (Based on: CON and INT)",
@ -76,5 +74,6 @@
"challengeTasksNoCast": "Casting a skill on challenge tasks is not allowed.",
"groupTasksNoCast": "Casting a skill on group tasks is not allowed.",
"spellNotOwned": "You don't own this skill.",
"spellLevelTooHigh": "You must be level <%= level %> to use this skill."
"spellLevelTooHigh": "You must be level <%= level %> to use this skill.",
"spellAlreadyCast": "You've cast this skill already. It won't have any additional effect."
}

View file

@ -1,6 +1,6 @@
import each from 'lodash/each';
import t from './translation';
import { NotAuthorized } from '../libs/errors';
import { NotAuthorized, BadRequest } from '../libs/errors';
import statsComputed from '../libs/statsComputed'; // eslint-disable-line import/no-cycle
import setDebuffPotionItems from '../libs/setDebuffPotionItems'; // eslint-disable-line import/no-cycle
import crit from '../fns/crit'; // eslint-disable-line import/no-cycle
@ -104,7 +104,10 @@ spells.wizard = {
lvl: 14,
target: 'self',
notes: t('spellWizardFrostNotes'),
cast (user) {
cast (user, target, req) {
// Check if chilling frost skill has been previously casted or not.
// See #12361 for more details.
if (user.stats.buffs.streaks === true) throw new BadRequest(t('spellAlreadyCast')(req.language));
user.stats.buffs.streaks = true;
},
},
@ -226,8 +229,8 @@ spells.healer = {
lvl: 11,
target: 'self',
notes: t('spellHealerHealNotes'),
cast (user) {
if (user.stats.hp >= 50) throw new NotAuthorized(t('messageHealthAlreadyMax')(user.language));
cast (user, target, req) {
if (user.stats.hp >= 50) throw new NotAuthorized(t('messageHealthAlreadyMax')(req.language));
user.stats.hp += (statsComputed(user).con + statsComputed(user).int + 5) * 0.075;
if (user.stats.hp > 50) user.stats.hp = 50;
},

View file

@ -163,6 +163,20 @@ async function castSpell (req, res, { isV3 = false }) {
task: results[1],
});
} else if (targetType === 'self') {
const spellName = spell.key;
// Check if stealth skill has been previously casted or not.
// See #12361 for more details.
if (spellName === 'stealth') {
const incompleteDailiesDue = await Tasks.Task.countDocuments({
userId: user._id,
type: 'daily',
completed: false,
isDue: true,
}).exec();
if (user.stats.buffs.stealth >= incompleteDailiesDue) {
throw new BadRequest(res.t('spellAlreadyCast'));
}
}
await castSelfSpell(req, user, spell, quantity);
let userToJson = user;