/** @format */ import {ComAttackable} from '../components/ComAttackable' import {ComRole} from '../components/ComRole' import {ComTransform} from '../components/ComTransform' import {ECSSystem} from '../lib/ECSSystem' import {FightWorld} from '../worlds/FightWorld' import {ComFindEnemy} from '../components/ComFindEnemy' import {ComCocosNode} from '../components/ComCocosNode' import {Data, Mgr} from '../../GameControl' import {cBody} from '../../collision/Body' import {ComDie} from '../components/ComDie' import {GenFilterKey} from '../lib/ECSComponent' import {EventRoleTip} from '../core/NodeEvent' import {BUFF_TYPE, ENTRY, FRAME_ANI_NAME, GAME_ROLE_TIP} from '../../enums/Enum' import {IAttackEffect} from '../core/GameInterface' import {ComBullet} from '../components/ComBullet' import {ComBehaviorTree} from '../components/ComBehaviorTree' const FILTER_ATTACKABLE = GenFilterKey([ComTransform, ComAttackable, ComRole, ComCocosNode, ComBehaviorTree], [ComDie]) export class SysAttack extends ECSSystem { /** 连接 */ public onAdd(world: FightWorld): void {} /** 断开连接 */ public onRemove(world: FightWorld): void {} /** 添加实体 */ public onEntityEnter(world: FightWorld, entity: number): void {} /** */ public onEntityLeave(world: FightWorld, entity: number): void {} /** 更新 */ public onUpdate(world: FightWorld, dt: number): void { let filter = world.getFilter(FILTER_ATTACKABLE) let rate = Data.game.rateNum filter.walk((entity: number) => { let comRole = world.getComponent(entity, ComRole) let comAttackable = world.getComponent(entity, ComAttackable) let comTransform = world.getComponent(entity, ComTransform) let comCocosNode = world.getComponent(entity, ComCocosNode) if (!comAttackable.dirty) return comAttackable.countDown -= dt if (comAttackable.countDown <= 0) { comAttackable.dirty = false } if (!comAttackable.hurtFrameCompleted && comAttackable.countDown <= comAttackable.hurtFrame) { let comFindEnemy = world.getComponent(entity, ComFindEnemy) let comRoleEnemy = world.getComponent(comAttackable.curAttack, ComRole) let comTransformEnemy = world.getComponent(comAttackable.curAttack, ComTransform) if (world.isDie(comAttackable.curAttack)) return comAttackable.hurtFrameCompleted = true comRole.attackNum += 1 let iAttack: IAttackEffect = { isCrit: Math.getProb(comRole.attackCrit / rate), isBack: Math.sign(comTransform.dir.x) == Math.sign(comTransformEnemy.dir.x), } //闪避率=1-(1+命中/10000)*(1-闪避/10000) 闪避率0%-90% let dodgeRate = 1 - (1 + comRole.hit / Data.game.rateNum) * (1 - comRoleEnemy.dodge / Data.game.rateNum) dodgeRate = Math.max(dodgeRate, 0) dodgeRate = Math.min(dodgeRate, 0.9) let isDodge = comRoleEnemy && Math.getProb(dodgeRate) let hurt = 0 let isKill = false if (comAttackable.isMelee) { hurt = world.getHurtByAttackRole(comRole, comAttackable.curAttack, iAttack) Mgr.audio.playSFX(comRole.roleCfg.sound) if (!isDodge) { if (hurt > 0) { //被反弹伤害 world.changeHpByRebound(entity, comAttackable.curAttack) //普攻吸血 if (comRole.entryMap.get(ENTRY.hurt2HP)?.num > 0) { let addHPNum = (comRole.entryMap.get(ENTRY.hurt2HP).num * hurt) / Data.game.rateNum world.addHP(addHPNum, entity) } } // world.changeHpByHurt( // comAttackable.curAttack, // hurt, // iAttack.isCrit, // comRole.roleCfg.hitID ? comRole.roleCfg.hitID : FRAME_ANI_NAME.normalHurt, // ) //临时屏蔽近战攻击特效 world.changeHpByHurt(comAttackable.curAttack, hurt, iAttack.isCrit, comRole.roleCfg.hitID) //杀人+1 if (world.isDie(comRoleEnemy)) { comRole.killNum += 1 isKill = true } } else { let curAttackCocosNode = world.getComponent(comAttackable.curAttack, ComCocosNode) curAttackCocosNode.events.push(new EventRoleTip(GAME_ROLE_TIP.missTip, 0, 'miss')) } //处理近战buff comRole.buffs.forEach(buff => { let buffConfig = buff.buffCfg if ( (buffConfig.buffType == BUFF_TYPE.attackGetHp || (buffConfig.buffType == BUFF_TYPE.attackCritGetHp && iAttack.isCrit)) && hurt > 0 && !isDodge ) { //攻击吸血 let addHPNum = (hurt * buffConfig.attrRate[0]) / rate world.addHP(addHPNum, entity) } else if (buffConfig.buffType == BUFF_TYPE.killNum && isKill) { //根据杀敌加攻击 comRole.attack += (comRole.roleCfg.attack * buffConfig.attrRate[0]) / rate } }) } else { let bullets = world.createBulletEntity(entity, iAttack.isCrit) bullets.forEach(bullet => { let comBullet = world.getComponent(bullet, ComBullet) comBullet.fightData.attackNum = comRole.attackNum }) } let sputterRate: number = 0 comRole.buffs.forEach(buff => { // 溅射比例 if (buff.buffCfg.buffType == BUFF_TYPE.sputter && buff.buffCfg.attrRate[0] > sputterRate) { sputterRate = buff.buffCfg.attrRate[0] } }) if (sputterRate > 0 && !isDodge) { iAttack.sputter = sputterRate comFindEnemy.attackCObject.containsBody.forEach((cBody: cBody, entityOther: number) => { // 溅射 if (entityOther != comAttackable.curAttack && !world.isDie(entityOther)) { let otherComTransform = world.getComponent(entityOther, ComTransform) if ( (comTransform.dir.x > 0 && otherComTransform.x - comTransform.x >= Data.game.meleeRange / 2) || (!(comTransform.dir.x > 0) && otherComTransform.x - comTransform.x <= Data.game.meleeRange / 2) ) { world.changeHpByHurt( entityOther, world.getHurtByAttackRole(comRole, entityOther, iAttack), false, 0, ) } } }) } } return false }) } }