Trade_1.lua 55 KB

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