PVPLogic.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import { Random } from "../core/utils/Random";
  2. export class PVPLogic {
  3. /**随机数种子(建议使用Date.now()) */
  4. private seed: number;
  5. /**基础伤害(配置) */
  6. private baseHit: number;
  7. /**第一组武将(前5个为自己的武将,后面放置好友武将,建议设置为进攻方武将,暨:自己的武将) */
  8. private g1: Array<PVPHeroData> = [];
  9. /**第二组武将(前5个为自己的武将,后面放置好友武将,建议设置为防守方武将,暨:被切磋玩家的武将) */
  10. private g2: Array<PVPHeroData> = [];
  11. /**第一组阵营加成 */
  12. public g1Camp: { attack: number, cri: number } = { attack: 0, cri: 0 };
  13. /**第二组阵营加成 */
  14. public g2Camp: { attack: number, cri: number } = { attack: 0, cri: 0 }
  15. /**线性随机数对象 */
  16. private random: Random;
  17. /**战报 */
  18. private pvpPages: Array<PVPPage> = [];
  19. /**胜者ID */
  20. private winner: number = 0;
  21. /**当前对战武将 */
  22. private curBattleHero: Map<number, PVPHeroData> = new Map();
  23. /**先手ID */
  24. private fristID: number = 0;
  25. /**后手ID */
  26. private lastID: number = 0;
  27. /**buff配置 */
  28. private buffConfig: any;
  29. /**羁绊id */
  30. public fetterID = 0;
  31. /**
  32. * PVP逻辑
  33. * @param g1 第一组武将(建议设置为进攻方武将,暨:自己的武将)
  34. * @param g2 第二组武将(建议设置为防守方武将,暨:被切磋玩家的武将)
  35. * @param seed 随机数种子(建议使用Date.now())
  36. * @param baseHit 基础伤害(配置)
  37. * @param buffConfig buff配置(配置)
  38. */
  39. constructor(g1: Array<PVPHeroData>, g2: Array<PVPHeroData>, seed: number, baseHit: number, buffConfig: any) {
  40. this.seed = seed;
  41. this.random = new Random(this.seed);
  42. this.g1 = g1.concat();
  43. this.g2 = g2.concat();
  44. this.baseHit = baseHit;
  45. this.buffConfig = buffConfig;
  46. this.checkCamp();
  47. }
  48. /**
  49. * 战斗开始
  50. * @returns pages 战报数据
  51. * @returns winner 胜者数据
  52. */
  53. public begin(): { pages: Array<PVPPage>, winner: number } {
  54. this.log("战斗开始");
  55. this.battle();
  56. return { pages: this.pvpPages, winner: this.winner };
  57. }
  58. /**战斗流程递归 */
  59. private battle() {
  60. if (this.curBattleHero.size < 2) {
  61. this.intoBattle();
  62. } else {
  63. if (this.curBattleHero.get(1)._att_count == 0 && this.curBattleHero.get(2)._att_count == 0) {
  64. this.fristID = this.checkFristAttack();
  65. this.lastID = this.fristID == 1 ? 2 : 1;
  66. this.log(`g${this.fristID}-->武将${this.curBattleHero.get(this.fristID).id},先手攻击`);
  67. this.attack(this.fristID);
  68. } else {
  69. let fromID = this.curBattleHero.get(this.fristID)._att_count > this.curBattleHero.get(this.lastID)._att_count ? this.lastID : this.fristID;
  70. this.attack(fromID);
  71. }
  72. }
  73. }
  74. /**武将出阵 */
  75. private intoBattle(): void {
  76. if (!this.curBattleHero.has(1)) {
  77. this.curBattleHero.set(1, this.g1.shift());
  78. this.pvpPages.push(new PVPPage(PVPPageType.intoBattle, 1, this.curBattleHero.get(1).id));
  79. 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}`);
  80. }
  81. if (!this.curBattleHero.has(2)) {
  82. this.curBattleHero.set(2, this.g2.shift());
  83. this.pvpPages.push(new PVPPage(PVPPageType.intoBattle, 2, this.curBattleHero.get(2).id));
  84. 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}`);
  85. }
  86. this.battle();
  87. }
  88. /**
  89. * 武将攻击
  90. * @param fromID 发生方ID
  91. */
  92. private attack(fromID: number): void {
  93. let defID = fromID == 1 ? 2 : 1;
  94. 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));
  95. let random = this.random.range(0, 10000);
  96. let isCRI = false;
  97. if (random <= 500 + this[`g${fromID}Camp`].cri) {
  98. hit = Math.floor(hit * 1.5);
  99. isCRI = true;
  100. }
  101. this.curBattleHero.get(defID)._hp -= hit;
  102. this.pvpPages.push(new PVPPage(PVPPageType.attack, fromID, this.curBattleHero.get(fromID).id, hit));
  103. this.curBattleHero.get(fromID)._att_count++;
  104. this.log(`g${fromID}-->武将${this.curBattleHero.get(fromID).id},是否暴击:${isCRI},攻击-->${hit},g${defID}-->防守武将剩余生命-->${this.curBattleHero.get(defID)._hp}`);
  105. if (this.curBattleHero.get(defID)._hp <= 0) {
  106. this.die(defID);
  107. return;
  108. }
  109. this.battle();
  110. }
  111. /**
  112. * 武将死亡
  113. * @param fromID 发生方ID
  114. */
  115. private die(fromID: number): void {
  116. this.pvpPages.push(new PVPPage(PVPPageType.die, fromID, this.curBattleHero.get(fromID).id));
  117. this.curBattleHero.get(fromID == 1 ? 2 : 1)._att_count = 0;
  118. this.log(`g${fromID}-->武将${this.curBattleHero.get(fromID).id},死亡`);
  119. this.curBattleHero.delete(fromID);
  120. if (this['g' + fromID].length == 0) {
  121. this.pvpPages.push(new PVPPage(PVPPageType.end, 0, 0));
  122. this.winner = fromID == 1 ? 2 : 1;
  123. this.log(`战斗结束:胜方:${this.winner}`);
  124. return;
  125. }
  126. this.battle();
  127. }
  128. /**检查阵营加成 */
  129. private checkCamp(): void {
  130. this.sortCamp(1);
  131. this.log(`g1阵营加成:${JSON.stringify(this.g1Camp)}`);
  132. this.sortCamp(2);
  133. this.log(`g2阵营加成:${JSON.stringify(this.g2Camp)}`);
  134. }
  135. /**整理阵营数据 */
  136. private sortCamp(id: number) {
  137. let camps = [{ camp: 1, count: 0 }, { camp: 2, count: 0 }, { camp: 3, count: 0 }, { camp: 4, count: 0 }];
  138. let length = this["g" + id].length >= 5 ? 5 : this["g" + id].length;
  139. for (let i = 0; i < length; i++) {
  140. let camp = parseInt(this["g" + id][i].camp);
  141. camps[camp - 1].count++;
  142. }
  143. camps = camps.sort(function (a, b) {
  144. if (a.count > b.count) {
  145. return -1;
  146. } else {
  147. return 1;
  148. }
  149. });
  150. switch (camps[0].count) {
  151. case 2:
  152. this.fetterID = 1;
  153. this[`g${id}Camp`] = { attack: this.buffConfig["1"].attackPer, cri: 0 };
  154. break;
  155. case 3:
  156. this.fetterID = 2;
  157. this[`g${id}Camp`] = { attack: this.buffConfig["2"].attackPer, cri: 0 };
  158. if (camps[1].count == 2) {
  159. this.fetterID = 3;
  160. this[`g${id}Camp`] = { attack: this.buffConfig["3"].attackPer, cri: this.buffConfig["6"].cri };
  161. }
  162. break;
  163. case 4:
  164. this.fetterID = 4;
  165. this[`g${id}Camp`] = { attack: this.buffConfig["4"].attackPer, cri: this.buffConfig["7"].cri };
  166. break;
  167. case 5:
  168. this.fetterID = 5;
  169. this[`g${id}Camp`] = { attack: this.buffConfig["5"].attackPer, cri: this.buffConfig["8"].cri };
  170. break;
  171. }
  172. }
  173. /**检查先手武将 */
  174. private checkFristAttack(): number {
  175. this.log("检查先手武将");
  176. if (this.curBattleHero.get(1).star != this.curBattleHero.get(2).star) {
  177. return this.curBattleHero.get(1).star > this.curBattleHero.get(2).star ? 1 : 2;
  178. }
  179. if (this.curBattleHero.get(1).color != this.curBattleHero.get(2).color) {
  180. return this.curBattleHero.get(1).color > this.curBattleHero.get(2).color ? 1 : 2;
  181. }
  182. return Math.floor(this.random.range(1, 3));
  183. }
  184. private useLog = true;
  185. private log(msg: string): void {
  186. //服务器可以根据seed写入不同文件文件,方便调试
  187. if (this.useLog) {
  188. console.log(msg);
  189. }
  190. }
  191. }
  192. /**
  193. * PVP武将数据
  194. */
  195. export class PVPHeroData {
  196. public id: number;
  197. public lv: number;
  198. public star: number;
  199. public color: number;
  200. public camp: number;
  201. public _hp: number = 100;
  202. public _att_count: number = 0;
  203. constructor(id: number, lv: number, star: number, color: number, camp: number) {
  204. this.id = id;
  205. this.lv = lv;
  206. this.star = star;
  207. this.color = color;
  208. this.camp = camp;
  209. }
  210. }
  211. /**
  212. * PVP战报数据
  213. */
  214. export class PVPPage {
  215. /**战报类型 */
  216. public type: PVPPageType = PVPPageType.none;
  217. /**发生事件方ID */
  218. public formID: number;
  219. /**如果是类型是攻击,则是伤害值 否则为0*/
  220. public hit: number = 0;
  221. /**发生事件的英雄ID */
  222. public heroID: number;
  223. constructor(type: PVPPageType, fromID: number, heroID: number, hit: number = 0) {
  224. this.type = type;
  225. this.formID = fromID;
  226. this.heroID = heroID;
  227. this.hit = hit;
  228. }
  229. }
  230. export enum PVPPageType {
  231. none,
  232. intoBattle,
  233. attack,
  234. die,
  235. end
  236. }