Skip to content

Commit

Permalink
implement preaffect interface in protect class (#308)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyvg authored Dec 26, 2023
1 parent 9eff5f2 commit 49296d3
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 79 deletions.
69 changes: 18 additions & 51 deletions src/arena/Constuructors/PhysConstructor.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const { floatNumber } = require('../../utils/floatNumber');
const MiscService = require('../MiscService');
const { dodge, parry, disarm } = require('../skills');
const { isSuccessResult } = require('./utils');

/**
Expand Down Expand Up @@ -30,7 +29,7 @@ class PhysConstructor { /**
*
* @param {import('./PreAffect').PreAffect[]} preAffects
*/
constructor(atkAct, preAffects = [dodge, parry, disarm]) {
constructor(atkAct) {
this.name = atkAct.name;
this.displayName = atkAct.displayName;
this.desc = atkAct.desc;
Expand All @@ -40,7 +39,7 @@ class PhysConstructor { /**
/**
* @type {import('./PreAffect').PreAffect[]}
* */
this.preAffects = preAffects;
this.preAffects = [];
}

/**
Expand All @@ -57,10 +56,11 @@ class PhysConstructor { /**
this.status = { hit: 0, exp: 0 };
try {
this.fitsCheck();
this.calculateHit();
this.checkPreAffects();
this.isBlurredMind();
this.protectCheck();
// тут должен идти просчет дефа
this.applyHit();

this.checkPostEffect();
this.checkTargetIsDead();
this.next();
Expand All @@ -76,7 +76,7 @@ class PhysConstructor { /**
if (this.params.game.flags.global.isEclipsed) throw this.breaks('ECLIPSE');

this.preAffects.forEach((preAffect) => {
const result = preAffect.check(this.params);
const result = preAffect.check(this.params, { value: this.status.hit });

if (result && isSuccessResult(result)) {
throw this.breaks(result.message, result);
Expand Down Expand Up @@ -116,32 +116,24 @@ class PhysConstructor { /**
* Если проверка провалена, выставляем флаг isHited, означающий что
* атака прошла
*/
protectCheck() {
const { initiator, target } = this.params;
const atc = initiator.stats.val('patk') * initiator.proc;
const prt = target.flags.isProtected.length > 0 ? target.stats.val('pdef') : 0.1;
const at = floatNumber(Math.round(atc / prt));
console.log('at', at);
const r = MiscService.rndm('1d100');
// const c = Math.round(Math.sqrt(at) + (10 * at) + 5);
// new formula for phys attack chance
const c = 20 * at + 50;
const result = c > r;
console.log('left', c, 'right', r, 'result', result);
calculateHit() {
const { initiator } = this.params;

const initiatorHitParam = initiator.stats.val('hit');
const hitval = MiscService.randInt(
initiatorHitParam.min,
initiatorHitParam.max,
);
this.status.hit = floatNumber(hitval * initiator.proc);
if (result) {
this.params.target.flags.isHited = {
initiator: initiator.nick, val: this.status.hit,
};
this.run();
} else {
throw this.protectorsGetExp();
}
}

applyHit() {
const { initiator } = this.params;

this.params.target.flags.isHited = {
initiator: initiator.nick, val: this.status.hit,
};
this.run();
}

/**
Expand Down Expand Up @@ -224,31 +216,6 @@ class PhysConstructor { /**
initiator.stats.mode('up', 'exp', this.status.exp);
}
}

/**
* Функция выдающая exp для каждого протектора в зависимости от его защиты
* @todo тут скорее всего бага, которая будет давать по 5 раз всем защищающим.
* Экспу за протект нужно выдавать в отдельном action'е который будет идти
* за протектом
*/
protectorsGetExp() {
if (!this.params) return;
const { initiator, target, game } = this.params;
const pdef = target.stats.val('pdef'); // общий показатель защиты цели
/** @type {import('./types').ExpArr} */
const expArr = target.flags.isProtected.map((flag) => {
const defender = game.players.getById(flag.initiator);
if (defender.id === initiator.id || !game.isPlayersAlly(defender, target)) {
return { name: defender.nick, exp: 0 };
}
const protect = Math.floor(flag.val * 100) / pdef;
const exp = Math.round(this.status.hit * 0.8 * protect);
defender.stats.up('exp', exp);
return { name: defender.nick, exp };
});

return { ...this.breaks('DEF'), expArr };
}
}

module.exports = PhysConstructor;
5 changes: 4 additions & 1 deletion src/arena/Constuructors/PreAffect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ import type { Player } from '../PlayersService';
import type { SuccessArgs } from './types';

export interface PreAffect {
check(params: { initiator: Player, target: Player, game: GameService}): SuccessArgs | void
check(
params: { initiator: Player, target: Player, game: GameService},
status: { value: number }
): SuccessArgs | void
}
4 changes: 3 additions & 1 deletion src/arena/Constuructors/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-use-before-define */
import type { Item } from '../../models/item';
import type { ProtectNext } from '../actions/protect';
import type GameService from '../GameService';
import type { Player } from '../PlayersService';
import type { AoeDmgMagicNext } from './AoeDmgMagicConstructor';
Expand Down Expand Up @@ -88,7 +89,8 @@ export type SuccessArgs =
SkillNext |
PhysNext |
HealMagicNext |
HealNext;
HealNext |
ProtectNext;

export type ActionType = SuccessArgs['actionType'];

Expand Down
2 changes: 2 additions & 0 deletions src/arena/LogService/utils/format-cause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export function formatCause(cause: SuccessArgs) {
switch (cause.actionType) {
case 'skill':
return `_${cause.action}_ *${cause.initiator}*: 📖${cause.exp}`;
case 'protect':
return `_${cause.action}_ ${cause.expArr.map(({ name, exp }) => `*${name}*: 📖${exp}`)}`;
default:
return `_${cause.action}_ *${cause.initiator}*`;
}
Expand Down
2 changes: 2 additions & 0 deletions src/arena/LogService/utils/format-exp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export function formatExp(args: SuccessArgs): string {
}
case 'heal':
return expBrackets(args.expArr.map(({ name, exp, val }) => `${name}: 💖${val}/${args.hp} 📖${exp}`).join(', '));
case 'protect':
return expBrackets(args.expArr.map(({ name, exp }) => `${name}: 📖${exp}`).join(', '));
case 'phys':
return expBrackets(`💔-${args.dmg}/${args.hp} 📖${args.exp}`);
case 'skill':
Expand Down
110 changes: 84 additions & 26 deletions src/arena/actions/protect.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,99 @@
import type { OrderType } from '../Constuructors/types';
import type Game from '../GameService';
import type { Player } from '../PlayersService';
import { PreAffect } from '@/arena/Constuructors/PreAffect';
import type { BaseNext, ExpArr, OrderType } from '@/arena/Constuructors/types';
import type Game from '@/arena/GameService';
import MiscService from '@/arena/MiscService';
import type { Player } from '@/arena/PlayersService';
import { floatNumber } from '@/utils/floatNumber';

export type ProtectNext = Omit<BaseNext, 'exp'> & {
actionType: 'protect'
expArr: ExpArr;
}

/**
* Класс защиты
*/
class Protect implements PreAffect {
name = 'protect';
displayName = 'Защита';
desc = 'Защита от физических атак';
lvl = 0;
orderType: OrderType = 'all';

class Protect {
name: string;
displayName: string;
desc: string;
lvl: number;
orderType: OrderType;
/**
* Изменяем протект цели, создаем custom run
* Каст протекта
* @param initiator Объект кастера
* @param target Объект цели
* @param [game] Объект игры
*/
constructor() {
this.name = 'protect';
this.displayName = 'Защита';
this.desc = 'Защита от физических атак';
this.lvl = 0;
this.orderType = 'all';
cast(initiator: Player, target: Player, _game: Game) {
const protectValue = initiator.stats.val('pdef') * initiator.proc;

target.stats.up('pdef', protectValue);
target.flags.isProtected.push({
initiator: initiator.id, val: protectValue,
});
}

check(...[params, status]: Parameters<PreAffect['check']>): ReturnType<PreAffect['check']> {
const { initiator, target, game } = params;
const attackValue = initiator.stats.val('patk') * initiator.proc;
const protectValue = target.flags.isProtected.length > 0 ? target.stats.val('pdef') : 0.1;
const ratio = floatNumber(Math.round(attackValue / protectValue));
console.log('at', ratio);

const randomValue = MiscService.rndm('1d100');
const chance = 20 * ratio + 50;
const result = chance > randomValue;
console.log('chance', chance, 'random', randomValue, 'result', result);

if (!result) {
return this.getSuccessResult({ initiator, target, game }, status.value);
}
}

/**
* Каст протекта
* @param {player} initiator Объект кастера
* @param {player} target Объект цели
* @param {game} [game] Объект игры
* Функция выдающая exp для каждого протектора в зависимости от его защиты
* @todo тут скорее всего бага, которая будет давать по 5 раз всем защищающим.
* Экспу за протект нужно выдавать в отдельном action'е который будет идти
* за протектом
*/
// eslint-disable-next-line class-methods-use-this
cast(initiator: Player, target: Player, _game: Game) {
const tect = initiator.stats.val('pdef') * initiator.proc;
target.stats.up('pdef', tect);
target.flags.isProtected.push({
initiator: initiator.id, val: tect,
getSuccessResult(
params: { initiator: Player; target: Player; game: Game; },
expMultiplier: number,
): ProtectNext {
const { initiator, target, game } = params;
const pdef = target.stats.val('pdef'); // общий показатель защиты цели

const expArr: ExpArr = target.flags.isProtected.map((flag) => {
const defender = game.players.getById(flag.initiator) as Player;

if (defender.id === initiator.id || !game.isPlayersAlly(defender, target)) {
return {
id: defender.id,
name: defender.nick,
exp: 0,
};
}

const protect = Math.floor(flag.val * 100) / pdef;
const exp = Math.round(expMultiplier * 0.8 * protect);
defender.stats.up('exp', exp);

return {
id: defender.id,
name: defender.nick,
exp,
};
});

return {
expArr,
action: this.displayName,
actionType: 'protect',
target: target.nick,
initiator: initiator.nick,
};
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/fwo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as middlewares from './middlewares';
import { connect } from './models';
import { ItemModel } from './models/item';
import { stage } from './scenes/stage';
import { registerAffects } from './utils/registerAffects';

interface BotSession extends Scenes.SceneSession {
character: Char;
Expand All @@ -34,6 +35,8 @@ arena.magics = magics;
arena.skills = skills;
arena.actions = actions;

registerAffects();

bot.use(session());
bot.use(stage.middleware());
bot.use(middlewares.chatMiddleware());
Expand Down
14 changes: 14 additions & 0 deletions src/utils/registerAffects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import arena from '@/arena';

const registerAttackAffects = () => {
arena.actions.attack.preAffects = [
arena.actions.protect,
arena.skills.dodge,
arena.skills.parry,
arena.skills.disarm,
];
};

export const registerAffects = () => {
registerAttackAffects();
};

0 comments on commit 49296d3

Please sign in to comment.