Trade.lua 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484
  1. Trade = {}
  2. MINUTE_SECOND = 60 * 1000
  3. TRADE_WAY = {
  4. GARD_BOSS = 1, -- 战盟boss
  5. SIEGE = 2, -- 攻城战
  6. UNION = 3, -- 战盟
  7. WORLD_UP = 4, -- 世界上架
  8. SYSTEM_UP = 5, -- 系统上架
  9. UNION_FLOW = 6, -- 战盟流拍
  10. STALL = 7 -- 面对面商店
  11. }
  12. TRADE_GOODS_TIPS = {
  13. SHOW = 1, -- 显示tips
  14. NO_SHOW = 0 -- 不显示
  15. }
  16. TRADE_RECORD_TYPE = {
  17. PREORDER = 0, -- 预购
  18. PURCHASE = 1, -- 购买
  19. SALE = 2 -- 售出
  20. }
  21. SORT_TYPE = {
  22. DEFAULT = 0, -- 默认
  23. ASC_BY_TIME = 1, -- 按照时间升序
  24. DESC_BY_TIME = 2, -- 按照时间降序
  25. ASC_BY_PRICE = 3, -- 按照价格升序
  26. DESC_BY_PRICE = 4 -- 按照价格降序
  27. }
  28. TRADE_CAPACITY_GLOBAL_ID = 8001
  29. local TRADE_GOODS_RECORD_UPPER_LIMIT = 80
  30. SYS_TRADE_WORLD_GOODS = "R$tradeWorldGoods"
  31. ROLE_TRADE_WORLD_GOODS = "T$tradeWorldGoods"
  32. ROLE_TRADE_GOODS_RECORD = "T$tradeWorldRecord"
  33. ROLE_TRADE_PRE_GOODS = "T$tradeWorldPre"
  34. local LogRecord = {}
  35. function LogRecord.new()
  36. local log = {}
  37. log.type = "" -- 上架 或 购买
  38. log.goodsName = "" -- 商品名字
  39. log.totalPrice = 0 -- 交易价格
  40. log.count = 0 -- 交易数量
  41. return log
  42. end
  43. function LogRecord.log(actor, log)
  44. local recharge = RechargeRecord.getTotalMoney(actor)
  45. local level = getbaseinfo(actor, "level")
  46. local time = getbaseinfo(actor, "nowsec")
  47. local timeToDate = TimeUtil.timeFormat(time)
  48. local roleName = getbaseinfo(actor, "rolename")
  49. local content = roleName .. log.type .. log.goodsName .. "数量为:" .. log.count .. ",总价格为:" ..
  50. log.totalPrice .. ",玩家充值:" .. recharge .. ",玩家等级为:" .. level ..
  51. ",当前时间是:" .. timeToDate
  52. logop(actor, LogOpType.TRADE, content)
  53. info(content)
  54. end
  55. ---@class Trade.GoodInfo 世界商品信息
  56. ---@field itemcfgid number 商品配置id
  57. ---@field itemid number 商品id
  58. ---@field itemname string 商品名字
  59. ---@field entrysize number 词条属性数量
  60. ---@field garde number 品质
  61. ---@field ownid string 商品所属人id
  62. ---@field count number 商品数量
  63. ---@field unitPrice number 商品单价
  64. ---@field totalprice number 商品总价
  65. ---@field job table 职业
  66. ---@field cointype number 货币类型
  67. ---@field publicitytime number 公示时间
  68. ---@field upshelfduration number 竞拍时间
  69. ---@field tax table 税率
  70. ---@field subtype number 商品子类型
  71. ---@field type number 商量类型
  72. ---@field peroreder table 预购人员id
  73. ---@field publicitystatue boolean 是不是公示期间
  74. ---@field listingtime number 上架时间
  75. -- 世界交易行上架
  76. -- msgData 中要包含 itemcfgid,bagindex,count,listingprice,totalprice,id
  77. function Trade.worldTradeListing(actor, msgData)
  78. -- local isOpen, _ = PrivilegeMonth.hasPrivilege(actor, PrivilegeMonth.PrivilegeType.TRADE_SALE)
  79. -- if not isOpen then
  80. -- noticeTip.noticeinfo(actor, StringIdConst.TEXT491)
  81. -- return
  82. -- end
  83. local itemCfgId = msgData["itemcfgid"]
  84. local coinType = tostring(msgData["coinType"])
  85. local stallInfo = ConfigDataManager.getTable("cfg_stall", "id", itemCfgId, "way", TRADE_WAY.WORLD_UP)
  86. if not stallInfo and table.isEmpty(stallInfo) then
  87. noticeTip.noticeinfo(actor, StringIdConst.TEXT383)
  88. return
  89. end
  90. local have = Trade.checkCapacity(actor)
  91. if not have then
  92. noticeTip.noticeinfo(actor, StringIdConst.TEXT370)
  93. return
  94. end
  95. local itemStall = stallInfo[1]
  96. local jobTable = itemStall["job"]
  97. if not jobTable then
  98. jobTable = {0}
  99. elseif jobTable then
  100. jobTable = string.split(jobTable, "#")
  101. end
  102. local money = itemStall["money"]
  103. local moneys = itemStall["moneys"]
  104. local ready = itemStall["ready"]
  105. local readyTime = tonumber(ready) * MINUTE_SECOND
  106. local time = itemStall["time"]
  107. local shellTime = tonumber(time) * MINUTE_SECOND
  108. local tax = itemStall["tax"]
  109. moneys = string.split(moneys, "#")
  110. local isMatchMoney, v = table.findByCondi(moneys, function(a)
  111. return a == coinType;
  112. end)
  113. if isMatchMoney == nil then
  114. tipinfo(actor, "货币类型错误")
  115. return
  116. end
  117. local taxTable = {}
  118. if not tax then
  119. taxTable = {0, 0}
  120. elseif tax then
  121. local taxInfo = string.split(tax, "|")
  122. for index, value in ipairs(taxInfo) do
  123. local taxDetail = string.split(value, "#")
  124. table.insert(taxTable, tonumber(taxDetail[2]))
  125. end
  126. end
  127. local subtypeItem = tonumber(itemStall["subtype"])
  128. local typeItem = tonumber(itemStall["type"])
  129. local minNumber = tonumber(itemStall["minnumber"]) or 1
  130. if tonumber(msgData["count"]) % minNumber ~= 0 then
  131. return
  132. end
  133. local entryCount = 0
  134. local garde = 0
  135. if msgData["id"] ~= 0 then
  136. local itemInfo = getotheritemattinfo(actor, 1, actor:toString(), msgData["id"])
  137. if table.isNullOrEmpty(itemInfo) then
  138. error("交易行上架,获取道具细信息失败,道具id:", msgData["id"])
  139. noticeTip.noticeinfo(actor, StringIdConst.TEXT371)
  140. return
  141. end
  142. local itemCount = itemInfo["itemcount"]
  143. if minNumber == nil or itemCount == nil then
  144. tipinfo(actor, "当前位置的道具数量小于交易行上架最小数量")
  145. return
  146. end
  147. if minNumber > itemCount then
  148. tipinfo(actor, "当前位置的道具数量小于交易行上架最小数量")
  149. -- noticeTip.noticeinfo(actor, StringIdConst.TEXT371)
  150. return
  151. end
  152. local entries = itemInfo["entries"]
  153. if not table.isNullOrEmpty(entries) then
  154. entryCount = table.count(entries)
  155. end
  156. garde = itemInfo["garde"] or 0
  157. else
  158. local itemCount = getbagitemcountbyid(actor, tonumber(msgData["itemcfgid"]));
  159. if minNumber > itemCount then
  160. tipinfo(actor, "当前位置的道具数量小于交易行上架最小数量")
  161. -- noticeTip.noticeinfo(actor, StringIdConst.TEXT371)
  162. return
  163. end
  164. end
  165. info(actor:toString(), "上架道具信息", msgData)
  166. local result = bagtoshell(actor, msgData)
  167. if table.isNullOrEmpty(result) then
  168. info(actor:toString(), "上架", itemStall["name"], "失败,道具被吞噬")
  169. end
  170. if msgData["id"] == 0 then
  171. msgData["id"] = result["itemid"]
  172. end
  173. ---type Trade.GoodInfo 世界商品信息
  174. local itemName = ConfigDataManager.getById("cfg_item", msgData["itemcfgid"]).name
  175. local goods = {
  176. itemcfgid = tonumber(msgData["itemcfgid"]),
  177. itemid = tonumber(msgData["id"]),
  178. placeIn = tonumber(msgData["placeIn"] or "0"),
  179. garde = garde,
  180. itemname = itemName,
  181. entrysize = entryCount,
  182. ownid = actor:toString(),
  183. count = tonumber(msgData["count"]),
  184. unitPrice = tonumber(msgData["listingprice"]),
  185. totalprice = math.round(tonumber(msgData["listingprice"]) * tonumber(msgData["count"]) / minNumber),
  186. job = jobTable,
  187. cointype = coinType,
  188. publicitytime = readyTime,
  189. upshelfduration = shellTime,
  190. tax = taxTable,
  191. subtype = subtypeItem,
  192. type = typeItem,
  193. peroreder = nil,
  194. publicitystatue = true,
  195. listingtime = getbaseinfo(actor, "now")
  196. }
  197. Trade.worldGoodsSave(actor, goods)
  198. --- 保存埋点信息
  199. local log = LogRecord.new()
  200. log.type = "上架"
  201. log.goodsName = itemStall["name"]
  202. log.totalPrice = math.round(tonumber(msgData["listingprice"]) * tonumber(msgData["count"]) / minNumber)
  203. log.count = tonumber(msgData["count"])
  204. LogRecord.log(actor, log)
  205. sendluamsg(actor, LuaMessageIdToClient.RES_TRADE_LISTING_GOODS, true)
  206. TaskHandler.TriggerTaskGoal(actor, TaskTargetType.TRADE_LINE_UP_GOODS, itemCfgId)
  207. end
  208. -- 交易行上架商品
  209. function Trade.tradeHallPlaceIn(actor, msg_data)
  210. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  211. if not allWorldGoods then
  212. return
  213. end
  214. local roleAllGoods = allWorldGoods[actor:toString()]
  215. if not roleAllGoods or table.count(roleAllGoods) <= 0 then
  216. return
  217. end
  218. local placeIn = msg_data.placeIn
  219. for _, itemGoods in pairs(roleAllGoods) do
  220. itemGoods.placeIn = placeIn
  221. if itemGoods.subtype == nil then
  222. local stallInfo = ConfigDataManager.getTable("cfg_stall", "id", itemGoods.itemcfgid, "way", TRADE_WAY.WORLD_UP)
  223. local itemStall = stallInfo[1]
  224. itemGoods.type = tonumber(itemStall["type"])
  225. itemGoods.subType = tonumber(itemStall["subtype"])
  226. end
  227. Trade.worldGoodsSave(actor, itemGoods)
  228. end
  229. end
  230. local goodsCallback = {}
  231. --- 单线程处理全局变量
  232. function trade_listing_good_save(actor, goods)
  233. -- info("上架商品信息", goods)
  234. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  235. if not allWorldGoods then
  236. allWorldGoods = {}
  237. end
  238. local roleAllGoods = allWorldGoods[actor:toString()]
  239. if not roleAllGoods then
  240. roleAllGoods = {}
  241. allWorldGoods[actor:toString()] = roleAllGoods
  242. end
  243. roleAllGoods[tostring(goods.itemid)] = goods
  244. setsysvar(actor, SYS_TRADE_WORLD_GOODS, allWorldGoods)
  245. local cd = goodsCallback[goods.itemid]
  246. if cd ~= nil then
  247. goodsCallback[goods.itemid] = nil
  248. cd.callback(cd.goods)
  249. end
  250. end
  251. -- 保存上架商品
  252. function Trade.worldGoodsSave(actor, goods, callback)
  253. if callback ~= nil then
  254. goodsCallback[goods.itemid] = {
  255. goods = goods,
  256. callback = callback
  257. }
  258. end
  259. callonserial(actor, "trade_listing_good_save", goods)
  260. end
  261. -- 交易行检查格子是否够用
  262. function Trade.checkCapacity(actor)
  263. local capacity = ConfigDataManager.getTableValue("cfg_global", "value", "id", TRADE_CAPACITY_GLOBAL_ID)
  264. local is_has, count = PrivilegeMonth.hasPrivilege(actor, PrivilegeMonth.PrivilegeType.TRADE_LINE_UP_COUNT_INCREASE)
  265. capacity = capacity + count
  266. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  267. if not allWorldGoods then
  268. return true
  269. end
  270. local count = 0
  271. local roleAllGoods = allWorldGoods[actor:toString()]
  272. if roleAllGoods then
  273. count = table.count(roleAllGoods)
  274. end
  275. if count >= capacity then
  276. return false
  277. end
  278. return true
  279. end
  280. -- 下架商品
  281. -- msgData 中要包含 itemcfgid,itemId
  282. function Trade.worldOffShelfGoods(actor, msgData)
  283. local itemId = msgData[2]
  284. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  285. if not allWorldGoods then
  286. noticeTip.noticeinfo(actor, StringIdConst.TEXT372)
  287. return
  288. end
  289. local roleAllGoods = allWorldGoods[actor:toString()]
  290. local goodsDetail = roleAllGoods[tostring(itemId)]
  291. if not goodsDetail then
  292. noticeTip.noticeinfo(actor, StringIdConst.TEXT373)
  293. return
  294. end
  295. -- info("下架商品信息", goodsDetail)
  296. local ownid = goodsDetail.ownid
  297. if actor:toString() ~= tostring(ownid) then
  298. noticeTip.noticeinfo(actor, StringIdConst.TEXT375)
  299. return
  300. end
  301. local publicityTime = goodsDetail.listingtime + goodsDetail.publicitytime
  302. local peroreder = goodsDetail.peroreder
  303. -- info("下架商品预购人员信息", peroreder)
  304. local now = getbaseinfo("now")
  305. if now < publicityTime and not table.isNullOrEmpty(peroreder) then
  306. -- noticeTip.noticeinfo(actor, StringIdConst.TEXT374)
  307. -- 清理预购人员存储的信息
  308. for index, preRid in pairs(peroreder) do
  309. local preActor = getactor(preRid)
  310. local myPreInfo = getplaydef(preActor, ROLE_TRADE_PRE_GOODS)
  311. if not table.isEmpty(myPreInfo) then
  312. local preIndex = Trade.findPreInfo(myPreInfo, tostring(itemId), tostring(goodsDetail.ownid))
  313. if preIndex then
  314. table.remove(myPreInfo, preIndex)
  315. setplaydef(preActor, ROLE_TRADE_PRE_GOODS, myPreInfo)
  316. end
  317. end
  318. sendconfigmailbyrid(actor, preRid, EmailConfig.TRADE_PRE_FAILED, {
  319. [tonumber(goodsDetail.cointype)] = tonumber(goodsDetail.totalprice)
  320. }, goodsDetail.itemname .. "#" .. "货币")
  321. end
  322. end
  323. local count = goodsDetail.count
  324. shelltobag(actor, actor:toString(), itemId, count, actor:toString(), 0, "")
  325. --- 全部下架无需关心组
  326. Trade.changeGoodsInfo(actor, itemId, count, count, 0)
  327. sendluamsg(actor, LuaMessageIdToClient.RES_TRADE_OFF_GOODS, true)
  328. -- WbAuction.Publish()
  329. end
  330. function trade_change_good_info(ownActor, goodId, itemCount, buyCount, minNumber)
  331. local allWorldGoods = getsysvar(ownActor, SYS_TRADE_WORLD_GOODS)
  332. -- info("商品组数", minNumber)
  333. -- info("修改数据前", allWorldGoods)
  334. -- local tradeWorldGoodsInfo = getplaydef(ownActor, ROLE_TRADE_WORLD_GOODS)
  335. if itemCount == buyCount then
  336. local roleAllGoods = allWorldGoods[ownActor:toString()]
  337. roleAllGoods[tostring(goodId)] = nil
  338. setsysvar(ownActor, SYS_TRADE_WORLD_GOODS, allWorldGoods)
  339. elseif itemCount < buyCount then
  340. noticeTip.noticeinfo(actor, StringIdConst.TEXT376)
  341. return
  342. elseif itemCount > buyCount then
  343. local roleAllGoods = allWorldGoods[ownActor:toString()]
  344. local sysGoodDetail = roleAllGoods[tostring(goodId)]
  345. sysGoodDetail.count = itemCount - buyCount
  346. sysGoodDetail.totalprice = math.round(sysGoodDetail.count * sysGoodDetail.unitPrice / minNumber)
  347. setsysvar(ownActor, SYS_TRADE_WORLD_GOODS, allWorldGoods)
  348. end
  349. -- info("修改数据后", allWorldGoods)
  350. end
  351. -- lua中保存商品信息改变
  352. function Trade.changeGoodsInfo(ownActor, goodId, itemCount, buyCount, minNumber)
  353. callonserial(ownActor, "trade_change_good_info", goodId, itemCount, buyCount, minNumber)
  354. end
  355. -- 获取世界商品
  356. function Trade.getTradeWorldGoods(actor, msgData)
  357. Trade.flushWorldGoods()
  358. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  359. if table.isNullOrEmpty(allWorldGoods) then
  360. sendluamsg(actor, LuaMessageIdToClient.RES_GET_TRADE_GOODS, allWorldGoods)
  361. return
  362. end
  363. local goods = Trade.filterGoods(actor, allWorldGoods, msgData)
  364. sendluamsg(actor, LuaMessageIdToClient.RES_GET_TRADE_GOODS, goods)
  365. end
  366. -- 过滤商品
  367. function Trade.filterGoods(actor, allWorldGoods, msgData)
  368. local goods = {}
  369. if msgData[1] == 100 then
  370. Trade.publicityGoods(goods, msgData, allWorldGoods)
  371. return goods
  372. elseif msgData[1] == 200 then
  373. Trade.myPreGoods(actor, goods, msgData, allWorldGoods)
  374. -- Trade.getPreBuyGoods(actor,msgData)
  375. return goods
  376. end
  377. Trade.arrangeGoods(goods, msgData, allWorldGoods)
  378. return goods
  379. end
  380. -- 获取公示商品
  381. function Trade.publicityGoods(goods, msgData, allWorldGoods)
  382. local now = getbaseinfo("now")
  383. for _, roleAllGoods in pairs(allWorldGoods) do
  384. for _, good in pairs(roleAllGoods) do
  385. local listingTime = good.listingtime
  386. local time = listingTime + good.publicitytime
  387. if now < time then
  388. local itemRank = ConfigDataManager.getTableValue("cfg_item", "rank", "id", good.itemCfgId)
  389. if (msgData[5] == 0 or itemRank == msgData[5]) and (msgData[6] == 0 or good.garde == msgData[6]) then
  390. if msgData[4] == 0 or good.job[1] == 0 or table.contains(good.job, tostring(msgData[4])) then
  391. good["publicity"] = 1
  392. good["timename"] = "公示中"
  393. good["time"] = (time - now) / 1000
  394. table.insert(goods, good)
  395. end
  396. end
  397. end
  398. end
  399. end
  400. end
  401. -- 预购商品
  402. function Trade.myPreGoods(actor, goods, msgData, allWorldGoods)
  403. local preGoodInfo = getplaydef(actor, ROLE_TRADE_PRE_GOODS)
  404. if not preGoodInfo or not allWorldGoods then
  405. return
  406. end
  407. for _, preGood in pairs(preGoodInfo) do
  408. local roleAllGoods = allWorldGoods[preGood.rid]
  409. if roleAllGoods then
  410. local good = roleAllGoods[tostring(preGood.goodId)]
  411. if good then
  412. local itemRank = ConfigDataManager.getTableValue("cfg_item", "rank", "id", good.itemCfgId)
  413. if (msgData[1] == 0 or good.type == msgData[1]) and (msgData[2] == 0 or msgData[2] == good.subtype) and
  414. (msgData[5] == 0 or itemRank == msgData[5]) and (msgData[6] == 0 or good.garde == msgData[6]) then
  415. if msgData[4] == 0 or good.job[1] == 0 or table.contains(good.job, tostring(msgData[4])) then
  416. good["publicity"] = 1
  417. good["timename"] = "公示中"
  418. good["time"] = (publicityTime - now) / 1000
  419. table.insert(goods, good)
  420. end
  421. end
  422. end
  423. end
  424. end
  425. end
  426. -- 获取分类商品
  427. function Trade.arrangeGoods(goods, msgData, allWorldGoods)
  428. local now = getbaseinfo("now")
  429. for _, roleAllGoods in pairs(allWorldGoods) do
  430. for _, good in pairs(roleAllGoods) do
  431. -- 获取摆摊时间,如果摊位时间失效,则不放入列表中
  432. local stallInfo = Stall.getStallTimeInfo(getactor(good.ownid))
  433. if stallInfo == nil or stallInfo.endTime * 1000 <= now then
  434. goto continue
  435. end
  436. local itemRank = ConfigDataManager.getTableValue("cfg_item", "rank", "id", good.itemcfgid)
  437. if good and good.placeIn ~= nil and good.placeIn > 0 and good.listingtime and good.publicitytime then
  438. local publicityTime = good.listingtime + good.publicitytime
  439. local offShelfTime = publicityTime + good.upshelfduration
  440. if (msgData[1] == 0 or good.type == msgData[1]) and (msgData[2] == 0 or msgData[2] == good.subtype) and
  441. (msgData[5] == 0 or tonumber(itemRank) == msgData[5]) and
  442. (msgData[6] == 0 or good.garde == msgData[6]) then
  443. if msgData[4] == 0 or good.job[1] == 0 or table.contains(good.job, tostring(msgData[4])) then
  444. -- local have = Trade.checkGood(allWorldGoods,good)
  445. if publicityTime > now then
  446. good["publicity"] = 1
  447. good["timename"] = "公示中"
  448. good["time"] = (publicityTime - now) / 1000
  449. table.insert(goods, good)
  450. elseif publicityTime < now and offShelfTime > now then
  451. good["publicity"] = 0
  452. good["timename"] = "下架时间"
  453. good["time"] = (offShelfTime - now) / 1000
  454. table.insert(goods, good)
  455. end
  456. end
  457. end
  458. end
  459. end
  460. ::continue::
  461. end
  462. Trade.sortGoods(goods, msgData[3])
  463. end
  464. -- 商品排序
  465. function Trade.sortGoods(goods, type)
  466. if type == 0 then
  467. table.sort(goods, function(a, b)
  468. return a.listingtime < b.listingtime
  469. end)
  470. elseif type == SORT_TYPE.ASC_BY_TIME then
  471. table.sort(goods, function(a, b)
  472. return a.listingtime < b.listingtime
  473. end)
  474. elseif type == SORT_TYPE.DESC_BY_TIME then
  475. table.sort(goods, function(a, b)
  476. return a.listingtime > b.listingtime
  477. end)
  478. elseif type == SORT_TYPE.ASC_BY_PRICE then
  479. table.sort(goods, function(a, b)
  480. return a.totalprice < b.totalprice
  481. end)
  482. elseif type == SORT_TYPE.DESC_BY_PRICE then
  483. table.sort(goods, function(a, b)
  484. return a.totalprice > b.totalprice
  485. end)
  486. end
  487. end
  488. -- 购买世界交易行商品
  489. -- msgData 中要包含 itemcfgid,itemId,type,count
  490. function Trade.bugWorldGoods(actor, msgData)
  491. local buyCount = msgData[4]
  492. local itemId = msgData[2]
  493. local goodRid = msgData[5]
  494. local needTax = msgData[6]
  495. local goodActor = getactor(actor, goodRid)
  496. if not PrivilegeMonth.hasPrivilege(actor, PrivilegeMonth.PrivilegeType.STALL) then
  497. tipinfo(actor, "没有交易权限")
  498. return
  499. end
  500. local allWorldGoods = getsysvar(goodActor, SYS_TRADE_WORLD_GOODS)
  501. if not allWorldGoods then
  502. noticeTip.noticeinfo(actor, StringIdConst.TEXT372)
  503. return
  504. end
  505. local roleAllGoods = allWorldGoods[tostring(goodRid)]
  506. if not roleAllGoods then
  507. noticeTip.noticeinfo(actor, StringIdConst.TEXT372)
  508. return
  509. end
  510. local goodsDetail = roleAllGoods[tostring(itemId)]
  511. if not goodsDetail then
  512. noticeTip.noticeinfo(actor, StringIdConst.TEXT373)
  513. return
  514. end
  515. if goodsDetail.specifyId ~= nil then
  516. return
  517. end
  518. -- info("购买商品信息", goodsDetail)
  519. local minNumber = ConfigDataManager.getTableValue("cfg_stall", "minnumber", "id", goodsDetail.itemcfgid, "way",
  520. TRADE_WAY.WORLD_UP)
  521. -- jprint("minNumber", minNumber)
  522. if not minNumber then
  523. error(actor, "购买道具", goodsDetail.itemcfgid, "未配置minNumber")
  524. return
  525. end
  526. if minNumber and tonumber(buyCount) % minNumber ~= 0 then
  527. error(actor, "购买道具", goodsDetail.itemcfgid, "不是minNumber的倍数")
  528. return
  529. end
  530. local publicityTime = goodsDetail.listingtime + goodsDetail.publicitytime
  531. local now = getbaseinfo("now")
  532. if now < publicityTime then
  533. noticeTip.noticeinfo(actor, StringIdConst.TEXT377)
  534. return
  535. end
  536. local ownid = goodsDetail.ownid
  537. if actor:toString() == tostring(ownid) then
  538. noticeTip.noticeinfo(actor, StringIdConst.TEXT378)
  539. return
  540. end
  541. local unitPrice = goodsDetail.unitPrice
  542. local price = math.round(unitPrice * buyCount / minNumber)
  543. local cointype = goodsDetail.cointype
  544. local ownActor = getactor(actor, ownid)
  545. local itemCount = goodsDetail.count
  546. local haveCount = getbagitemcountbyid(actor, cointype)
  547. if haveCount < price then
  548. noticeTip.noticeinfo(actor, StringIdConst.TEXT379)
  549. return
  550. end
  551. local saleName = getbaseinfo(ownActor, "rolename")
  552. local buyName = getbaseinfo(actor, "rolename")
  553. local desc = string.format("%s%s购买了%s%s的%s*%s",
  554. buyName,
  555. actor:toString(),
  556. saleName,
  557. ownActor:toString(),
  558. goodsDetail.itemname,
  559. tostring(goodsDetail.count))
  560. removeitemfrombag(actor, cointype, price, 0, 9999, '交易行')
  561. shelltobag(ownActor, ownid, itemId, buyCount, actor:toString(), EmailConfig.TRADE_BUY, goodsDetail.itemname, nil, desc)
  562. Trade.changeGoodsInfo(ownActor, itemId, itemCount, buyCount, minNumber)
  563. local afterTaxPrice = Trade.calculationTax(ownActor, goodsDetail, buyCount, minNumber, needTax)
  564. sendconfigmailbyrid(ownActor, ownid, EmailConfig.TRADE_SUCCESSFUL_SOLD, {
  565. [tonumber(cointype)] = tonumber(afterTaxPrice)
  566. }, goodsDetail.itemname)
  567. Trade.saveTradeHistory(actor, TRADE_RECORD_TYPE.PURCHASE, goodsDetail, price)
  568. Trade.saveTradeHistory(ownActor, TRADE_RECORD_TYPE.SALE, goodsDetail, afterTaxPrice)
  569. sendluamsg(actor, LuaMessageIdToClient.RES_TRADE_BUY_GOODS, true)
  570. Trade.changeItemInfo(actor, ownid, itemId)
  571. end
  572. -- 计算税率
  573. function Trade.calculationTax(ownActor, goodsDetail, count, minNumber, needTax)
  574. local unitPrice = goodsDetail.unitPrice
  575. local totalPrice = math.round(unitPrice * count / minNumber)
  576. local is_open, rate = PrivilegeMonth.hasPrivilege(ownActor, PrivilegeMonth.PrivilegeType.TAX_RATE)
  577. if is_open or needTax <= 0 then
  578. totalPrice = totalPrice * (10000 - rate) / 10000
  579. totalPrice = math.round(totalPrice)
  580. else
  581. local table = goodsDetail.tax
  582. local tax = tonumber(table[1])
  583. local has_vip, vip_rate = VipGiftPack.hasPrivilege(ownActor, VipPrivilege.Type.tax)
  584. if has_vip and string.tonumber(vip_rate) > 0 then
  585. tax = tax * (100 - tonumber(vip_rate)) / 100
  586. tax = math.round(tax)
  587. end
  588. totalPrice = totalPrice * (100 - tax) / 100
  589. totalPrice = math.round(totalPrice)
  590. local deleteCount = tonumber(table[2])
  591. if has_vip then
  592. local addCount = math.round((deleteCount * tonumber(vip_rate)) / 100)
  593. deleteCount = deleteCount - addCount
  594. end
  595. totalPrice = totalPrice - deleteCount
  596. end
  597. return totalPrice
  598. end
  599. -- 保存交易记录
  600. function Trade.saveTradeHistory(actor, type, goodsDetail, totalPrice)
  601. local tradeRecorde = getplaydef(actor, ROLE_TRADE_GOODS_RECORD)
  602. if table.isNullOrEmpty(tradeRecorde) then
  603. tradeRecorde = {}
  604. end
  605. --- 整理交易记录
  606. if table.count(tradeRecorde) > TRADE_GOODS_RECORD_UPPER_LIMIT then
  607. local haveCount = table.count(tradeRecorde)
  608. local deleteCount = haveCount - TRADE_GOODS_RECORD_UPPER_LIMIT
  609. for i = 1, deleteCount do
  610. table.remove(tradeRecorde, 1)
  611. end
  612. end
  613. ---type Trade.Recorde 交易记录
  614. local goodRecord = {
  615. itemname = goodsDetail.itemname,
  616. time = getbaseinfo("now"),
  617. tradetype = type,
  618. cointype = goodsDetail.cointype,
  619. price = totalPrice
  620. }
  621. table.insert(tradeRecorde, goodRecord)
  622. setplaydef(actor, ROLE_TRADE_GOODS_RECORD, tradeRecorde)
  623. end
  624. ---@class Trade.Recorde 交易记录
  625. ---@field itemname string 商品名字
  626. ---@field time number 成交时间
  627. ---@field tradetype number 成交类型
  628. ---@field cointype number 货币类型
  629. ---@field price number 成交价格
  630. -- 获取我的交易记录
  631. function Trade.getWorldTradeRecord(actor)
  632. local tradeRecorde = getplaydef(actor, ROLE_TRADE_GOODS_RECORD)
  633. sendluamsg(actor, LuaMessageIdToClient.RES_TRADE_RECORD, tradeRecorde)
  634. end
  635. -- 获取我上架商品
  636. function Trade.getWorldMyListing(actor)
  637. local listingGood = {}
  638. local capacity = ConfigDataManager.getTableValue("cfg_global", "value", "id", TRADE_CAPACITY_GLOBAL_ID)
  639. local is_has, count = PrivilegeMonth.hasPrivilege(actor, PrivilegeMonth.PrivilegeType.TRADE_LINE_UP_COUNT_INCREASE)
  640. capacity = capacity + count
  641. listingGood["capacity"] = capacity
  642. local allgoods = {}
  643. local stallInfo = Stall.getStallTimeInfo(actor)
  644. if not stallInfo then
  645. stallInfo = {}
  646. end
  647. sendluamsg(actor, LuaMessageIdToClient.RES_STALL_INFO, stallInfo)
  648. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  649. if not allWorldGoods then
  650. local roleWorld = {}
  651. listingGood["number"] = 0
  652. listingGood["allgoods"] = roleWorld
  653. sendluamsg(actor, LuaMessageIdToClient.RES_TRADE_MY_SHELVES, listingGood)
  654. -- noticeTip.noticeinfo(actor, StringIdConst.TEXT372)
  655. return
  656. end
  657. local roleWorld = allWorldGoods[actor:toString()]
  658. -- local roleWorld = getplaydef(actor, ROLE_TRADE_WORLD_GOODS)
  659. if not roleWorld then
  660. roleWorld = {}
  661. listingGood["number"] = 0
  662. listingGood["allgoods"] = roleWorld
  663. sendluamsg(actor, LuaMessageIdToClient.RES_TRADE_MY_SHELVES, listingGood)
  664. return
  665. end
  666. local now = getbaseinfo("now")
  667. for index, good in pairs(roleWorld) do
  668. local publicityTime = good.listingtime + good.publicitytime
  669. local offShelfTime = publicityTime + good.upshelfduration
  670. if publicityTime > now then
  671. good["publicity"] = 1
  672. good["timename"] = "公示中"
  673. good["time"] = (publicityTime - now) / 1000
  674. elseif publicityTime < now and offShelfTime > now then
  675. good["publicity"] = 0
  676. good["timename"] = "下架时间"
  677. good["time"] = (offShelfTime - now) / 1000
  678. end
  679. table.insert(allgoods, good)
  680. end
  681. if allgoods then
  682. Trade.sortGoods(allgoods, 0)
  683. end
  684. listingGood["number"] = #allgoods
  685. listingGood["allgoods"] = allgoods
  686. -- jprint("listingGood", listingGood)
  687. sendluamsg(actor, LuaMessageIdToClient.RES_TRADE_MY_SHELVES, listingGood)
  688. end
  689. -- 预购商品
  690. -- msgData 中要包含 itemcfgid,itemId,type
  691. function Trade.preWorldGoods(actor, msgData)
  692. local itemId = msgData[2]
  693. local goodRid = msgData[4]
  694. local goodActor = getactor(actor, goodRid)
  695. local allWorldGoods = getsysvar(goodActor, SYS_TRADE_WORLD_GOODS)
  696. if not allWorldGoods then
  697. noticeTip.noticeinfo(actor, StringIdConst.TEXT372)
  698. return
  699. end
  700. local roleAllGoods = allWorldGoods[tostring(goodRid)]
  701. if not roleAllGoods then
  702. noticeTip.noticeinfo(actor, StringIdConst.TEXT372)
  703. return
  704. end
  705. local goodsDetail = roleAllGoods[tostring(itemId)]
  706. if not goodsDetail then
  707. noticeTip.noticeinfo(actor, StringIdConst.TEXT373)
  708. return
  709. end
  710. -- info("预购商品信息", goodsDetail)
  711. local publicityTime = goodsDetail.listingtime + goodsDetail.publicitytime
  712. local now = getbaseinfo("now")
  713. if now > publicityTime then
  714. noticeTip.noticeinfo(actor, StringIdConst.TEXT380)
  715. return
  716. end
  717. local ownid = goodsDetail.ownid
  718. if actor:toString() == tostring(ownid) then
  719. noticeTip.noticeinfo(actor, StringIdConst.TEXT381)
  720. return
  721. end
  722. local peroreder = goodsDetail.peroreder
  723. if peroreder then
  724. for index, preRid in pairs(peroreder) do
  725. if tostring(preRid) == actor:toString() then
  726. noticeTip.noticeinfo(actor, StringIdConst.TEXT382)
  727. return
  728. end
  729. end
  730. end
  731. local totalprice = goodsDetail.totalprice
  732. local cointype = goodsDetail.cointype
  733. local haveCount = getbagitemcountbyid(actor, cointype)
  734. if haveCount < totalprice then
  735. noticeTip.noticeinfo(actor, StringIdConst.TEXT379)
  736. return
  737. end
  738. removeitemfrombag(actor, cointype, totalprice, 0, 9999, '交易行')
  739. Trade.addPre(goodActor, itemId, goodRid, actor)
  740. local preGoodInfo = getplaydef(actor, ROLE_TRADE_PRE_GOODS)
  741. if not preGoodInfo then
  742. preGoodInfo = {}
  743. end
  744. local perGoodInfo = {
  745. rid = goodRid,
  746. goodId = itemId
  747. }
  748. table.insert(preGoodInfo, perGoodInfo)
  749. setplaydef(actor, ROLE_TRADE_PRE_GOODS, preGoodInfo)
  750. Trade.saveTradeHistory(actor, TRADE_RECORD_TYPE.PREORDER, goodsDetail, totalprice)
  751. sendluamsg(actor, LuaMessageIdToClient.RES_TRADE_PRE_ORDER, true)
  752. end
  753. -- 商品中添加预购信息
  754. function Trade.addPre(actor, goodId, goodRid, preActor)
  755. callonserial(actor, "trade_add_pre_info", goodId, goodRid, preActor)
  756. end
  757. function trade_add_pre_info(actor, goodId, goodRid, preActor)
  758. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  759. local roleAllGoods = allWorldGoods[tostring(goodRid)]
  760. local goodsDetail = roleAllGoods[tostring(goodId)]
  761. local peroreder = goodsDetail.peroreder
  762. if not peroreder then
  763. peroreder = {}
  764. end
  765. table.insert(peroreder, preActor:toString())
  766. goodsDetail.peroreder = peroreder
  767. setsysvar(actor, SYS_TRADE_WORLD_GOODS, allWorldGoods)
  768. end
  769. function trade_flush_world_goods()
  770. local serverType = getbaseinfo("servertype")
  771. if serverType == 2 then
  772. -- 跨服服务器不执行
  773. return
  774. end
  775. local allWorldGoods = getsysvar(SYS_TRADE_WORLD_GOODS)
  776. if table.isNullOrEmpty(allWorldGoods) then
  777. return
  778. end
  779. local now = getbaseinfo("now")
  780. for index, roleAllGoods in pairs(allWorldGoods) do
  781. for index, good in pairs(roleAllGoods) do
  782. if good and good.listingtime and good.publicitytime then
  783. local publicityTime = good.listingtime + good.publicitytime
  784. local offShelfTime = publicityTime + good.upshelfduration
  785. if now > publicityTime and now < offShelfTime and good.publicitystatue then
  786. local peroreder = good.peroreder
  787. if table.isNullOrEmpty(peroreder) then
  788. good.publicitystatue = false
  789. -- Trade.changeGoodState(good, roleAllGoods)
  790. elseif peroreder then
  791. Trade.handlePre(good, roleAllGoods)
  792. end
  793. elseif offShelfTime < now then
  794. local isFinish = Trade.flowFilming(good, roleAllGoods)
  795. if isFinish == false then
  796. roleAllGoods[index] = nil
  797. end
  798. end
  799. end
  800. end
  801. end
  802. setsysvar(SYS_TRADE_WORLD_GOODS, allWorldGoods)
  803. end
  804. -- 交易行刷新
  805. function Trade.flushWorldGoods()
  806. callonserial("trade_flush_world_goods")
  807. end
  808. -- 合服时下架所有商品
  809. function Trade.combineglobalvar(varName, varData)
  810. gameDebug.print("合服时交易行全部商品信息", varData)
  811. for index, allWorldGoods in pairs(varData) do
  812. if not table.isEmpty(allWorldGoods) then
  813. for index, roleAllGoods in pairs(allWorldGoods) do
  814. for index, good in pairs(roleAllGoods) do
  815. if not table.isEmpty(good) then
  816. local peroreder = good.peroreder
  817. if table.isNullOrEmpty(peroreder) then
  818. Trade.flowFilming(good, roleAllGoods)
  819. else
  820. Trade.handlePre(good, roleAllGoods)
  821. end
  822. end
  823. end
  824. end
  825. end
  826. end
  827. setsysvar(SYS_TRADE_WORLD_GOODS, {})
  828. end
  829. -- 清理交易行脏数据
  830. function cleartradedata(actor)
  831. setsysvar(actor, SYS_TRADE_WORLD_GOODS, {})
  832. end
  833. -- 改变商品状态(公示状态改成竞拍)
  834. function Trade.changeGoodState(good, roleAllGoods)
  835. local ownId = good.ownid
  836. local ownActor = getactor(ownId)
  837. local allWorldGood = getsysvar(ownActor, SYS_TRADE_WORLD_GOODS)
  838. local myListingGoods = allWorldGood[ownActor:toString()]
  839. if not myListingGoods then
  840. return
  841. end
  842. local myGoodInfo = myListingGoods[tostring(good.itemid)]
  843. myGoodInfo.publicitystatue = false
  844. myListingGoods[tostring(good.itemid)] = myGoodInfo
  845. allWorldGood[ownActor:toString()] = myListingGoods
  846. setsysvar(ownActor, SYS_TRADE_WORLD_GOODS, allWorldGood)
  847. end
  848. -- 处理预购商品
  849. function Trade.handlePre(good, roleAllGoods)
  850. local peroreder = good.peroreder
  851. local successIndex = math.random(1, #peroreder)
  852. local successRid = peroreder[successIndex]
  853. local ownActor = getactor(good.ownid)
  854. local goodId = good.itemid
  855. -- 清理预购人员存储的信息
  856. for index, preRid in pairs(peroreder) do
  857. if tostring(successRid) ~= tostring(preRid) then
  858. local preActor = getactor(preRid)
  859. local myPreInfo = getplaydef(preActor, ROLE_TRADE_PRE_GOODS)
  860. if not table.isEmpty(myPreInfo) then
  861. local preIndex = Trade.findPreInfo(myPreInfo, tostring(goodId), tostring(good.ownid))
  862. if preIndex then
  863. table.remove(myPreInfo, preIndex)
  864. setplaydef(preActor, ROLE_TRADE_PRE_GOODS, myPreInfo)
  865. end
  866. end
  867. sendconfigmailbyrid(ownActor, preRid, EmailConfig.TRADE_PRE_FAILED, {
  868. [tonumber(good.cointype)] = tonumber(good.totalprice)
  869. }, good.itemname .. "#" .. "货币")
  870. end
  871. end
  872. local successActor = getactor(successRid)
  873. local minNumber = ConfigDataManager.getTableValue("cfg_stall", "minnumber", "id", good.itemcfgid, "way",
  874. TRADE_WAY.WORLD_UP)
  875. -- Trade.changeGoodsInfo(ownActor,itemId,itemCount,buyCount)
  876. local afterTaxPrice = Trade.calculationTax(ownActor, good, good.count, minNumber)
  877. sendconfigmailbyrid(ownActor, good.ownid, EmailConfig.TRADE_SUCCESSFUL_SOLD, {
  878. [tonumber(good.cointype)] = tonumber(afterTaxPrice)
  879. }, good.itemname)
  880. shelltobag(ownActor, good.ownid, goodId, good.count, successRid, EmailConfig.TRADE_BUY, good.itemname)
  881. roleAllGoods[tostring(good.itemid)] = nil
  882. -- Trade.saveTradeHistory(actor,TRADE_RECORD_TYPE.PURCHASE,goodsDetail,price)
  883. Trade.saveTradeHistory(ownActor, TRADE_RECORD_TYPE.SALE, good, afterTaxPrice)
  884. Trade.changeItemInfo(successActor, good.ownid, goodId)
  885. end
  886. -- 获取预购商品索引
  887. function Trade.findPreInfo(myPreInfo, goodId, rid)
  888. for index, preInfo in pairs(myPreInfo) do
  889. if tostring(preInfo.goodId) == tostring(goodId) and tostring(preInfo.rid) == tostring(rid) then
  890. return index
  891. end
  892. end
  893. end
  894. -- 商品流拍
  895. function Trade.flowFilming(good, roleAllGoods)
  896. local ownId = good.ownid
  897. if ownId == nil or ownId == "nil" then
  898. error("当前商品没有归属", good)
  899. return false
  900. end
  901. local ownActor = getactor(ownId)
  902. if table.isNullOrEmpty(roleAllGoods) then
  903. error("当前玩家没有上架交易行商品", roleAllGoods)
  904. return false
  905. end
  906. shelltobag(ownActor, ownActor:toString(), good.itemid, good.count, ownActor:toString())
  907. roleAllGoods[tostring(good.itemid)] = nil
  908. return true
  909. end
  910. -- 发送充值消息
  911. function Trade.sendRecharge(actor)
  912. local allRechargeInfo = getsysvar(actor, SYS_RECHARGE_INFO)
  913. if table.isEmpty(allRechargeInfo) then
  914. allRechargeInfo = {}
  915. end
  916. local rechargeInfo = allRechargeInfo[actor:toString()]
  917. sendluamsg(actor, LuaMessageIdToClient.RES_RECHARGE_TRADE_INFO, rechargeInfo)
  918. end
  919. -- 午夜刷新重置记录
  920. function Trade.serverMiddleNight()
  921. local allRechargeInfo = getsysvar(SYS_RECHARGE_INFO)
  922. if table.isEmpty(allRechargeInfo) then
  923. return
  924. end
  925. local now = getbaseinfo("now")
  926. for index, roleRechargeInfo in pairs(allRechargeInfo) do
  927. local actor = getactor(index)
  928. local rechargeGear = ConfigDataManager.getTable("cfg_lines", "id", roleRechargeInfo.gearPosition)
  929. if rechargeGear then
  930. local currentGearInfo = rechargeGear[1]
  931. local decayTime = tonumber(currentGearInfo.decaytime)
  932. local lsatGearChangeTime = roleRechargeInfo.lsatGearChangeTime
  933. local decay = lsatGearChangeTime + decayTime * 24 * 60 * MINUTE_SECOND
  934. if decay < now then
  935. -- 降档处理
  936. local decayGears = tonumber(currentGearInfo.decaygears)
  937. if roleRechargeInfo.gearPosition ~= 1 then
  938. roleRechargeInfo.gearPosition = decayGears
  939. roleRechargeInfo.lsatGearChangeTime = now
  940. local limit = Trade.calculationGearMaxLimit(nil, decayGears)
  941. roleRechargeInfo.upperLimit = limit
  942. end
  943. roleRechargeInfo.quit = true
  944. roleRechargeInfo.gearRecharge = 0
  945. if tonumber(currentGearInfo.decaytime) > 1 then
  946. roleRechargeInfo.bubble = false
  947. else
  948. roleRechargeInfo.bubble = true
  949. end
  950. else
  951. -- 不降档位检查是否要显示气泡
  952. local time = lsatGearChangeTime + (decayTime - 1) * 24 * 60 * MINUTE_SECOND
  953. if time < now then
  954. roleRechargeInfo.bubble = true
  955. else
  956. roleRechargeInfo.bubble = false
  957. end
  958. end
  959. roleRechargeInfo.cost = 0
  960. allRechargeInfo[index] = roleRechargeInfo
  961. end
  962. sendluamsg(actor, LuaMessageIdToClient.RES_RECHARGE_TRADE_INFO, roleRechargeInfo)
  963. end
  964. setsysvar(SYS_RECHARGE_INFO, allRechargeInfo)
  965. end
  966. ---@class recharge 充值记录
  967. ---@field totalRecharge number 总共充值金额
  968. ---@field lastRechargeTime number 上次充值时间(毫秒时间戳)
  969. ---@field gearPosition number 当前档位
  970. ---@field gearRecharge number 档位充值金额
  971. ---@field quit boolean 是否退档
  972. ---@field lsatGearChangeTime number 重置档位时间
  973. ---@field cost number 花费额度
  974. ---@field upperLimit number 额度上限
  975. ---@field bubble boolean 是否显示气泡
  976. SYS_RECHARGE_INFO = "R$rechargeInfo"
  977. function tsetrechargegear(actor)
  978. Trade.recharge(actor, 1)
  979. end
  980. -- 检查当前额度是否够
  981. function Trade.checkCost(actor, price)
  982. local allRechargeInfo = getsysvar(actor, SYS_RECHARGE_INFO)
  983. if table.isEmpty(allRechargeInfo) then
  984. allRechargeInfo = {}
  985. end
  986. local rechargeInfo = allRechargeInfo[actor:toString()]
  987. if table.isEmpty(rechargeInfo) then
  988. noticeTip.noticeinfo(actor, StringIdConst.TEXT462)
  989. return false
  990. end
  991. local cost = rechargeInfo.cost
  992. local upperLimit = rechargeInfo.upperLimit
  993. if upperLimit >= cost + price then
  994. return true
  995. else
  996. noticeTip.noticeinfo(actor, StringIdConst.TEXT462)
  997. return false
  998. end
  999. end
  1000. -- 增加花费
  1001. function Trade.addCost(actor, price)
  1002. local allRechargeInfo = getsysvar(actor, SYS_RECHARGE_INFO)
  1003. if table.isEmpty(allRechargeInfo) then
  1004. allRechargeInfo = {}
  1005. end
  1006. local rechargeInfo = allRechargeInfo[actor:toString()]
  1007. if table.isEmpty(rechargeInfo) then
  1008. return
  1009. end
  1010. rechargeInfo.cost = rechargeInfo.cost + price
  1011. allRechargeInfo[actor:toString()] = rechargeInfo
  1012. setsysvar(actor, SYS_RECHARGE_INFO, allRechargeInfo)
  1013. end
  1014. -- 减少花费
  1015. function Trade.deleteCost(actor, price)
  1016. local allRechargeInfo = getsysvar(actor, SYS_RECHARGE_INFO)
  1017. if table.isEmpty(allRechargeInfo) then
  1018. allRechargeInfo = {}
  1019. end
  1020. local rechargeInfo = allRechargeInfo[actor:toString()]
  1021. if table.isEmpty(rechargeInfo) then
  1022. return
  1023. end
  1024. if rechargeInfo.cost > price then
  1025. rechargeInfo.cost = rechargeInfo.cost - price
  1026. else
  1027. rechargeInfo.cost = 0
  1028. end
  1029. allRechargeInfo[actor:toString()] = rechargeInfo
  1030. setsysvar(actor, SYS_RECHARGE_INFO, allRechargeInfo)
  1031. end
  1032. -- 更新充值信息
  1033. function Trade.recharge(actor, cfg, count, amount, ext, outRewards)
  1034. local allRechargeInfo = getsysvar(actor, SYS_RECHARGE_INFO)
  1035. if table.isEmpty(allRechargeInfo) then
  1036. allRechargeInfo = {}
  1037. end
  1038. local rechargeInfo = allRechargeInfo[actor:toString()]
  1039. if table.isEmpty(rechargeInfo) then
  1040. rechargeInfo = {
  1041. totalRecharge = amount,
  1042. lastRechargeTime = getbaseinfo(actor, "now"),
  1043. gearPosition = Trade.getRechargeGear(actor, amount),
  1044. gearRecharge = 0,
  1045. quit = false,
  1046. lsatGearChangeTime = getbaseinfo(actor, "now"),
  1047. cost = 0,
  1048. upperLimit = 0,
  1049. bubble = false
  1050. }
  1051. local upperLimit = Trade.calculationUpperLimit(actor, rechargeInfo.gearPosition, rechargeInfo.totalRecharge,
  1052. rechargeInfo.quit)
  1053. rechargeInfo.upperLimit = upperLimit
  1054. allRechargeInfo[actor:toString()] = rechargeInfo
  1055. setsysvar(actor, SYS_RECHARGE_INFO, allRechargeInfo)
  1056. sendluamsg(actor, LuaMessageIdToClient.RES_RECHARGE_TRADE_INFO, rechargeInfo)
  1057. return
  1058. end
  1059. -- 已经充值过逻辑处理
  1060. rechargeInfo.totalRecharge = rechargeInfo.totalRecharge + amount
  1061. rechargeInfo.lastRechargeTime = getbaseinfo(actor, "now")
  1062. local gearPosition = rechargeInfo.gearPosition
  1063. local rechargeGear = ConfigDataManager.getTable("cfg_lines", "id", gearPosition)
  1064. if not rechargeGear then
  1065. -- error("当前充值档位出现错误")
  1066. return
  1067. end
  1068. local gearInfo = rechargeGear[1]
  1069. local activationRecharge = tonumber(gearInfo.activationrecharge)
  1070. local allRecharge = rechargeInfo.gearRecharge + amount
  1071. if rechargeInfo.quit then
  1072. -- 有退档现象,检查是否可以提升档位
  1073. if allRecharge >= activationRecharge then
  1074. -- 可以提升档位
  1075. local maxGear = Trade.getRechargeGear(actor, rechargeInfo.totalRecharge)
  1076. rechargeInfo.gearPosition = maxGear
  1077. rechargeInfo.gearRecharge = 0
  1078. rechargeInfo.quit = false
  1079. local upperLimit = Trade.calculationUpperLimit(actor, maxGear, rechargeInfo.totalRecharge, false)
  1080. rechargeInfo.upperLimit = upperLimit
  1081. else
  1082. -- 不能提升档位
  1083. rechargeInfo.gearRecharge = rechargeInfo.gearRecharge + amount
  1084. end
  1085. else
  1086. -- 没有发生过退档
  1087. if allRecharge >= activationRecharge then
  1088. -- 可以提升档位
  1089. local maxGear = Trade.getRechargeGear(actor, rechargeInfo.totalRecharge)
  1090. rechargeInfo.gearPosition = maxGear
  1091. rechargeInfo.gearRecharge = 0
  1092. rechargeInfo.quit = false
  1093. else
  1094. -- 不能提升档位
  1095. rechargeInfo.gearRecharge = rechargeInfo.gearRecharge + amount
  1096. end
  1097. local upperLimit = Trade.calculationUpperLimit(actor, rechargeInfo.gearPosition, rechargeInfo.totalRecharge,
  1098. false)
  1099. rechargeInfo.upperLimit = upperLimit
  1100. end
  1101. rechargeInfo.lsatGearChangeTime = getbaseinfo(actor, "now")
  1102. rechargeInfo.bubble = false
  1103. allRechargeInfo[actor:toString()] = rechargeInfo
  1104. setsysvar(actor, SYS_RECHARGE_INFO, allRechargeInfo)
  1105. -- 发送lua信息
  1106. sendluamsg(actor, LuaMessageIdToClient.RES_RECHARGE_TRADE_INFO, rechargeInfo)
  1107. end
  1108. -- 获取充值最高档位
  1109. function Trade.getRechargeGear(actor, totalRecharge)
  1110. local rechargeGear = ConfigDataManager.getTable("cfg_lines")
  1111. if table.isEmpty(rechargeGear) then
  1112. return 0
  1113. end
  1114. local maxGear = 0
  1115. for index, gear in pairs(rechargeGear) do
  1116. local interval = gear.interval
  1117. local intervalTable = string.split(interval, "#")
  1118. local minRecharge = tonumber(intervalTable[1])
  1119. local maxRecharge = tonumber(intervalTable[2])
  1120. if tonumber(gear.id) > maxGear then
  1121. maxGear = tonumber(gear.id)
  1122. end
  1123. if totalRecharge >= minRecharge and totalRecharge <= maxRecharge then
  1124. return tonumber(gear.id)
  1125. end
  1126. end
  1127. return maxGear
  1128. end
  1129. -- 计算额度上限.
  1130. function Trade.calculationUpperLimit(actor, gear, totalRecharge, quit)
  1131. if quit then
  1132. return Trade.calculationGearMaxLimit(actor, gear)
  1133. else
  1134. return Trade.calculationAllMaxLimit(actor, gear, totalRecharge)
  1135. end
  1136. end
  1137. -- 计算档位的最大限额
  1138. function Trade.calculationGearMaxLimit(actor, currentGear)
  1139. if currentGear < 1 then
  1140. return 0
  1141. end
  1142. local rechargeGear = ConfigDataManager.getTable("cfg_lines")
  1143. if table.isEmpty(rechargeGear) then
  1144. return 0
  1145. end
  1146. local limit = 0
  1147. for index, gear in pairs(rechargeGear) do
  1148. if currentGear >= tonumber(gear.id) then
  1149. local interval = gear.interval
  1150. local intervalTable = string.split(interval, "#")
  1151. local minRecharge = tonumber(intervalTable[1])
  1152. local maxRecharge = tonumber(intervalTable[2])
  1153. local each = tonumber(gear.each)
  1154. local quotaLimit = tonumber(gear.quotalimit)
  1155. local gearLimit = math.ceil((maxRecharge - minRecharge + 1) / each) * quotaLimit
  1156. limit = limit + gearLimit
  1157. end
  1158. end
  1159. return limit
  1160. end
  1161. -- 计算总共充值的最大额度
  1162. function Trade.calculationAllMaxLimit(actor, currentGear, totalRecharge)
  1163. local rechargeGear = ConfigDataManager.getTable("cfg_lines", "id", currentGear)
  1164. if table.isEmpty(rechargeGear) then
  1165. -- error("当前充值档位出现错误")
  1166. end
  1167. local currentGearInfo = rechargeGear[1]
  1168. local interval = currentGearInfo.interval
  1169. local intervalTable = string.split(interval, "#")
  1170. local minRecharge = tonumber(intervalTable[1])
  1171. local each = tonumber(currentGearInfo.each)
  1172. local quotaLimit = tonumber(currentGearInfo.quotalimit)
  1173. local currentPrice = totalRecharge - minRecharge + 1
  1174. local gearLimit = math.ceil(currentPrice / each) * quotaLimit
  1175. local gear = currentGear - 1
  1176. local allLimit = Trade.calculationGearMaxLimit(actor, gear)
  1177. return gearLimit + allLimit
  1178. end
  1179. -- ------------------------------旧方法------------------------------------------------------------------------
  1180. -- 战盟boss上架交易行
  1181. function Trade.unionListGoods(actor, activityId, closetDay, listingGoods, myHurtMember, allianceId)
  1182. for index, goods in pairs(listingGoods) do
  1183. local itemCfgId = goods["itemcfgid"]
  1184. local stallInfo = ConfigDataManager.getTable("cfg_stall", "id", itemCfgId, "startday", closetDay, "way",
  1185. TRADE_WAY.GARD_BOSS)
  1186. if not stallInfo then
  1187. noticeTip.noticeinfo(actor, StringIdConst.TEXT383)
  1188. return
  1189. end
  1190. local itemStall = stallInfo[1]
  1191. local job = itemStall["job"]
  1192. goods["job"] = job
  1193. local time = itemStall["time"]
  1194. goods["time"] = time
  1195. local money = itemStall["money"]
  1196. goods["money"] = money
  1197. local fixedPrice = itemStall["fixedprice"]
  1198. goods["fixedPrice"] = fixedPrice
  1199. local startingPrice = itemStall["startingprice"]
  1200. goods["startingPrice"] = startingPrice
  1201. local auction = itemStall["auction"]
  1202. goods["auction"] = auction
  1203. local type = itemStall["type"]
  1204. local subtype = itemStall["subtype"]
  1205. goods["type"] = type
  1206. goods["subtype"] = subtype
  1207. goods["position"] = tostring(TRADE_WAY.GARD_BOSS)
  1208. end
  1209. uniontradelisting(actor, activityId, listingGoods, myHurtMember, allianceId)
  1210. end
  1211. -- 战盟boss竞价
  1212. function unionListGoods(actor, activityId, listingGoods)
  1213. for index, goods in pairs(listingGoods) do
  1214. local itemCfgId = goods["itemcfgid"]
  1215. local stallInfo = ConfigDataManager.getTable("cfg_stall", "id", itemCfgId, "way", TRADE_WAY.GARD_BOSS)
  1216. if not stallInfo then
  1217. noticeTip.noticeinfo(actor, StringIdConst.TEXT383)
  1218. return
  1219. end
  1220. local itemStall = stallInfo[1]
  1221. local job = itemStall["job"]
  1222. goods["job"] = job
  1223. local money = itemStall["money"]
  1224. goods["money"] = money
  1225. local fixedPrice = itemStall["fixedPrice"]
  1226. goods["fixedPrice"] = fixedPrice
  1227. local startingPrice = itemStall["startingPrice"]
  1228. goods["startingPrice"] = startingPrice
  1229. local auction = itemStall["auction"]
  1230. goods["auction"] = auction
  1231. local type = itemStall["type"]
  1232. local subtype = itemStall["subtype"]
  1233. goods["type"] = type
  1234. goods["subtype"] = subtype
  1235. goods["position"] = tostring(TRADE_WAY.GARD_BOSS)
  1236. end
  1237. uniontradelisting(actor, activityId, listingGoods)
  1238. end
  1239. -- 获取世界商品 商品配置id 商品id
  1240. function Trade.getGoodsInfo(actor, msgData)
  1241. -- jprint("msgData",msgData)
  1242. local ownActor = getactor(actor, msgData[2])
  1243. goodsdetailinfo(ownActor, msgData[1], TRADE_WAY.WORLD_UP, actor:toString())
  1244. end
  1245. -- 购买成功后交换lua中存储的道具信息
  1246. function Trade.changeItemInfo(actor, ownId, itemId)
  1247. local ownActor = getactor(actor, ownId)
  1248. local allequip = getplaydef(ownActor, "T$luaitemextdata")
  1249. if not allequip then
  1250. return
  1251. end
  1252. local equipext = allequip[itemId]
  1253. if not equipext then
  1254. return
  1255. end
  1256. local allEquipActor = getplaydef(actor, "T$luaitemextdata")
  1257. if not allEquipActor then
  1258. allEquipActor = {}
  1259. end
  1260. allEquipActor[itemId] = equipext
  1261. -- EquipAndAppear.SetItemExtData(actor, itemId, equipext)
  1262. setplaydef(actor, "T$luaitemextdata", allEquipActor)
  1263. allequip[itemId] = nil
  1264. setplaydef(ownActor, "T$luaitemextdata", allequip)
  1265. end
  1266. function getroletet(actor)
  1267. local actorId = getactor(actor, "18023607160522752")
  1268. local name = getbaseinfo(actorId, "rolename")
  1269. -- jprint("name", name)
  1270. end
  1271. local TRADE_DATA_REPAIR = "T$_TRADE_DATA_REPAIR"
  1272. local TRADE_DATA_20250311 = "T$_TRADE_DATA_20250311"
  1273. function Trade.login(actor)
  1274. RepairRoleData.action(actor, TRADE_DATA_REPAIR, 20250115, Trade.TradeDataRepair_2025_01_15, actor)
  1275. RepairRoleData.action(actor, TRADE_DATA_20250311, 20250311, Trade.TradeDataRepair_2025_03_11, actor)
  1276. end
  1277. function Trade.TradeDataRepair_2025_01_15(actor)
  1278. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  1279. if table.isNullOrEmpty(allWorldGoods) then
  1280. shellclean(actor)
  1281. return
  1282. end
  1283. local roleWorld = allWorldGoods[actor:toString()]
  1284. if table.isNullOrEmpty(roleWorld) then
  1285. shellclean(actor)
  1286. return
  1287. end
  1288. local allItemId = {}
  1289. for index, good in pairs(roleWorld) do
  1290. local itemId = good.itemid
  1291. table.insert(allItemId, itemId)
  1292. end
  1293. shellclean(actor, allItemId)
  1294. end
  1295. function Trade.TradeDataRepair_2025_03_11(actor)
  1296. local serverType = getbaseinfo("servertype")
  1297. if serverType == 2 then
  1298. -- 跨服服务器不执行
  1299. return
  1300. end
  1301. local allWorldGoods = getsysvar(actor, SYS_TRADE_WORLD_GOODS)
  1302. if table.isNullOrEmpty(allWorldGoods) then
  1303. return
  1304. end
  1305. local now = getbaseinfo("now")
  1306. for index, roleAllGoods in pairs(allWorldGoods) do
  1307. if not table.isNullOrEmpty(roleAllGoods) then
  1308. for index, good in pairs(roleAllGoods) do
  1309. if not table.isNullOrEmpty(good) and good.listingtime and good.publicitytime then
  1310. if not good.itemid then
  1311. roleAllGoods[tostring(good.itemid)] = nil
  1312. else
  1313. local publicityTime = good.listingtime + good.publicitytime
  1314. local offShelfTime = publicityTime + good.upshelfduration
  1315. if offShelfTime < now then
  1316. local ownId = good.ownid
  1317. local ownActor = getactor(ownId)
  1318. shelltobag(ownActor, ownActor:toString(), good.itemid, good.count, ownActor:toString())
  1319. -- jprint("清理脏数据")
  1320. roleAllGoods[tostring(good.itemid)] = nil
  1321. end
  1322. end
  1323. end
  1324. end
  1325. end
  1326. end
  1327. setsysvar(SYS_TRADE_WORLD_GOODS, allWorldGoods)
  1328. end
  1329. function Trade.tradeGrailOff()
  1330. local goodsData = getsysvar(SYS_TRADE_WORLD_GOODS)
  1331. local offFlag = getsysvar(SystemVarConst.TRADE_GRAIL_OFF_FLAG)
  1332. if string.isNullOrEmpty(offFlag) or offFlag ~= "2025-03-28" then
  1333. if not table.isNullOrEmpty(goodsData) then
  1334. for roleId, allWorldGoods in pairs(goodsData) do
  1335. if not table.isNullOrEmpty(allWorldGoods) then
  1336. local flag = false
  1337. local actor = getactor(roleId)
  1338. for itemId, goodsDetail in pairs(allWorldGoods) do
  1339. if not table.isNullOrEmpty(goodsDetail) then
  1340. if AngelMajorGrail.isAngelGrail(goodsDetail.itemcfgid) then
  1341. flag = true
  1342. info(actor, "TradeGrailOffHandle itemId", itemId)
  1343. local peroreder = goodsDetail.peroreder
  1344. local publicityTime = goodsDetail.listingtime + goodsDetail.publicitytime
  1345. local now = getbaseinfo("now")
  1346. if now < publicityTime and not table.isNullOrEmpty(peroreder) then
  1347. -- 清理预购人员存储的信息
  1348. for _, preRid in pairs(peroreder) do
  1349. local preActor = getactor(preRid)
  1350. local myPreInfo = getplaydef(preActor, ROLE_TRADE_PRE_GOODS)
  1351. if not table.isEmpty(myPreInfo) then
  1352. local preIndex =
  1353. Trade.findPreInfo(myPreInfo, tostring(itemId),
  1354. tostring(goodsDetail.ownid))
  1355. if preIndex then
  1356. table.remove(myPreInfo, preIndex)
  1357. setplaydef(preActor, ROLE_TRADE_PRE_GOODS, myPreInfo)
  1358. end
  1359. end
  1360. sendconfigmailbyrid(actor, preRid, EmailConfig.TRADE_PRE_FAILED, {
  1361. [tonumber(goodsDetail.cointype)] = tonumber(goodsDetail.totalprice)
  1362. }, goodsDetail.itemname .. "#" .. "货币")
  1363. end
  1364. end
  1365. local count = goodsDetail.count
  1366. shelltobag(actor, actor:toString(), itemId, count, actor:toString(), 0, "")
  1367. --- 全部下架无需关心组
  1368. Trade.changeGoodsInfo(actor, itemId, count, count, 0)
  1369. end
  1370. end
  1371. end
  1372. if flag then
  1373. sendconfigmailbyrid(actor, getbaseinfo(actor, "rid"), EmailConfig.TRADE_GRAIL_OFF)
  1374. end
  1375. end
  1376. end
  1377. Trade.flushWorldGoods()
  1378. setsysvar(SystemVarConst.TRADE_GRAIL_OFF_FLAG, "2025-03-28")
  1379. end
  1380. end
  1381. end
  1382. -- TODO 一定要放到文件最后
  1383. -- 注册充值事件
  1384. -- RechargeEventListerTable:eventLister("0", "交易行", Trade.recharge)