--[[ Descripttion:战斗房间 version: Author: Neo,Huang Date: 2023-11-16 23:24:42 LastEditors: Neo,Huang LastEditTime: 2023-11-16 23:25:34 --]] local lib_battle_redis = require("lib_battle_redis") local timeUtil = require("utils.timeUtil") local redisBattleUtil = require("redisBattleUtil") local util_player = require("utils.util_player") local util_box = require("utils.util_box") local gameConst = require("const.gameConst") local util_user = require("utils.util_user") local nodeMgr = require("nodeMgr") local util_battle = require("utils.util_battle") local battleData = require("data.battle") local bagData = require("data.bag") local boxAdapt = require("adapt.boxAdapt") local resAdapt = require("adapt.resAdapt") local root = {} local function _get_global_room_key() return "global:room" end local function _get_room_key(id) return string.format("room:%s", tostring(id)) end local function _get_active_room_id_key() return "active:rooms" end -- 分配房间ID function root:gen_room_id() local key = _get_global_room_key() local subKey = "max:room:id" local id = lib_battle_redis:hincrby(key, subKey, 1) if id > 200000000 then id = 1 lib_battle_redis:hset(key, subKey, id) end return id end -- 获取当前活跃房间ID列表 function root:get_active_room_id_list() local key = _get_active_room_id_key() return lib_battle_redis:smembers(key) end -- 打包房间玩家信息 function root:pack_room_player_info(roomId, uid) local info = self:get_room_player_info(roomId, uid) if is_empty(info) then return end info.playerInfo = util_player:get_base_info(uid) return info end -- 打包房间玩家信息列表 function root:pack_room_player_info_list(playerList) if is_empty(playerList) then return end local infoList = {} for _, v in ipairs(playerList) do local info = { playerInfo = util_player:get_base_info(v.uid), seatId = v.seatId, status = v.status } table.insert(infoList, info) end return infoList end -- 打包房间信息 function root:pack_room_info(roomId) if is_empty(roomId) then return end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return end local info = { roomId = roomId, playCount = redisBattleUtil.hget_int(key, "playCount"), battleBoxList = redisBattleUtil.hget_json(key, "boxIdList"), status = redisBattleUtil.hget_int(key, "status"), createTime = redisBattleUtil.hget_int(key, "createTime") } -- 玩家信息列表 local playerList = redisBattleUtil.hget_json(key, "playerList") info.playerList = self:pack_room_player_info_list(playerList) return info end -- 打包所有房间信息 function root:pack_room_info_list() local roomIdList = self:get_active_room_id_list() if is_empty(roomIdList) then return end local roomInfoList = {} for _, v in ipairs(roomIdList) do local roomId = tonumber(v) local info = self:pack_room_info(roomId) if not is_empty(info) then table.insert(roomInfoList, info) end end return roomInfoList end -- 打包玩家房间信息 function root:pack_player_room_info(uid) if is_empty(uid) then return end local roomId = battleData:get_room_id(uid) if is_empty(roomId) then return end return self:pack_room_info(roomId) end -- 创建房间 function root:create_room(uid, playCount, boxIdList) if is_empty(uid) then return false end if is_empty(playCount) or playCount < 2 or playCount > 3 then return false end if is_empty(boxIdList) or #boxIdList < 1 then return false end local roomId = self:gen_room_id() -- 设置房间信息 local playerList = {{uid = uid, seatId = 1, status = 1}} local key = _get_room_key(roomId) redisBattleUtil.hset(key, "createTime", timeUtil.now()) -- 创建时间 redisBattleUtil.hset(key, "hostUid", uid) -- 房主 redisBattleUtil.hset(key, "playCount", playCount) -- 战斗人数 redisBattleUtil.hset(key, "boxIdList", boxIdList) -- 战斗箱子ID列表 redisBattleUtil.hset(key, "playerList", playerList) -- 玩家列表 redisBattleUtil.hset(key, "status", 0) -- 战斗状态 -- 房间进入准备战斗集合 key = _get_active_room_id_key() lib_battle_redis:sadd(key, roomId) return true, roomId end -- 房间是否存在 function root:is_room_exist(roomId) local key = _get_room_key(roomId) -- 房间是否存在 return lib_battle_redis:exists(key) end -- 座位是否已被占 function root:get_seat_player(roomId, seatId) if is_empty(roomId) or is_empty(seatId) then return end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return end local playerList = redisBattleUtil.hget_json(key, "playerList") for _, v in ipairs(playerList) do if v.seatId and v.seatId == seatId then return v.uid end end end -- 进入房间 function root:enter_room(uid, roomId) if is_empty(uid) or is_empty(roomId) then return false end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return false end local playerList = redisBattleUtil.hget_json(key, "playerList") for _, v in ipairs(playerList) do if v.uid == uid then -- 玩家已进入房间 return false end end table.insert(playerList, {uid = uid, status = 0}) redisBattleUtil.hset(key, "playerList", playerList) return true end -- 坐下 function root:seat_down(uid, roomId, seatId) if is_empty(uid) or is_empty(roomId) or is_empty(seatId) then return false end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return false end local isMatch = false local playerList = redisBattleUtil.hget_json(key, "playerList") for _, v in ipairs(playerList) do if v.uid == uid then v.seatId = seatId v.status = 1 isMatch = true break end end if not isMatch then table.insert(playerList, {uid = uid, seatId = seatId, status = 1}) end redisBattleUtil.hset(key, "playerList", playerList) return true end -- 站起 function root:stand_up(uid, roomId) if is_empty(uid) or is_empty(roomId) then return false end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return false end local isMatch = false local playerList = redisBattleUtil.hget_json(key, "playerList") for _, v in ipairs(playerList) do if v.uid == uid then if v.seatId == nil or v.seatId == 0 then return false end v.seatId = nil v.status = 0 isMatch = true break end end if not isMatch then return false end redisBattleUtil.hset(key, "playerList", playerList) return true end -- 离开房间 function root:leave(uid, roomId) if is_empty(uid) or is_empty(roomId) then return false end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return false end local playerList = redisBattleUtil.hget_json(key, "playerList") for k, v in ipairs(playerList) do if v.uid == uid then table.remove(playerList, k) break end end redisBattleUtil.hset(key, "playerList", playerList) return true end -- 获取房间玩家信息 function root:get_room_player_info(roomId, uid) if is_empty(roomId) or is_empty(uid) then return end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return end local playerList = redisBattleUtil.hget_json(key, "playerList") for _, v in ipairs(playerList) do if v.uid == uid then return v end end end -- 获取房间消耗价格 function root:get_room_price(roomId) local key = _get_room_key(roomId) local boxIdList = redisBattleUtil.hget_json(key, "boxIdList") if is_empty(boxIdList) then return end return boxAdapt:battle_get_box_price(boxIdList) end -- 获取房间状态 -- 0:等待 1:进行中 2:结算 3:销毁 function root:get_room_status(roomId) if is_empty(roomId) then return 3 end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return 3 end local status = redisBattleUtil.hget_int(key, "status") return status end -- 销毁房间 function root:destroy_room(roomId) if is_empty(roomId) then return false end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then -- 从活跃房间集合删除 lib_battle_redis:sismember(_get_active_room_id_key(), roomId) return false end local status = redisBattleUtil.hget_int(key, "status") if status >= 0 then -- 战斗已开始 return false end -- 删除房间信息 lib_battle_redis:del(key) -- 从活跃房间集合删除 lib_battle_redis:sismember(_get_active_room_id_key(), roomId) return true end -- 是否等待开战结束 function root:is_wait_battle_end(roomId) if is_empty(roomId) then return false end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then return true end local currTime = timeUtil.now() local createTime = redisBattleUtil.hget_int(key, "createTime") local waitSeconds = boxAdapt:battle_const("no_full_close_room_time") or 10 if currTime < createTime + waitSeconds then return false end return true end ---------------------------------------- -- 战斗 --------------------------------------- -- 房间是否开始战斗 function root:is_room_start_battle(roomId) local status = self:get_room_status(roomId) if status > 0 then return false end local seatCount = 0 local key = _get_room_key(roomId) local playerList = redisBattleUtil.hget_json(key, "playerList") for _, v in ipairs(playerList) do if v.seatId and v.seatId > 0 then seatCount = seatCount + 1 end end local playCount = redisBattleUtil.hget_int(key, "playCount") return seatCount >= playCount end -- 生成战斗编号 function root:gen_battle_id(roomId) local currTime = timeUtil.now() return string.format("BT%s%08d", os.date("%Y%m%d", currTime), roomId) end -- 战斗 function root:start_battle(roomId) if is_empty(roomId) then return false end local key = _get_room_key(roomId) -- 房间是否存在 local isExist = lib_battle_redis:exists(key) if not isExist then -- 从活跃房间集合删除 lib_battle_redis:sismember(_get_active_room_id_key(), roomId) return false end -- 更新状态 redisBattleUtil.hset(key, "status", 1) local battleId = self:gen_battle_id(roomId) local battleBoxList = redisBattleUtil.hget_json(key, "boxIdList") local playerList = redisBattleUtil.hget_json(key, "playerList") -- 射击轮次 local rounds = {} local totalPrice = 0 for k, v in ipairs(battleBoxList) do local roundInfo = {round = k, shotList = {}} for _, _v in ipairs(playerList) do if _v.seatId and _v.seatId > 0 then local itemId = util_box:battle_get_box_drop_item_and_count(v) local price = resAdapt:get_item_price(itemId) local shotInfo = { uid = _v.uid, itemId = itemId, price = price } table.insert(roundInfo.shotList, shotInfo) totalPrice = totalPrice + price end end table.insert(rounds, roundInfo) end -- 胜利玩家 local mapUidPrice = {} for _, v in ipairs(rounds) do for _, _v in ipairs(v.shotList) do mapUidPrice[_v.uid] = (mapUidPrice[_v.uid] or 0) + _v.price end end local winUid = nil local maxPrice = nil for uid, price in pairs(mapUidPrice) do if maxPrice == nil or price > maxPrice then winUid = uid end end -- 战斗玩家列表 local n1Price = resAdapt:get_item_price(gameConst.ITEM_ID.N1) local battlePlayerList = {} for _, v in ipairs(playerList) do if v.seatId and v.seatId > 0 then if v.uid == winUid then -- 收集所有玩家射击 local info = {uid = v.uid, seatId = v.seatId, shotList = {}} for _, _v in ipairs(rounds) do for _, __v in ipairs(_v.shotList) do table.insert(info.shotList, {itemId = __v.itemId, price = __v.price}) end end table.insert(battlePlayerList, info) else -- 安慰奖 local info = { uid = v.uid, seatId = v.seatId, shotList = {{itemId = gameConst.ITEM_ID.N1, price = n1Price}} } table.insert(battlePlayerList, info) end end end -- 发放奖励 for _, v in ipairs(battleBoxList) do local items = {} for _, _v in ipairs(v.shotList) do table.insert(items, {id = v.itemId, count = 1}) end local keyEvent = string.format("battle-settle-%s-%s", battleId, tostring(v.uid == winUid and 1 or 0)) bagData:add_items(v.uid, items, keyEvent) end redisBattleUtil.hset(key, "status", 2) local settle = { roomInfo = self:pack_room_info(roomId), winUid = winUid, battleId = battleId, rounds = rounds, battlePlayerList = battlePlayerList } -- 通知所有房间玩家 for _, v in ipairs(playerList) do util_user:user_proto_notify(v.uid, "on_room_battle_settle", {settle = settle}) end -- 新增战斗记录 util_battle:add_battle_record(settle, totalPrice) -- 关闭房间 -- 删除房间信息 lib_battle_redis:del(key) -- 从活跃房间集合删除 lib_battle_redis:sismember(_get_active_room_id_key(), roomId) -- 通知在线玩家 - 销毁房间 nodeMgr.broadcast_proto_notify("on_room_destroy", {roomId = roomId}) end ---------------------------------------- -- 玩家战斗信息 ---------------------------------------- local bagData = require("data.bag") -- 绑定房间 function root:band_room(uid, roomId, costItems) if is_empty(uid) or is_empty(costItems) then return end battleData:band_room(uid, roomId, costItems) -- 消耗道具 local keyEvent = string.format("room-seat-down-%s", tostring(roomId)) bagData:consume_items(uid, costItems, keyEvent) end -- 解绑房间 -- ty - 解绑类型: leave:离开 dismiss:解散 seat:更换座位 settle:结算 function root:unband_room(uid, ty) if is_empty(uid) then return end local costItems = battleData:get_room_cost_items(uid) if (ty == "leave" or ty == "dismiss" or ty == "seat") and not is_empty(costItems) then -- 返回物品 local keyEvent = string.format("room-%s", ty) bagData:add_items(uid, costItems, keyEvent) end battleData:band_room(uid) return true end return root