Trade.lua 53 KB

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