WorldBossAuction.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. -- 世界BOSS拍卖系统
  2. local this = {}
  3. WorldBossAuction = {}
  4. -- 拍卖状态
  5. local AUCTION_STATUS = {
  6. WAITING = 0, -- 等待开始
  7. BIDDING = 1, -- 竞拍中
  8. FINISHED = 2, -- 已结束
  9. SOLD = 3 -- 已售出
  10. }
  11. -- 拍卖配置
  12. local AUCTION_CONFIG = {
  13. BID_INCREMENT = 0.1, -- 加价比例10%
  14. MIN_BID_INCREMENT = 50, -- 最小加价金额
  15. AUTO_EXTEND_TIME = 30, -- 自动延长时间(秒)
  16. MAX_BID_HISTORY = 20 -- 最大竞拍记录数
  17. }
  18. -- 拍卖物品数据结构
  19. local function createAuctionItem(itemData, startingPrice)
  20. return {
  21. id = itemData.id,
  22. type = itemData.type,
  23. name = itemData.name,
  24. attributes = itemData.attributes,
  25. startingPrice = startingPrice,
  26. currentPrice = startingPrice,
  27. status = AUCTION_STATUS.WAITING,
  28. startTime = 0,
  29. endTime = 0,
  30. bidders = {}, -- 竞拍者列表
  31. bidHistory = {}, -- 竞拍历史
  32. winner = nil, -- 获胜者
  33. finalPrice = 0, -- 最终价格
  34. autoExtendCount = 0 -- 自动延长次数
  35. }
  36. end
  37. -- 开始拍卖
  38. function this.StartAuction()
  39. local auctionItems = getsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS) or {}
  40. local now = os.time()
  41. for _, item in ipairs(auctionItems) do
  42. local auctionItem = createAuctionItem(item, item.startingPrice)
  43. auctionItem.startTime = now
  44. auctionItem.endTime = now + WorldBossDefine.ACTIVITY_CONFIG.AUCTION_DURATION * 60
  45. auctionItem.status = AUCTION_STATUS.BIDDING
  46. -- 保存拍卖物品
  47. this.SaveAuctionItem(auctionItem)
  48. end
  49. -- info("世界BOSS拍卖开始,物品数量:", #auctionItems)
  50. end
  51. -- 保存拍卖物品
  52. function this.SaveAuctionItem(auctionItem)
  53. local auctionItems = getsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS) or {}
  54. for i, item in ipairs(auctionItems) do
  55. if item.id == auctionItem.id then
  56. auctionItems[i] = auctionItem
  57. break
  58. end
  59. end
  60. setsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS, auctionItems)
  61. end
  62. -- 玩家竞拍
  63. function this.PlayerBid(actor, itemId, bidPrice)
  64. -- 检查玩家是否可参与拍卖
  65. if not this.CanPlayerParticipate(actor) then
  66. tipinfo(actor, "您不能参与此次拍卖")
  67. return false
  68. end
  69. -- 获取拍卖物品
  70. local auctionItem = this.GetAuctionItem(itemId)
  71. if not auctionItem then
  72. tipinfo(actor, "拍卖物品不存在")
  73. return false
  74. end
  75. -- 检查拍卖状态
  76. if auctionItem.status ~= AUCTION_STATUS.BIDDING then
  77. tipinfo(actor, "拍卖已结束")
  78. return false
  79. end
  80. -- 检查竞拍价格
  81. if not this.IsValidBid(auctionItem, bidPrice) then
  82. tipinfo(actor, "竞拍价格无效")
  83. return false
  84. end
  85. -- 检查玩家钻石是否足够
  86. local diamondCount = getitemcount(actor, "diamond")
  87. if diamondCount < bidPrice then
  88. tipinfo(actor, "钻石不足")
  89. return false
  90. end
  91. -- 执行竞拍
  92. local success = this.ExecuteBid(actor, auctionItem, bidPrice)
  93. if success then
  94. tipinfo(actor, "竞拍成功!当前价格:" .. bidPrice)
  95. -- 检查是否需要自动延长
  96. this.CheckAutoExtend(auctionItem)
  97. -- 通知其他玩家
  98. this.NotifyOtherBidders(auctionItem, actor, bidPrice)
  99. end
  100. return success
  101. end
  102. -- 检查玩家是否可参与拍卖
  103. function this.CanPlayerParticipate(actor)
  104. local playerDamage = getsysvar(WorldBossDefine.DB_KEYS.PLAYER_DAMAGE) or {}
  105. local playerId = actor:toString()
  106. return playerDamage[playerId] and playerDamage[playerId] > 0
  107. end
  108. -- 获取拍卖物品
  109. function this.GetAuctionItem(itemId)
  110. local auctionItems = getsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS) or {}
  111. for _, item in ipairs(auctionItems) do
  112. if item.id == itemId then
  113. return item
  114. end
  115. end
  116. return nil
  117. end
  118. -- 检查竞拍价格是否有效
  119. function this.IsValidBid(auctionItem, bidPrice)
  120. local minBid = auctionItem.currentPrice + math.max(
  121. math.floor(auctionItem.currentPrice * AUCTION_CONFIG.BID_INCREMENT),
  122. AUCTION_CONFIG.MIN_BID_INCREMENT
  123. )
  124. return bidPrice >= minBid
  125. end
  126. -- 执行竞拍
  127. function this.ExecuteBid(actor, auctionItem, bidPrice)
  128. local playerId = actor:toString()
  129. -- 扣除钻石
  130. local result = removeitemfrombag(actor, "diamond", bidPrice, 0, 9999, '世界BOSS竞拍')
  131. if not result then
  132. tipinfo(actor, "扣除钻石失败")
  133. return false
  134. end
  135. -- 如果有之前的竞拍者,退还钻石
  136. if auctionItem.winner then
  137. local previousWinner = getactor(tonumber(auctionItem.winner))
  138. if previousWinner then
  139. additemtobag(previousWinner, "diamond", auctionItem.currentPrice, 0, 9999, '世界BOSS竞拍退款')
  140. tipinfo(previousWinner, "您的竞拍被超越,钻石已退还")
  141. end
  142. end
  143. -- 更新拍卖物品信息
  144. auctionItem.currentPrice = bidPrice
  145. auctionItem.winner = playerId
  146. auctionItem.finalPrice = bidPrice
  147. -- 记录竞拍历史
  148. this.RecordBidHistory(auctionItem, actor, bidPrice)
  149. -- 保存更新
  150. this.SaveAuctionItem(auctionItem)
  151. return true
  152. end
  153. -- 记录竞拍历史
  154. function this.RecordBidHistory(auctionItem, actor, bidPrice)
  155. local bidRecord = {
  156. playerId = actor:toString(),
  157. playerName = getbaseinfo(actor, "rolename"),
  158. bidPrice = bidPrice,
  159. bidTime = os.time()
  160. }
  161. table.insert(auctionItem.bidHistory, bidRecord)
  162. -- 限制历史记录数量
  163. if #auctionItem.bidHistory > AUCTION_CONFIG.MAX_BID_HISTORY then
  164. table.remove(auctionItem.bidHistory, 1)
  165. end
  166. end
  167. -- 检查是否需要自动延长
  168. function this.CheckAutoExtend(auctionItem)
  169. local now = os.time()
  170. local timeLeft = auctionItem.endTime - now
  171. -- 如果剩余时间少于30秒且有新的竞拍,自动延长
  172. if timeLeft < AUCTION_CONFIG.AUTO_EXTEND_TIME and auctionItem.autoExtendCount < 3 then
  173. auctionItem.endTime = auctionItem.endTime + AUCTION_CONFIG.AUTO_EXTEND_TIME
  174. auctionItem.autoExtendCount = auctionItem.autoExtendCount + 1
  175. this.SaveAuctionItem(auctionItem)
  176. -- 通知所有参与者
  177. this.NotifyAutoExtend(auctionItem)
  178. -- info("拍卖物品自动延长:", auctionItem.name, ",新结束时间:", auctionItem.endTime)
  179. end
  180. end
  181. -- 通知其他竞拍者
  182. function this.NotifyOtherBidders(auctionItem, currentBidder, bidPrice)
  183. local playerId = currentBidder:toString()
  184. -- 这里需要实现具体的通知逻辑
  185. -- 可以发送邮件或系统消息给其他竞拍者
  186. -- info("竞拍通知:玩家", playerId, "竞拍物品", auctionItem.name, ",价格:", bidPrice)
  187. end
  188. -- 通知自动延长
  189. function this.NotifyAutoExtend(auctionItem)
  190. -- 这里需要实现具体的通知逻辑
  191. -- info("拍卖自动延长通知:", auctionItem.name)
  192. end
  193. -- 结束拍卖
  194. function this.EndAuction()
  195. local auctionItems = getsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS) or {}
  196. local now = os.time()
  197. for _, item in ipairs(auctionItems) do
  198. if item.status == AUCTION_STATUS.BIDDING then
  199. if now >= item.endTime then
  200. this.FinalizeAuction(item)
  201. end
  202. end
  203. end
  204. end
  205. -- 完成拍卖
  206. function this.FinalizeAuction(auctionItem)
  207. if auctionItem.winner then
  208. auctionItem.status = AUCTION_STATUS.SOLD
  209. -- info("拍卖物品售出:", auctionItem.name, ",获胜者:", auctionItem.winner, ",价格:", auctionItem.finalPrice)
  210. -- 处理物品交付
  211. this.DeliverItem(auctionItem)
  212. else
  213. auctionItem.status = AUCTION_STATUS.FINISHED
  214. -- info("拍卖物品流拍:", auctionItem.name)
  215. -- 处理流拍物品
  216. this.HandleFailedAuction(auctionItem)
  217. end
  218. this.SaveAuctionItem(auctionItem)
  219. end
  220. -- 交付物品
  221. function this.DeliverItem(auctionItem)
  222. local winner = getactor(tonumber(auctionItem.winner))
  223. if winner then
  224. -- 这里需要实现具体的物品交付逻辑
  225. -- 根据物品类型调用相应的接口
  226. tipinfo(winner, "恭喜您竞拍成功!物品:" .. auctionItem.name)
  227. -- 发送邮件通知
  228. this.SendAuctionSuccessMail(winner, auctionItem)
  229. end
  230. end
  231. -- 处理流拍物品
  232. function this.HandleFailedAuction(auctionItem)
  233. -- 流拍物品可以进入战盟拍卖或其他处理方式
  234. -- 这里可以根据具体需求设计
  235. -- info("处理流拍物品:", auctionItem.name)
  236. end
  237. -- 发送竞拍成功邮件
  238. function this.SendAuctionSuccessMail(actor, auctionItem)
  239. local mailData = {
  240. title = "竞拍成功通知",
  241. content = "恭喜您在世界BOSS拍卖中成功竞拍到物品!\n物品名称:" .. auctionItem.name .. "\n竞拍价格:" .. auctionItem.finalPrice .. " 钻石",
  242. items = {},
  243. diamonds = 0
  244. }
  245. -- 这里需要调用具体的邮件发送接口
  246. -- sendmail(actor, mailData)
  247. end
  248. -- 获取拍卖信息
  249. function this.GetAuctionInfo(actor)
  250. local auctionItems = getsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS) or {}
  251. local now = os.time()
  252. local auctionInfo = {}
  253. for _, item in ipairs(auctionItems) do
  254. local info = {
  255. id = item.id,
  256. name = item.name,
  257. type = item.type,
  258. attributes = item.attributes,
  259. currentPrice = item.currentPrice,
  260. status = item.status,
  261. timeLeft = math.max(0, item.endTime - now),
  262. winner = item.winner,
  263. bidCount = #item.bidHistory
  264. }
  265. table.insert(auctionInfo, info)
  266. end
  267. return auctionInfo
  268. end
  269. -- 获取竞拍历史
  270. function this.GetBidHistory(itemId)
  271. local auctionItem = this.GetAuctionItem(itemId)
  272. if auctionItem then
  273. return auctionItem.bidHistory
  274. end
  275. return {}
  276. end
  277. -- 获取我的竞拍
  278. function this.GetMyBids(actor)
  279. local auctionItems = getsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS) or {}
  280. local playerId = actor:toString()
  281. local myBids = {}
  282. for _, item in ipairs(auctionItems) do
  283. if item.winner == playerId then
  284. table.insert(myBids, {
  285. id = item.id,
  286. name = item.name,
  287. currentPrice = item.currentPrice,
  288. status = item.status,
  289. timeLeft = math.max(0, item.endTime - os.time())
  290. })
  291. end
  292. end
  293. return myBids
  294. end
  295. -- 取消竞拍
  296. function this.CancelBid(actor, itemId)
  297. local auctionItem = this.GetAuctionItem(itemId)
  298. if not auctionItem then
  299. tipinfo(actor, "拍卖物品不存在")
  300. return false
  301. end
  302. local playerId = actor:toString()
  303. if auctionItem.winner ~= playerId then
  304. tipinfo(actor, "您不是当前最高竞拍者")
  305. return false
  306. end
  307. if auctionItem.status ~= AUCTION_STATUS.BIDDING then
  308. tipinfo(actor, "拍卖已结束,无法取消")
  309. return false
  310. end
  311. -- 退还钻石
  312. additemtobag(actor, "diamond", auctionItem.currentPrice, 0, 9999, '世界BOSS竞拍取消退款')
  313. -- 重置竞拍状态
  314. auctionItem.winner = nil
  315. auctionItem.finalPrice = 0
  316. -- 如果有其他竞拍者,恢复之前的最高价
  317. if #auctionItem.bidHistory > 1 then
  318. local previousBid = auctionItem.bidHistory[#auctionItem.bidHistory - 1]
  319. auctionItem.currentPrice = previousBid.bidPrice
  320. auctionItem.winner = previousBid.playerId
  321. auctionItem.finalPrice = previousBid.bidPrice
  322. else
  323. auctionItem.currentPrice = auctionItem.startingPrice
  324. end
  325. this.SaveAuctionItem(auctionItem)
  326. tipinfo(actor, "竞拍已取消,钻石已退还")
  327. return true
  328. end
  329. -- 一口价购买
  330. function this.BuyNow(actor, itemId)
  331. local auctionItem = this.GetAuctionItem(itemId)
  332. if not auctionItem then
  333. tipinfo(actor, "拍卖物品不存在")
  334. return false
  335. end
  336. if auctionItem.status ~= AUCTION_STATUS.BIDDING then
  337. tipinfo(actor, "拍卖已结束")
  338. return false
  339. end
  340. -- 计算一口价(当前价格的2倍)
  341. local buyNowPrice = auctionItem.currentPrice * 2
  342. -- 检查钻石是否足够
  343. local diamondCount = getitemcount(actor, "diamond")
  344. if diamondCount < buyNowPrice then
  345. tipinfo(actor, "钻石不足")
  346. return false
  347. end
  348. -- 执行一口价购买
  349. local success = this.ExecuteBid(actor, auctionItem, buyNowPrice)
  350. if success then
  351. -- 立即结束拍卖
  352. auctionItem.status = AUCTION_STATUS.SOLD
  353. auctionItem.endTime = os.time()
  354. this.SaveAuctionItem(auctionItem)
  355. tipinfo(actor, "一口价购买成功!物品:" .. auctionItem.name)
  356. -- 交付物品
  357. this.DeliverItem(auctionItem)
  358. end
  359. return success
  360. end
  361. -- 获取推荐竞拍价格
  362. function this.GetRecommendedBidPrice(itemId)
  363. local auctionItem = this.GetAuctionItem(itemId)
  364. if not auctionItem then
  365. return 0
  366. end
  367. local minBid = auctionItem.currentPrice + math.max(
  368. math.floor(auctionItem.currentPrice * AUCTION_CONFIG.BID_INCREMENT),
  369. AUCTION_CONFIG.MIN_BID_INCREMENT
  370. )
  371. return minBid
  372. end
  373. -- 检查拍卖状态
  374. function this.CheckAuctionStatus()
  375. local auctionItems = getsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS) or {}
  376. local now = os.time()
  377. local hasActiveAuction = false
  378. for _, item in ipairs(auctionItems) do
  379. if item.status == AUCTION_STATUS.BIDDING and now < item.endTime then
  380. hasActiveAuction = true
  381. break
  382. end
  383. end
  384. if not hasActiveAuction then
  385. -- 所有拍卖都结束了
  386. this.FinalizeAllAuctions()
  387. end
  388. end
  389. -- 完成所有拍卖
  390. function this.FinalizeAllAuctions()
  391. local auctionItems = getsysvar(WorldBossDefine.DB_KEYS.AUCTION_ITEMS) or {}
  392. for _, item in ipairs(auctionItems) do
  393. if item.status == AUCTION_STATUS.BIDDING then
  394. this.FinalizeAuction(item)
  395. end
  396. end
  397. -- info("所有拍卖已完成")
  398. end
  399. -- 启动拍卖检查定时器
  400. function this.StartAuctionTimer()
  401. -- 每10秒检查一次拍卖状态
  402. setTimer(10000, function()
  403. this.CheckAuctionStatus()
  404. end)
  405. end
  406. -- 初始化拍卖系统
  407. function this.Init()
  408. -- info("世界BOSS拍卖系统初始化")
  409. this.StartAuctionTimer()
  410. end
  411. return this