import { Equip, Skills, Monster, Attribute, Player, battle_msg_types } from '@/config'; import { randonBootyEquip, deepCopy, replace, callReducPercent, callDmgReduc, callDmgPercent } from '@/tool'; import i18n from '@/config/i18n'; const { t } = i18n; export class BattleRole { attr: Attribute; actions: Skills.Skill[] = new Array(); passives: Skills.Skill[] = new Array(); commit; type: string; attackBuff: Map = new Map(); attackedBuff: Map = new Map(); //临时状态 action: Skills.ActionSkill | null = null; atk: number = 0; dmg: number = 0; baseDmg: number = 0; crit: boolean = false; extraAttr: Attribute = new Attribute(); shield: number = 0; skillPercent: number = 100; constructor(attr: Attribute, commit, type: string) { this.attr = attr; this.commit = commit; this.type = type; this.addSkill(attr.skill); //添加默认主动技能普通攻击 this.initTmp(); } initTmp = () => { this.action = null; this.atk = 0; this.dmg = 0; this.baseDmg = 0; this.crit = false; this.extraAttr = new Attribute(); this.extraAttr.hp = 0; this.extraAttr.critDmg = 0; this.shield = Math.ceil(this.shield * 0.9); this.skillPercent = 0; }; addSkill = (skillName, lv?) => { lv = lv || 1; const skills = createSkill(skillName, lv); skills.forEach((skill) => { const type = skill.type; if (type == Skills.skill_type_action) { this.actions.push(skill); //主动技能 } else if (type == Skills.skill_type_passive) { this.passives.push(skill); //被动技能 } }); }; onStartBattle = (target: BattleRole) => { //技能排序 this.actions.sort((a, b) => { return a.order - b.order; }); this.passives.sort((a, b) => { return a.order - b.order; }); //战斗开始前触发的技能 this.passives.forEach((skill) => { skill.beforeBattle(this, target); }); }; attack = (target: BattleRole) => { //选择使用的主动技能 this.actions.forEach((skill) => { skill.beforeAtk(this, target); }); //攻击前触发的被动技能 this.passives.forEach((skill) => { skill.beforeAtk(this, target); }); //攻击前计算双方BUFF this.callAttackBuff(); target.callAttackedBuff(); this.action?.use(this, target); //攻击后触发的被动技能 this.passives.forEach((skill) => { skill.afterAtk(this, target); }); //触发攻击目标的反制技能 target.onAttacked(this); }; onAttacked = (target: BattleRole) => { //触发反制技能 this.passives.forEach((skill) => { skill.onAtked(this, target); }); //初始化临时状态 this.initTmp(); }; atteckLog = (log: string) => { const type = (this.crit ? battle_msg_types.crit : battle_msg_types.attack) + '_' + this.type; this.commit('set_sys_info', { type: type, msg: log }); }; gainLog = (log: string) => { const type = battle_msg_types.gain + '_' + this.type; this.commit('set_sys_info', { type: type, msg: log }); }; debuffLog = (log: string) => { const type = battle_msg_types.debuff + '_' + this.type; this.commit('set_sys_info', { type: type, msg: log }); }; extraDmgLog = (log: string) => { const type = battle_msg_types.extra + '_' + this.type; this.commit('set_sys_info', { type: type, msg: log }); }; addHp = (hp: number) => { if (hp < 0 && this.shield > 0) { if (this.shield > -1 * hp) { this.shield += hp; return; } else { hp += this.shield; this.shield = 0; } } if (this.type == 'player') { this.commit('add_player_curhp', hp); } else { this.attr.curHp += hp; } }; getBootys = (target: BattleRole) => { //战斗结束后触发的技能 this.passives.forEach((skill) => { skill.afterBattle(this, target); }); const equips = randonBootyEquip(target.attr); const coins = target.attr.coins; return { equips: equips, coins: coins }; }; isDeath = () => { return this.attr.curHp <= 0; }; /** * * @param skillPercent 技能伤害倍率 * @param target 被攻击目标 * @returns */ callDmg = (target: BattleRole) => { const attr = this.attr; const extra = this.extraAttr; const baseAtk = attr.baseAtk + extra.baseAtk; //基础攻击 const atkPercent = 1 + (attr.atkPercent + extra.atkPercent) / 100; //攻击加成 this.atk = baseAtk * atkPercent; //回合最终攻击力 const dmgPercent = callDmgPercent(attr.dmgPercent, extra.dmgPercent) / 100; //伤害加成 const factor = Math.random() * 0.1 + 0.95; //伤害随机系数 this.baseDmg = this.atk * (1 + dmgPercent) * (this.skillPercent / 100) * factor; //造成伤害 const crit = attr.crit + extra.crit - target.attr.critAvoid - target.extraAttr.critAvoid; //最终暴击率 this.crit = Math.random() < crit / 100; if (this.crit) { let critDmg = attr.critDmg + extra.critDmg - target.attr.critDmgReduc - target.extraAttr.critDmg; //目标最终承受暴击伤害 critDmg = critDmg < 100 ? 100 : critDmg; //暴击伤害不低于100% this.baseDmg *= critDmg / 100; //暴击时目标承受伤害 } const reducPercent = callReducPercent(target.attr.def + target.extraAttr.def, target.attr.lv); //目标防御提供的减伤比例 const dmgReduc = callDmgReduc(target.attr.dmgReduc, target.extraAttr.dmgReduc); //目标伤害减免 const takeDmgPercent = (1 - reducPercent) * (1 - dmgReduc / 100); //目标承受伤害比例 const bloc = target.attr.bloc + target.extraAttr.bloc; //目标格挡值 const dmg = Math.ceil(this.baseDmg * takeDmgPercent - bloc); //目标承受伤害 this.dmg = dmg < 1 ? 1 : dmg; }; putBuff(buff: Skills.AttackBuff, retains?: string[]) { const name = buff.name; const type = buff.type; const exit: Skills.Buff = this[type].get(name); this[type].set(name, buff); if (exit) { if (retains) { retains.forEach((key) => { buff[key] = exit[key]; }); } buff.addLayer(exit.layer); } } callAttackBuff() { this.attackBuff.forEach((value: Skills.Buff, key: string) => { value.takeEffect(this); }); } callAttackedBuff() { this.attackedBuff.forEach((value: Skills.Buff, key: string) => { value.takeEffect(this); }); } checkBuff() { checkBuf(this.attackBuff); checkBuf(this.attackedBuff); } } const checkBuf = (map: Map) => { const keys: string[] = new Array(); map.forEach((value: Skills.Buff, key: string, map: Map) => { if (!value || !value.check()) { keys.push(key); } }); keys.forEach((key: string) => { map.delete(key); }); }; export const createBattleRole = (player: Player, monster: Monster, commit) => { const playerRole = new BattleRole(player.attribute, commit, 'player'); const palyerEquips = [player.weapon, player.armor, player.neck, player.ring, player.jewelry, player.pants, player.shoes, player.bracers]; palyerEquips.forEach((equip) => { equip && playerRole.addSkill(equip.base.skill, equip.lv); }); monster = deepCopy(monster); monster.curHp = monster.hp; const monsterRole = new BattleRole(monster, commit, monster.type); playerRole.onStartBattle(monsterRole); monsterRole.onStartBattle(playerRole); return { player: playerRole, monster: monsterRole }; }; export const battleOneBout = (player: BattleRole, monster: BattleRole): boolean => { player.attack(monster); if (player.isDeath() || monster.isDeath()) { return true; } monster.attack(player); if (player.isDeath() || monster.isDeath()) { return true; } player.checkBuff(); monster.checkBuff(); return false; }; /** * 初始化装备技能 * @param equip 装备 * @returns */ export const createEquipSkill = (equip): Skills.Skill[] => { if (!equip) { return []; } return createSkill(equip.base.skill, equip.lv); }; /** * 初始化技能 * @param skillName 技能名称 * @returns */ export const createSkill = (skillName, lv): Skills.Skill[] => { const skills: Skills.Skill[] = new Array(); if (!skillName) { return skills; } const names: string[] = skillName.split(','); names.forEach((name) => { const clazz = Skills[name]; if (clazz) { const skill: Skills.Skill = new clazz(); skill.lv = lv; skills.push(skill); } }); return skills; };