RecycleItem.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. -- 收纳箱(回收道具)
  2. --
  3. -- doCalcHero 统计收纳箱英雄属性加成
  4. -- RecycleItem_Query 查询收纳箱等级/经验/属性
  5. -- RecycleItem_RecycleItemListQuery 查询可回收道具列表
  6. -- RecycleItem_Recycle_Do 执行回收
  7. --db
  8. --[=[
  9. human.db.recycleData = {
  10. level = nil,
  11. exp = nil,
  12. }
  13. ]=]--
  14. local Msg = require("core.Msg")
  15. local Lang = require("common.Lang")
  16. local Broadcast = require("broadcast.Broadcast")
  17. local Util = require("common.Util")
  18. local BagLogic = require("bag.BagLogic")
  19. local RoleAttr = require("role.RoleAttr")
  20. local RoleDefine = require("role.RoleDefine")
  21. local ObjHuman = require("core.ObjHuman")
  22. local RecycleConfig = require("excel.recycleItem").RecycleLvList
  23. local ItemConfig = require("excel.item").item
  24. local FuwenConfig = require("excel.fuwen").fuwen
  25. local ItemDefine = require("bag.ItemDefine")
  26. local FuwenLogic = require("fuwen.FuwenLogic")
  27. -- local RoleSystemLogic = require("roleSystem.RoleSystemLogic")
  28. -- local RoleSystemDefine = require("roleSystem.RoleSystemDefine")
  29. local LOG_TAG = "RecycleItem" -- 本系统的日志标识
  30. local OPEN_COND_LV = 150 -- 开启功能需要的等级
  31. local RECYCLE_ITEM_TYPE_ITEM = 1 -- item表道具
  32. local RECYCLE_ITEM_TYPE_FUWEN = 2 -- 符文
  33. -- 初始化收纳箱数据
  34. local function initRecycleData(human)
  35. human.db.recycleData = { level = 0, exp = 0 }
  36. end
  37. -- 获取收纳箱数据
  38. local function getRecycleData(human)
  39. return human.db.recycleData
  40. end
  41. -- 获取道具/符文的回收值, 仅 val > 0 时可回收
  42. local function getRecycleVal(itemId)
  43. if ItemDefine.isFuwen(itemId) then
  44. local fuwenCfg = FuwenConfig[itemId]
  45. if fuwenCfg and fuwenCfg.val and fuwenCfg.val > 0 then
  46. return fuwenCfg.val
  47. end
  48. return
  49. end
  50. local itemCfg = ItemConfig[itemId]
  51. if itemCfg and itemCfg.val and itemCfg.val > 0 then
  52. return itemCfg.val
  53. end
  54. end
  55. -- 收集背包中可回收的item表道具, 返回 {{id, recycleVal, extraInfo}, ...}
  56. local function collectItemRecycleList(human)
  57. local itemArr = {}
  58. local bagData = BagLogic.GetBagData(human)
  59. if not bagData then
  60. return itemArr
  61. end
  62. for itemId in pairs(bagData) do
  63. if not ItemDefine.isFuwen(itemId) then
  64. local itemCfg = ItemConfig[itemId]
  65. if itemCfg and itemCfg.val and itemCfg.val > 0 then
  66. itemArr[#itemArr + 1] = {itemId, itemCfg.val, 0}
  67. end
  68. end
  69. end
  70. return itemArr
  71. end
  72. -- 收集符文背包中可回收的符文, extraInfo 为符文背包idx
  73. local function collectFuwenRecycleList(human)
  74. local itemArr = {}
  75. local fuwenBag = FuwenLogic.getFuwenBagData(human)
  76. if not fuwenBag then
  77. return itemArr
  78. end
  79. for index, fuwenGrid in pairs(fuwenBag) do
  80. local fuwenId = fuwenGrid and fuwenGrid.id
  81. if fuwenId then
  82. local recycleVal = getRecycleVal(fuwenId)
  83. if recycleVal then
  84. itemArr[#itemArr + 1] = {fuwenId, recycleVal, index}
  85. end
  86. end
  87. end
  88. return itemArr
  89. end
  90. -- 解析回收请求字符串, 返回 {{id, value}, ...}
  91. local function parseRecycleEntries(recycleItemStr)
  92. local entries = Util.parseKVList(recycleItemStr, "|", "-", Util.TONUMBER_ALL)
  93. if #entries == 0 then
  94. return
  95. end
  96. return entries
  97. end
  98. -- 合并相同道具id的回收数量, 避免重复条目导致数量校验/扣除错误
  99. local function mergeItemRecycleEntries(entries)
  100. local mergedMap = {}
  101. for _, entry in ipairs(entries) do
  102. local itemId, itemCnt = entry[1], entry[2]
  103. mergedMap[itemId] = (mergedMap[itemId] or 0) + (itemCnt or 0)
  104. end
  105. local mergedList = {}
  106. for itemId, itemCnt in pairs(mergedMap) do
  107. mergedList[#mergedList + 1] = {itemId, itemCnt}
  108. end
  109. return mergedList
  110. end
  111. -- 校验item表道具回收, 成功返回 totalExp, 失败返回 nil, errLang
  112. local function validateItemRecycle(human, entries)
  113. local totalExp = 0
  114. for _, entry in ipairs(entries) do
  115. local itemId, itemCnt = entry[1], entry[2]
  116. if not itemId or not itemCnt or itemCnt <= 0 then
  117. return nil, Lang.COMMON_ARGUMENT_ERROR
  118. end
  119. if ItemDefine.isFuwen(itemId) then
  120. return nil, Lang.ITEM_CANNOT_RECYCLE
  121. end
  122. local recycleVal = getRecycleVal(itemId)
  123. if not recycleVal then
  124. return nil, Lang.ITEM_CANNOT_RECYCLE
  125. end
  126. if BagLogic.getItemCnt(human, itemId) < itemCnt then
  127. return nil, Lang.COMMON_ITEM_NOT_ENOUGH
  128. end
  129. totalExp = totalExp + recycleVal * itemCnt
  130. end
  131. return totalExp
  132. end
  133. -- 校验符文回收, 成功返回 totalExp, 失败返回 nil, errLang
  134. local function validateFuwenRecycle(human, entries)
  135. local totalExp = 0
  136. local indexMap = {}
  137. for _, entry in ipairs(entries) do
  138. local fuwenId, index = entry[1], entry[2]
  139. if not fuwenId or not index or index <= 0 or indexMap[index] then
  140. return nil, Lang.COMMON_ARGUMENT_ERROR
  141. end
  142. indexMap[index] = true
  143. local recycleVal = getRecycleVal(fuwenId)
  144. if not recycleVal then
  145. return nil, Lang.ITEM_CANNOT_RECYCLE
  146. end
  147. local fuwenGrid = FuwenLogic.getFuwenGrid(human, index)
  148. if not fuwenGrid or fuwenGrid.id ~= fuwenId then
  149. return nil, Lang.COMMON_ITEM_NOT_ENOUGH
  150. end
  151. totalExp = totalExp + recycleVal
  152. end
  153. return totalExp
  154. end
  155. -- 删除待回收的item表道具
  156. local function deleteItemRecycle(human, entries)
  157. for _, entry in ipairs(entries) do
  158. BagLogic.delItem(human, entry[1], entry[2], LOG_TAG)
  159. end
  160. end
  161. -- 删除待回收的符文
  162. local function deleteFuwenRecycle(human, entries)
  163. for _, entry in ipairs(entries) do
  164. FuwenLogic.del(human, entry[2], LOG_TAG)
  165. end
  166. end
  167. -- 回收校验处理器, 按 itemType 分发
  168. local RECYCLE_VALIDATE_HANDLER = {
  169. [RECYCLE_ITEM_TYPE_ITEM] = validateItemRecycle,
  170. [RECYCLE_ITEM_TYPE_FUWEN] = validateFuwenRecycle,
  171. }
  172. -- 回收删除处理器, 按 itemType 分发
  173. local RECYCLE_DELETE_HANDLER = {
  174. [RECYCLE_ITEM_TYPE_ITEM] = deleteItemRecycle,
  175. [RECYCLE_ITEM_TYPE_FUWEN] = deleteFuwenRecycle,
  176. }
  177. -- 更新收纳箱等级和经验
  178. local function updateRecycleData(human, newLv, newExp)
  179. local recycleData = getRecycleData(human)
  180. if not recycleData then
  181. initRecycleData(human)
  182. recycleData = getRecycleData(human)
  183. end
  184. recycleData.level = newLv
  185. recycleData.exp = newExp
  186. end
  187. -- 是否开启本系统
  188. local function isOpen(human)
  189. -- return RoleSystemLogic.isOpen(human, RoleSystemDefine.ROLE_SYS_ID_2031) -- 待修改
  190. return human.db.lv >= OPEN_COND_LV
  191. end
  192. -- 计算当前等级加成属性
  193. local function calcCurrentLvAttrs(currentLevel)
  194. if not currentLevel or currentLevel <= 0 then
  195. return
  196. end
  197. local attrs = {}
  198. for i=1, currentLevel do
  199. local cfg = RecycleConfig[i]
  200. if cfg and cfg.attrs then
  201. for _,v in ipairs(cfg.attrs) do
  202. local attrId = v[1]
  203. local attrVal = v[2]
  204. attrs[attrId] = (attrs[attrId] or 0) + attrVal
  205. end
  206. end
  207. end
  208. return attrs
  209. end
  210. -- 重算战力
  211. local function updatePower(human)
  212. RoleAttr.cleanHeroAttrCache(human)
  213. RoleAttr.doCalc(human)
  214. ObjHuman.sendAttr(human, RoleDefine.ZHANDOULI)
  215. end
  216. -- 计算出新的等级和经验
  217. local function calcLv(human, addExp)
  218. local recycleData = getRecycleData(human)
  219. local currentLevel = recycleData and recycleData.level or 0
  220. local currentExp = recycleData and recycleData.exp or 0
  221. currentExp = currentExp + addExp
  222. local newLv = currentLevel
  223. for i=currentLevel+1, #RecycleConfig do
  224. local cfg = RecycleConfig[i]
  225. if currentExp < cfg.exp then
  226. break
  227. end
  228. currentExp = currentExp - cfg.exp
  229. newLv = i
  230. if currentExp <= 0 then
  231. break
  232. end
  233. end
  234. return newLv, currentExp
  235. end
  236. -- 填充当前等级属性到协议结构
  237. local function populateCurrentLvAttrs(net, currentLevel)
  238. local isZero = false
  239. if currentLevel <= 0 then
  240. currentLevel = 1
  241. isZero = true
  242. end
  243. local len = 0
  244. net[0] = len
  245. local attrs = calcCurrentLvAttrs(currentLevel)
  246. for attrId, attrVal in pairs(attrs or {}) do
  247. len = len + 1
  248. net[0] = len
  249. net[len].key = attrId
  250. net[len].value = isZero and 0 or attrVal
  251. end
  252. end
  253. -- 填充下一等级属性到协议结构
  254. local function populateNextLvAttrs(net, nextLv)
  255. local isMax = false
  256. local maxLv = #RecycleConfig
  257. if maxLv <= nextLv then
  258. nextLv = maxLv
  259. isMax = true
  260. end
  261. net[0] = 0
  262. local cfg = RecycleConfig[nextLv]
  263. if cfg and cfg.attrs then
  264. net[0] = #cfg.attrs
  265. for k,v in ipairs(cfg.attrs) do
  266. net[k].key = v[1]
  267. net[k].value = isMax and 0 or v[2]
  268. end
  269. end
  270. end
  271. -- local function populateRecycleItem(net, human)
  272. -- net[0] = 0
  273. -- local bagData = BagLogic.GetBagData(human)
  274. -- if not bagData then
  275. -- return
  276. -- end
  277. -- local len = 0
  278. -- for itemId in pairs(bagData) do
  279. -- local itemCfg = ItemConfig[itemId]
  280. -- if itemCfg and itemCfg.val and itemCfg.val > 0 then
  281. -- len = len + 1
  282. -- net[0] = len
  283. -- net[len].id = itemId
  284. -- net[len].recycleVal = itemCfg.val
  285. -- end
  286. -- end
  287. -- end
  288. -- 外部调用, 统计收纳箱加成属性
  289. function doCalcHero(human, addAttrs)
  290. if not human then
  291. return
  292. end
  293. local recycleData = getRecycleData(human)
  294. if not recycleData then
  295. return
  296. end
  297. local currentLevel = recycleData and recycleData.level or 0
  298. if currentLevel <= 0 then
  299. return
  300. end
  301. local attrs = calcCurrentLvAttrs(currentLevel)
  302. for attrId, attrVal in pairs(attrs or {}) do
  303. RoleAttr.updateValue(attrId, attrVal, addAttrs)
  304. end
  305. end
  306. -- 查询收纳箱等级、经验及属性加成
  307. function RecycleItem_Query(human)
  308. if not isOpen(human) then
  309. return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED)
  310. end
  311. local recycleData = getRecycleData(human)
  312. local currentLevel = recycleData and recycleData.level or 0
  313. local currentExp = recycleData and recycleData.exp or 0
  314. local maxLevel = #RecycleConfig
  315. local nextLvExp = 0
  316. if currentLevel < maxLevel then
  317. local nextLvCfg = RecycleConfig[currentLevel + 1]
  318. nextLvExp = nextLvCfg.exp
  319. end
  320. local msgRet = Msg.gc.GC_RECYCLE_QUERY
  321. msgRet.currentLevel = currentLevel
  322. msgRet.maxLevel = maxLevel
  323. msgRet.currentExp = currentExp
  324. msgRet.nextLvExp = nextLvExp
  325. populateCurrentLvAttrs(msgRet.currentLvAttrs, currentLevel)
  326. populateNextLvAttrs(msgRet.nextLvAttrs, currentLevel+1)
  327. -- populateRecycleItem(msgRet.recycleList, human)
  328. Msg.send(msgRet, human.fd)
  329. end
  330. -- 查询可回收道具列表, itemType: 1-item表道具, 2-符文
  331. function RecycleItem_RecycleItemListQuery(human, itemType)
  332. if not isOpen(human) then
  333. return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED)
  334. end
  335. if itemType ~= RECYCLE_ITEM_TYPE_ITEM and itemType ~= RECYCLE_ITEM_TYPE_FUWEN then
  336. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  337. end
  338. local msgRet = Msg.gc.GC_RECYCLE_GET_RECYCLE_LIST
  339. msgRet.recycleList[0] = 0
  340. msgRet.isStart = 1
  341. msgRet.isEnd = 0
  342. local itemArr
  343. if itemType == RECYCLE_ITEM_TYPE_FUWEN then
  344. itemArr = collectFuwenRecycleList(human)
  345. else
  346. itemArr = collectItemRecycleList(human)
  347. end
  348. local itemNum = #itemArr
  349. if itemNum == 0 then
  350. msgRet.isEnd = 1
  351. return Msg.send(msgRet, human.fd)
  352. end
  353. local len = 0
  354. local onceMsgLen = 50
  355. for _, itemInfo in ipairs(itemArr) do
  356. len = len + 1
  357. msgRet.recycleList[0] = len
  358. msgRet.recycleList[len].id = itemInfo[1]
  359. msgRet.recycleList[len].recycleVal = itemInfo[2]
  360. msgRet.recycleList[len].extraInfo = itemInfo[3] or 0
  361. if len >= onceMsgLen then
  362. itemNum = itemNum - len
  363. if itemNum <= 0 then
  364. msgRet.isEnd = 1
  365. return Msg.send(msgRet, human.fd)
  366. end
  367. Msg.send(msgRet, human.fd)
  368. len = 0
  369. msgRet.isStart = 0
  370. end
  371. end
  372. if len > 0 then
  373. msgRet.isEnd = 1
  374. Msg.send(msgRet, human.fd)
  375. end
  376. end
  377. -- 执行回收, itemType: 1-item表道具, 2-符文
  378. function RecycleItem_Recycle_Do(human, itemType, recycleItemStr)
  379. if not isOpen(human) then
  380. return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED)
  381. end
  382. if itemType ~= RECYCLE_ITEM_TYPE_ITEM and itemType ~= RECYCLE_ITEM_TYPE_FUWEN then
  383. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  384. end
  385. local recycleData = getRecycleData(human)
  386. local currentLevel = recycleData and recycleData.level or 0
  387. if currentLevel >= #RecycleConfig then
  388. return Broadcast.sendErr(human, Lang.COMMON_MAXLEVEL)
  389. end
  390. local entries = parseRecycleEntries(recycleItemStr)
  391. if not entries then
  392. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  393. end
  394. if itemType == RECYCLE_ITEM_TYPE_ITEM then
  395. entries = mergeItemRecycleEntries(entries)
  396. end
  397. local validateHandler = RECYCLE_VALIDATE_HANDLER[itemType]
  398. local deleteHandler = RECYCLE_DELETE_HANDLER[itemType]
  399. local totalExp, errLang = validateHandler(human, entries)
  400. if errLang then
  401. return Broadcast.sendErr(human, errLang)
  402. end
  403. deleteHandler(human, entries)
  404. local newLv, newExp = calcLv(human, totalExp)
  405. updateRecycleData(human, newLv, newExp)
  406. updatePower(human)
  407. RecycleItem_Query(human)
  408. RecycleItem_RecycleItemListQuery(human, itemType)
  409. end