From 06662b16805ed8cdb58e356416fdf01469756063 Mon Sep 17 00:00:00 2001 From: kyvg Date: Tue, 19 Nov 2024 22:39:26 +0200 Subject: [PATCH] add modifiers --- src/arena/ActionService.ts | 17 +++ src/arena/Constuructors/BaseAction.ts | 1 + src/arena/Constuructors/MagicConstructor.ts | 4 +- src/arena/Constuructors/types.ts | 39 ++++--- src/arena/EngineService.ts | 69 ++++++++++++ src/arena/GameService.ts | 2 +- src/arena/InventoryService.ts | 43 ++++++-- src/arena/OrderService.ts | 10 +- src/arena/PlayersService/Player.ts | 40 +++---- src/arena/PlayersService/utils/index.ts | 19 ++++ src/arena/actions/regeneration.ts | 33 +++--- src/arena/config.ts | 100 ++++++++++-------- src/arena/engineService.ts | 69 ------------ src/arena/index.ts | 25 +++-- src/arena/magics/aura.ts | 3 +- src/arena/passiveSkills/index.ts | 1 + src/fwo.ts | 14 +-- src/helpers/itemHelper.ts | 32 +++--- src/models/item-set.ts | 56 +++++----- src/schemas/item/index.ts | 2 + src/schemas/item/itemAttributesSchema.ts | 7 -- src/schemas/item/itemSchema.ts | 15 ++- src/schemas/itemSet/itemSetSchema.ts | 17 +-- .../{bonusAttributes.ts => modifiers.ts} | 4 +- .../character/characterAttributesSchema.ts | 4 - 25 files changed, 350 insertions(+), 276 deletions(-) create mode 100644 src/arena/ActionService.ts create mode 100644 src/arena/EngineService.ts create mode 100644 src/arena/PlayersService/utils/index.ts delete mode 100644 src/arena/engineService.ts create mode 100644 src/arena/passiveSkills/index.ts rename src/schemas/shared/{bonusAttributes.ts => modifiers.ts} (50%) delete mode 100644 src/types/character/characterAttributesSchema.ts diff --git a/src/arena/ActionService.ts b/src/arena/ActionService.ts new file mode 100644 index 00000000..34e1fa5e --- /dev/null +++ b/src/arena/ActionService.ts @@ -0,0 +1,17 @@ +import arena from '@/arena'; + +export type Action = keyof typeof arena.actions; + +export class ActionService { + static isAction(maybeAction: string): maybeAction is Action { + return maybeAction in arena.actions; + } + + static isBaseAction(action: string) { + if (ActionService.isAction(action)) { + return arena.actions[action].lvl === 0; + } + + return false; + } +} diff --git a/src/arena/Constuructors/BaseAction.ts b/src/arena/Constuructors/BaseAction.ts index 1babc1b8..1e662ffa 100644 --- a/src/arena/Constuructors/BaseAction.ts +++ b/src/arena/Constuructors/BaseAction.ts @@ -30,6 +30,7 @@ export abstract class BaseAction { orderType: OrderType; actionType: ActionType; effectType?: DamageType; + lvl: number; context: BaseActionContext; params: BaseActionParams; diff --git a/src/arena/Constuructors/MagicConstructor.ts b/src/arena/Constuructors/MagicConstructor.ts index ff6b903b..0395880a 100644 --- a/src/arena/Constuructors/MagicConstructor.ts +++ b/src/arena/Constuructors/MagicConstructor.ts @@ -166,8 +166,8 @@ export abstract class Magic extends AffectableAction { const { initiator, target } = this.params; const initiatorMagicLvl = initiator.magics[this.name]; const imc = initiator.modifiers.castChance; // мод шанс прохождения - const castChance = initiator.castChance?.[this.name] ?? 0; // мод action'а - const failChance = target.failChance?.[this.name] ?? 0; + const castChance = initiator.getCastChance(this.name); // мод action'а + const failChance = target.getFailChance(this.name); let chance = this.chance[initiatorMagicLvl - 1]; if (typeof chance === 'string') { chance = MiscService.dice(chance); diff --git a/src/arena/Constuructors/types.ts b/src/arena/Constuructors/types.ts index 899fc208..d9e5f557 100644 --- a/src/arena/Constuructors/types.ts +++ b/src/arena/Constuructors/types.ts @@ -8,16 +8,16 @@ export type OrderType = 'all' | 'any' | 'enemy' | 'self' | 'team' | 'teamExceptS export type AOEType = 'target' | 'team'; export type DamageType = 'acid' | 'fire' | 'lighting' | 'frost' | 'physical' | 'clear'; export type BreaksMessage = - 'NO_INITIATOR' | - 'NO_TARGET' | - 'NO_MANA' | - 'NO_ENERGY' | - 'CHANCE_FAIL' | - 'GOD_FAIL' | - 'HEAL_FAIL' | - 'SKILL_FAIL' | - 'PHYS_FAIL' | - 'NO_WEAPON'; + | 'NO_INITIATOR' + | 'NO_TARGET' + | 'NO_MANA' + | 'NO_ENERGY' + | 'CHANCE_FAIL' + | 'GOD_FAIL' + | 'HEAL_FAIL' + | 'SKILL_FAIL' + | 'PHYS_FAIL' + | 'NO_WEAPON'; export type ExpArr = { initiator: Player; @@ -51,14 +51,27 @@ export type SuccessArgs = { effect: number; hp: number; expArr: ExpArr; - weapon: Item | undefined + weapon: Item | undefined; effectType?: DamageType; orderType: OrderType; affects?: SuccessArgs[]; msg?: CustomMessageFn; -} +}; -export type ActionType = 'magic' | 'dmg-magic' | 'dmg-magic-long' | 'aoe-dmg-magic' | 'magic-long' | 'skill' | 'phys' | 'heal-magic' | 'heal' | 'protect' | 'dodge' | 'passive'; +export type ActionType = + | 'magic' + | 'dmg-magic' + | 'dmg-magic-long' + | 'aoe-dmg-magic' + | 'magic-long' + | 'skill' + | 'phys' + | 'heal-magic' + | 'heal' + | 'protect' + | 'dodge' + | 'passive' + | 'regeneration'; export interface FailArgs { actionType: ActionType; diff --git a/src/arena/EngineService.ts b/src/arena/EngineService.ts new file mode 100644 index 00000000..90546a24 --- /dev/null +++ b/src/arena/EngineService.ts @@ -0,0 +1,69 @@ +import arena from '@/arena'; +import { type Action, ActionService } from '@/arena/ActionService'; +import type Game from '@/arena/GameService'; +import config from '@/arena/config'; +import _ from 'lodash'; + +type Stages = Readonly<(Action | Readonly)[]>; + +/** + * @param stages массив строк + * @param game объект игры + * @return измененный объект игры + */ +function runStage(stages: Stages, game: Game) { + const ordersByAction = Object.groupBy(game.orders.ordersList, ({ action }) => action); + stages.forEach((stage) => { + if (typeof stage !== 'string') { + runStage(stage, game); + return; + } + + console.log('stage run:', stage); + if (!ActionService.isAction(stage)) { + console.log('stage fail (unknown action):', stage); + return; + } + const action = arena.actions[stage]; + const orders = ordersByAction[stage]; + if (!orders) { + return; + } + + orders.forEach((order) => { + const initiator = game.players.getById(order.initiator); + const target = game.players.getById(order.target); + if (initiator && target) { + // FIXME прокидывать проценты в action вместо initiator + initiator.setProc(order.proc / 100); + action.cast(initiator, target, game); + } else { + console.log('stage fail (no player):', initiator?.id, target?.id); + } + }); + + if ('castLong' in action) { + action.castLong(game); + } + }); + return game; +} + +/** + * Engine + * Модуль обработки боя + * @todo wip + */ + +/** + * @param game Объект игры + */ +export function engine(game: Game): Game | undefined { + try { + return runStage(config.stages, game); + } catch (e) { + console.debug(e); + } finally { + console.info('engine done'); + } +} diff --git a/src/arena/GameService.ts b/src/arena/GameService.ts index d08ec6a6..aba85008 100644 --- a/src/arena/GameService.ts +++ b/src/arena/GameService.ts @@ -4,7 +4,7 @@ import { Profs } from '../data'; import * as channelHelper from '../helpers/channelHelper'; import type { Game } from '../models/game'; import type { LongItem } from './Constuructors/LongMagicConstructor'; -import { engine } from './engineService'; +import { engine } from './EngineService'; import { HistoryService, type HistoryItem } from './HistoryService'; import { LogService } from './LogService'; import type * as magics from './magics'; diff --git a/src/arena/InventoryService.ts b/src/arena/InventoryService.ts index a77642d3..2eb9552c 100644 --- a/src/arena/InventoryService.ts +++ b/src/arena/InventoryService.ts @@ -1,14 +1,15 @@ -import _ from 'lodash'; -import { getItems, addItem, removeItem, putOnItem, putOffItem } from '@/api/inventory'; +import { addItem, getItems, putOffItem, putOnItem, removeItem } from '@/api/inventory'; import arena from '@/arena'; import ValidationError from '@/arena/errors/ValidationError'; import type { Char } from '@/models/character'; import type { InventoryDocument } from '@/models/inventory'; import type { Inventory } from '@/schemas/inventory'; -import { assignWithSum } from '@/utils/assignWithSum'; -import { itemAttributesSchema, type ItemAttributes } from '@/schemas/item/itemAttributesSchema'; import type { Item } from '@/schemas/item'; +import { type ItemAttributes, itemAttributesSchema } from '@/schemas/item/itemAttributesSchema'; import type { ItemSet } from '@/schemas/itemSet'; +import type { Modifiers } from '@/schemas/shared/modifiers'; +import { assignWithSum } from '@/utils/assignWithSum'; +import _ from 'lodash'; export class InventoryService { harksFromItems: ItemAttributes; @@ -24,17 +25,43 @@ export class InventoryService { return inventory.map(({ code }) => arena.items[code]); } - static getItemsSetsByInventory(inventory: InventoryDocument[]): ItemSet[] { + static getItemsSetsByInventory(inventory: InventoryDocument[], full = true): ItemSet[] { const codes = new Set(inventory.map(({ code }) => code)); return Object.values(arena.itemsSets).filter(({ items }) => { - items.some(( item ) => codes.has(item)); - }) + if (full) { + return items.every((item) => codes.has(item)); + } + + return items.some((item) => codes.has(item)); + }); + } + + static getItemSetsModifiersByInventory(inventory: InventoryDocument[]): Modifiers[] { + const itemsSets = InventoryService.getItemsSetsByInventory(inventory, false); + const codes = new Set(inventory.map(({ code }) => code)); + const modifiers: Modifiers[] = []; + + for (const itemSet of itemsSets) { + const itemsCount = itemSet.items.reduce((sum, item) => (codes.has(item) ? sum + 1 : sum), 0); + + for (const modifier of itemSet.modifiers) { + if (modifier.itemsRequired <= itemsCount) { + modifiers.push(modifier); + } + } + } + + return modifiers; } get attributes() { return this.harksFromItems.attributes; } + get modifiers() { + return InventoryService.getItemSetsModifiersByInventory(this.inventory); + } + getItem(itemId) { return this.inventory.find((item) => item._id.equals(itemId)); } @@ -118,7 +145,7 @@ export class InventoryService { const itemAttriributes = itemAttributesSchema.array().parse(items); const harksFromItems = itemAttriributes.reduce(assignWithSum, itemAttributesSchema.parse({})); - const itemsSets = InventoryService.getItemsSetsByInventory(this.getEquippedItems()) + const itemsSets = InventoryService.getItemsSetsByInventory(this.getEquippedItems()); const itemsSetsAttriributes = itemAttributesSchema.array().parse(itemsSets); const harksFromItemsSets = itemsSetsAttriributes.reduce(assignWithSum, harksFromItems); diff --git a/src/arena/OrderService.ts b/src/arena/OrderService.ts index 12498401..1a45cab4 100644 --- a/src/arena/OrderService.ts +++ b/src/arena/OrderService.ts @@ -1,8 +1,8 @@ +import arena from '@/arena'; +import { ActionService } from '@/arena/ActionService'; +import { RoundStatus } from '@/arena/RoundService'; +import OrderError from '@/arena/errors/OrderError'; import _ from 'lodash'; -import * as actions from './actions'; -import OrderError from './errors/OrderError'; -import { RoundStatus } from './RoundService'; -import arena from './index'; export interface Order { initiator: string; @@ -29,7 +29,7 @@ export default class Orders { * @desc Проверка доступно ли действие для персонажа */ static isValidAct({ initiator, action }: Order): boolean { - if (actions[action]) { + if (ActionService.isBaseAction(action)) { return true; } const { skills, magics } = arena.characters[initiator]; diff --git a/src/arena/PlayersService/Player.ts b/src/arena/PlayersService/Player.ts index 2dbf81e8..d3535ea0 100644 --- a/src/arena/PlayersService/Player.ts +++ b/src/arena/PlayersService/Player.ts @@ -1,19 +1,20 @@ import arena from '@/arena'; +import type { Action } from '@/arena/ActionService'; import type { CharacterService } from '@/arena/CharacterService'; import FlagsConstructor from '@/arena/Constuructors/FlagsConstructor'; import type { DamageType } from '@/arena/Constuructors/types'; -import type * as magics from '@/arena/magics'; import type { Stats } from '@/arena/StatsService'; import StatsService from '@/arena/StatsService'; import type { Prof } from '@/data/profs'; import type { Clan } from '@/models/clan'; import { PlayerWeapon } from './PlayerWeapon'; +import { convertItemModifiers } from './utils'; export type Resists = Record; export interface Chance { - fail?: Partial> - cast?: Partial> + fail: Partial>; + cast: Partial>; } /** @@ -38,9 +39,7 @@ export default class Player { stats: StatsService; flags: FlagsConstructor; modifiers: { - magics: { - chance: Chance; - } + chance: Chance; castChance: number; }; @@ -62,17 +61,10 @@ export default class Player { this.favoriteMagics = params.favoriteMagicList; this.stats = new StatsService(params.dynamicAttributes); this.flags = new FlagsConstructor(); - // @todo закладка для вычисляемых статов this.modifiers = { - magics: { - chance: { - fail: {}, - cast: {}, - }, - }, + chance: convertItemModifiers(params.inventory.modifiers), castChance: 0, - }; // Объект - // модификаторов + }; // Объект модификаторов this.resists = {}; // Объект резистов this.skills = params.skills || {}; // Обькт доступных скилов this.magics = params.magics || {}; // объект изученых магий @@ -89,12 +81,12 @@ export default class Player { return new Player(arena.characters[charId]); } - get failChance(): Chance['fail'] { - return this.modifiers.magics.chance.fail ?? {}; + getFailChance(action: Action) { + return this.modifiers.chance.fail[action] ?? 0; } - get castChance(): Chance['cast'] { - return this.modifiers.magics.chance.cast ?? {}; + getCastChance(action: Action) { + return this.modifiers.chance.cast[action] ?? 0; } /** @@ -118,16 +110,16 @@ export default class Player { } /** - * Возвращает убийцу игрока если он записан - */ + * Возвращает убийцу игрока если он записан + */ getKiller(): string { return this.flags.isDead; } /** - * Устанавливает убийцу игрока - * @param player записывает id убийцы - */ + * Устанавливает убийцу игрока + * @param player записывает id убийцы + */ setKiller(player: Player): void { this.flags.isDead = player.id; } diff --git a/src/arena/PlayersService/utils/index.ts b/src/arena/PlayersService/utils/index.ts new file mode 100644 index 00000000..9eaed5a9 --- /dev/null +++ b/src/arena/PlayersService/utils/index.ts @@ -0,0 +1,19 @@ +import type { Chance } from '@/arena/PlayersService/Player'; +import type { Modifiers } from '@/schemas/shared/modifiers'; + +export function convertItemModifiers(modifiers: Modifiers[]): Chance { + return modifiers.reduce( + (acc, { type, chance }) => { + if (chance < 0) { + acc.fail[type] ??= 0; + acc.fail[type] -= chance; + } else { + acc.cast[type] ??= 0; + acc.cast[type] += chance; + } + + return acc; + }, + { fail: {}, cast: {} }, + ); +} diff --git a/src/arena/actions/regeneration.ts b/src/arena/actions/regeneration.ts index 83c415dc..3b3e176c 100644 --- a/src/arena/actions/regeneration.ts +++ b/src/arena/actions/regeneration.ts @@ -1,4 +1,5 @@ -import type { OrderType } from '../Constuructors/types'; +import { AffectableAction } from '../Constuructors/AffectableAction'; +import type { ActionType, OrderType } from '../Constuructors/types'; import type Game from '../GameService'; import type { Player } from '../PlayersService'; @@ -6,22 +7,13 @@ import type { Player } from '../PlayersService'; * Класс регенерации */ -class Regeneration { - name: string; - displayName: string; - desc: string; - lvl: number; - orderType: OrderType; - /** - * Изменяем состояние цели, создаем custom run - */ - constructor() { - this.name = 'regeneration'; - this.displayName = 'Восстановление'; - this.desc = 'Регенерация маны/энергии'; - this.lvl = 0; - this.orderType = 'self'; - } +class Regeneration extends AffectableAction { + name = 'regeneration'; + displayName = 'Восстановление'; + desc = 'Регенерация маны/энергии'; + lvl = 0; + orderType: OrderType = 'self'; + actionType: ActionType = 'regeneration'; /** * Каст регенерации @@ -31,7 +23,12 @@ class Regeneration { * @param game Объект игры (не обязателен) */ // eslint-disable-next-line class-methods-use-this - cast(initiator: Player, _target: Player, _game: Game) { + cast(initiator: Player, target: Player, game: Game) { + this.createContext(initiator, target, game) + this.run(initiator, target, game) + } + + run(initiator: Player, _target: Player, _game: Game) { if (initiator.prof === 'l' || initiator.prof === 'w') { const val = initiator.stats.val('regen.en') * initiator.proc; // размер восстан initiator.stats.up('en', val); diff --git a/src/arena/config.ts b/src/arena/config.ts index c84584de..366927f7 100644 --- a/src/arena/config.ts +++ b/src/arena/config.ts @@ -5,7 +5,6 @@ * */ - export default { Name: 'Arena-Beta', noReg: false, // Запрещена регистрация @@ -31,56 +30,59 @@ export default { learnChance: 60, }, defaultItems: { - w: 'waa', l: 'wab', p: 'wac', m: 'wac', + w: 'waa', + l: 'wab', + p: 'wac', + m: 'wac', }, // Порядок выполнения магия (ОЧЕНЬ ОПАСНО!) stages: [ 'silence', 'magicDefense', - 'mass_silence', + // 'mass_silence', 'dispel', 'exorcism', 'anathema', // 8mpb armag // 8pmb podmena?!? // 8wpb clonirivanie - 'magic_devastation', - 'energy_devastation', // predlagay sna4alo sdelat energy potom mag - 'satanic_glitches', + // 'magic_devastation', + // 'energy_devastation', // predlagay sna4alo sdelat energy potom mag + // 'satanic_glitches', // 8mpa ahuyalipsis - 'sacrifice', - 'dead_call', - 'firestorm', + // 'sacrifice', + // 'dead_call', + // 'firestorm', // 8mma mozgovaya huyaka - 'plague', - 'pray', + // 'plague', + // 'pray', 'sleep', // ?!?!?!?!!? why there? 'lightShield', - 'sphere', - 'mana_burn', + // 'sphere', + // 'mana_burn', // 8ppa [ - 'blessing', - 'curse', - 'entangle'], // ??? - [ - 'blight', - 'bodySpirit'], - 'mirror_reflection', + // 'blessing', + // 'curse', + // 'entangle' + ], // ??? + ['blight', 'bodySpirit'], + // 'mirror_reflection', [ - 'smallAura', - 'magicArmor', 'strongAura', - 'dustShield', 'mediumAura', + // 'smallAura', + 'magicArmor', + // 'strongAura', + 'dustShield', + // 'mediumAura', 'stoneSkin', - 'magicWall'], // ??? - 'cats_claw', - 'vampiric_aura', + 'magicWall', + ], // ??? + // 'cats_claw', + // 'vampiric_aura', 'glitch', 'madness', - 'holy_weapon', + // 'holy_weapon', // - [ - 'paralysis', - 'eclipse'], + ['paralysis', 'eclipse'], // @todo Тут пойду ВСЕ скилы, очередность в процессе // SKILLS: 'berserk', @@ -89,29 +91,37 @@ export default { 'disarm', [ 'protect', - 'regen_energy', - 'regen_mana', - 'regeneration'], + // 'regen_energy', + // 'regen_mana', + 'regeneration', + ], 'attack', // [ 'fireBall', - 'ice_lance', + // 'ice_lance', 'magicArrow', 'poisonBreath', - 'frostTouch', 'acidSpittle', 'chainLightning', 'fireRain', - 'wild_lighting', + 'frostTouch', + 'acidSpittle', + 'chainLightning', + 'fireRain', + // 'wild_lighting', 'rockfall', - 'physicalSadness'], - 'magic_sadness', + 'physicalSadness', + ], + // 'magic_sadness', [ 'lightHeal', - 'mass_heal', 'mediumHeal', 'strongHeal'], + // 'mass_heal', + 'mediumHeal', + 'strongHeal', + ], 'handsHeal', - 'postHeal', - 'life_force', - 'vampirism', - 'spirit_unity', 'secondLife'], /** - * Суммируемые атрибуты для вещей - */ + // 'postHeal', + // 'life_force', + // 'vampirism', + // 'spirit_unity', + 'secondLife', + ] as const, }; diff --git a/src/arena/engineService.ts b/src/arena/engineService.ts deleted file mode 100644 index ab6b94c6..00000000 --- a/src/arena/engineService.ts +++ /dev/null @@ -1,69 +0,0 @@ -import _ from 'lodash'; -import * as actions from './actions'; -import config from './config'; -import type Game from './GameService'; -import * as magics from './magics'; -import * as skills from './skills'; - -const ACTIONS = { - ...actions, ...magics, ...skills, -}; -type ActionKeys = keyof typeof ACTIONS; -type Stages = (ActionKeys | ActionKeys[])[] -const STAGES = config.stages as Stages; - -/** - * @param ar массив строк - * @param gameObj объект игры - * @return измененный объект игры - */ -function runStage(ar: Stages, gameObj: Game) { - const allActions = { ...ACTIONS }; - const ord = _.groupBy(gameObj.orders.ordersList, ({ action }) => action); - ar.forEach((x) => { - if (typeof x !== 'string') { - runStage(x, gameObj); - } else { - const act = allActions[x]; - console.log('stage run:', x); - if (!act) return; - - if (ord[x]) { - const ordObj = ord[x]; - ordObj.forEach((o) => { - const initiator = gameObj.players.getById(o.initiator); - const target = gameObj.players.getById(o.target); - if (initiator && target) { - initiator.setProc(o.proc / 100); - act.cast(initiator, target, gameObj); - } else { - console.log('stage fail (no player):', initiator?.id, target?.id); - } - }); - } - if ('castLong' in act) { - act.castLong(gameObj); - } - } - }); - return gameObj; -} - -/** - * Engine - * Модуль обработки боя - * @todo wip - */ - -/** - * @param gameObj Объект игры -*/ -export function engine(gameObj: Game): Game | undefined { - try { - return runStage(STAGES, gameObj); - } catch (e) { - console.debug(e); - } finally { - console.info('engine done'); - } -} diff --git a/src/arena/index.ts b/src/arena/index.ts index 1089be83..4666c04e 100644 --- a/src/arena/index.ts +++ b/src/arena/index.ts @@ -1,27 +1,30 @@ -import type { Telegraf } from 'telegraf'; import type { BotContext } from '@/fwo'; import type { Clan } from '@/models/clan'; -import type * as actions from './actions'; +import type { Item } from '@/schemas/item'; +import type { ItemSet } from '@/schemas/itemSet'; +import type { Telegraf } from 'telegraf'; import type { CharacterService } from './CharacterService'; import type GameService from './GameService'; -import type * as magics from './magics'; import type MatchMaking from './MatchMakingService'; +import type * as actions from './actions'; +import type * as magics from './magics'; +import type * as passiveSkills from './passiveSkills'; import type * as skills from './skills'; -import type { Item } from '@/schemas/item'; -import type { ItemSet } from '@/schemas/itemSet'; +import type * as weaponMastery from './weaponMastery'; export default { mm: null as unknown as typeof MatchMaking, characters: {} as Record, games: {} as Record, - /** - * @description Item from DB - */ items: {} as unknown as Record, itemsSets: {} as unknown as Record, - magics: null as unknown as typeof magics, - skills: null as unknown as typeof skills, - actions: null as unknown as typeof actions, + magics: {} as unknown as typeof magics, + skills: {} as unknown as typeof skills, + actions: {} as unknown as typeof actions & + typeof magics & + typeof skills & + typeof passiveSkills & + typeof weaponMastery, clans: new Map(), bot: null as unknown as Telegraf, }; diff --git a/src/arena/magics/aura.ts b/src/arena/magics/aura.ts index f83cfa2e..472cf5bc 100644 --- a/src/arena/magics/aura.ts +++ b/src/arena/magics/aura.ts @@ -7,12 +7,11 @@ import { LongMagic } from '../Constuructors/LongMagicConstructor'; export class Aura extends LongMagic { run(): void { const { target } = this.params; - target.stats.mode('up', 'phys.defence', this.effectVal()); + target.stats.up('phys.defence', this.effectVal()); } runLong(): void { const { target } = this.params; - target.stats.up('phys.defence', this.effectVal()) target.stats.up('phys.defence', this.effectVal()); } } diff --git a/src/arena/passiveSkills/index.ts b/src/arena/passiveSkills/index.ts new file mode 100644 index 00000000..7b747306 --- /dev/null +++ b/src/arena/passiveSkills/index.ts @@ -0,0 +1 @@ +export { default as staticProtect } from "./staticProtect"; \ No newline at end of file diff --git a/src/fwo.ts b/src/fwo.ts index 8d7d90ee..fba177d0 100644 --- a/src/fwo.ts +++ b/src/fwo.ts @@ -1,18 +1,18 @@ +import { server } from '@/server'; import type { Context, Scenes } from 'telegraf'; -import { - Telegraf, session, -} from 'telegraf'; +import { Telegraf, session } from 'telegraf'; import arena from './arena'; -import * as actions from './arena/actions'; import type { CharacterService } from './arena/CharacterService'; -import * as magics from './arena/magics'; import MM from './arena/MatchMakingService'; +import * as actions from './arena/actions'; +import * as magics from './arena/magics'; +import * as passiveSkills from './arena/passiveSkills'; import * as skills from './arena/skills'; +import * as weaponMastery from './arena/weaponMastery'; import * as middlewares from './middlewares'; import { connect } from './models'; import { ItemModel } from './models/item'; import { stage } from './scenes/stage'; -import { server } from '@/server'; import { registerAffects } from './utils/registerAffects'; interface BotSession extends Scenes.SceneSession { @@ -35,7 +35,7 @@ void connect(async () => { arena.mm = MM; arena.magics = magics; arena.skills = skills; -arena.actions = actions; +arena.actions = { ...actions, ...magics, ...skills, ...passiveSkills, ...weaponMastery }; registerAffects(); diff --git a/src/helpers/itemHelper.ts b/src/helpers/itemHelper.ts index 5d82f76e..d7f0c221 100644 --- a/src/helpers/itemHelper.ts +++ b/src/helpers/itemHelper.ts @@ -1,6 +1,6 @@ -import { itemSchema } from "@/schemas/item/itemSchema"; -import { itemSetSchema } from "@/schemas/itemSet/itemSetSchema"; -import csv from 'csvtojson' +import { itemSchema } from '@/schemas/item/itemSchema'; +import { itemSetSchema } from '@/schemas/itemSet/itemSetSchema'; +import csv from 'csvtojson'; export const generateItems = async () => { const rawItems = await csv({ @@ -9,12 +9,12 @@ export const generateItems = async () => { colParser: { class: (value) => value.split(', '), }, - }).fromFile('./items.csv') + }).fromFile('./items.csv'); const items = itemSchema.array().parse(rawItems); return items; -} +}; export const generateItemsSets = async () => { const rawItemsSets = await csv({ @@ -23,26 +23,26 @@ export const generateItemsSets = async () => { colParser: { items: (value) => value.split(', '), }, - }).fromFile('./items-sets.csv') + }).fromFile('./items-sets.csv'); - const mergeBonuses = (acc, curr) => { - const prev = acc.at(-1) + const mergeModifiers = (acc, curr) => { + const prev = acc.at(-1); if (prev?.code === curr.code) { - prev.bonus ??= []; - if (curr.bonus) { - prev.bonus.push(curr.bonus); + prev.modifiers ??= []; + if (curr.modifiers) { + prev.modifiers.push(curr.modifiers); } - return acc + return acc; } - curr.bonus = []; + curr.modifiers = []; acc.push(curr); return acc; - } + }; - const mergedItemsSets = rawItemsSets.reduce(mergeBonuses, []) + const mergedItemsSets = rawItemsSets.reduce(mergeModifiers, []); const itemsSets = itemSetSchema.array().parse(mergedItemsSets); return itemsSets; -} +}; diff --git a/src/models/item-set.ts b/src/models/item-set.ts index 6927e263..ff1b9484 100644 --- a/src/models/item-set.ts +++ b/src/models/item-set.ts @@ -1,24 +1,23 @@ -import type { Model } from 'mongoose'; -import mongoose, { Document, Schema } from 'mongoose'; import arena from '@/arena'; -import type { Item } from '@/schemas/item'; -import { itemAttributesSchema } from '@/schemas/item/itemAttributesSchema'; -import _ from 'lodash'; import { generateItemsSets } from '@/helpers/itemHelper'; +import type { Item } from '@/schemas/item'; import type { ItemSet } from '@/schemas/itemSet/itemSetSchema'; +import _ from 'lodash'; +import type { Model } from 'mongoose'; +import mongoose, { Document, Schema } from 'mongoose'; export type ItemSetModel = Model & typeof ItemSetDocument; export class ItemSetDocument extends Document { static async load(this: ItemSetModel) { const timer = Date.now(); + try { const items = await this.find({}); if (items.length) { arena.itemsSets = _.keyBy(items, ({ code }) => code); } else { - const itemsSets = await generateItemsSets() - console.log('File Loaded: ', Date.now() - timer, 'ms'); + const itemsSets = await generateItemsSets(); const createdItems = await ItemSetModel.create(itemsSets); arena.itemsSets = _.keyBy(createdItems, ({ code }) => code); @@ -29,14 +28,6 @@ export class ItemSetDocument extends Document { console.log('Items loaded.T:', Date.now() - timer, 'ms'); } } - - /** - * @description Собираем все харки со шмотки - * @param itemCode код вещи - */ - static getAttributes(this: ItemSetModel, itemCode: string) { - return itemAttributesSchema.parse(arena.items[itemCode]) - } } /** @@ -46,22 +37,27 @@ export class ItemSetDocument extends Document { * @module Model/ItemSet */ -const itemSet = new Schema({ - code: { - type: String, unique: true, required: true +const itemSet = new Schema( + { + code: { + type: String, + unique: true, + required: true, + }, + info: { type: Object }, + attributes: { type: Object }, + base: { type: Object }, + phys: { type: Object }, + magic: { type: Object }, + heal: { type: Object }, + hit: { type: Object }, + modifiers: [{ type: Object }], + }, + { + versionKey: false, }, - info: { type: Object }, - requiredAttributes: { type: Object }, - attributes: { type: Object }, - base: { type: Object }, - phys: { type: Object }, - magic: { type: Object }, - heal: { type: Object }, - hit: { type: Object }, -}, { - versionKey: false, -}); +); itemSet.loadClass(ItemSetDocument); -export const ItemSetModel = mongoose.model('Item', itemSet); +export const ItemSetModel = mongoose.model('ItemSet', itemSet); diff --git a/src/schemas/item/index.ts b/src/schemas/item/index.ts index 0e7ffe6d..922cbfbd 100644 --- a/src/schemas/item/index.ts +++ b/src/schemas/item/index.ts @@ -1 +1,3 @@ export * from './itemSchema'; +export * from './itemAttributesSchema'; +export * from './itemInfoSchema'; diff --git a/src/schemas/item/itemAttributesSchema.ts b/src/schemas/item/itemAttributesSchema.ts index 3f0f5934..777d513b 100644 --- a/src/schemas/item/itemAttributesSchema.ts +++ b/src/schemas/item/itemAttributesSchema.ts @@ -7,13 +7,6 @@ import { baseAttributesSchema } from '@/schemas/shared/baseAttributes'; import { elementAttributesSchema } from '@/schemas/shared/elementAttributes'; export const itemAttributesSchema = z.object({ - requiredAttributes: characterAttributesSchema.default({ - str: 0, - dex: 0, - con: 0, - int: 0, - wis: 0, - }), attributes: characterAttributesSchema.default({ str: 0, dex: 0, diff --git a/src/schemas/item/itemSchema.ts b/src/schemas/item/itemSchema.ts index 537feeb1..bdb8fb9a 100644 --- a/src/schemas/item/itemSchema.ts +++ b/src/schemas/item/itemSchema.ts @@ -1,8 +1,7 @@ import { z } from 'zod'; -import { characterClassSchema } from '../character'; -import { itemAttributesSchema } from './itemAttributesSchema'; -import { itemInfoSchema } from './itemInfoSchema'; -import { bonusAttributesSchema } from '../shared/bonusAttributes'; +import { characterAttributesSchema, characterClassSchema } from '@/schemas/character'; +import { itemAttributesSchema } from '@/schemas/item/itemAttributesSchema'; +import { itemInfoSchema } from '@/schemas/item/itemInfoSchema'; export const itemSchema = z .object({ @@ -13,7 +12,13 @@ export const itemSchema = z wear: z.string(), weight: z.number(), class: characterClassSchema.array(), - bonus: bonusAttributesSchema.array().default([]), + requiredAttributes: characterAttributesSchema.default({ + str: 0, + dex: 0, + con: 0, + int: 0, + wis: 0, + }), }) .merge(itemAttributesSchema); diff --git a/src/schemas/itemSet/itemSetSchema.ts b/src/schemas/itemSet/itemSetSchema.ts index 65ffd9d7..4bf89f94 100644 --- a/src/schemas/itemSet/itemSetSchema.ts +++ b/src/schemas/itemSet/itemSetSchema.ts @@ -1,17 +1,20 @@ +import { itemAttributesSchema, itemInfoSchema } from '@/schemas/item'; +import { modifiersSchema } from '@/schemas/shared/modifiers'; import { z } from 'zod'; -import { itemInfoSchema } from '../item/itemInfoSchema'; -import { itemAttributesSchema } from '../item/itemAttributesSchema'; -import { bonusAttributesSchema } from '../shared/bonusAttributes'; export const itemSetSchema = z .object({ code: z.string(), info: itemInfoSchema, items: z.string().array(), - bonus: bonusAttributesSchema.merge(z.object({ - itemsRequired: z.number(), - })).array().default([]) + modifiers: modifiersSchema + .merge( + z.object({ + itemsRequired: z.number(), + }), + ) + .array(), }) - .merge(itemAttributesSchema) + .merge(itemAttributesSchema); export type ItemSet = z.infer; diff --git a/src/schemas/shared/bonusAttributes.ts b/src/schemas/shared/modifiers.ts similarity index 50% rename from src/schemas/shared/bonusAttributes.ts rename to src/schemas/shared/modifiers.ts index 08be8a25..af9e1d48 100644 --- a/src/schemas/shared/bonusAttributes.ts +++ b/src/schemas/shared/modifiers.ts @@ -1,9 +1,9 @@ import { z } from 'zod'; -export const bonusAttributesSchema = z.object({ +export const modifiersSchema = z.object({ type: z.string(), chance: z.number().default(0), effect: z.number().default(0), }); -export type BonusAttributes = z.infer; +export type Modifiers = z.infer; diff --git a/src/types/character/characterAttributesSchema.ts b/src/types/character/characterAttributesSchema.ts deleted file mode 100644 index fff9aa10..00000000 --- a/src/types/character/characterAttributesSchema.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { characterAttributesSchema } from '@/schemas/character'; -import type { z } from 'zod'; - -export type CharacterAttributes = z.infer;