GlobalManager.ts 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. /** @format */
  2. import {ccUtils} from '../utils/ccUtils'
  3. import {Data, Mgr} from '../GameControl'
  4. import {BaseUI} from '../ui/BaseUI'
  5. import {card, equip, hero, idNum} from '../proto/typedef'
  6. import {RoleConfig} from '../config/RoleConfig'
  7. import {CardSkillConfig} from '../config/CardSkillConfig'
  8. import {CardConsumeConfig} from '../config/CardConsumeConfig'
  9. import {RoleQualityConfig} from '../config/RoleQualityConfig'
  10. import {ArmorConfig} from '../config/ArmorConfig'
  11. import {EquipmentQualityConfig} from '../config/EquipmentQualityConfig'
  12. import {TalentConfig} from '../config/TalentConfig'
  13. import {EntryConfig} from '../config/EntryConfig'
  14. import {
  15. ATTR_NAME,
  16. BUILDING,
  17. CONDITION_FUNC,
  18. ENTRY,
  19. GAME_TYPE,
  20. GOODS,
  21. GOODS_TYPE,
  22. LANGUAGE_TYPE,
  23. LOCAL,
  24. MOD,
  25. PREFAB_TYPE,
  26. PROFESSION,
  27. RECRUIT_TYPE,
  28. ROLE_TYPE,
  29. } from '../enums/Enum'
  30. import {IAdStatus, IBaseAttr, ICard, ICardDebris, ICastleSkill, IEquip, IRole} from '../interface/GlobalInterface'
  31. import {FunctionsConfig} from '../config/FunctionsConfig'
  32. import {StageInfoConfig} from '../config/StageInfoConfig'
  33. import {UI} from '../enums/UI'
  34. import {ConstValue} from '../data/ConstValue'
  35. import {GoodsConfig} from '../config/GoodsConfig'
  36. import {boxGetAward} from '../proto/game'
  37. import {msgCmd} from '../proto/msg_cmd'
  38. import {ItemUICfg} from '../interface/UIInterface'
  39. import UserGuide from '../userguide/UserGuide'
  40. import value = cc.js.value
  41. import {CastleSkillConfig} from '../config/CastleSkillConfig'
  42. import {MonsterManualConfig} from '../config/MonsterManualConfig'
  43. export class GlobalManager {
  44. userGuideCom: UserGuide
  45. curGuideStep: number = 0
  46. lastPower: number
  47. adInfoStorage: any
  48. startPoint: cc.Vec2 //开始触摸的位置
  49. curPoint: cc.Vec2 //触摸的当前位置
  50. moveOverstepPx: number = 30 //触摸物品后移动超过多少像素就不弹出详细信息
  51. reset() {
  52. this.adInfoStorage = null
  53. this.curGuideStep = 0
  54. }
  55. getItemNode(parent, type: PREFAB_TYPE, url: string, baseUI: BaseUI) {
  56. let pool = Data.main.itemsPoolMap.get(`${type}_${url}`)
  57. if (!pool) {
  58. pool = new cc.NodePool()
  59. Data.main.itemsPoolMap.set(`${type}_${url}`, pool)
  60. }
  61. parent.children.forEach(child => {
  62. if (PREFAB_TYPE[type] && child.name != `${type}_${url}`) {
  63. Data.main.itemsPoolMap.get(child.name)?.put(child)
  64. }
  65. })
  66. let node = cc.find(`${type}_${url}`, parent)
  67. if (!node) {
  68. node = pool.size() ? pool.get() : cc.instantiate(Data.main.itemsPrefabMap.get(type))
  69. baseUI.itemsNodes.push(node)
  70. }
  71. node.parent = parent
  72. node.name = `${type}_${url}`
  73. node['uiID'] = baseUI.uiID
  74. return node
  75. }
  76. initRoleItem(iRole: IRole, parent: cc.Node, baseUI: BaseUI, cfg?: ItemUICfg) {
  77. let node = this.initCfgRoleItem(iRole.cfg, parent, baseUI, cfg)
  78. ccUtils.setLabel(cfg && cfg.hideLv ? '' : `lv.${iRole.hero.lv}`, node, 'lv')
  79. }
  80. initCfgRoleItem(
  81. {quality, qualityType, profession, url, type, ID, cost},
  82. parent: cc.Node,
  83. baseUI: BaseUI,
  84. cfg?: ItemUICfg,
  85. ): cc.Node {
  86. let node = this.getItemNode(parent, PREFAB_TYPE.role, `${ID}_${qualityType}`, baseUI)
  87. baseUI.loadNotRefTexImg(`Public/goodsQuality/item_frame${qualityType}`, node, 'item_frame')
  88. baseUI.loadNotRefTexImg(`Public/role/icon/${url}`, node, 'icon')
  89. let professionNode = cc.find('role_type', node)
  90. professionNode.active = !cfg || !cfg.hideProfession
  91. baseUI.loadNotRefTexImg(`Public/role/role_type_${profession}`, professionNode)
  92. let maxGrade = Data.user.maxGradeArr[qualityType - 1]
  93. // let grade = cc.find('grade', node)
  94. let gradeNum = Data.user.gradeArr[quality - 1]
  95. let stars = cc.find('stars', node)
  96. if (stars) {
  97. stars.active = maxGrade > 0 && gradeNum > 0
  98. ccUtils.instantChildren(stars.children[0], gradeNum)
  99. // if (gradeNum > 0) {
  100. // baseUI.loadNotRefTexImg(`Public/role/grade_${qualityType}`, grade)
  101. // ccUtils.setLabel(gradeNum.toString(), grade, 'lv')
  102. // }
  103. }
  104. let isOnly = type == ROLE_TYPE.only
  105. let special = cc.find('item_special', node)
  106. if (special) {
  107. special.active = isOnly
  108. if (special.active) baseUI.loadNotRefTexImg(`Public/role/item_special_frame${qualityType}`, special)
  109. }
  110. ccUtils.setLabel('', node, 'lv')
  111. let costNode = cc.find('cost', node)
  112. if (costNode) {
  113. costNode.active = cost > 0 && !cfg?.hideCost
  114. if (cost > 0) ccUtils.setLabel(cost.toString(), costNode, 'lb')
  115. }
  116. return node
  117. }
  118. initRoleSpine(iRole: IRole, node: cc.Node, childUrl?: string) {
  119. if (childUrl) {
  120. node = cc.find(childUrl, node)
  121. }
  122. if (!node['_originScale']) {
  123. node['_originScale'] = node.scale
  124. }
  125. node.scale = (node['_originScale'] * iRole.cfg.uiScale) / 100
  126. let skeleton: sp.Skeleton = node.getComponent(sp.Skeleton)
  127. skeleton.skeletonData = Data.main.roleSpineMap.get(iRole.cfg.url)
  128. skeleton.setAnimation(0, 'stand', true)
  129. }
  130. initRoleSpineByName(name: string, node: cc.Node, childUrl?: string) {
  131. if (childUrl) {
  132. node = cc.find(childUrl, node)
  133. }
  134. let skeleton: sp.Skeleton = node.getComponent(sp.Skeleton)
  135. skeleton.skeletonData = Data.main.roleSpineMap.get(name)
  136. skeleton.setAnimation(0, 'stand', true)
  137. }
  138. initCardItem(iCard: ICard, parent: cc.Node, baseUI: BaseUI, cfg?: ItemUICfg) {
  139. let node = this.getItemNode(parent, PREFAB_TYPE.card, `${iCard.card.id}_${iCard.cfg.qualityType}`, baseUI)
  140. ccUtils.setLabel(
  141. `lv.${iCard.card.lv}${cfg && cfg.lvMax ? '/' + RoleQualityConfig[iCard.cfg.quality].maxLv : ''}`,
  142. node,
  143. 'lv',
  144. )
  145. baseUI.loadNotRefTexImg(`Public/goodsQuality/item_frame${iCard.cfg.qualityType}`, node, 'item_frame')
  146. baseUI.loadNotRefTexImg(`Public/card/icon/${iCard.cfg.url}`, node, 'icon')
  147. let maxGrade = Data.user.maxGradeArr[iCard.cfg.qualityType - 1]
  148. let grade = cc.find('grade', node)
  149. if (grade) {
  150. grade.active = maxGrade > 0 && iCard.grade > 0
  151. if (iCard.grade > 0) {
  152. baseUI.loadNotRefTexImg(`Public/role/grade_${iCard.cfg.qualityType}`, grade)
  153. ccUtils.setLabel(iCard.grade.toString(), grade, 'lv')
  154. }
  155. }
  156. }
  157. initCardDebrisItem(card: ICardDebris, parent: cc.Node, baseUI: BaseUI): cc.Node {
  158. let node = this.getItemNode(parent, PREFAB_TYPE.cardDebris, `${card.id}_${card.cfg.qualityType}`, baseUI)
  159. baseUI.loadNotRefTexImg(`Public/goodsQuality/item_frame${card.cfg.qualityType}`, node, 'item_frame')
  160. baseUI.loadNotRefTexImg(`Public/card/icon/${card.cfg.url}`, node, 'icon')
  161. ccUtils.setSpriteGray(true, node, 'icon')
  162. cc.find('debris', node).active = true
  163. return node
  164. }
  165. detailsTouchStart(flag, event) {
  166. this.startPoint = event.getLocation()
  167. this.curPoint = event.getLocation() //如果不移动的话当前位置会是空、所以默认给开始位置
  168. }
  169. detailsTouchMove(flag, event) {
  170. this.curPoint = event.getLocation()
  171. }
  172. showGoodsDetails(goodID: number) {
  173. let isXOverstep = Math.abs(this.curPoint.x - this.startPoint.x) <= this.moveOverstepPx
  174. let isYOverstep = Math.abs(this.curPoint.y - this.startPoint.y) <= this.moveOverstepPx
  175. if (isXOverstep && isYOverstep) {
  176. Mgr.ui.show(UI.ItemDetailsUI, Mgr.goods.getGoodShowInfo(goodID))
  177. }
  178. }
  179. initEquipItem(equip: IEquip, parent: cc.Node, baseUI: BaseUI, cfg: ItemUICfg = {showDetails: false}) {
  180. let node = Mgr.global.getItemNode(
  181. parent,
  182. PREFAB_TYPE.equip,
  183. `${equip.equip.id}_${equip.cfg.qualityType}`,
  184. baseUI,
  185. )
  186. node.targetOff(this)
  187. if (cfg && cfg.showDetails) {
  188. node.on(cc.Node.EventType.TOUCH_START, this.detailsTouchStart.bind(this, true), this)
  189. node.on(cc.Node.EventType.TOUCH_END, this.showGoodsDetails.bind(this, equip.equip.id), this)
  190. node.on(cc.Node.EventType.TOUCH_MOVE, this.detailsTouchMove.bind(this, false), this)
  191. }
  192. ccUtils.setLabel(
  193. `lv.${equip.equip.lv}${cfg && cfg.lvMax ? '/' + EquipmentQualityConfig[equip.cfg.quality]?.maxLv : ''}`,
  194. node,
  195. 'lv',
  196. )
  197. baseUI.loadNotRefTexImg(`Public/goodsQuality/item_frame${equip.cfg.qualityType}`, node, 'item_frame')
  198. baseUI.loadNotRefTexImg(`Public/equip/type_base${equip.cfg.qualityType}`, node, 'type_base')
  199. baseUI.loadNotRefTexImg(`Public/equip/type_icon${equip.cfg.type}`, node, 'type_base/type_icon')
  200. baseUI.loadNotRefTexImg(`Public/equip/icon/${equip.cfg.icon}`, node, 'icon')
  201. let maxGrade = Data.user.maxGradeArr[equip.cfg.qualityType - 1]
  202. let grade = cc.find('grade', node)
  203. if (grade) {
  204. grade.active = maxGrade > 0 && equip.grade > 0
  205. if (equip.grade > 0) {
  206. baseUI.loadNotRefTexImg(`Public/role/grade_${equip.cfg.qualityType}`, grade)
  207. ccUtils.setLabel(equip.grade.toString(), grade, 'lv')
  208. }
  209. }
  210. }
  211. getPowerByAttr(baseAttr: IBaseAttr): number {
  212. //比例值(万分比)
  213. let rate = Data.game.rateNum
  214. // 物理防御系数 1 - 物理防御/(物理防御+防御常数)
  215. let defenseCoe = +(
  216. 1 / +(1 - baseAttr.defense / (baseAttr.defense + Data.game.defenseConst)).toFixed(2)
  217. ).toFixed(2)
  218. defenseCoe = defenseCoe || 0
  219. // 法术防御系数 1 - 法术防御/(法术防御+防御常数)
  220. let spellDefenseCoe = +(
  221. 1 / +(1 - baseAttr.spellDefense / (baseAttr.spellDefense + Data.game.defenseConst)).toFixed(2)
  222. ).toFixed(2)
  223. spellDefenseCoe = spellDefenseCoe || 0
  224. //攻速系数 攻速/比例值
  225. let attackSpeedCoe = +(baseAttr.attackSpeed / rate).toFixed(2)
  226. attackSpeedCoe = attackSpeedCoe || 0
  227. //暴击系数 暴击伤害倍数/比例值 * 暴击率/比例值 * 2
  228. let critCoe = +(baseAttr.critNum / rate).toFixed(2) * +(baseAttr.attackCrit / rate).toFixed(2) * 2
  229. critCoe = critCoe || 0
  230. //命中系数 1/攻击CD/比例值 * 命中率/比例值
  231. let hitCoe = +(1 / +(baseAttr.attackSpeed / rate).toFixed(2)).toFixed(2) * +(baseAttr.hit / rate).toFixed(2)
  232. hitCoe = hitCoe || 0
  233. //闪避系数 1/(1-闪避率/比例值)
  234. let dodgeCoe = +(1 / +(1 - baseAttr.dodge / rate).toFixed(2)).toFixed(2)
  235. dodgeCoe = dodgeCoe || 0
  236. let power =
  237. baseAttr.attack * (1 + attackSpeedCoe + critCoe + hitCoe) * 2 +
  238. baseAttr.spellAttack * (1 + attackSpeedCoe + critCoe + hitCoe) * 2 +
  239. baseAttr.HP * (1 + defenseCoe + spellDefenseCoe + dodgeCoe) * 0.8
  240. return Math.floor(power)
  241. }
  242. buildIRole(hero: hero, role?: IRole): IRole {
  243. let iRole: IRole
  244. if (hero.id > 0 && !RoleConfig[hero.id]) {
  245. console.error('没有这个英雄')
  246. return
  247. }
  248. if (role) {
  249. iRole = role
  250. iRole.cfg = RoleConfig[hero.id]
  251. iRole.hero = hero
  252. iRole.grade = Data.user.gradeArr[iRole.cfg.quality - 1]
  253. } else {
  254. let baseAttr = this.buildIBaseAttr(RoleConfig[hero.id])
  255. iRole = {
  256. ...baseAttr,
  257. cfg: RoleConfig[hero.id],
  258. grade: Data.user.gradeArr[RoleConfig[hero.id].quality - 1],
  259. hero: hero,
  260. power: 0,
  261. isAlter: false,
  262. equips: new Array(Data.main.equipMaxNum).fill(null),
  263. }
  264. hero.equip.forEach(equip => {
  265. let iEquip = Data.user.equips.find(value => value.equip.sid == equip)
  266. if (iEquip) iRole.equips[iEquip.cfg.type - 1] = iEquip
  267. })
  268. }
  269. iRole.isAlter = Data.user.altarInfoList.findIndex(item => item.sid === iRole.hero.sid) != -1
  270. //等级加成 1 + 等级/100
  271. let lvAdd = 1 + +((iRole.hero.lv - 1) / 100).toFixed(2)
  272. this.setIBaseAttr(iRole, iRole.cfg, lvAdd, iRole.equips)
  273. iRole.power = this.getPowerByAttr(iRole)
  274. return iRole
  275. }
  276. buildHeroByCfg(id: number): IRole {
  277. if (id > 0 && !RoleConfig[id]) {
  278. console.error('没有这个英雄')
  279. return
  280. }
  281. let iHero: hero = {
  282. sid: '',
  283. id: id,
  284. lv: 0,
  285. equip: new Array(Data.main.equipMaxNum).fill(null),
  286. }
  287. return this.buildIRole(iHero)
  288. }
  289. buildICard(card: card, iCardObj?: ICard): ICard {
  290. let iCard: ICard
  291. if (card.id > 0 && !CardSkillConfig[card.id]) {
  292. console.error('没有这个卡牌')
  293. return
  294. }
  295. if (iCardObj) {
  296. iCard = iCardObj
  297. iCard.cfg = CardSkillConfig[card.id]
  298. iCard.card = card
  299. iCard.debrisCfg = Object.values(CardConsumeConfig).find(
  300. item => item.card == Math.floor(iCard.cfg.ID / 100) * 100 + 1,
  301. )
  302. iCard.grade = Data.user.gradeArr[iCard.cfg.quality - 1]
  303. } else {
  304. let baseAttr = this.buildIBaseAttr(CardSkillConfig[card.id])
  305. iCard = {
  306. ...baseAttr,
  307. cfg: CardSkillConfig[card.id],
  308. grade: Data.user.gradeArr[CardSkillConfig[card.id].quality - 1],
  309. card: card,
  310. power: 0,
  311. debrisCfg: Object.values(CardConsumeConfig).find(
  312. item => item.card == Math.floor(CardSkillConfig[card.id].ID / 100) * 100 + 1,
  313. ),
  314. }
  315. }
  316. // -----卡牌战斗力不受装备,天赋加成----
  317. //等级加成 1 + 等级/比例值
  318. let lvAdd = 1 + +((iCard.card.lv - 1) / 100).toFixed(2)
  319. this.setIBaseAttr(iCard, iCard.cfg, lvAdd, [])
  320. iCard.power = this.getPowerByAttr(iCard)
  321. return iCard
  322. }
  323. buildCardByCfg(id: number): ICard {
  324. if (id > 0 && !CardSkillConfig[id]) {
  325. console.error('没有这个卡牌')
  326. return
  327. }
  328. let iCard: card = {
  329. sid: '',
  330. id: id,
  331. lv: 0,
  332. }
  333. return this.buildICard(iCard)
  334. }
  335. buildICardDebris(idNum: idNum, iCardDebrisObj?: ICardDebris): ICardDebris {
  336. let iCardDebris: ICardDebris
  337. if (idNum.id > 0 && !CardConsumeConfig[idNum.id]) {
  338. console.error('没有这个卡牌碎片')
  339. return
  340. }
  341. if (iCardDebrisObj) {
  342. iCardDebris = iCardDebrisObj
  343. iCardDebris.cfg = CardConsumeConfig[idNum.id]
  344. iCardDebris.num = idNum.num
  345. iCardDebris.id = idNum.id
  346. } else {
  347. iCardDebris = {cfg: CardConsumeConfig[idNum.id], id: idNum.id, num: idNum.num}
  348. }
  349. return iCardDebris
  350. }
  351. buildIEquip(equip: equip, iEquipObj?: IEquip): IEquip {
  352. let iEquip: IEquip
  353. let curCfg = ArmorConfig[equip.id]
  354. if (equip.id > 0 && !curCfg) {
  355. console.error('没有这个装备')
  356. return
  357. }
  358. let baseAttr = this.buildIBaseAttr(curCfg)
  359. //等级加成 1 + 等级/比例值 废弃
  360. /*let rate = Data.game.rateNum
  361. let lvAdd = 1 + +((equip.lv - 1) / 200).toFixed(2)
  362. this.scaleBaseAttr(baseAttr, lvAdd)
  363. //舍弃小数
  364. for (let key in baseAttr) {
  365. baseAttr[key] = Math.floor(baseAttr[key])
  366. }*/
  367. //等级加成为固定值
  368. let lvAddAttr = [ATTR_NAME.HP, ATTR_NAME.attack, ATTR_NAME.spellAttack]
  369. for (let attr of lvAddAttr) {
  370. if (baseAttr[attr] > 0) {
  371. baseAttr[attr] += (equip.lv - 1) * curCfg.increaseLv
  372. }
  373. }
  374. if (iEquipObj) {
  375. iEquip = iEquipObj
  376. iEquip.cfg = curCfg
  377. iEquip.equip = equip
  378. this.changeBaseAttr(iEquip, baseAttr)
  379. iEquip.grade = Data.user.gradeArr[iEquip.cfg.quality - 1]
  380. } else {
  381. iEquip = {
  382. ...baseAttr,
  383. cfg: curCfg,
  384. equip: equip,
  385. grade: Data.user.gradeArr[curCfg.quality - 1],
  386. power: 0,
  387. }
  388. }
  389. iEquip.power = this.getPowerByAttr(iEquip)
  390. return iEquip
  391. }
  392. buildEquipByCfg(id: number): IEquip {
  393. if (id > 0 && !ArmorConfig[id]) {
  394. console.error('没有这个装备')
  395. return
  396. }
  397. let iEquip: equip = {
  398. sid: '',
  399. id: id,
  400. lv: 0,
  401. hero: '',
  402. }
  403. return this.buildIEquip(iEquip)
  404. }
  405. buildICastleSkill(id: number): ICastleSkill {
  406. let cfg = CastleSkillConfig[id]
  407. let baseAttr = this.buildIBaseAttr(cfg)
  408. return {
  409. ...baseAttr,
  410. cfg,
  411. lv: cfg.ID % 100,
  412. isUse: id == Data.user.useCastleSkillID,
  413. }
  414. }
  415. buildIBaseAttr(cfg: IBaseAttr, isZero: boolean = false) {
  416. let baseAttr = {
  417. HP: isZero ? 0 : cfg.HP,
  418. attack: isZero ? 0 : cfg.attack,
  419. spellAttack: isZero ? 0 : cfg.spellAttack,
  420. realAttack: isZero ? 0 : cfg.realAttack,
  421. defense: isZero ? 0 : cfg.defense,
  422. spellDefense: isZero ? 0 : cfg.spellDefense,
  423. attackSpeed: isZero ? 0 : cfg.attackSpeed,
  424. attackCrit: isZero ? 0 : cfg.attackCrit,
  425. critNum: isZero ? 0 : cfg.critNum,
  426. hit: isZero ? 0 : cfg.hit,
  427. dodge: isZero ? 0 : cfg.dodge,
  428. moveSpeed: isZero ? 0 : cfg.moveSpeed,
  429. }
  430. return baseAttr
  431. }
  432. changeBaseAttr(baseAttr: IBaseAttr, changeAttr: IBaseAttr, isAdd: boolean = false) {
  433. baseAttr.HP = isAdd ? baseAttr.HP + changeAttr.HP : changeAttr.HP
  434. baseAttr.attack = isAdd ? baseAttr.attack + changeAttr.attack : changeAttr.attack
  435. baseAttr.attackSpeed = isAdd ? baseAttr.attackSpeed + changeAttr.attackSpeed : changeAttr.attackSpeed
  436. baseAttr.attackCrit = isAdd ? baseAttr.attackCrit + changeAttr.attackCrit : changeAttr.attackCrit
  437. baseAttr.critNum = isAdd ? baseAttr.critNum + changeAttr.critNum : changeAttr.critNum
  438. baseAttr.defense = isAdd ? baseAttr.defense + changeAttr.defense : changeAttr.defense
  439. baseAttr.dodge = isAdd ? baseAttr.dodge + changeAttr.dodge : changeAttr.dodge
  440. baseAttr.hit = isAdd ? baseAttr.hit + changeAttr.hit : changeAttr.hit
  441. baseAttr.spellAttack = isAdd ? baseAttr.spellAttack + changeAttr.spellAttack : changeAttr.spellAttack
  442. baseAttr.spellDefense = isAdd ? baseAttr.spellDefense + changeAttr.spellDefense : changeAttr.spellDefense
  443. baseAttr.realAttack = isAdd ? baseAttr.realAttack + changeAttr.realAttack : changeAttr.realAttack
  444. baseAttr.moveSpeed = isAdd ? baseAttr.moveSpeed + changeAttr.moveSpeed : changeAttr.moveSpeed
  445. return baseAttr
  446. }
  447. scaleBaseAttr(baseAttr: IBaseAttr, scale: number) {
  448. baseAttr.HP *= scale
  449. baseAttr.attack *= scale
  450. baseAttr.attackSpeed *= scale
  451. baseAttr.attackCrit *= scale
  452. baseAttr.critNum *= scale
  453. baseAttr.defense *= scale
  454. baseAttr.dodge *= scale
  455. baseAttr.hit *= scale
  456. baseAttr.spellAttack *= scale
  457. baseAttr.spellDefense *= scale
  458. baseAttr.realAttack *= scale
  459. baseAttr.moveSpeed = baseAttr.moveSpeed
  460. return baseAttr
  461. }
  462. setIBaseAttr(obj: ICard | IRole, cfg: IBaseAttr, lvAdd: number, equips: IEquip[]) {
  463. //装备加成
  464. let attr = this.buildIBaseAttr(null, true)
  465. let allEntryArr: number[] = []
  466. for (let i = 0; i < equips.length; i++) {
  467. if (equips[i]) {
  468. this.changeBaseAttr(attr, equips[i], true)
  469. if (equips[i].cfg.entry) allEntryArr.push(equips[i].cfg.entry)
  470. }
  471. }
  472. obj.HP = cfg.HP * lvAdd + attr.HP
  473. obj.attack = cfg.attack * lvAdd + attr.attack
  474. obj.attackSpeed = cfg.attackSpeed * lvAdd + attr.attackSpeed
  475. obj.attackCrit = cfg.attackCrit * lvAdd + attr.attackCrit
  476. obj.critNum = cfg.critNum * lvAdd + attr.critNum
  477. obj.defense = cfg.defense * lvAdd + attr.defense
  478. obj.dodge = cfg.dodge * lvAdd + attr.dodge
  479. obj.hit = cfg.hit * lvAdd + attr.hit
  480. obj.spellAttack = cfg.spellAttack * lvAdd + attr.spellAttack
  481. obj.spellDefense = cfg.spellDefense * lvAdd + attr.spellDefense
  482. obj.realAttack = cfg.realAttack * lvAdd + attr.realAttack
  483. obj.moveSpeed = cfg.moveSpeed + attr.moveSpeed
  484. //天赋词条加成
  485. if ('hero' in obj) {
  486. let profession = obj.cfg.profession
  487. if (Data.main.talentAdd && Data.main.talentAdd[profession]) {
  488. this.changeBaseAttr(obj, Data.main.talentAdd[profession], true)
  489. }
  490. }
  491. // 所有角色卡牌基础属性万分比词条加成
  492. for (let entry of allEntryArr) {
  493. switch (EntryConfig[entry].type) {
  494. case ENTRY.addRoleHP:
  495. obj.HP *= 1 + EntryConfig[entry].rateArr[0] / Data.game.rateNum
  496. case ENTRY.equipAddAttack:
  497. obj.attack *= 1 + EntryConfig[entry].rateArr[0] / Data.game.rateNum
  498. break
  499. }
  500. }
  501. obj.HP = Math.floor(obj.HP)
  502. obj.attack = Math.floor(obj.attack)
  503. obj.attackSpeed = Math.floor(obj.attackSpeed)
  504. obj.attackCrit = Math.floor(obj.attackCrit)
  505. obj.critNum = Math.floor(obj.critNum)
  506. obj.defense = Math.floor(obj.defense)
  507. obj.dodge = Math.floor(obj.dodge)
  508. obj.hit = Math.floor(obj.hit)
  509. obj.spellAttack = Math.floor(obj.spellAttack)
  510. obj.spellDefense = Math.floor(obj.spellDefense)
  511. obj.realAttack = Math.floor(obj.realAttack)
  512. obj.moveSpeed = Math.floor(obj.moveSpeed)
  513. }
  514. getPower() {
  515. let power = 0
  516. Data.user.teamRole.forEach(iRole => {
  517. if (iRole) {
  518. this.buildIRole(iRole.hero, iRole)
  519. power += iRole.power
  520. }
  521. })
  522. Data.user.teamCard.forEach(iCard => {
  523. if (iCard) {
  524. this.buildICard(iCard.card, iCard)
  525. power += iCard.power
  526. }
  527. })
  528. return power
  529. }
  530. getPowerString() {
  531. return Math.toKMBNum(this.getPower())
  532. }
  533. initPower() {
  534. this.lastPower = this.getPower()
  535. }
  536. updatePower() {
  537. let newPower = this.getPower()
  538. if (newPower > this.lastPower) {
  539. Mgr.ui.show(UI.PowerUpUI, `+${newPower - this.lastPower}`)
  540. this.lastPower = newPower
  541. }
  542. }
  543. entryBaseAttrAdd(baseAttr: IBaseAttr, entryID: number[]) {
  544. for (let id of entryID) {
  545. let entryCfg = EntryConfig[id]
  546. if (entryCfg.type >= ENTRY.HP && entryCfg.type <= ENTRY.realAttack) {
  547. baseAttr[ENTRY[entryCfg.type]] += entryCfg.parmArr[0]
  548. }
  549. if (entryCfg.type >= ENTRY.HPRate && entryCfg.type <= ENTRY.realAttackRate) {
  550. baseAttr[ENTRY[entryCfg.type].replace(/Rate/, '')] += entryCfg.rateArr[0]
  551. }
  552. if (entryCfg.type == ENTRY.talAddAllDefense) {
  553. baseAttr.defense += entryCfg.parmArr[0]
  554. baseAttr.spellDefense += entryCfg.parmArr[0]
  555. }
  556. }
  557. }
  558. //天赋加成是基础值
  559. initTalentAdd() {
  560. Data.user.talents.sort((a, b) => a - b)
  561. let talentAdds = []
  562. for (let i = PROFESSION.warrior; i <= PROFESSION.archer; i++) {
  563. let talentAdd = this.buildIBaseAttr(null, true)
  564. let entryIDs: number[] = []
  565. Data.user.talents.forEach(value => {
  566. if (EntryConfig[TalentConfig[value].entryID].profession.includes(i)) {
  567. entryIDs.push(TalentConfig[value].entryID)
  568. }
  569. })
  570. this.entryBaseAttrAdd(talentAdd, entryIDs)
  571. let addAllAttrRateArr: ENTRY[] = [
  572. ENTRY.talAddHP,
  573. ENTRY.talAddattack,
  574. ENTRY.talAddspellAttack,
  575. ENTRY.talAdddefense,
  576. ENTRY.talAddspellDefense,
  577. ]
  578. for (let id of Data.user.talents) {
  579. let cfg = TalentConfig[id]
  580. let entryCfg = EntryConfig[cfg.entryID]
  581. if (addAllAttrRateArr.includes(entryCfg.type)) {
  582. talentAdd[ENTRY[entryCfg.type].replace('talAdd', '')] *= 1 + entryCfg.rateArr[0] / Data.game.rateNum
  583. }
  584. }
  585. talentAdds[i] = talentAdd
  586. }
  587. Data.main.talentAdd = talentAdds
  588. }
  589. checkModOpen(modID: number) {
  590. // if (CC_DEV) return true
  591. return this.checkModOpenBeyond(modID)
  592. }
  593. checkModOpenBeyond(modID: number, checkCurrent: boolean = false) {
  594. let cfg = FunctionsConfig[modID]
  595. let check = true
  596. //mod为0时,不跳转页面
  597. if (!checkCurrent && cfg == undefined) return check
  598. if (!cfg && checkCurrent) return false
  599. switch (cfg.condition) {
  600. case CONDITION_FUNC.teamLevel:
  601. check = checkCurrent ? Data.user.level == cfg.parameter : Data.user.level >= cfg.parameter
  602. break
  603. case CONDITION_FUNC.normalBarrier:
  604. check = checkCurrent
  605. ? Data.user.adventureId == cfg.parameter + 1
  606. : Data.user.adventureId >= cfg.parameter + 1
  607. break
  608. case CONDITION_FUNC.createRoleDay:
  609. let day = Date.getDayDHMS(Data.main.serverTime - Data.user.createTime).day
  610. check = checkCurrent ? day == cfg.parameter : day >= cfg.parameter
  611. break
  612. case CONDITION_FUNC.eliteBarrier:
  613. check = checkCurrent ? Data.user.eliteId == cfg.parameter + 1 : Data.user.eliteId >= cfg.parameter + 1
  614. break
  615. }
  616. return check
  617. }
  618. getModLockTip(modID: number) {
  619. let cfg = FunctionsConfig[modID]
  620. let text = ''
  621. if (cfg) {
  622. let target = Mgr.i18n.getLabel(FunctionsConfig[modID].name)
  623. switch (cfg.condition) {
  624. case CONDITION_FUNC.teamLevel:
  625. text = Mgr.i18n.getLabel(LANGUAGE_TYPE.teamLevel, [cfg.parameter.toString(), target])
  626. break
  627. case CONDITION_FUNC.normalBarrier:
  628. let stageInfoCfg = StageInfoConfig[cfg.parameter],
  629. barrierName = `${Mgr.i18n.getLabel(stageInfoCfg.name)}-${stageInfoCfg.des}`
  630. text = Mgr.i18n.getLabel(LANGUAGE_TYPE.normalBarrier, [barrierName, target])
  631. break
  632. case CONDITION_FUNC.createRoleDay:
  633. text = Mgr.i18n.getLabel(LANGUAGE_TYPE.createRoleDay, [cfg.parameter.toString(), target])
  634. break
  635. }
  636. }
  637. return text
  638. }
  639. showModLockTip(modID: number) {
  640. Mgr.ui.tip(this.getModLockTip(modID))
  641. }
  642. //检查是否功能开启,并显示跳转页面
  643. tryJumpMod(modID: number) {
  644. //modID为0时,不跳转
  645. if (modID == 0) return
  646. let isOpen = Mgr.global.checkModOpen(modID)
  647. if (isOpen) {
  648. //对金币&体力购买界面做特殊处理
  649. if (modID == MOD.fatigueBuy || modID == MOD.moneyBuy) {
  650. return
  651. }
  652. let uiID = null
  653. let uiArgs = null
  654. let preOpenUIs = []
  655. let preOpenUIArgs = []
  656. if (!UI[modID]) {
  657. switch (modID) {
  658. case MOD.giftStore:
  659. case MOD.dailyGift:
  660. case MOD.weekGift:
  661. case MOD.noviceGift:
  662. case MOD.dailyStore:
  663. case MOD.resourceStore:
  664. case MOD.relicStore:
  665. uiID = UI.ShopUI
  666. uiArgs = modID
  667. break
  668. case MOD.advancedCharge:
  669. case MOD.elite:
  670. uiID = UI.StageChooseUI
  671. uiArgs = GAME_TYPE.elite
  672. break
  673. case MOD.equipGet:
  674. uiID = UI.RecruitUI
  675. uiArgs = RECRUIT_TYPE.forging //装备锻造
  676. break
  677. case MOD.explore:
  678. preOpenUIs.push(UI.CurrencyUI)
  679. preOpenUIArgs[preOpenUIs.length - 1] = [GOODS.coin, GOODS.diamond, GOODS.fatigue]
  680. uiArgs = modID
  681. break
  682. }
  683. } else {
  684. uiID = modID
  685. switch (modID) {
  686. case UI.StageChooseUI:
  687. uiArgs = GAME_TYPE.normal
  688. break
  689. case UI.RecruitUI:
  690. //默认抽奖-人物
  691. uiArgs = RECRUIT_TYPE.summoning //英雄召唤
  692. }
  693. }
  694. if (Mgr.ui.isTopUI(uiID)) {
  695. Mgr.ui.callOnShow(uiID, uiArgs)
  696. return
  697. }
  698. Mgr.ui.closeAll([UI.MainUI])
  699. preOpenUIs.forEach((v, i) => Mgr.ui.show(v, preOpenUIArgs[i]))
  700. if (uiID) Mgr.ui.show(uiID, uiArgs)
  701. } else {
  702. this.showModLockTip(modID)
  703. }
  704. }
  705. tryOpenNextReadyBox() {
  706. let open = false
  707. if (Data.user.readyOpenBox.length > 0) {
  708. let idNum = Data.user.readyOpenBox.shift()
  709. switch (GoodsConfig[idNum.id].type) {
  710. case GOODS_TYPE.randomBox:
  711. let req = boxGetAward.create()
  712. req.type = GOODS_TYPE.randomBox
  713. Data.user.readyOpenBox = Data.user.readyOpenBox.filter(
  714. value => GoodsConfig[value.id].type != GOODS_TYPE.randomBox,
  715. )
  716. Mgr.net.send(msgCmd.cmd_box_get_award, req)
  717. break
  718. case GOODS_TYPE.selectBox:
  719. open = true
  720. Data.user.readyOpenBox.unshift(idNum)
  721. break
  722. }
  723. }
  724. return open
  725. }
  726. //存入&修改localStorage中adFree相关信息(id: adFree_id, time: 结束时间戳)
  727. storageAdInfo(id: number, timeStamp: number, leftDailyTimes: number) {
  728. if (!id) return
  729. let obj = {timeStamp, leftDailyTimes}
  730. if (this.adInfoStorage) {
  731. this.adInfoStorage[id] = obj
  732. } else {
  733. let item = Mgr.storage.getObject(LOCAL.adFreeInfo, {})
  734. item[id] = obj
  735. this.adInfoStorage = item
  736. }
  737. Mgr.storage.set(LOCAL.adFreeInfo, this.adInfoStorage)
  738. }
  739. //获得对应adfree_id对应时间戳
  740. getAdInfo(id: number) {
  741. let adFreeInfos = this.adInfoStorage
  742. if (!adFreeInfos) {
  743. adFreeInfos = Mgr.storage.getObject(LOCAL.adFreeInfo, {})
  744. }
  745. let time = adFreeInfos[id] ? adFreeInfos[id].timeStamp - Data.main.serverTime : -0.1
  746. let min = Math.floor(time / 60)
  747. let sec = time % 60
  748. let dailyTimes = adFreeInfos[id] ? adFreeInfos[id].leftDailyTimes : 0
  749. let status: IAdStatus = {
  750. time,
  751. min: min.toString().zeroPrefix(min, 2),
  752. sec: sec.toString().zeroPrefix(sec, 2),
  753. isZero: time == 0,
  754. inTime: time > 0 && dailyTimes > 0,
  755. dailyTimes,
  756. }
  757. return status
  758. }
  759. tryShowUserGuide(keys: string[], callback: Function = null) {
  760. //没有账号不进入引导
  761. if (!Data.user.uid) return false
  762. if (!keys || keys.length == 0) return false
  763. let bigStep = +keys[0].split('_')[0]
  764. if (this.curGuideStep > 2 && this.curGuideStep != bigStep) return false
  765. //1级0经验引导
  766. if (bigStep == 1 && (Data.user.exp > 0 || Data.user.level > 1)) {
  767. return false
  768. }
  769. //打完第一关引导
  770. if (bigStep == 2 && Data.user.adventureId != 2) {
  771. return false
  772. }
  773. //功能引导
  774. if (bigStep > 2 && bigStep < 10000 && !this.checkModOpenBeyond(bigStep, true)) {
  775. return false
  776. }
  777. //密林5第十关Boss说明引导
  778. if (bigStep == 10001 && Data.game.stageID != 10) {
  779. return false
  780. }
  781. //特殊怪物引导
  782. if (
  783. bigStep == 10002 &&
  784. !Object.values(MonsterManualConfig)
  785. .map(v => v.trigger)
  786. .includes(Data.game.stageID)
  787. ) {
  788. return false
  789. }
  790. let curStep = Mgr.storage.getNumber(`userGuide_${bigStep}`)
  791. if (curStep) {
  792. keys = keys.filter(value => +value.split('_')[1] > curStep)
  793. //当前引导小于等于存储的不引导
  794. if (keys.length == 0) return false
  795. }
  796. Mgr.storage.set(`userGuide_${bigStep}`, +keys[keys.length - 1].split('_')[1])
  797. this.userGuideCom.showGuideByGroup(keys, callback)
  798. this.curGuideStep = bigStep
  799. return true
  800. }
  801. initAvatar(node, baseUI: BaseUI) {
  802. let sprite = node.getComponent(cc.Sprite)
  803. if (Data.user.avatarTex) {
  804. sprite.spriteFrame = new cc.SpriteFrame(Data.user.avatarTex)
  805. } else {
  806. baseUI.loadTexImg(`Public/avatar/${Data.user.avatar}`, node)
  807. }
  808. }
  809. }