Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#153 Magic Wall #321

Merged
merged 3 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/arena/BattleService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ function getTargetKeyboard(charId: string, game: Game, action: string) {
if (orderType === 'team') {
return game.isPlayersAlly(player, target);
}
if (orderType === 'teamExceptSelf') {
return game.isPlayersAlly(player, target) && player.id !== target.id;
}

return !orders.some((order) => target.id === order.target && action === order.action);
})
Expand Down
2 changes: 2 additions & 0 deletions src/arena/Constuructors/FlagsConstructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default class FlagsConstructor {
isDisarmed = false;
isSleeping = false;
isLightShielded: Flag[] = [];
isBehindWall?: Flag;

/**
* Обнуление флагов
Expand All @@ -39,5 +40,6 @@ export default class FlagsConstructor {
this.isDisarmed = false;
this.isShielded = 0;
this.isLightShielded = [];
this.isBehindWall = undefined;
}
}
2 changes: 1 addition & 1 deletion src/arena/Constuructors/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type GameService from '../GameService';
import type { Player } from '../PlayersService';

export type CostType = 'en' | 'mp';
export type OrderType = 'all' | 'any' | 'enemy' | 'self' | 'team';
export type OrderType = 'all' | 'any' | 'enemy' | 'self' | 'team' | 'teamExceptSelf';
export type AOEType = 'target' | 'team';
export type DamageType = 'acid' | 'fire' | 'lighting' | 'frost' | 'physical' | 'clear';
export type BreaksMessage =
Expand Down
1 change: 1 addition & 0 deletions src/arena/LogService/utils/format-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export function formatAction(msgObj: SuccessArgs): string {
case 'aoe-dmg-magic':
return `*${msgObj.initiator}* сотворил _${msgObj.action}_ на *${msgObj.target}* нанеся ${msgObj.effect} урона`;
case 'magic':
case 'magic-long':
return !msgObj.effect
? `*${msgObj.initiator}* использовал _${msgObj.action}_ на *${msgObj.target}*`
: `*${msgObj.initiator}* использовал _${msgObj.action}_ на *${msgObj.target}* с эффектом ${msgObj.effect}`;
Expand Down
2 changes: 1 addition & 1 deletion src/arena/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export default {
'magicArmor', 'strongAura',
'dustShield', 'mediumAura',
'stoneSkin',
'magic_wall'], // ???
'magicWall'], // ???
'cats_claw',
'vampiric_aura',
'glitch',
Expand Down
10 changes: 10 additions & 0 deletions src/arena/magics/__snapshots__/magicWall.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`magicWall target should be behind wall 1`] = `147.01`;

exports[`magicWall target should be behind wall 2`] = `
"*asperiores* использовал _Магическая стена_ на *alias* с эффектом 140.21
\\[ 📖14 ]
*alias* пытался атаковать *asperiores*, но у него не получилось
_Магическая стена_ *asperiores*"
`;
1 change: 1 addition & 0 deletions src/arena/magics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ export { default as blight } from './blight';
export { default as dustShield } from './dustShield';
export { default as lightShield } from './lightShield';
export { default as sleep } from './sleep';
export { default as magicWall } from './magicWall';
47 changes: 47 additions & 0 deletions src/arena/magics/magicWall.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import casual from 'casual';
import CharacterService from '@/arena/CharacterService';
import GameService from '@/arena/GameService';
import TestUtils from '@/utils/testUtils';
import attack from '../actions/attack';
import magicWall from './magicWall';

// npm t src/arena/magics/magicWall.test.ts

describe('magicWall', () => {
let game: GameService;

beforeAll(() => {
casual.seed(1);

attack.registerPreAffects([magicWall]);
});

beforeEach(async () => {
const initiator = await TestUtils.createCharacter({ prof: 'm', magics: { magicWall: 1 } });
const target = await TestUtils.createCharacter({ prof: 'w' }, { withWeapon: true });

await Promise.all([initiator.id, target.id].map(CharacterService.getCharacterById));

game = new GameService([initiator.id, target.id]);
});

beforeEach(() => {
jest.spyOn(global.Math, 'random').mockReturnValue(0.1);
});

afterEach(() => {
jest.spyOn(global.Math, 'random').mockRestore();
});

it('target should be behind wall', async () => {
game.players.players[0].proc = 1;
game.players.players[0].stats.set('mp', magicWall.cost);
game.players.players[1].proc = 1;

magicWall.cast(game.players.players[0], game.players.players[1], game);
attack.cast(game.players.players[1], game.players.players[0], game);

expect(game.players.players[1].stats.val('pdef')).toMatchSnapshot();
expect(TestUtils.normalizeRoundHistory(game.getRoundResults())).toMatchSnapshot();
});
});
55 changes: 55 additions & 0 deletions src/arena/magics/magicWall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { PreAffect } from '@/arena/Constuructors/interfaces/PreAffect';
import CastError from '@/arena/errors/CastError';
import { LongMagic } from '../Constuructors/LongMagicConstructor';

/**
* Магическая стена
* Основное описание магии общее требовани есть в конструкторе
*/
class MagicWall extends LongMagic implements PreAffect {
constructor() {
super({
name: 'magicWall',
displayName: 'Магическая стена',
desc: 'Защищает цель, цель не может атаковать, нельзя использовать на себя',
cost: 30,
baseExp: 0.1,
costType: 'mp',
lvl: 4,
orderType: 'teamExceptSelf',
aoeType: 'target',
magType: 'good',
chance: [100, 100, 100],
profList: ['p'],
effect: ['1d25+125', '1d50+150', '1d100+200'],
});
}

calculateExp(effect: number, baseExp = 0) {
return Math.round(effect * baseExp * this.params.initiator.proc);
}

run() {
const { target, initiator } = this.params;
target.stats.up('pdef', this.effectVal());
target.flags.isBehindWall = { initiator: initiator.id, val: this.status.effect };
}

runLong() {
const { target, initiator } = this.params;
target.stats.up('pdef', this.effectVal());
target.flags.isBehindWall = { initiator: initiator.id, val: this.status.effect };
}

preAffect({ initiator, game } = this.params) {
if (initiator.flags.isBehindWall) {
const wallCaster = game.players.getById(initiator.flags.isBehindWall.initiator);
if (wallCaster) {
// eslint-disable-next-line max-len
throw new CastError(this.getSuccessResult({ initiator: wallCaster, target: initiator, game }));
}
}
}
}

export default new MagicWall();
1 change: 1 addition & 0 deletions src/utils/registerAffects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const registerAttackAffects = () => {
arena.magics.paralysis,
arena.magics.eclipse,
arena.magics.sleep,
arena.magics.magicWall,
]);

arena.actions.attack.registerPostAffects([
Expand Down
Loading