import type { BattleSession } from 'db://assets/mx/module/battle'; import { AttributeComp, BattleTeamId, TeamComp, TagComp, EntityTag, } from 'db://assets/mx/module/battle'; import type { EntityId } from 'db://assets/mx/module/ecs'; import { TableNames } from '../../game/ConfigTableData'; import { heroCharacterIds, isElementHero } from '../config/BattleHeroTable'; import { Weapon2TileType } from 'db://assets/mx/module/merge'; function _parseBaseAttr(raw: string): Array<{ type: number; value: number }> { if (!raw) return []; const out: Array<{ type: number; value: number }> = []; for (const seg of raw.split(';')) { const part = seg.trim(); if (!part) continue; const [typeStr, valueStr] = part.split(','); const type = Number(typeStr); const value = Number(valueStr); if (!Number.isFinite(type) || !Number.isFinite(value)) continue; out.push({ type, value }); } return out; } /** 全局词条:已删表字段,恒 false */ export function isGlobalSkillEntry(_entry: ITableSkill): boolean { return false; } /** 物化到某武器塔:词条表已删,恒空 */ export function entriesAffectingWeapon( _skills: readonly ITableSkill[], _weapon1Id: number, ): ITableSkill[] { return []; } /** 汇总已选词条 base_attr(词条已删,恒 0) */ export function sumSelectedBaseAttrWan( skills: readonly ITableSkill[], attrType: number, ): number { let sum = 0; for (const entry of skills) { const raw = (entry as ITableSkill & { base_attr?: string }).base_attr ?? ''; for (const { type, value } of _parseBaseAttr(raw)) { if (type === attrType) sum += value; } } return sum; } /** 万分比加成 → 权重乘数:1000 → ×1.1 */ export function wanToWeightMul(wan: number): number { if (wan <= 0) return 1; return 1 + wan / 10000; } const GLOBAL_SLOW_SOURCE = 'global_skill_slow'; /** * 怪物减速:base_attr type8,万分比减速量(1000=减速10%→移速×0.9)。 * 对单个敌人写入持久 Mul(无 remain)。 */ export function applyGlobalMonsterSlowToEntity( session: BattleSession, entityId: EntityId, slowWan: number, ): void { if (slowWan <= 0) return; const world = session.world; if (!world.isAlive(entityId)) return; if (!_isEnemy(world, entityId)) return; if (!world.getComponent(entityId, AttributeComp)) { world.addComponent(entityId, new AttributeComp()); } const attrs = session.attributes; const attr = world.getComponent(entityId, AttributeComp); if (attr) { attr.modifiers = attr.modifiers.filter((m) => m.source !== GLOBAL_SLOW_SOURCE); } const speedMul = Math.max(0, 1 - slowWan / 10000); attrs.addModifier(entityId, { attr: 'move_speed_mul', op: 'Mul', value: speedMul, source: GLOBAL_SLOW_SOURCE, }); } /** 对场上全部敌人应用全局减速(选技能后立刻生效) */ export function applyGlobalMonsterSlowToAllEnemies( session: BattleSession, skills: readonly ITableSkill[], ): void { const slowWan = sumSelectedBaseAttrWan(skills, 8); if (slowWan <= 0) return; session.world.forEachAlive((id) => { applyGlobalMonsterSlowToEntity(session, id, slowWan); }); } function _isEnemy(world: BattleSession['world'], id: EntityId): boolean { const team = world.getComponent(id, TeamComp); if (team && BattleTeamId.isEnemyTeam(team.team)) return true; const tags = world.getComponent(id, TagComp); return !!tags?.tags.includes(EntityTag.Enemy); } /** Weapon2 是否属于五行英雄(characters 成员) */ export function isHeroWeapon2Id(weapon2Id: number): boolean { const id = Number(weapon2Id); if (!Number.isFinite(id) || id <= 0) return false; const list = gg.data.table.getTableList(TableNames.Hero) ?? []; for (const w1 of list) { if (!isElementHero(w1)) continue; for (const g of heroCharacterIds(w1)) { if (Number(g) === id) return true; } } return false; } /** * 背包刷新:按已选全局词条修正 Weapon2 基础权重。 * type10 英雄概率、type11 格子概率:基础 weight ×(1+万分比)。 */ export function applyBagRefreshWeightBonus( baseWeight: number, weapon2Type: number, weapon2Id: number, skills: readonly ITableSkill[], ): number { if (baseWeight <= 0 || !skills.length) return baseWeight; let wan = 0; if (Number(weapon2Type) === Weapon2TileType.Grid) { wan += sumSelectedBaseAttrWan(skills, 11); } if (isHeroWeapon2Id(weapon2Id)) { wan += sumSelectedBaseAttrWan(skills, 10); } if (wan <= 0) return baseWeight; return baseWeight * wanToWeightMul(wan); }