local Passive = require "adv.AdvPassive" -- 工具函数--第一象限 < 10000 < 第二象限 < 20000 < 第四象限 < 30000 < 第三象限 local function getIdByCr(c, r) local crId = math.abs(r) + math.abs(c) * 100 -- row + column * 100 if c < 0 then crId = crId + 10000 end if r < 0 then crId = crId + 20000 end return crId end local function getCrById(crId) local c = math.floor(crId % 10000 / 100) local r = crId % 100 local last = math.floor(crId / 10000) if last == 3 then c, r = -c, -r elseif last == 1 then c = -c elseif last == 2 then r = -r end return c, r end -----------------------------随机地图----------------------------- --检查 是否满足层数限制条件 -- if checktype == 1 then check value in range a=b else check value in array a=b=c local function checkIsIn(checkValue, checkType, checkRange) if not checkValue then return end if checkType == 1 then local limits = checkRange:toNumMap() for min, max in pairs(limits) do if checkValue >= min and checkValue <= max then return true end end else local limit = checkRange:toArray(true, "=") for _, _l in ipairs(limit) do if _l == checkValue then return true end end end end --关卡事件库 local function getEventLib(chapterId, level, needEventType) -- needEventType 需要的事件 local chapter = math.floor(chapterId / 100) % 100 local libsToType = { ["event_monsterCsv"] = {AdvEventType.Monster, AdvEventType.BOSS, AdvEventType.Monster}, ["event_chooseCsv"] = AdvEventType.Choose, ["event_dropCsv"] = AdvEventType.Drop, ["event_buildingCsv"] = AdvEventType.Build, ["event_traderCsv"] = AdvEventType.Trader, ["event_trapCsv"] = AdvEventType.Trap, ["event_clickCsv"] = AdvEventType.Click, } local eventLib = {} for lib, eventType in pairs(libsToType) do -- init eventLib if type(eventType) == "table" then for _, temp in ipairs(eventType) do eventLib[temp] = {} end else eventLib[eventType] = {} end -- needEventType 只获取这个事件类型 if not needEventType or eventLib[needEventType] then for id, data in pairs(csvdb[lib]) do if data.levelchapter == chapter then if checkIsIn(level, data.leveltype, data.levellimit) then if type(eventType) == "table" then eventLib[eventType[data.type]][data.BlockEventType] = eventLib[eventType[data.type]][data.BlockEventType] or {} eventLib[eventType[data.type]][data.BlockEventType][id] = {showup = data.showup, limit = data.limit} else eventLib[eventType][data.BlockEventType] = eventLib[eventType][data.BlockEventType] or {} eventLib[eventType][data.BlockEventType][id] = {showup = data.showup, limit = data.limit} end end end end if needEventType then break end end end return eventLib end -- 生成地图 是否可以生成地图上层判断 local function randomAdvMap(role, chapterId, level, notNotify) local chapterData = csvdb["adv_chapterCsv"][chapterId] if not chapterData then error("chapterId " .. chapterId .. " dont exist!") return end if level > chapterData.limitlevel then error("level overflow!") return end --随出地图 local raw_pool = chapterData.mapid:toArray(true, "=") local advInfo = role:getProperty("advInfo") local lastMapId = advInfo.mapId --非同一层不连续随出同一张类似的地图 local lastChapterId = advInfo.chapter local lastScore = advInfo.score or {} -- 分数 local pool = {} for _, mapId in ipairs(raw_pool) do local temp = csvdb["mapCsv"][mapId] if temp and (lastChapterId == chapterId or lastMapId ~= mapId) then --非同一层不连续随出同一张类似的地图 if checkIsIn(level, temp.leveltype, temp.levellimit) then table.insert(pool, mapId) end end end if not next(pool) then error("mapIds is empty!") return end local mapId = pool[math.randomInt(1, #pool)] --随出事件 local mapData = csvdb["map_" .. csvdb["mapCsv"][mapId]["path"] .. "Csv"] if not mapData then error("mapId " .. mapId .. " dont exist!") return end table.clear(advInfo) advInfo.chapter = chapterId advInfo.level = level advInfo.mapId = mapId advInfo.score = lastScore advInfo.enemyId = 1 --怪递增的索引 advInfo.rooms = {} -- {[roomId] = {event = {}, open = {}},} -- event 事件信息(具体信息查看randomEvent), open 是否解锁 --事件随机 local eventLib = getEventLib(chapterId, level) -- 同时记录出现次数 local monsterEvents = {} --处理钥匙掉落 local haveBoss = false local function randomEvent(roomId, blockId, eventType) if advInfo.rooms[roomId]["event"][blockId] then return end --已经有事件了 不覆盖 local etype, especial = eventType, 0 if eventType > 100 then -- 特殊事件(固定) etype = math.floor(eventType / 100) especial = eventType % 100 end local event = {etype = etype} local randomFunc = {} local function randomCommon() if not eventLib[etype] or not next(eventLib[etype]) or not eventLib[etype][especial] or not next(eventLib[etype][especial]) then return false end event.id = math.randWeight(eventLib[etype][especial], "showup") if not event.id then return false end if eventLib[etype][especial][event.id].limit > 1 then eventLib[etype][especial][event.id].limit = eventLib[etype][especial][event.id].limit - 1 elseif eventLib[etype][especial][event.id].limit == 1 then eventLib[etype][especial][event.id] = nil end end --入口 randomFunc[AdvEventType.In] = function()end --出口 randomFunc[AdvEventType.Out] = function() end --boss randomFunc[AdvEventType.BOSS] = function() if haveBoss then return false end if randomCommon() == false then return false end haveBoss = true end --怪物 randomFunc[AdvEventType.Monster] = function() if randomCommon() == false then return false end table.insert(monsterEvents, event) end --选择点 randomFunc[AdvEventType.Choose] = randomCommon --掉落点 randomFunc[AdvEventType.Drop] = randomCommon --交易所 randomFunc[AdvEventType.Trader] = randomCommon --建筑 randomFunc[AdvEventType.Build] = randomCommon --陷阱 randomFunc[AdvEventType.Trap] = randomCommon --点击生效 randomFunc[AdvEventType.Click] = randomCommon if randomFunc[etype] then if randomFunc[etype]() ~= false then advInfo.rooms[roomId]["event"][blockId] = event end end end local stagePool = {["global"] = {}} for roomId, roomName in pairs(mapData["rooms"]) do stagePool[roomId] = {} advInfo.rooms[roomId] = {event = {}, open = {}} -- 事件, open open == 1 房间内地块全部开放 local roomData if roomName == "path" then roomData = mapData["path"] else roomName = roomName:gsub("/", "_") roomData = csvdb["room_" .. roomName .. "Csv"] end for blockId, stageType in pairs(roomData["blocks"]) do if AdvSpecialStage[stageType] then local eventType = AdvEventType[AdvSpecialStage[stageType]] -- 地块固定类型 randomEvent(roomId, blockId, eventType) else stagePool["global"][stageType] = stagePool["global"][stageType] or {} stagePool[roomId][stageType] = stagePool[roomId][stageType] or {} table.insert(stagePool["global"][stageType], {room = roomId, block = blockId}) stagePool[roomId][stageType][blockId] = 1 end end end -- 全地图事件 优先级高 for stageType, events in pairs(mapData["events"]) do for _, event in ipairs(events) do local lastCount = stagePool["global"][stageType] and #stagePool["global"][stageType] or 0 if lastCount <= 0 then break end if math.randomFloat(0, 1) <= (event["rate"] or 1) then local count = math.randomInt(math.min(lastCount, event["minc"]), math.min(lastCount, event["maxc"])) for i = 1, count do local idx = math.randomInt(1, lastCount) local cur = stagePool["global"][stageType][idx] randomEvent(cur["room"], cur["block"], event["event"]) table.remove(stagePool["global"][stageType], idx) lastCount = lastCount - 1 stagePool[cur["room"]][stageType][cur["block"]] = nil end end end end -- 随机单个房间的事件 for roomId, roomName in pairs(mapData["rooms"]) do local roomData if roomName == "path" then roomData = mapData["path"] else roomName = roomName:gsub("/", "_") roomData = csvdb["room_" .. roomName .. "Csv"] end for stageType, events in pairs(roomData["events"]) do local bpool = {} if stagePool[roomId][stageType] then for block, _ in pairs(stagePool[roomId][stageType]) do table.insert(bpool, block) end end for _, event in ipairs(events) do if #bpool <= 0 then break end if math.randomFloat(0, 1) <= (event["rate"] or 1) then local count = math.randomInt(math.min(#bpool, event["minc"]), math.min(#bpool, event["maxc"])) for i = 1, count do local idx = math.randomInt(1, #bpool) randomEvent(roomId, bpool[idx], event["event"]) table.remove(bpool, idx) end end end end end if not haveBoss then if not next(monsterEvents) then print("这个地图没有钥匙!!! mapId : " .. mapId) else local event = monsterEvents[math.randomInt(1, #monsterEvents)] event.item = {ItemId.AdvKey, 1} --掉落钥匙 end end end --块类型 local Block = class("Block") function Block:ctor(blockId, event, isOpen) self.blockId = blockId self.col, self.row = getCrById(self.blockId) self.isOpen = isOpen and true or false self.event = event -- 拿到的是引用可以直接更新 end function Block:isBoss() if not self.event then return end return self.event["etype"] == AdvEventType.BOSS end --事件有需要额外处理的部分 function Block:open(adv, room) --如果翻开有数据处理在这里处理 local randomFunc = {} --怪 randomFunc[AdvEventType.Monster] = function() self.event.mId = adv.advInfo.enemyId --给怪一个有序id 回合逻辑时使用 adv.advInfo.enemyId = adv.advInfo.enemyId + 1 local enemy = adv.battle:getEnemy(room.roomId, self.blockId) if enemy then enemy:unlock(self.event.mId) else enemy = adv.battle:addEnemy(room, self) end enemy:triggerPassive(Passive.BORN_ONCE) end randomFunc[AdvEventType.BOSS] = randomFunc[AdvEventType.Monster] --掉落 randomFunc[AdvEventType.Drop] = function() self.event.item = csvdb["event_dropCsv"][self.event.id]["range"]:randWeight(true) end --交易 randomFunc[AdvEventType.Trader] = function() local data = csvdb["event_traderCsv"][self.event.id] self.event.shop = {} self.event.status = "" --购买次数状态 1 就是购买过了 -- 购买id就是shop索引 for i = 1, 10 do local numS, rangeS = "num" .. i, "range" .. i if data[numS] and data[rangeS] then for j = 1, data[numS] do table.insert(self.event.shop, data[rangeS]:randWeight(true)) end else break end end end --建筑 randomFunc[AdvEventType.Build] = function() local data = csvdb["event_buildingCsv"][self.event.id] self.event.effect = data["range"]:randWeight(true) --随出建筑效果 if self.event.effect[1] == 1 then --获得某道具 local reward = csvdb["event_dropCsv"][self.event.effect[2]]["range"]:randWeight(true) self.event.effect[2] = reward[1] self.event.effect[3] = reward[2] end end randomFunc[AdvEventType.Trap] = function() local data = csvdb["event_trapCsv"][self.event.id] for _, buffId in ipairs(data.effect:toArray(true, "=")) do adv.battle.player:addBuff(buffId) end adv:backTrap() room:clearBEvent(self) end if self.event then -- 随机出具体的事件 if randomFunc[self.event.etype] then randomFunc[self.event.etype]() end end self.isOpen = true end local Room = class("Room") function Room:ctor(adv, roomId, csvData, info, isPath) self.roomId = roomId self.col, self.row = getCrById(self.roomId) self.isPath = isPath self.isBossRoom = false -- boss房间 --击败boss 以后重置为false self.info = info -- 拿到引用 方便更新advInfo self.isShow = false self.blocks = {} for blockId, _ in pairs(csvData["blocks"]) do self.blocks[blockId] = Block.new(blockId, info.event[blockId], info.open == 1 or info.open[blockId]) if not self.isPath and self.blocks[blockId]:isBoss() then self.isBossRoom = true end if self.blocks[blockId].isOpen then self.isShow = true else if self.blocks[blockId].event and self.blocks[blockId].event.etype == AdvEventType.In then -- 开放 self.isShow = true self.blocks[blockId].isOpen = true self.info.open[blockId] = 1 --入口房间只会在这里首次展示开放 --触发固有技 adv:triggerPassive(Passive.ROOM_SHOW, {roomId = self.roomId}) end end end end function Room:tranGToL(c, r) return c - self.col, r - self.row end function Room:tranLtoG(c, r) return c + self.col, r + self.row end function Room:getBByGPos(c, r) local c, r = self:tranGToL(c, r) return self.blocks[getIdByCr(c, r)] end function Room:openBlock(block, adv) if self.blocks[block.blockId] ~= block then return end if block.isOpen == true then return end if self.isBossRoom then for _, _block in pairs(self.blocks) do _block:open(adv, self) end else block:open(adv, self) end local allOpen = true for _, _block in pairs(self.blocks) do if not _block.isOpen then allOpen = false break end end if allOpen then self.info.open = 1 else self.info.open[block.blockId] = 1 end adv:scoreChange(AdvScoreType.Block) if not self.isShow then self.isShow = true --首次展示房间 adv:triggerPassive(Passive.ROOM_SHOW, {roomId = self.roomId}) end end function Room:clearBEvent(block) if self.blocks[block.blockId] ~= block then return end if block.event.etype == AdvEventType.Trap then -- 记录陷阱位置 self.info.trap = self.info.trap or {} self.info.trap[block.blockId] = block.event.id end block.event = nil self.info.event[block.blockId] = nil end local Adv = class("Adv") function Adv:ctor(owner) assert(owner, "Adv instance must have owner(role)") self.owner = owner self.advInfo = self.owner:getProperty("advInfo") --这个变量置空使用 table.clear self.advTeam = self.owner:getProperty("advTeam") --这个变量置空使用 table.clear self:clear() self.backEvents = {} --发给客户端的事件组 self.tempBackEvents = {} --发给客户端的事件组(缓存) end -- 清空自己组织的数据 function Adv:clear() self.rooms = {} self.cachePassiveEvent = {} -- 在battle 没有创建成功时 触发的被动技信息 self.battle = nil -- 战斗逻辑 end --关卡通关,非层 score < 0 失败 function Adv:over(success) local score = self:getScore() local scoreInfo = self.advInfo.score local reward if success then self.owner:updateProperty({field = "advPass", self.owner:getProperty("advPass"):setv(self.advInfo.chapter, score)}) reward = self.owner:award(self.owner:getProperty("advItems"):toNumMap()) self.owner:checkTaskEnter(self.owner.TaskType.AdvPass, {id = self.advInfo.chapter}) end table.clear(self.advInfo) --清空advInfo self.advTeam.player = nil --重置玩家的数据 self:clear() self.owner:updateProperty({field = "advItems", value = ""}) self:backEnd(success, score, scoreInfo, reward) end function Adv:exit() self:over(false) self:saveDB() end function Adv:getMapInfo() if not next(self.advInfo) then return end return csvdb["mapCsv"][self.advInfo.mapId] end function Adv:getMapData() local mapInfo = self:getMapInfo() if not mapInfo then return end return csvdb["map_" .. self:getMapInfo()["path"] .. "Csv"] end function Adv:initByInfo() self:clear() if not next(self.advInfo) then return end --未初始化的 advInfo local mapData = self:getMapData() if not mapData then return end for roomId, roomName in pairs(mapData["rooms"]) do if roomName == "path" then self.rooms[roomId] = Room.new(self, roomId, mapData["path"], self.advInfo.rooms[roomId], true) else roomName = roomName:gsub("/", "_") self.rooms[roomId] = Room.new(self, roomId, csvdb["room_" .. roomName .. "Csv"], self.advInfo.rooms[roomId], false) end end self:initBattle() return true end function Adv:triggerPassive(condType, params) if not self.battle then table.insert(self.cachePassiveEvent, {condType, params}) else self.battle:triggerPassive(condType, params) end end function Adv:initBattle() self.battle = require("adv.AdvBattle").new(self) for _, passiveC in ipairs(self.cachePassiveEvent) do self.battle:triggerPassive(passiveC[1], passiveC[2]) end self.cachePassiveEvent = {} end -- 随机地图 function Adv:initByChapter(chapterId, level, notNotify) level = level or 1 randomAdvMap(self.owner, chapterId, level, notNotify) if not next(self.advInfo) then return end if level > 1 then self:scoreChange(AdvScoreType.Level) end self:initByInfo() --初始化 self.owner:updateProperties({advInfo = self.advInfo, advTeam = self.advTeam}, notNotify) end --获取,某个位置上的 room 和 block function Adv:getRBByPos(c, r) for roomId, room in pairs(self.rooms) do local block = room:getBByGPos(c, r) if block then return room, block end end end function Adv:getAroundBlocks(room, block) local blocks = {} local range = {1, -1} local col, row = room:tranLtoG(block.col, block.row) for _, add in ipairs(range) do local rroom, rblock = self:getRBByPos(col + add, row) if rroom then table.insert(blocks, {rroom, rblock}) end end for _, add in ipairs(range) do local rroom, rblock = self:getRBByPos(col, row + add) if rroom then table.insert(blocks, {rroom, rblock}) end end return blocks end --随机一个空的位置生成怪, 如果没有就没有 function Adv:addNewMonsterRand(monsterId, where) local room, block if where then room, block = where[1], where[2] else local pool = {} for _, room_ in pairs(self.rooms) do for _, block_ in pairs(room_.blocks) do if block_.isOpen and not block_.event then table.insert(pool, {room_, block_}) end end end if not next(pool) then return end local idx = math.randomInt(1, #pool) room, block = pool[idx][1], pool[idx][2] end if not monsterId then local eventLib = getEventLib(self.advInfo.chapter, self.advInfo.level, AdvEventType.Monster) if not next(eventLib[AdvEventType.Monster][0]) then return false end monsterId = math.randWeight(eventLib[AdvEventType.Monster][0], "showup") end local event = {etype = AdvEventType.Monster, mId = self.advInfo.enemyId} self.advInfo.enemyId = self.advInfo.enemyId + 1 event.id = monsterId block.event = event room.info.event[block.blockId] = event self.battle:addEnemy(room, block):triggerPassive(Passive.BORN_ONCE) return room, block end -- 随机翻开 num 个 以开放的房间的 地块 function Adv:openBlockRand(num) local pool = {} for _, room in pairs(self.rooms) do if room.isShow and not room.isPath then for _, block in pairs(room.blocks) do if not block.isOpen then table.insert(pool, {room.roomId, block.blockId}) end end end end if #pool <= num then for _, temp in ipairs(pool) do self:openBlock(temp[1], temp[2]) end else for i = 1, num do local idx = math.randomInt(1, #pool) self:openBlock(pool[idx][1], pool[idx][2]) table.remove(pool, idx) end end end -- 打开一个地块 function Adv:openBlock(roomId, blockId) local room = self.rooms[roomId] if not room then return end local block = room.blocks[blockId] if not block then return end room:openBlock(block, self) self:backBlockChange(roomId, blockId) end -- 在冒险中获得的物品都发放在冒险背包内 function Adv:award(gift, params) params = params or {} local tgift = {} if type(gift) == "string" then for _, one in pairs(gift:toTableArray(true)) do tgift[one[1]] = (tgift[one[1]] or 0) + one[2] end else tgift = gift end local items = self.owner:getProperty("advItems") for itemId, count in pairs(tgift) do if count > 0 then self:scoreChange(AdvScoreType.Item, {itemId, count}) end local origin = items:getv(itemId, 0) local nums = origin + count if nums <= 0 then items = items:delk(itemId) nums = 0 else items = items:incrv(itemId, count) end end self.owner:updateProperty({field = "advItems", value = items, notNotify = params.notNotify}) return tgift end -- 消耗物品 优先冒险背包 --check 只是检查够不够 function Adv:cost(item, params, check) local items = self.owner:getProperty("advItems") local less = {} local advCost = {} for itemId, count in pairs(item) do advCost[itemId] = - math.min(items:getv(itemId, 0), count) if advCost[itemId] == 0 then advCost[itemId] = nil end local last = items:getv(itemId, 0) - count if last < 0 then less[itemId] = -last end end if next(less) and not self.owner:checkItemEnough(less) then return end --不够 if check then return true end self:award(advCost, params) self.owner:costItems(less, params) return true end --事件点击处理 local function clickOut(self, room, block, params) if self:cost({[ItemId.AdvKey] = 1}, {}) then if self.advInfo.level >= csvdb["adv_chapterCsv"][self.advInfo.chapter].limitlevel then --关卡结束 self:over(true) else self:initByChapter(self.advInfo.chapter, self.advInfo.level + 1, true) self:backNext() --下一关 end return true end end --战斗 普通攻击 local function clickMonster(self, room, block, params) self.battle:battleBegin(room.roomId, block.blockId, params.quick) return true end local function clickChoose(self, room, block, params) local choose = params.choose local chooseData = csvdb["event_chooseCsv"][block.event.id] if not chooseData or not chooseData["button".. choose .."cond"] then return end local cond = chooseData["button".. choose .."cond"]:toArray(true, "=") local checkCond = { -- 拥有道具 [1] = function() if self:cost({[cond[2]] = cond[3]}, {}, true) then return true end end, -- xx角色(todo 队长) [2] = function() for slot, heroId in pairs(self.advTeam.heros) do if self.owner.heros[heroId] then if self.owner.heros[heroId]:getProperty("type") == cond[2] then return true end end end end, --消灭所有怪 [3] = function() for _, room in pairs(self.rooms) do for _, block in pairs(room.blocks) do if block.event and (block.event.etype == AdvEventType.BOSS or block.event.etype == AdvEventType.Monster) then return end end end return true end, --制定属性 > [4] = function() if (self.battle.player[AttsEnumEx[cond[2]]] or 0) > cond[3] then return true end end, } assert(not cond[1] or checkCond[cond[1]], "error cond, event_chooseCsv id :" .. block.event.id) if cond[1] and not checkCond[cond[1]]() then return end local clearBlock = true local effects = chooseData["button".. choose .."effect"]:toTableArray(true) for _, effect in ipairs(effects) do if effect[1] == 1 then local reward = csvdb["event_dropCsv"][effect[2]]["range"]:randWeight(true) effect[2] = reward[1] effect[3] = reward[2] end local doEffect = { [1] = function() -- 获得某道具N个 self:backReward(self:award({[effect[2]] = effect[3]}, {})) end, [2] = function() --获得冒险buff self.battle.player:addBuff(effect[2]) end, [3] = function() --发现怪物 self:addNewMonsterRand(effect[2], {room, block}) clearBlock = false end, [4] = function() --无事发生 end } assert(doEffect[effect[1]], "error effect, event_chooseCsv id :" .. block.event.id) doEffect[effect[1]]() end if clearBlock then room:clearBEvent(block) end return true end local function clickDrop(self, room, block, params) local reward = {} if not block.event.item then return end local reward = self:award({[block.event.item[1]] = block.event.item[2]}) room:clearBEvent(block) self:backReward(reward) return true end local function clickTrader(self, room, block, params) local buyId = params.id local traderData = csvdb["event_traderCsv"][block.event.id] if not traderData then return end -- 偷偷改表了 if not block.event.shop or not block.event.shop[buyId] then return end if (block.event.status or ""):getv(buyId, 0) == 1 then return end -- 买过了 if not self:cost({[traderData.type] = block.event.shop[buyId][3]}, {}) then return end --不够 local reward = self:award({[block.event.shop[buyId][1]] = block.event.shop[buyId][2]}) block.event.status = block.event.status:setv(buyId, 1) self:backReward(reward) return true end local function clickBuild(self, room, block, params) local buildData = csvdb["event_buildingCsv"][block.event.id] if not buildData then return end-- 偷偷改表了 if not block.event.effect then return end -- 没有效果 气人不 local clearBlock = true local effect = block.event.effect --todo 效果生效 local doEffect = { [1] = function() -- 获得某道具N个 self:backReward(self:award({[effect[2]] = effect[3]}, {})) end, [2] = function() --获得冒险buff self.battle.player:addBuff(effect[2]) end, [3] = function() --发现怪物 self:addNewMonsterRand(effect[2], {room, block}) clearBlock = false end, [4] = function() --无事发生 end } assert(doEffect[effect[1]], "error effect, event_buildingCsv id :" .. block.event.id) if not self:cost(buildData.required:toNumMap(), {}) then return end doEffect[effect[1]]() if clearBlock then room:clearBEvent(block) end return true end local function clickClick(self, room, block, params) local clickData = csvdb["event_clickCsv"][block.event.id] if not clickData then return end local clearBlock = true local doEffect = { [1] = function() -- 技能 for _, skillId in ipairs(clickData.effect:toArray(true, "=")) do self.battle.player:releaseSkill(skillId) end end, [2] = function() -- dropId local reward = {} for _, dropId in ipairs(clickData.effect:toArray(true, "=")) do local item = csvdb["event_dropCsv"][dropId]["range"]:randWeight(true) reward[item[1]] = (reward[item[1]] or 0) + reward[item[2]] end self:backReward(self:award(reward, {})) end, } if clearBlock then room:clearBEvent(block) end return true end local eventCallFunc = { [AdvEventType.Out] = clickOut, [AdvEventType.BOSS] = clickMonster, [AdvEventType.Monster] = clickMonster, [AdvEventType.Choose] = clickChoose, [AdvEventType.Drop] = clickDrop, [AdvEventType.Trader] = clickTrader, [AdvEventType.Build] = clickBuild, [AdvEventType.Click] = clickClick, } --点击处理 roomId, blockId --params 某些事件需要的客户端传递的参数 function Adv:clickBlock(roomId, blockId, params) local room = self.rooms[roomId] if not room then return end local block = room.blocks[blockId] if not block then return end local status = false local clickEvent = false if not block.isOpen then local canOpen = false --如果未开放是否可以开放 local hadMonster = false -- 周围是否有解锁的怪未击败 for _, one in ipairs(self:getAroundBlocks(room, block)) do local _room, _block = one[1], one[2] if _block.isOpen then canOpen = true end if _block.isOpen and _block.event and (_block.event.etype == AdvEventType.BOSS or _block.event.etype == AdvEventType.Monster) then hadMonster = true end end if canOpen and not hadMonster then --开放 room:openBlock(block, self) status = true end else clickEvent = true --点了空地 if not block.event then return end --可点击的事件 if not room.isBossRoom or block.event.etype == AdvEventType.BOSS then if eventCallFunc[block.event.etype] then status = eventCallFunc[block.event.etype](self, room, block, params) end end end local needChange = true if clickEvent and block.event then if block.event.etype == AdvEventType.Out then needChange = false end if (block.event.etype == AdvEventType.Monster or block.event.etype == AdvEventType.BOSS) and not self.battle:isBattleEnd() then needChange = false end end if status and needChange then --出去了就不计算回合了 self:backBlockChange(roomId, blockId) self:afterRound() end self:saveDB() return status end --使用道具产生效果 function Adv:useItem(itemId, count, target) count = count or 1 local itemData = csvdb["adv_itemCsv"][itemId] if not itemData then return end --重置数量 if itemData["function"] == 0 or itemData["function"] == 2 then count = 1 end if not self:cost({[itemId] = count}, {}, true) then return true end --消耗 if itemData["function"] == 0 or itemData["function"] == 1 then self:cost({[itemId] = count}, {}) end --生效 if itemData.type == 1 or itemData.type == 0 then --技能 self.battle.player:releaseSkill(itemData.effect, target) elseif itemData.type == 2 then --掉落 local item = csvdb["event_dropCsv"][itemData.effect]["range"]:randWeight(true) self:backReward(self:award({[item[1]] = item[2]}, {})) else return end self:afterRound() self:saveDB() return true end --使用技能 function Adv:usePotion(potionId, potionLevel, target) -- cost local potionData = csvdb["adv_potionCsv"][potionId][potionLevel] local enemy = self.battle:getEnemy(target.roomId, target.blockId) if not enemy then return end --生效 if potionData.type == 1 or potionData.type == 0 then --技能 self.battle.player:releaseSkill(potionData.effect, enemy) elseif potionData.type == 2 then --掉落 local item = csvdb["event_dropCsv"][potionData.effect]["range"]:randWeight(true) self:backReward(self:award({[item[1]] = item[2]}, {})) else return end self:afterRound() self:saveDB() return true end --敌人死亡 function Adv:enemyDead(roomId, blockId, escape) local room = self.rooms[roomId] local block = room.blocks[blockId] --死了以后掉东西 if block.event and (block.event.etype == AdvEventType.BOSS or block.event.etype == AdvEventType.Monster) then --处理死亡 if block.event.etype == AdvEventType.BOSS then room.isBossRoom = false end if escape then room:clearBEvent(block) else local monsterData = csvdb["event_monsterCsv"][block.event.id] self:scoreChange(AdvScoreType.Kill, monsterData.type) local item = block.event.item if not item then if block.event.etype == AdvEventType.BOSS then item = {ItemId.AdvKey, 1} else local dropData = csvdb["event_dropCsv"][monsterData.dropid] item = dropData["range"]:randWeight(true) end end if item[1] == 0 then room:clearBEvent(block) else table.clear(block.event) block.event.etype = AdvEventType.Drop block.event.item = item end end end self:backBlockChange(roomId, blockId) end function Adv:pushBackEvent(btype, params) table.insert(self.backEvents, {btype = btype, params = params}) end function Adv:backReward(items) self:pushBackEvent(AdvBackEventType.Reward, {items = items}) end -- if is player enemyId is nil --isMax 是否是改变血量上限 function Adv:backHpChange(enemyId, change, isMax) self:pushBackEvent(AdvBackEventType.HpChange, {enemyId = enemyId, change = change, isMax = isMax}) end function Adv:backMiss(enemyId) self:pushBackEvent(AdvBackEventType.Miss, {enemyId = enemyId}) end -- if is player enemyId is nil function Adv:backAtkChange(enemyId, change) self:pushBackEvent(AdvBackEventType.AtkChange, {enemyId = enemyId, change = change}) end -- if is player enemyId is nil function Adv:backDefChange(enemyId, change) self:pushBackEvent(AdvBackEventType.DefChange, {enemyId = enemyId, change = change}) end -- if is player enemyId is nil function Adv:backBuff(enemyId, buffId, isDel) self:pushBackEvent(AdvBackEventType.Buff, {enemyId = enemyId, buffId = buffId, isDel = isDel}) end -- if is player enemyId is nil function Adv:backSkill(enemyId, skillId, receiver) self:pushBackEvent(AdvBackEventType.Skill, {enemyId = enemyId, skillId = skillId, receiver = receiver}) end -- if is player enemyId is nil function Adv:backPassive(enemyId, passiveId) self:pushBackEvent(AdvBackEventType.Passive, {enemyId = enemyId, passiveId = passiveId}) end function Adv:backNext() self:pushBackEvent(AdvBackEventType.Next, {}) end function Adv:backEnd(success, score, scoreInfo, reward) self:pushBackEvent(AdvBackEventType.End, {success = success, score = score, scoreInfo = scoreInfo, reward = reward}) end function Adv:backBlockChange(roomId, blockId) self:pushBackEvent(AdvBackEventType.BlockChange, {roomId = roomId, blockId = blockId}) end function Adv:backAtk(enemyId, receiver) self:pushBackEvent(AdvBackEventType.Atk, {enemyId = enemyId, receiver = receiver}) end function Adv:backDead(enemyId) self:pushBackEvent(AdvBackEventType.Dead, {enemyId = enemyId}) end function Adv:backTrap() self:pushBackEvent(AdvBackEventType.Trap, {}) end function Adv:scoreChange(scoreType, pms) local cutTypes = {} local score = 0 cutTypes[AdvScoreType.Level] = function() score = globalCsv.adv_score_floor end cutTypes[AdvScoreType.Kill] = function() local chapterData = csvdb["adv_chapterCsv"][self.advInfo.chapter] score = globalCsv.adv_score_monster[pms] * chapterData["monRatio"] end cutTypes[AdvScoreType.Item] = function() score = csvdb["itemCsv"][pms[1]].adv_score_item * pms[2] end cutTypes[AdvScoreType.Hurt] = function() score = globalCsv.adv_score_hurt * pms end cutTypes[AdvScoreType.Block] = function() score = globalCsv.adv_score_block end if cutTypes[scoreType] then cutTypes[scoreType]() else return end self.advInfo.score[scoreType] = self.advInfo.score[scoreType] or 0 self.advInfo.score[scoreType] = self.advInfo.score[scoreType] + score end function Adv:getScore() self.advInfo.score[AdvScoreType.Level] = math.floor(self.advInfo.score[AdvScoreType.Level] or 0) self.advInfo.score[AdvScoreType.Block] = math.floor(self.advInfo.score[AdvScoreType.Block] or 0) self.advInfo.score[AdvScoreType.Hurt] = math.max(math.floor(self.advInfo.score[AdvScoreType.Hurt] or 0), - (self.advInfo.score[AdvScoreType.Level] + self.advInfo.score[AdvScoreType.Block])) self.advInfo.score[AdvScoreType.Kill] = math.floor(self.advInfo.score[AdvScoreType.Kill] or 0) self.advInfo.score[AdvScoreType.Item] = math.floor(self.advInfo.score[AdvScoreType.Item] or 0) return self.advInfo.score[AdvScoreType.Level] + self.advInfo.score[AdvScoreType.Block] + self.advInfo.score[AdvScoreType.Hurt] + self.advInfo.score[AdvScoreType.Kill] + self.advInfo.score[AdvScoreType.Item] end function Adv:popBackEvents() local events = self.backEvents -- TODO 缓存数据需要分类,防止发错,暂时只有战斗,可以不分 self.tempBackEvents = events self.backEvents = {} return events end --回合事件处理 function Adv:afterRound() if self.battle then self.battle:afterRound() end -- TODO 房间回合事件 end function Adv:saveDB() if self.battle then self.battle:getDB() end self.owner:updateProperties({advInfo = self.advInfo, advTeam = self.advTeam}) end return Adv