TaskUI.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /** @format */
  2. import {UI} from '../enums/UI'
  3. import {BaseUI} from './BaseUI'
  4. import {Data, Mgr} from '../GameControl'
  5. import {ccUtils} from '../utils/ccUtils'
  6. import {label, list, node, observer, render} from '../mobx/observer'
  7. import {msgCmd} from '../proto/msg_cmd'
  8. import {ITaskConfig, TaskConfig} from '../config/TaskConfig'
  9. import {CONDITION_FUNC, GOODS, LANGUAGE_TYPE, STATE, TASK_TYPE} from '../enums/Enum'
  10. import {i18nLabel} from '../uiutils/i18nLabel'
  11. import List from '../uiutils/List'
  12. import {questActiveAwardRsp, questGetDataRsp} from '../proto/game'
  13. import {idNum, quest} from '../proto/typedef'
  14. import {ActiverewardConfig, IActiverewardConfig} from '../config/ActiverewardConfig'
  15. import {EliteInfoConfig} from '../config/EliteInfoConfig'
  16. import {StageInfoConfig} from '../config/StageInfoConfig'
  17. import {FunctionsConfig} from '../config/FunctionsConfig'
  18. import {IRewardNty} from '../interface/UIInterface'
  19. const {ccclass, property} = cc._decorator
  20. interface task {
  21. taskCfg: ITaskConfig
  22. quest: quest
  23. reward: idNum[]
  24. }
  25. interface taskList {
  26. type: number //类型
  27. level: number //等级
  28. award: number //领取奖励 0/20/40/60/80/100
  29. activationNum: number
  30. tasks: task[]
  31. }
  32. enum Touch_UI {
  33. adventureMainUI = 23,
  34. adventureEliteUI,
  35. challengeUI,
  36. }
  37. @ccclass
  38. @observer
  39. export class TaskUI extends BaseUI {
  40. //任务奖励节点列表
  41. rewards: cc.Node[]
  42. @list('task_list')
  43. taskPageList: List
  44. @list('achievement_list')
  45. achievementList: List
  46. //宝箱
  47. @node('activation/activation_progress/chest_box')
  48. chestBox: cc.Node
  49. //包含活跃值、宝箱和进度条的总类节点
  50. @node('activation')
  51. activationNode: cc.Node
  52. @node('task_list')
  53. tasklistNode: cc.Node
  54. @node('achievement_list')
  55. achievementListNode: cc.Node
  56. @node('taskType_list')
  57. typeNode: cc.Node
  58. bubble_box: cc.Node
  59. bubble_arrow: cc.Node
  60. //所有任务列表
  61. taskAllData: Map<TASK_TYPE, taskList> = new Map()
  62. hasActiveReward: boolean = false
  63. checkBubbleShow: boolean = false
  64. activeRewardsData: IActiverewardConfig[] = [] //活跃度奖励数据
  65. selTaskType: TASK_TYPE = TASK_TYPE.daily
  66. selTaskItemIndex: number = 0
  67. selRewardIdNum: idNum[]
  68. isTaskRewards: boolean = true
  69. activeRewardsNum: number = 2
  70. activeDailyIndex: number = 0
  71. activeWeekIndex: number = 0
  72. chestActivationData: number[] = [20, 40, 60, 80, 100]
  73. onShow(args, fromUI?: number) {
  74. cc.find('trans', this.node).on(cc.Node.EventType.TOUCH_END, this.cancelBubbleBox, this)
  75. cc.find('trans', this.node)['_touchListener'].swallowTouches = false
  76. Mgr.net.add(msgCmd.cmd_quest_get_data_rsp, this, this.onQuestRsp)
  77. //从右到左显示货币
  78. Mgr.ui.show(UI.CurrencyUI, [GOODS.coin, GOODS.diamond, GOODS.fatigue])
  79. //活跃宝箱获取奖励
  80. Mgr.net.add(msgCmd.cmd_quest_active_award_rsp, this, this.getRewardRsp)
  81. //任务获取奖励
  82. Mgr.net.add(msgCmd.cmd_quest_get_award_rsp, this, this.getRewardRsp)
  83. Mgr.net.send(msgCmd.cmd_quest_get_data)
  84. //强制初始化
  85. this.selTaskType = TASK_TYPE.daily
  86. this.typeNode.children[0].getComponent(cc.Toggle).isChecked = true
  87. }
  88. onHide(): any {
  89. Mgr.event.removeAll(this)
  90. }
  91. //分拣任务类型 daily:日常 weekly:周常 achievement:成就
  92. classifyTasks(task: taskList, level: number, award: number, quests: quest[]) {
  93. task.level = level
  94. task.award = award
  95. for (let i = 0; i < quests.length; i++) {
  96. task.tasks.push({
  97. quest: quests[i],
  98. taskCfg: TaskConfig[quests[i].id],
  99. reward: Mgr.goods.getIdNumByCfgArr(TaskConfig[quests[i].id].reward),
  100. })
  101. }
  102. return task
  103. }
  104. //初始化任务列表数据
  105. initTaskAllListData(data: questGetDataRsp) {
  106. for (let i = TASK_TYPE.daily; i <= TASK_TYPE.achievement; i++) {
  107. let taskList: taskList = {
  108. type: 0,
  109. award: 0,
  110. level: 0,
  111. activationNum: 0,
  112. tasks: [],
  113. },
  114. activationNum = 0
  115. taskList.type = i
  116. switch (taskList.type) {
  117. case TASK_TYPE.daily:
  118. taskList = this.classifyTasks(taskList, data.dlv, data.daward, data.daily)
  119. activationNum = Data.user.goods.get(GOODS.activation)
  120. taskList.activationNum = activationNum == undefined ? 0 : activationNum
  121. break
  122. case TASK_TYPE.weekly:
  123. taskList = this.classifyTasks(taskList, data.wlv, data.waward, data.weekly)
  124. activationNum = Data.user.goods.get(GOODS.weeklyIntegral)
  125. taskList.activationNum = activationNum == undefined ? 0 : activationNum
  126. break
  127. case TASK_TYPE.achievement:
  128. taskList = this.classifyTasks(taskList, 0, 0, data.achievement)
  129. break
  130. }
  131. this.taskAllData.set(i, taskList)
  132. //排列任务顺序 id升序 可领取任务置前,已领取任务置后
  133. let list = this.taskAllData.get(i)
  134. let readyTasks: task[] = list.tasks.filter(task => task.quest.state === STATE.ready)
  135. let completedTasks: task[] = list.tasks.filter(task => task.quest.state === STATE.done)
  136. list.tasks = list.tasks.filter(task => task.quest.state !== STATE.ready && task.quest.state !== STATE.done)
  137. list.tasks.sort((a, b) => a.quest.id - b.quest.id)
  138. readyTasks.sort((a, b) => a.quest.id - b.quest.id)
  139. completedTasks.sort((a, b) => a.quest.id - b.quest.id)
  140. readyTasks.forEach(task => list.tasks.unshift(task))
  141. completedTasks.forEach(task => list.tasks.push(task))
  142. }
  143. }
  144. initUi() {
  145. this.handleGetAwardRemainTime()
  146. //初始化宝箱
  147. this.initChestBox()
  148. //根据任务日常/周常初始化全部活跃奖励
  149. this.activeRewardsData = []
  150. let list = this.selTaskType == TASK_TYPE.achievement ? this.achievementList : this.taskPageList,
  151. level = this.taskAllData.get(this.selTaskType).level
  152. for (let item in ActiverewardConfig) {
  153. if (ActiverewardConfig[item].type == this.selTaskType) {
  154. if (level >= ActiverewardConfig[item].interval[0] && level <= ActiverewardConfig[item].interval[1]) {
  155. this.activeRewardsData.push(ActiverewardConfig[item])
  156. }
  157. }
  158. }
  159. //查看左侧页签红点状态
  160. for (let type = TASK_TYPE.daily; type <= TASK_TYPE.achievement; type++) {
  161. //查看是否有可领取任务
  162. let node = this.typeNode.children[type - 1],
  163. tasks = this.taskAllData.get(type).tasks,
  164. checkGet = tasks.some(task => task.quest.state == STATE.ready)
  165. //对已领取的宝箱置灰
  166. //红点显示:
  167. //成就页面有可领取任务,其他需同时满足任务领取&宝箱领取
  168. if (type == TASK_TYPE.achievement) {
  169. cc.find('red_dots', node).active = checkGet
  170. } else {
  171. //是否存在可领取活跃奖励
  172. let curActiveIndex = type == TASK_TYPE.daily ? this.activeDailyIndex : this.activeWeekIndex
  173. let hasActiveReward =
  174. Math.floor(this.taskAllData.get(type).activationNum / 20) - 1 >= curActiveIndex &&
  175. curActiveIndex < this.chestActivationData.length
  176. cc.find('red_dots', node).active = checkGet || hasActiveReward
  177. if (type == this.selTaskType) this.hasActiveReward = hasActiveReward
  178. }
  179. }
  180. //默认跳转至列表第一个位置
  181. list.scrollTo(0)
  182. list.numItems = this.taskAllData.get(this.selTaskType).tasks.length
  183. if (this.selTaskType != TASK_TYPE.achievement) {
  184. let node = cc.find('activation_progress/progress_bottom', this.activationNode)
  185. //周常 周积分 110004 日常 活跃度 110003
  186. //初始化进度条
  187. let progress = this.taskAllData.get(this.selTaskType).activationNum
  188. //初始化活跃值
  189. let activateBox = cc.find('activate_box', this.activationNode)
  190. ccUtils.setLabel(progress.toString(), activateBox, 'num')
  191. ccUtils.initProgressBar(node, progress, 100)
  192. }
  193. //根据activation节点可见日常、周常、成就列表
  194. this.activationNode.active = !(this.selTaskType == TASK_TYPE.achievement)
  195. this.tasklistNode.active = !(this.selTaskType == TASK_TYPE.achievement)
  196. this.achievementListNode.active = this.selTaskType == TASK_TYPE.achievement
  197. }
  198. //初始化任务单例奖励列表
  199. initRewards(parent: cc.Node) {
  200. let children = parent.children,
  201. idNum: idNum[] = []
  202. for (let i = 0; i < children.length; i++) {
  203. let data: idNum = null
  204. //任务列表奖励初始化
  205. if (this.isTaskRewards) {
  206. data = this.taskAllData.get(this.selTaskType).tasks[this.selTaskItemIndex].reward[i]
  207. cc.find('select_1', children[i]).active =
  208. this.taskAllData.get(this.selTaskType).tasks[this.selTaskItemIndex].quest.state == STATE.done
  209. } else {
  210. //宝箱bubble奖励初始化
  211. data = this.selRewardIdNum[i]
  212. }
  213. idNum.push({id: data.id, num: data.num})
  214. }
  215. Mgr.goods.initGoods(
  216. idNum,
  217. children.map(goodsParent => cc.find('goods', goodsParent)),
  218. this,
  219. )
  220. }
  221. //初始化活跃宝箱
  222. initChestBox() {
  223. let item = cc.find('chest_item', this.chestBox)
  224. ccUtils.instantChildren(item, this.chestActivationData.length, this.chestBox)
  225. for (let i = 0; i < this.chestActivationData.length; i++) {
  226. let node = this.chestBox.children[i]
  227. node['index'] = i
  228. let activation = this.taskAllData.get(this.selTaskType).activationNum
  229. let icon = cc.find('chest_icon', node)
  230. let hasReward = cc.find('hasReward', node)
  231. let canGet = Math.floor(activation / 20) - 1 >= i
  232. ccUtils.setLabel(this.chestActivationData[i].toString(), node, 'label')
  233. //对已领取的宝箱置灰
  234. let hasGet: boolean = this.chestActivationData[i] <= this.taskAllData.get(this.selTaskType).award
  235. ccUtils.setSpriteGray(hasGet, icon)
  236. cc.find('active', node).active = canGet
  237. hasReward.active = canGet && !hasGet
  238. icon.active = !hasReward.active
  239. }
  240. let getCurActive = (type: TASK_TYPE) => {
  241. let curActive: number = 0
  242. for (let i = 0; i < this.chestActivationData.length; i++) {
  243. let activeChest: boolean = this.chestActivationData[i] <= this.taskAllData.get(type).award
  244. if (activeChest) curActive = i + 1
  245. }
  246. return curActive
  247. }
  248. this.activeDailyIndex = getCurActive(TASK_TYPE.daily)
  249. this.activeWeekIndex = getCurActive(TASK_TYPE.weekly)
  250. }
  251. //初始化任务列表
  252. initTaskItem(node: cc.Node, index: number) {
  253. //任务在任务列表中的下标
  254. this.selTaskItemIndex = index
  255. let data = this.taskAllData.get(this.selTaskType).tasks[index]
  256. //生成任务描述
  257. let label = cc.find('task_decs', node).getComponent(i18nLabel)
  258. ccUtils.setLabel(data.taskCfg.des, node, 'task_decs')
  259. //label 参数 #0/#1
  260. //单独为成就写入param
  261. if (this.selTaskType == TASK_TYPE.achievement) {
  262. let param = data.taskCfg.parameter,
  263. cfg = null
  264. switch (data.taskCfg.touch) {
  265. case Touch_UI.adventureMainUI:
  266. cfg = StageInfoConfig[param]
  267. label.init(data.taskCfg.des, [`${Mgr.i18n.getLabel(cfg.name, [])}-${cfg.des}`])
  268. break
  269. case Touch_UI.adventureEliteUI:
  270. cfg = EliteInfoConfig[param]
  271. label.init(data.taskCfg.des, [`${Mgr.i18n.getLabel(cfg.name, [])}-${cfg.ID % 10}`])
  272. break
  273. default:
  274. label.init(data.taskCfg.des, [data.taskCfg.parameter.toString()])
  275. break
  276. }
  277. }
  278. //生成奖励列表
  279. this.isTaskRewards = true
  280. let rewardItem = cc.find('rewards/reward_item', node)
  281. ccUtils.instantChildren(rewardItem, data.reward.length, rewardItem.parent)
  282. this.initRewards(rewardItem.parent)
  283. //获取完成进度
  284. //mark -1需要记录 -0不需要记录
  285. let progressNode = cc.find('progress_bottom', node)
  286. let progress =
  287. data.taskCfg.mark == 0 ? (data.quest.state == STATE.undo ? STATE.undo : STATE.ready) : data.quest.progress
  288. let needSum = data.taskCfg.mark == 0 ? 1 : data.taskCfg.parameter
  289. ccUtils.initProgressBar(progressNode, progress, needSum, 'progress_label')
  290. //初始化跳转按钮
  291. let state = data.quest.state
  292. let go_btn = cc.find('go_btn', node),
  293. clain_btn = cc.find('clain_btn', node),
  294. com_label = cc.find('com_label', node)
  295. go_btn.active = state == STATE.undo
  296. clain_btn.active = state == STATE.ready
  297. com_label.active = state == STATE.done
  298. if (go_btn.active || clain_btn.active) {
  299. if (state == STATE.ready) {
  300. clain_btn['id'] = data.taskCfg.ID
  301. } else {
  302. go_btn['jump'] = data.taskCfg.jump
  303. }
  304. }
  305. //针对不同完成状态显示高亮与普通任务背景
  306. cc.find('complete', node).active = state == STATE.ready
  307. //对已领取奖励任务进行node置灰
  308. cc.find('gray', node).active = state == STATE.done
  309. }
  310. //网络事件=======================================
  311. onQuestRsp(data: questGetDataRsp) {
  312. this.initTaskAllListData(data)
  313. this.initUi()
  314. }
  315. getRewardRsp(data: questActiveAwardRsp, reward: IRewardNty) {
  316. Mgr.ui.showReward(reward)
  317. Mgr.net.send(msgCmd.cmd_quest_get_data)
  318. }
  319. //触发事件=======================================
  320. @render
  321. //处理任务领取剩余时间
  322. handleGetAwardRemainTime() {
  323. let time = Data.main.serverTime,
  324. lb = cc.find('remain_time/layout/info', this.activationNode),
  325. endOfDay = this.selTaskType == TASK_TYPE.weekly ? Date.getWeekTime(time, 0) : Date.getDayTime(time),
  326. remain = Math.floor(endOfDay - time) < 60 ? 60 : Math.floor(endOfDay - time)
  327. if (remain == 0) {
  328. Mgr.net.send(msgCmd.cmd_quest_get_data)
  329. } else {
  330. ccUtils.setLabel(`${Mgr.i18n.getTimeLabel(remain)}`, lb)
  331. }
  332. }
  333. // 点击事件=======================================
  334. onTypeClick(event, data) {
  335. if (this.selTaskType == parseInt(data)) {
  336. return
  337. }
  338. this.selTaskType = parseInt(data)
  339. this.initUi()
  340. }
  341. onClainClick(event) {
  342. Mgr.net.send(msgCmd.cmd_quest_get_award, {id: event.target.id})
  343. }
  344. onGoClick(event) {
  345. Mgr.global.tryJumpMod(event.target['jump'])
  346. }
  347. //活跃宝箱点击事件
  348. //按钮可交互时 存在两种状态
  349. //1. 存在可领取奖励 点击一次性领取全部奖励,并刷新页面
  350. //2. 无领取奖励 点击宝箱上方显示奖励气泡(气泡默认隐藏)
  351. onChestClick(event) {
  352. let parent = event.currentTarget.parent,
  353. index = parent['index']
  354. if (this.hasActiveReward) {
  355. Mgr.net.send(msgCmd.cmd_quest_active_award, {type: this.selTaskType})
  356. } else {
  357. this.checkBubbleShow = !this.checkBubbleShow
  358. if (this.bubble_box == null) {
  359. this.bubble_box = cc.find('bubble_box', parent)
  360. this.bubble_arrow = cc.find('arrow', parent)
  361. }
  362. this.bubble_box.active = this.checkBubbleShow
  363. this.bubble_arrow.active = this.checkBubbleShow
  364. this.isTaskRewards = false
  365. if (this.bubble_box.active) {
  366. this.selRewardIdNum = Mgr.goods.getIdNumByCfgArr(this.activeRewardsData[index].reward)
  367. let rewardItem = cc.find('reward_item', this.bubble_box)
  368. ccUtils.instantChildren(rewardItem, this.selRewardIdNum.length, this.bubble_box)
  369. this.initRewards(this.bubble_box)
  370. }
  371. if (!this.checkBubbleShow) {
  372. this.bubble_box = null
  373. }
  374. }
  375. }
  376. cancelBubbleBox() {
  377. if (this.bubble_box != null) {
  378. this.bubble_box.active = false
  379. this.bubble_arrow.active = false
  380. this.checkBubbleShow = false
  381. this.bubble_box = null
  382. }
  383. }
  384. }