296 lines
9.5 KiB
TypeScript
296 lines
9.5 KiB
TypeScript
|
|
import { getAtkTarget } from "./atkTarget";
|
|
import { getSkillConf, randNumber } from "./fightFun";
|
|
import { FightObj, fightResult, joinFightData, recordDataType, roleDataType } from "./fightType";
|
|
import { Player } from "./Player";
|
|
import { Role } from "./Role";
|
|
|
|
export class FightControl {
|
|
startTime: number = Date.now();
|
|
//所有战斗成员,包含双方的所有“伙伴”
|
|
fightRoles: k_v<Role> = {};
|
|
//所有战斗对象,包含了双方的“伙伴”和“主角”
|
|
fightRolesArr: FightObj[] = [];
|
|
fightOver = false;
|
|
roundNums = 0;
|
|
recordData: recordDataType[] = [];
|
|
event = new G.getEvent(999);
|
|
// event = new myEventEmitter();
|
|
initial: joinFightData[];
|
|
winSide: number;
|
|
totalDamage = { "0": 0, "1": 0 };
|
|
//战斗统计
|
|
fightStatistics: { [k: string]: { [k: string]: number; }; } = {};
|
|
player_0: FightObj = null;
|
|
player_1: FightObj = null;
|
|
recordSkillDps: { [key: string]: number } = {};
|
|
constructor(public DATA: joinFightData[], public maxRoundNums: number = 30, public fightType: 'pvp' | 'pve' = 'pve') {
|
|
this.initial = JSON.parse(JSON.stringify(DATA));
|
|
this.initControl();
|
|
this.addFightObj();
|
|
this.startTurnRound();
|
|
}
|
|
|
|
/**
|
|
* 释放内存资源
|
|
*/
|
|
release(){
|
|
this.fightRolesArr.map( obj =>{
|
|
obj?.release();
|
|
});
|
|
this.fightRoles = null;
|
|
this.fightRolesArr = null;
|
|
this.recordData = null;
|
|
this.event.removeAllListeners();
|
|
this.event = null;
|
|
this.initial = null;
|
|
this.fightStatistics = null;
|
|
this.player_0 = null;
|
|
this.player_1 = null;
|
|
this.recordSkillDps = null;
|
|
this.DATA = null;
|
|
}
|
|
|
|
initControl() {
|
|
// this.event.setMaxListeners(1000);
|
|
}
|
|
|
|
addFightObj() {
|
|
for (let side = 0; side < this.DATA.length; side++) {
|
|
this.DATA[side].player.side = side.toString();
|
|
this.DATA[side].player.pos = 7;
|
|
|
|
let _data = this.DATA[side];
|
|
let _joindataRole = _data.roles;
|
|
for (let key in _joindataRole) {
|
|
let d = _joindataRole[key];
|
|
d.pos = key;
|
|
d.side = side.toString();
|
|
this.addRole(_joindataRole[key]);
|
|
}
|
|
this.addPlyer(_data.player);
|
|
};
|
|
}
|
|
|
|
addRole(data: roleDataType) {
|
|
if (data.attr.hp <= 0) return;
|
|
let role = new Role(this, data);
|
|
this.fightRoles[role.rid] = role;
|
|
this.fightRolesArr.push(role);
|
|
}
|
|
|
|
addPlyer(data: joinFightData['player']) {
|
|
let player = new Player(this, data);
|
|
this.fightRolesArr.push(player);
|
|
this['player_' + data.side] = player;
|
|
}
|
|
|
|
|
|
/**
|
|
* 战斗循环
|
|
*/
|
|
startTurnRound() {
|
|
while (!this.fightOver) {
|
|
this._tunrRound();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 每轮次战斗具体实现
|
|
*/
|
|
_tunrRound() {
|
|
if (this.roundNums == 0) this.beforeSkill();
|
|
|
|
this.roundNums += 1;
|
|
this.record({ act: 'trun', roundNums: this.roundNums });
|
|
this.event.emit('fightEvent_roundNums', { "turn": this.roundNums });
|
|
|
|
|
|
this.fightRolesArr.sort((a, b) => {
|
|
let aSeep = a.getData('speed') * (1 + a.getDataPro('speed'));
|
|
let bSeep = b.getData('speed') * (1 + b.getDataPro('speed'));
|
|
if (aSeep != bSeep) {
|
|
return bSeep - aSeep;
|
|
} else {
|
|
return parseInt(a.roleData.side) - parseInt(b.roleData.side)
|
|
}
|
|
});
|
|
// if(G.config.debug) console.log(this.roundNums)
|
|
this.fightRolesArr.map(role => role.addpkNum = 0);
|
|
for (var i = 0; i < this.fightRolesArr.length; i++) {
|
|
this.checkEnd();
|
|
if (this.fightOver) break;
|
|
let role = this.fightRolesArr[i];
|
|
if (role.isDead || !role.isHasFightSkills) continue;
|
|
this.record({ act: 'startAct', fromRole: role.rid });
|
|
role.atk();
|
|
this.record({ act: 'stopAct', fromRole: role.rid });
|
|
//判断是否能两次行动
|
|
if (this.atkAgain(role)) {
|
|
i--;
|
|
}
|
|
if (role.hasbuff("addpk") && role.addpkNum == 0) {
|
|
i--;
|
|
role.clearBuff("addpk");
|
|
role.addpkNum += 1
|
|
}
|
|
}
|
|
|
|
this.checkEnd();
|
|
}
|
|
|
|
atkAgain(role: FightObj) {
|
|
let rid = role.rid;
|
|
if (rid.indexOf('player') != -1) return false;
|
|
let shiqi = role.getData('shiqi') * (1 + role.getDataPro('shiqi'));
|
|
let randnum = 1 + shiqi / (shiqi + 100 + role.getData('lv') * 100);
|
|
return randNumber() > randnum;
|
|
}
|
|
|
|
/** 战前技能检查 */
|
|
beforeSkill() {
|
|
this.eachLiveRoles((role) => {
|
|
let heroId = role.roleData.heroId;
|
|
// let shiwu = role.roleData?.shiwu || {};
|
|
// let talent = role.roleData?.talent || {};
|
|
let skills = G.gc.heroskill[heroId][role.roleData.jieji || 0].bdskill || [];
|
|
skills = skills.concat(role.roleData.attr.skillArr);
|
|
|
|
// for (let key in shiwu) {
|
|
// let zhushuan = shiwu[key]?.zhuanshu;
|
|
// if (!zhushuan) continue;
|
|
// if (zhushuan.skill) skills.push(zhushuan.skill);
|
|
// };
|
|
// const hero_tf = G.gc.hero_tf;
|
|
// for (let key in talent) {
|
|
// let cdata = hero_tf[key][talent[key]];
|
|
// if (cdata && cdata.skill_effect) skills.push(cdata.skill_effect);
|
|
// }
|
|
|
|
// skills.push('tx06309');
|
|
|
|
// if (!skills) return;
|
|
skills.forEach(_skill => {
|
|
let askillconf = getSkillConf(_skill);
|
|
if (!askillconf) return console.log('没有技能配置-->', _skill);
|
|
let randnum = askillconf.randnum;
|
|
if (randnum == '' || randNumber() > randnum) return;
|
|
let targets = getAtkTarget(role.fightControl, role , askillconf);
|
|
targets.forEach(_target => {
|
|
_target.runAfterSkill({
|
|
fromRole: role,
|
|
toRole: _target,
|
|
fromSkill: null,
|
|
skillConf: askillconf,
|
|
targetCount: targets.length
|
|
}, 'beforeSkill');
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
checkEnd() {
|
|
if (this.fightOver) return;
|
|
if (this.roundNums > this.maxRoundNums) this.fightOver = true;
|
|
|
|
let side0Arr = [], side1Arr = [];
|
|
this.eachLiveRoles((role) => {
|
|
if (role.roleData.side == '0') {
|
|
side0Arr.push(role);
|
|
} else {
|
|
side1Arr.push(role);
|
|
}
|
|
});
|
|
|
|
if (side0Arr.length == 0 || side1Arr.length == 0) {
|
|
this.fightOver = true;
|
|
}
|
|
|
|
if (this.fightOver) this.stopFight(side0Arr, side1Arr);
|
|
}
|
|
|
|
stopFight(side0Arr: Role[], side1Arr: Role[]) {
|
|
/*
|
|
获胜条件判断:
|
|
数量相同,人数多的获胜
|
|
人数一致,战力低的获胜
|
|
战力一直, 随机获胜
|
|
*/
|
|
let winside = 0;
|
|
if (this.fightType == "pve") {
|
|
winside = side1Arr.length != 0 ? 1 : 0;
|
|
} else {
|
|
let power0 = this.DATA[0].player.power, power1 = this.DATA[1].player.power;
|
|
if (side0Arr.length > side1Arr.length) {
|
|
winside = 0;
|
|
} else if (side0Arr.length < side1Arr.length) {
|
|
winside = 1;
|
|
} else if (power0 < power1) {
|
|
winside = 0;
|
|
} else if (power0 > power1) {
|
|
winside = 1;
|
|
} else {
|
|
winside = [0, 1].random();
|
|
}
|
|
}
|
|
|
|
this.winSide = winside as 1 | 0;
|
|
this.record({ act: 'fightEnd', winSide: this.winSide });
|
|
this.event.removeAllListeners()
|
|
}
|
|
|
|
eachLiveRoles(callback: (role: Role) => void) {
|
|
for (let rid in this.fightRoles) {
|
|
// if (this.fightOver) return;
|
|
if (!this.fightRoles[rid]) continue;
|
|
// 排除死亡
|
|
if (this.fightRoles[rid].isDead) continue;
|
|
callback && callback(this.fightRoles[rid]);
|
|
}
|
|
}
|
|
|
|
eachDeadRoles(callback: (role: Role) => void) {
|
|
for (let rid in this.fightRoles) {
|
|
if (this.fightOver) return;
|
|
if (!this.fightRoles[rid]) continue;
|
|
if (!this.fightRoles[rid].isDead) continue;
|
|
callback && callback(this.fightRoles[rid]);
|
|
}
|
|
}
|
|
|
|
record(data: recordDataType) {
|
|
this.recordData.push(data);
|
|
}
|
|
|
|
getRecordIdx() {
|
|
return this.recordData.length - 1;
|
|
}
|
|
|
|
fixRecordByIdx(idx: number, data: k_v<any>) {
|
|
this.recordData[idx] = Object.assign(this.recordData[idx], data);
|
|
// this.recordData[idx].targets = targets;
|
|
}
|
|
|
|
recordStatistics(role: FightObj, key: 'hit' | 'def', val: number) {
|
|
if (!this.fightStatistics[role.rid]) this.fightStatistics[role.rid] = {};
|
|
if (!this.fightStatistics[role.rid][key]) this.fightStatistics[role.rid][key] = 0;
|
|
this.fightStatistics[role.rid][key] += val;
|
|
}
|
|
|
|
debug(callback: () => void) {
|
|
// callback();
|
|
}
|
|
|
|
getResult(): fightResult {
|
|
return {
|
|
winSide: this.winSide,
|
|
fightLog: this.recordData,
|
|
initData: this.initial,
|
|
fightData: this.DATA,
|
|
totalDamage: this.totalDamage,
|
|
fightStatistics: this.fightStatistics
|
|
};
|
|
}
|
|
}
|
|
|