import { Random } from "../core/utils/Random"; export class PVPLogic { /**随机数种子(建议使用Date.now()) */ private seed: number; /**基础伤害(配置) */ private baseHit: number; /**第一组武将(前5个为自己的武将,后面放置好友武将,建议设置为进攻方武将,暨:自己的武将) */ private g1: Array = []; /**第二组武将(前5个为自己的武将,后面放置好友武将,建议设置为防守方武将,暨:被切磋玩家的武将) */ private g2: Array = []; /**第一组阵营加成 */ public g1Camp: { attack: number, cri: number } = { attack: 0, cri: 0 }; /**第二组阵营加成 */ public g2Camp: { attack: number, cri: number } = { attack: 0, cri: 0 } /**线性随机数对象 */ private random: Random; /**战报 */ private pvpPages: Array = []; /**胜者ID */ private winner: number = 0; /**当前对战武将 */ private curBattleHero: Map = new Map(); /**先手ID */ private fristID: number = 0; /**后手ID */ private lastID: number = 0; /**buff配置 */ private buffConfig: any; /**羁绊id */ public fetterID = 0; /** * PVP逻辑 * @param g1 第一组武将(建议设置为进攻方武将,暨:自己的武将) * @param g2 第二组武将(建议设置为防守方武将,暨:被切磋玩家的武将) * @param seed 随机数种子(建议使用Date.now()) * @param baseHit 基础伤害(配置) * @param buffConfig buff配置(配置) */ constructor(g1: Array, g2: Array, seed: number, baseHit: number, buffConfig: any) { this.seed = seed; this.random = new Random(this.seed); this.g1 = g1.concat(); this.g2 = g2.concat(); this.baseHit = baseHit; this.buffConfig = buffConfig; this.checkCamp(); } /** * 战斗开始 * @returns pages 战报数据 * @returns winner 胜者数据 */ public begin(): { pages: Array, winner: number } { this.log("战斗开始"); this.battle(); return { pages: this.pvpPages, winner: this.winner }; } /**战斗流程递归 */ private battle() { if (this.curBattleHero.size < 2) { this.intoBattle(); } else { if (this.curBattleHero.get(1)._att_count == 0 && this.curBattleHero.get(2)._att_count == 0) { this.fristID = this.checkFristAttack(); this.lastID = this.fristID == 1 ? 2 : 1; this.log(`g${this.fristID}-->武将${this.curBattleHero.get(this.fristID).id},先手攻击`); this.attack(this.fristID); } else { let fromID = this.curBattleHero.get(this.fristID)._att_count > this.curBattleHero.get(this.lastID)._att_count ? this.lastID : this.fristID; this.attack(fromID); } } } /**武将出阵 */ private intoBattle(): void { if (!this.curBattleHero.has(1)) { this.curBattleHero.set(1, this.g1.shift()); this.pvpPages.push(new PVPPage(PVPPageType.intoBattle, 1, this.curBattleHero.get(1).id)); this.log(`g1-->出战武将${this.curBattleHero.get(1).id},lv:${this.curBattleHero.get(1).lv},star:${this.curBattleHero.get(1).star},color:${this.curBattleHero.get(1).color},g1剩余武将:${this.g1.length}`); } if (!this.curBattleHero.has(2)) { this.curBattleHero.set(2, this.g2.shift()); this.pvpPages.push(new PVPPage(PVPPageType.intoBattle, 2, this.curBattleHero.get(2).id)); this.log(`g2-->出战武将${this.curBattleHero.get(2).id},lv:${this.curBattleHero.get(2).lv},star:${this.curBattleHero.get(2).star},color:${this.curBattleHero.get(2).color},g2剩余武将:${this.g2.length}`); } this.battle(); } /** * 武将攻击 * @param fromID 发生方ID */ private attack(fromID: number): void { let defID = fromID == 1 ? 2 : 1; let hit = Math.floor((this.baseHit * (1 + this[`g${fromID}Camp`].attack / 10000)) / Math.pow(2, this.curBattleHero.get(defID).lv - this.curBattleHero.get(fromID).lv)); let random = this.random.range(0, 10000); let isCRI = false; if (random <= 500 + this[`g${fromID}Camp`].cri) { hit = Math.floor(hit * 1.5); isCRI = true; } this.curBattleHero.get(defID)._hp -= hit; this.pvpPages.push(new PVPPage(PVPPageType.attack, fromID, this.curBattleHero.get(fromID).id, hit)); this.curBattleHero.get(fromID)._att_count++; this.log(`g${fromID}-->武将${this.curBattleHero.get(fromID).id},是否暴击:${isCRI},攻击-->${hit},g${defID}-->防守武将剩余生命-->${this.curBattleHero.get(defID)._hp}`); if (this.curBattleHero.get(defID)._hp <= 0) { this.die(defID); return; } this.battle(); } /** * 武将死亡 * @param fromID 发生方ID */ private die(fromID: number): void { this.pvpPages.push(new PVPPage(PVPPageType.die, fromID, this.curBattleHero.get(fromID).id)); this.curBattleHero.get(fromID == 1 ? 2 : 1)._att_count = 0; this.log(`g${fromID}-->武将${this.curBattleHero.get(fromID).id},死亡`); this.curBattleHero.delete(fromID); if (this['g' + fromID].length == 0) { this.pvpPages.push(new PVPPage(PVPPageType.end, 0, 0)); this.winner = fromID == 1 ? 2 : 1; this.log(`战斗结束:胜方:${this.winner}`); return; } this.battle(); } /**检查阵营加成 */ private checkCamp(): void { this.sortCamp(1); this.log(`g1阵营加成:${JSON.stringify(this.g1Camp)}`); this.sortCamp(2); this.log(`g2阵营加成:${JSON.stringify(this.g2Camp)}`); } /**整理阵营数据 */ private sortCamp(id: number) { let camps = [{ camp: 1, count: 0 }, { camp: 2, count: 0 }, { camp: 3, count: 0 }, { camp: 4, count: 0 }]; let length = this["g" + id].length >= 5 ? 5 : this["g" + id].length; for (let i = 0; i < length; i++) { let camp = parseInt(this["g" + id][i].camp); camps[camp - 1].count++; } camps = camps.sort(function (a, b) { if (a.count > b.count) { return -1; } else { return 1; } }); switch (camps[0].count) { case 2: this.fetterID = 1; this[`g${id}Camp`] = { attack: this.buffConfig["1"].attackPer, cri: 0 }; break; case 3: this.fetterID = 2; this[`g${id}Camp`] = { attack: this.buffConfig["2"].attackPer, cri: 0 }; if (camps[1].count == 2) { this.fetterID = 3; this[`g${id}Camp`] = { attack: this.buffConfig["3"].attackPer, cri: this.buffConfig["6"].cri }; } break; case 4: this.fetterID = 4; this[`g${id}Camp`] = { attack: this.buffConfig["4"].attackPer, cri: this.buffConfig["7"].cri }; break; case 5: this.fetterID = 5; this[`g${id}Camp`] = { attack: this.buffConfig["5"].attackPer, cri: this.buffConfig["8"].cri }; break; } } /**检查先手武将 */ private checkFristAttack(): number { this.log("检查先手武将"); if (this.curBattleHero.get(1).star != this.curBattleHero.get(2).star) { return this.curBattleHero.get(1).star > this.curBattleHero.get(2).star ? 1 : 2; } if (this.curBattleHero.get(1).color != this.curBattleHero.get(2).color) { return this.curBattleHero.get(1).color > this.curBattleHero.get(2).color ? 1 : 2; } return Math.floor(this.random.range(1, 3)); } private useLog = true; private log(msg: string): void { //服务器可以根据seed写入不同文件文件,方便调试 if (this.useLog) { console.log(msg); } } } /** * PVP武将数据 */ export class PVPHeroData { public id: number; public lv: number; public star: number; public color: number; public camp: number; public _hp: number = 100; public _att_count: number = 0; constructor(id: number, lv: number, star: number, color: number, camp: number) { this.id = id; this.lv = lv; this.star = star; this.color = color; this.camp = camp; } } /** * PVP战报数据 */ export class PVPPage { /**战报类型 */ public type: PVPPageType = PVPPageType.none; /**发生事件方ID */ public formID: number; /**如果是类型是攻击,则是伤害值 否则为0*/ public hit: number = 0; /**发生事件的英雄ID */ public heroID: number; constructor(type: PVPPageType, fromID: number, heroID: number, hit: number = 0) { this.type = type; this.formID = fromID; this.heroID = heroID; this.hit = hit; } } export enum PVPPageType { none, intoBattle, attack, die, end }