--扭蛋机 local MsgPack = MsgPack local Capsule = class("Capsule", require("shared.ModelBase")) function Capsule:ctor(properties) Capsule.super.ctor(self, properties) end RewardTYpe = { GOODS = 0, TOP = 1, CORE = 2, LAST = 3, JOKER = 4, KING = 5, GOOD = 6, INCENTIVE = 7, } CapsuleType = { PRIVATE = 0, PUBLIC = 1, } Capsule.schema = { id = {"number", 0}, --扭蛋机key,配置读取 room = {"number", 0}, --房间号, 配置读取 name = {"string", 0}, typ = {"number", 1}, -- 1=共享,2=独享 coin = {"number", 0}, --货币代号 register = {"table", {}}, --人数 {["id"]=0}, 0 围观, 1 已报名 record = {"table", {}}, --抽取记录 列表 recordByRole = {"table", {}}, -- 抽取记录,hash, {roleid=record} rank = {"table", {}}, --排行 goods = {"table", {}}, --奖励池 specials = {"table", {}}, --特殊赏 incentive = {"table", {}}, --激励奖 specialsFlag= {"table", {}}, --特殊赏是否已经领取 resetInfo = {"table", {}}, resetTimes = {"number", 0}, --每日一次手动重置的机会 hideTime = {"number", 0} , --隐藏时间 drawEndTime = {"number", 0}, --抽完时间 } function Capsule:isShow() if skynet.timex() >= self:getProperty("hideTime") then return false end return true end function Capsule:refreshing(now) local id = self:getProperty("id") local room = self:getProperty("room") local ichibankuji = csvdb["ichibankuji_mainCsv"][id][room] local reset = tostring(ichibankuji.reset) if reset == "0" then return false elseif reset == "1" then if self:getProperty("resetTimes") == 1 then return true end return false else local resetArr = reset:toArray(true, "=") if not next(resetArr) then return false end if resetArr[1] == "2" then if self:getGoodsAmount() > 0 then return false end local drawEndTime = self:getProperty("drawEndTime") or 0 if drawEndTime == 0 then return false end if now - drawEndTime >= resetArr[2] then return true end return false elseif resetArr[1] == "3" then elseif resetArr[1] == "4" then if now >= resetArr[2] then return true end end end return false end function Capsule:getResetFields() return { id = self:getProperty("id"), room = self:getProperty("room"), typ = self:getProperty("typ"), coin = 0, register = {}, record = {}, recordByRole = {}, rank = {}, goods = {}, specials = {}, incentive = {}, specialsFlag= {}, resetInfo = {}, resetTimes = 0, } end function Capsule:init() local id = self:getProperty("id") local room = self:getProperty("room") self:setProperties(self:getResetFields()) local ichibankuji = csvdb["ichibankuji_mainCsv"][id][room] --奖励池 local goods_id = ichibankuji["goods_id"] local goods, specials, incentive = {}, {}, {} for _, data in pairs(csvdb["ichibankuji_goodsCsv"]) do for _, val in pairs(data) do if val.key == goods_id then goods[goods_id..val.id] = clone(val) end end end for _, v in ipairs(goods) do v.weight = (v.weight or 0) * v.amount end --特殊赏 local special_ids = ichibankuji["special_id"] if special_ids ~= "" then for _, special_id in ipairs(special_ids:toArray(true, "=")) do local val = csvdb["ichibankuji_specialCsv"][special_id] if type(val.type) == "number" then specials[special_id] = {np= 1, amount = val.amount, award = val.award, quality = tonumber(val.type), showIndex = val.showIndex} elseif type(val.type) == "string" then local pos = val.type:find("=") if pos then for k, v in pairs(val.type:toNumMap()) do specials[special_id] = {np= v, amount = val.amount, award = val.award, quality = k, showIndex = val.showIndex} end else specials[special_id] = {np= 1, amount = val.amount, award = val.award, quality = tonumber(val.type), showIndex = val.showIndex} end end end end --激励奖 local incentive_ids = ichibankuji["incentive_id"] if incentive_ids ~= "" then for _, incentive_id in ipairs(incentive_ids:toArray(true, "=")) do local val = csvdb["ichibankuji_incentiveCsv"][incentive_id] if type(val.type) == "number" then incentive["last"] = {np=val.type, award = val.award} elseif type(val.type) == "string" then for k, v in pairs(val.type:toNumMap()) do if k == 2 then incentive["amount"] = {np= v, award = val.award} elseif k==3 then incentive["probabilities"] = {np= v, award = val.award} end end end end end --货币类型 local coin = ichibankuji["token"]:toArray(true, "=") self:setProperties({coin = coin[1] or 0, hideTime = ichibankuji.hide_time, goods = goods, specials = specials, incentive = incentive}) end function Capsule:getOnlineCount() local register = self:getProperty("register") or {} local reg, onlookers = 0, 0 for _, v in pairs(register) do if v == 1 then reg = reg + 1 else onlookers = onlookers + 1 end end return {[0]=onlookers, [1]=reg, [2] = reg+onlookers} end function Capsule:join(roleId) --一个房间最多人数 TODO local register = self:getProperty("register") or {} register[roleId] = 0 self:setProperty("register", register) return self:data(roleId) end function Capsule:getRegisterByRoleId(roleId) local register = self:getProperty("register") or {} return register[roleId] or 0 end function Capsule:isRegister(roleId) return self:getRegisterByRoleId(roleId) == 1 end function Capsule:register(roleId) local register = self:getProperty("register") or {} register[roleId] = 1 self:setProperty("register", register) return self:data(roleId) end function Capsule:exit(roleId) local register = self:getProperty("register") or {} if next(register) then register[roleId] = nil return true end return false end function Capsule:confirmed(cares) local goods = self:getProperty("goods") or {} local specials = self:getProperty("specials") or {} local change = {} for k, v in pairs(cares) do if v.typ == 1 then if goods[k] and goods[k].amount ~= v.count then change[k] = goods[k].amount end else if specials[k] and specials[k].amount ~= v.count then change[k] = specials[k].amount end end end return change end function Capsule:getGoodsAmount() local goods = self:getProperty("goods") or {} local amount = 0 for _, v in ipairs(goods) do amount = amount + v.amount end return amount end function Capsule:getSpecialByType(typ) local specials = self:getProperty("specials") or {} for k, v in pairs(specials) do if v.quality == typ then return k, v end end return nil end function Capsule:getTop(record) local specialsFlag = self:getProperty("specialsFlag") or {} if specialsFlag[RewardTYpe.TOP] then return nil end local specials = self:getProperty("specials") or {} local spKey, special = self:getSpecialByType(RewardTYpe.TOP) if not special then return nil end local np = special["np"] if #record >= special["np"] then local topRecord = {} local count = np for _, v in ipairs(record) do if count <= 0 then break end local tmpCount = 0 if count >= v.amount then count = count - v.amount tmpCount = v.amount else tmpCount = count count = 0 end if not topRecord[v.role_id]then topRecord[v.role_id] = {amount = v.amount } else topRecord[v.role_id] = {amount = (topRecord[v.rol_id]["amount"] or 0) + tmpCount} end end count = special["amount"] local topRoleIds = {} while(count > 0 and next(topRecord)) do local roleId = math.randWeight(topRecord, "amount") if roleId then table.insert(topRoleIds, roleId) local tmpTopRecord = topRecord[roleId] tmpTopRecord["amount"] = tmpTopRecord["amount"] - 1 if tmpTopRecord["amount"] <= 0 then topRecord[roleId] = nil end count = count - 1 end end special["amount"] = count specials[spKey] = special specialsFlag[RewardTYpe.TOP] = topRoleIds self:setProperty("specialsFlag", specialsFlag) self:setProperty("specials", specials) return {role_ids = topRoleIds, award = sspecial["award"]} end return nil end --TODO function Capsule:getCore(record) if self:getGoodsAmount() > 0 then return nil end local specialsFlag = self:getProperty("specialsFlag") or {} if specialsFlag[RewardTYpe.CORE] then return nil end local specials = self:getProperty("specials") or {} local spKey, special = self:getSpecialByType(RewardTYpe.CORE) if not special then return nil end local np = special["np"] if np > #record then return nil end local left = math.ceil((np - #record)/2) or 0 local count = np local roleRecord = {} for i, v in ipairs(record) do if count <= 0 then break end if i > left then local tmpCount = 0 if count >= v.amount then count = count - v.amount tmpCount = v.amount else tmpCount = count count = 0 end if not roleRecord[v.role_id]then roleRecord[v.role_id] = {amount = v.amount } else roleRecord[v.role_id] = {amount = (roleRecord[v.rol_id]["amount"] or 0) + tmpCount} end end end count = special["amount"] local roleIds = {} while(count > 0 and next(roleRecord)) do local roleId = math.randWeight(roleRecord, "amount") if roleId then table.insert(roleIds, roleId) local tmpLastRecord = roleRecord[roleId] tmpLastRecord["amount"] = tmpLastRecord["amount"] - 1 if tmpLastRecord["amount"] <= 0 then roleRecord[roleId] = nil end count = count - 1 end end special["amount"] = count specials[spKey] = special specialsFlag[RewardTYpe.CORE] = roleIds self:setProperty("specialsFlag", specialsFlag) self:setProperty("specials", specials) return {role_ids = roleIds, award = special["award"]} end function Capsule:getLast(record) if self:getGoodsAmount() > 0 then return nil end local specialsFlag = self:getProperty("specialsFlag") or {} if specialsFlag[RewardTYpe.LAST] then return nil end local specials = self:getProperty("specials") or {} local spKey, special = self:getSpecialByType(RewardTYpe.LAST) if not special then return nil end if not next(record) then return nil end table.sort(record, function(a, b) return a.create_time > b.create_time end) local np = special["np"] local count = np local lastRecord = {} for _, v in ipairs(record) do if count <= 0 then break end local tmpCount = 0 if count >= v.amount then count = count - v.amount tmpCount = v.amount else tmpCount = count count = 0 end if not lastRecord[v.role_id]then lastRecord[v.role_id] = {amount = v.amount } else lastRecord[v.role_id] = {amount = (lastRecord[v.rol_id]["amount"] or 0) + tmpCount} end end count = special["amount"] local lastRoleIds = {} while(count > 0 and next(lastRecord)) do local roleId = math.randWeight(lastRecord, "amount") if roleId then table.insert(lastRoleIds, roleId) local tmpLastRecord = lastRecord[roleId] tmpLastRecord["amount"] = tmpLastRecord["amount"] - 1 if tmpLastRecord["amount"] <= 0 then lastRecord[roleId] = nil end count = count - 1 end end special["amount"] = count specials[spKey] = special specialsFlag[RewardTYpe.LAST] = lastRoleIds self:setProperty("specialsFlag", specialsFlag) self:setProperty("specials", specials) return {role_ids = lastRoleIds, award = special["award"]} end function Capsule:getJoker(record) if self:getGoodsAmount() > 0 then return nil end local specialsFlag = self:getProperty("specialsFlag") or {} if specialsFlag[RewardTYpe.JOKER] then return nil end local specials = self:getProperty("specials") or {} local spKey, special = self:getSpecialByType(RewardTYpe.JOKER) if not special then return nil end local roleRecord = {} for _, v in ipairs(record) do if not roleRecord[v.role_id]then roleRecord[v.role_id] = {amount = v.amount } else roleRecord[v.role_id] = {amount = (roleRecord[v.rol_id]["amount"] or 0) + v.amount} end end local count = special["amount"] local roleIds = {} while(count > 0 and next(roleRecord)) do local roleId = math.randWeight(roleRecord, "amount") if roleId then table.insert(roleIds, roleId) local tmpRoleRecord = roleRecord[roleId] tmpRoleRecord["amount"] = tmpRoleRecord["amount"] - 1 if tmpRoleRecord["amount"] <= 0 then roleRecord[roleId] = nil end count = count - 1 end end special["amount"] = count specials[spKey] = special specialsFlag[RewardTYpe.JOKER] = roleIds self:setProperty("specialsFlag", specialsFlag) self:setProperty("specials", specials) return {role_ids = roleIds, award = special["award"]} end function Capsule:getKing(record) if self:getGoodsAmount() > 0 then return nil end local specialsFlag = self:getProperty("specialsFlag") or {} if specialsFlag[RewardTYpe.JOKER] then return nil end local specials = self:getProperty("specials") or {} local spKey, special = self:getSpecialByType(RewardTYpe.KING) if not special then return nil end local roleRecord = {} for _, v in ipairs(record) do if not roleRecord[v.role_id]then roleRecord[v.role_id] = {amount = v.amount } else roleRecord[v.role_id] = {amount = (roleRecord[v.rol_id]["amount"] or 0) + v.amount} end end local count = special["amount"] local roleIds = {} while(count > 0 and next(roleRecord)) do local roleId = math.randWeight(roleRecord, "amount") if roleId then table.insert(roleIds, roleId) local tmpRoleRecord = roleRecord[roleId] tmpRoleRecord["amount"] = tmpRoleRecord["amount"] - 1 if tmpRoleRecord["amount"] <= 0 then roleRecord[roleId] = nil end count = count - 1 end end special["amount"] = count specials[spKey] = special specialsFlag[RewardTYpe.KING] = roleIds self:setProperty("specialsFlag", specialsFlag) self:setProperty("specials", specials) return {role_ids = roleIds, award = special["award"]} end function Capsule:checkSpecialReward() local specials = self:getProperty("specials") or {} if not next(specials) then return nil end local record = self:getProperty("record") or {} if not next(record) then return nil end table.sort(record, function(a, b) return a.create_time < b.create_time end ) local notify = {} local topReward = self:getTop(record) if topReward then for _, roleId in ipairs(topReward.role_ids) do rpcRole(roleId, "paySpecialReward", RewardTYpe.TOP, topReward.award) table.insert(notify, {role_id = roleId, typ = RewardTYpe.TOP, award = topReward.award, amount = 1, create_time= skynet.timex()}) end end local coreReward = self:getCore(record) if coreReward then for _, roleId in ipairs(topReward.role_ids) do rpcRole(roleId, "paySpecialReward", RewardTYpe.CORE, coreReward.award) table.insert(notify, {role_id = roleId, typ = RewardTYpe.CORE, award = topReward.award, amount = 1, create_time= skynet.timex()}) end end local lastReward = self:getLast(record) if lastReward then for _, roleId in ipairs(lastReward.role_ids) do rpcRole(roleId, "paySpecialReward", RewardTYpe.LAST, lastReward.award) table.insert(notify, {role_id = roleId, typ = RewardTYpe.LAST, award = topReward.award, amount = 1, create_time= skynet.timex()}) end end local jokerReward = self:getJoker(record) if jokerReward then for _, roleId in ipairs(jokerReward.role_ids) do rpcRole(roleId, "paySpecialReward", RewardTYpe.JOKER, jokerReward.award) table.insert(notify, {role_id = roleId, typ = RewardTYpe.JOKER, award = topReward.award, amount = 1, create_time= skynet.timex()}) end end local kingReward = self:getKing(record) if kingReward then for _, roleId in ipairs(kingReward.role_ids) do rpcRole(roleId, "paySpecialReward", RewardTYpe.KING, kingReward.award) table.insert(notify, {role_id = roleId, typ = RewardTYpe.KING, award = topReward.award, amount = 1, create_time= skynet.timex()}) end end return notify end function Capsule:checkIncentive(roleId) local goods = self:getProperty("goods") or {} local record = self:getProperty("record") or {} local recordByRole = self:getProperty("recordByRole") or {} local roleRecord = recordByRole[roleId] or {} local incentive = self:getProperty("incentive") local reward -- 最后一抽 TODO if incentive["last"] then local last = true for k, v in pairs(goods) do if v and v.amount then last = false break end end reward = incentive["last"]["award"] end --次数 if incentive["amount"] then local amount = 0 for _, v in pairs(roleRecord) do if (v.calculated or 0) == 0 then amount = amount + v.amount end end local count = math.floor(amount / incentive["amount"]["np"]) local tmpCount = count * incentive["amount"]["np"] for i=1, count do reward = reward.. " " .. incentive["amount"]["award"] end --填充v.calculated 字段,标识已经用于每x抽的计算中。 for _, v in pairs(roleRecord) do if tmpCount <= 0 then break end v.calculated = v.calculated or 0 if v.calculated ~= v.amount then if tmpCount <= v.amount then v.calculated = tmpCount tmpCount = 0 else v.calculated = v.amount tmpCount = tmpCount - v.amount end end end end --概率 if incentive["probabilities"] then local probabilities = math.randomInt(1, 100) if probabilities <= incentive["probabilities"]["np"] then reward = reward .. " " .. incentive["probabilities"]["award"] end end if reward and reward ~= "" then local tmpReward, notify = {}, {} for k, v in pairs(reward:toNumMap()) do tmpReward[k] = (tmpReward[k] or 0) + v end notify = {role_id = roleId, typ = RewardTYpe.incentive, award = reward, amount = 1, create_time= skynet.timex()} table.insert(record, notify) self:setProperty("record", record) return tmpReward,notify end return nil, nil end function Capsule:drawByCount(roleId, count) if count <= 0 then return nil end local goods = self:getProperty("goods") or {} local record = self:getProperty("record") or {} local recordByRole = self:getProperty("recordByRole") or {} local id = self:getProperty("id") local room = self:getProperty("room") local ichibankuji = csvdb["ichibankuji_mainCsv"][id][room] local goods_id = ichibankuji["goods_id"] --奖励, 通知信息 local reward, notify= {}, {} while (goods and next(goods) and count > 0) do local good_id = math.randWeight(goods, "weight") if good_id then local good = goods[good_id] or {} if good.amount > 0 then good.amount = good.amount - 1 for k, v in pairs(good.award:toNumMap()) do reward[k] = (reward[k] or 0) + v end --插入记录 local tmpNotify = {role_id = roleId, good_id = good_id, typ = RewardTYpe.GOODS, award = good.award, amount = 1, quality = good.quality, create_time= skynet.timex()} table.insert(record, tmpNotify) table.insert(notify, tmpNotify) --记录角色的抽奖记录 local tmp = recordByRole[roleId] if not tmp then recordByRole[roleId] = {good_id=notify} else if not tmp[good_id] then tmp[good_id] = notify else tmp[good_id].amount = tmp[good_id].amount + 1 end end good.weight = good.weight - csvdb["ichibankuji_goodsCsv"][goods_id].weight count = count - 1 end end end self:setProperty("recordByRole", recordByRole) self:setProperty("record", record) self:setProperty("goods", goods) local incentiveReward, tmpNotify = self:checkIncentive(roleId) for k, v in pairs(incentiveReward or {}) do reward[k] = (reward[k] or 0) + v end if tmpNotify then table.insert(notify, tmpNotify) end local speciNotify = self:checkSpecialReward(roleId) if speciNotify and next(speciNotify) then table.insert(notify, speciNotify) end return reward, notify end function Capsule:drawAll(roleId) local goods = self:getProperty("goods") or {} local record = self:getProperty("record") or {} local recordByRole = self:getProperty("recordByRole") or {} local reward, notify = {}, {} for good_id, good in pairs(goods) do if good.amount > 0 then notify = {role_id = roleId, good_id = good_id, typ = RewardTYpe.GOODS, award = good.award, amount = good.amount, quality = good.quality, create_time = skynet.timex()} table.insert(record, notify) --记录角色的抽奖记录 local tmp = recordByRole[roleId] if not tmp then recordByRole[roleId] = {good_id=notify} else if not tmp[good_id] then tmp[good_id] = notify else tmp[good_id].amount = tmp[good_id].amount + good.amount end end end while(good.amount > 0) do for k, v in pairs(good.award:toNumMap()) do reward[k] = (reward[k] or 0) + v end good.amount = good.amount - 1 end end local incentiveReward, tmpNotify = self:checkIncentive(roleId) for k, v in pairs(incentiveReward or {}) do reward[k] = (reward[k] or 0) + v end if tmpNotify then table.insert(notify, tmpNotify) end local speciNotify = self:checkSpecialReward(roleId) if speciNotify and next(speciNotify) then table.insert(notify, speciNotify) end self:setProperty("recordByRole", recordByRole) self:setProperty("record", record) self:setProperty("goods", goods) return reward, notify end --@param --[[ @roleId @typ 1=全收 0=单次 @cares 关注{k=v} ]]-- function Capsule:draw(roleId, full, cares) if self:getGoodsAmount() == 0 then return 2 end if self:getProperty("typ") == 1 then --是否报名 if self:isRegister(roleId) == false then return 3 end --关注的奖品的数量发生了变化 if cares then local change = self:confirmed(cares) if next(change) then return 4, change end end end if full == 0 then return 5, self:drawByCount(roleId, 1) elseif full == 1 then return 5, self:drawByCount(roleId, 10) elseif full == 2 then return 5, self:drawAll(roleId) end end function Capsule:data(roleId) return { id = self:getProperty("id"), room = self:getProperty("room"), typ = self:getProperty("typ"), name = self:getProperty("name"), coin = self:getProperty("coin"), onlineCount = self:getOnlineCount(), playerStatus = self:getRegisterByRoleId(roleId), record = self:getProperty("record"), --recordByRole = self:getProperty("recordByRole"), rank = self:getProperty("rank"), goods = self:getProperty("goods"), specials = self:getProperty("specials"), incentive = self:getProperty("incentive"), specialsFlag= self:getProperty("specialsFlag"), } end return Capsule