diff --git a/src/GlobalVar.lua b/src/GlobalVar.lua index cce459f..2f832d0 100644 --- a/src/GlobalVar.lua +++ b/src/GlobalVar.lua @@ -87,6 +87,7 @@ AdvEventType = { Build = 5, --建筑物 Trap = 6, --陷阱 Click = 7, --点击生效 + Layer = 8, --切换层的点 } AdvBackEventType = { @@ -106,7 +107,8 @@ AdvBackEventType = { TurnEnd = 14, -- 回合结束 Miss = 15, -- miss BattleBegin = 16, -- 战斗开始 - Trap = 17, + Trap = 17, --陷阱 + Layer = 18, --切换层 } AdvScoreType = { diff --git a/src/adv/Adv.lua b/src/adv/Adv.lua index 1b54acd..798a333 100644 --- a/src/adv/Adv.lua +++ b/src/adv/Adv.lua @@ -1,488 +1,149 @@ 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 AdvCommon = require "adv.AdvCommon" +local AdvMap = require "adv.AdvMap" -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 +local Adv = class("Adv") +function Adv:ctor(owner) + assert(owner, "Adv instance must have owner(role)") + self.owner = owner + self.maps = {} + self.battle = nil + self.backEvents = {} --发给客户端的事件组 + self:initByInfo(self.owner:getProperty("advInfo")) 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 +--初始化adv 信息 +function Adv:initByInfo(advInfo) + if not next(advInfo) then return end --还没有 开始新地图 + + self.chapterId = advInfo.chapterId + self.level = advInfo.level or 1 + self.score = advInfo.score or {} + self.lastEnemyId = advInfo.lastEId or 1 + self.mapStack = advInfo.mstack or {} + self.maps = {} + for id, map in ipairs(advInfo.maps or {}) do + self.maps[id] = AdvMap.new(self, id, map) end + + self:initBattle() end ---关卡事件库 -local function getEventLib(chapterId, level, needEventType) -- needEventType 需要的事件 - local chapter = math.floor(chapterId / 100) % 100 +-- 随机新的地图 +function Adv:initByChapter(chapterId, level, isToNext, notNotify) + if self.chapterId and chapterId ~= self.chapterId then return end --新的关卡 或者 去到下一层 + self.chapterId = chapterId + self.level = level or 1 + self.score = self.score or {} + self.lastEnemyId = 1 + self.mapStack = {1} -- 最后一个为当前的地图 - 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 mapId = self:randomMapId(chapterId, level) + self.maps = {} + self.maps[1] = AdvMap.new(self, 1, mapId) - } - 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 + if isToNext then + self:scoreChange(AdvScoreType.Level) --增加层级加分 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 + self:initBattle() + + if not notNotify then + self:saveDB(notNotify) end - --随出地图 - local raw_pool = chapterData.mapid:toArray(true, "=") - local advInfo = role:getProperty("advInfo") +end - local lastMapId = advInfo.mapId --非同一层不连续随出同一张类似的地图 - local lastChapterId = advInfo.chapter - local lastScore = advInfo.score or {} -- 分数 +function Adv:clear() + self.chapterId = nil + self.level = nil + self.score = {} + self.lastEnemyId = 1 + self.mapStack = {} + self.maps = {} + self.battle = nil +end - 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 +function Adv:saveDB(notNotify) + local advInfo, advTeam = {}, self.owner:getProperty("advTeam") + if self.chapterId then - 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 + advInfo.chapterId = self.chapterId + advInfo.level = self.level + advInfo.score = self.score + advInfo.lastEId = self.lastEnemyId + advInfo.mstack = self.mapStack + advInfo.maps = {} - --入口 - 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 + self.battle:saveDB() - --选择点 - 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 + for id , map in ipairs(self.maps) do + advInfo.maps[id] = map:getDB() 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 + advTeam.player = self.battle.player:getDB() ---事件有需要额外处理的部分 -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 + else + advTeam.player = nil end - self.isOpen = true + + self.owner:updateProperties({advInfo = advInfo, advTeam = advTeam}, notNotify) 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 +function Adv:initBattle() + self.battle = require("adv.AdvBattle").new(self) + for _, passiveC in ipairs(self.cachePassiveEvent or {}) do + self.battle:triggerPassive(passiveC[1], passiveC[2]) end + self.cachePassiveEvent = {} end -function Room:tranGToL(c, r) - return c - self.col, r - self.row +function Adv:triggerPassive(condType, params) + self.cachePassiveEvent = self.cachePassiveEvent or {} + if not self.battle then + table.insert(self.cachePassiveEvent, {condType, params}) + else + self.battle:triggerPassive(condType, params) + end end -function Room:tranLtoG(c, r) - return c + self.col, r + self.row +function Adv:getCurMap() + return self.maps[self.mapStack[#self.mapStack]] end -function Room:getBByGPos(c, r) - local c, r = self:tranGToL(c, r) - return self.blocks[getIdByCr(c, r)] +function Adv:getCurMapIdx() + return self.mapStack[#self.mapStack] 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) +function Adv:getRoom(roomId, mapIdx) + mapIdx = mapIdx or self:getCurMapIdx() + local map = self.maps[mapIdx] + if map then + return map.rooms[roomId] 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 +function Adv:getBlock(roomId, blockId, mapIdx) + local room = self:getRoom(roomId, mapIdx) + if room then + return room.blocks[blockId] 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 scoreInfo = self.score local reward if success then - self.owner:updateProperty({field = "advPass", self.owner:getProperty("advPass"):setv(self.advInfo.chapter, score)}) + self.owner:updateProperty({field = "advPass", self.owner:getProperty("advPass"):setv(self.chapterId, score)}) reward = self.owner:award(self.owner:getProperty("advItems"):toNumMap()) - self.owner:checkTaskEnter(self.owner.TaskType.AdvPass, {id = self.advInfo.chapter}) + self.owner:checkTaskEnter(self.owner.TaskType.AdvPass, {id = self.chapterId}) end - table.clear(self.advInfo) --清空advInfo - self.advTeam.player = nil --重置玩家的数据 self:clear() self.owner:updateProperty({field = "advItems", value = ""}) @@ -495,162 +156,41 @@ function Adv:exit() 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 +function Adv:randomMapId(chapterId, level) + local chapterData = csvdb["adv_chapterCsv"][chapterId] + if not chapterData then + error("chapterId " .. chapterId .. " dont exist!") + return end - for _, add in ipairs(range) do - local rroom, rblock = self:getRBByPos(col, row + add) - if rroom then - table.insert(blocks, {rroom, rblock}) - end + if level > chapterData.limitlevel then + error("level overflow!") + return end - return blocks -end + --随出地图Id + local raw_pool = chapterData.mapid:toArray(true, "=") ---随机一个空的位置生成怪, 如果没有就没有 -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] + local lastMapIds = {} + for id, map in ipairs(self.maps or {}) do + lastMapIds[map.mapId] = 1 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 + for _, mapId in ipairs(raw_pool) do + local temp = csvdb["mapCsv"][mapId] + if temp and not lastMapIds[mapId] then + if AdvCommon.checkIsIn(level, temp.leveltype, temp.levellimit) then + table.insert(pool, mapId) 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 + if not next(pool) then + error("mapIds is empty!") + return 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) + return pool[math.randomInt(1, #pool)] end + -- 在冒险中获得的物品都发放在冒险背包内 function Adv:award(gift, params) params = params or {} @@ -707,13 +247,19 @@ 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() --下一关 + if self:getCurMap():checkOver() then --检查是否可以出去了 + if #self.mapStack > 1 then -- 处于夹层中 + table.remove(self.mapStack) --退出夹层 + self:backLayer() + else --处于底层 + if self.level >= csvdb["adv_chapterCsv"][self.chapterId].limitlevel then --关卡结束 + self:over(true) + else + self:initByChapter(self.chapterId, self.level + 1, true, true) + self:backNext() --下一关 + end end + return true end end @@ -739,17 +285,14 @@ local function clickChoose(self, room, block, params) 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 + local hero = self.owner.heros[self.owner:getProperty("advTeam").leader] + if hero and hero:getProperty("type") == cond[2] then + return true end end, --消灭所有怪 [3] = function() - for _, room in pairs(self.rooms) do + for _, room in pairs(self:getCurMap().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 @@ -784,7 +327,7 @@ local function clickChoose(self, room, block, params) self.battle.player:addBuff(effect[2]) end, [3] = function() --发现怪物 - self:addNewMonsterRand(effect[2], {room, block}) + self:getCurMap():addNewMonsterRand(effect[2], {room, block}) clearBlock = false end, [4] = function() --无事发生 @@ -795,7 +338,7 @@ local function clickChoose(self, room, block, params) end if clearBlock then - room:clearBEvent(block) + block:clear() end return true end @@ -804,7 +347,7 @@ 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) + block:clear() self:backReward(reward) return true end @@ -840,7 +383,7 @@ local function clickBuild(self, room, block, params) self.battle.player:addBuff(effect[2]) end, [3] = function() --发现怪物 - self:addNewMonsterRand(effect[2], {room, block}) + self:getCurMap():addNewMonsterRand(effect[2], {room, block}) clearBlock = false end, [4] = function() --无事发生 @@ -850,7 +393,7 @@ local function clickBuild(self, room, block, params) if not self:cost(buildData.required:toNumMap(), {}) then return end doEffect[effect[1]]() if clearBlock then - room:clearBEvent(block) + block:clear() end return true end @@ -875,11 +418,28 @@ local function clickClick(self, room, block, params) end, } if clearBlock then - room:clearBEvent(block) + block:clear() end return true end +local function clickLayer(self, room, block, params) + if block.event.mapIdx then + table.insert(self.mapStack, block.event.mapIdx) --进入夹层 + else + --生成夹层 + local mapId = csvdb["event_layerCsv"][block.event.id].effect + local mapIdx = #self.maps + 1 + block.event.mapIdx = mapIdx + table.insert(self.mapStack, mapIdx) + + self.maps[mapIdx] = AdvMap.new(self, mapIdx, mapId) + self.battle:initMapEnemys(mapIdx) + end + self:backLayer() + return true +end + local eventCallFunc = { [AdvEventType.Out] = clickOut, [AdvEventType.BOSS] = clickMonster, @@ -889,14 +449,15 @@ local eventCallFunc = { [AdvEventType.Trader] = clickTrader, [AdvEventType.Build] = clickBuild, [AdvEventType.Click] = clickClick, + [AdvEventType.Layer] = clickLayer, } --点击处理 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] + local map = self:getCurMap() + local room = self:getRoom(roomId) + local block = self:getBlock(roomId, blockId) if not block then return end local status = false @@ -904,15 +465,15 @@ function Adv:clickBlock(roomId, blockId, params) if not block.isOpen then local canOpen = false --如果未开放是否可以开放 local hadMonster = false -- 周围是否有解锁的怪未击败 - for _, one in ipairs(self:getAroundBlocks(room, block)) do + for _, one in ipairs(map: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 + if _block.isOpen and _block:isMonster() then hadMonster = true end end if canOpen and not hadMonster then --开放 - room:openBlock(block, self) + room:openBlock(block) status = true end else @@ -922,15 +483,15 @@ function Adv:clickBlock(roomId, blockId, params) return end --可点击的事件 - if not room.isBossRoom or block.event.etype == AdvEventType.BOSS then + if not room.isBossRoom or block:isBoss() then if eventCallFunc[block.event.etype] then - status = eventCallFunc[block.event.etype](self, room, block, params) + status = eventCallFunc[block:getEventType()](self, room, block, params) end end end local needChange = true if clickEvent and block.event then - if block.event.etype == AdvEventType.Out then + if block:getEventType() == AdvEventType.Out then needChange = false end end @@ -991,34 +552,33 @@ end --敌人死亡 function Adv:enemyDead(roomId, blockId, escape) - local room = self.rooms[roomId] - local block = room.blocks[blockId] + local map = self:getCurMap() + local room = self:getRoom(roomId) + local block = self:getBlock(roomId, blockId) + if not block then return end --死了以后掉东西 - if block.event and (block.event.etype == AdvEventType.BOSS or block.event.etype == AdvEventType.Monster) then --处理死亡 - if block.event.etype == AdvEventType.BOSS then + if block:isMonster() then --处理死亡 + if block:isBoss() then room.isBossRoom = false end if escape then - room:clearBEvent(block) + block:clear() 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 + local dropData = csvdb["event_dropCsv"][monsterData.dropid] + item = dropData["range"]:randWeight(true) end if item[1] == 0 then - room:clearBEvent(block) + block:clear() else - table.clear(block.event) - block.event.etype = AdvEventType.Drop - block.event.item = item + block:updateEvent({ + etype = AdvEventType.Drop, + item = item + }) end end end @@ -1090,6 +650,10 @@ function Adv:backTrap() self:pushBackEvent(AdvBackEventType.Trap, {}) end +function Adv:backLayer() + self:pushBackEvent(AdvBackEventType.Layer, {}) +end + function Adv:scoreChange(scoreType, pms) local cutTypes = {} local score = 0 @@ -1097,7 +661,7 @@ function Adv:scoreChange(scoreType, pms) score = globalCsv.adv_score_floor end cutTypes[AdvScoreType.Kill] = function() - local chapterData = csvdb["adv_chapterCsv"][self.advInfo.chapter] + local chapterData = csvdb["adv_chapterCsv"][self.chapterId] score = globalCsv.adv_score_monster[pms] * chapterData["monRatio"] end cutTypes[AdvScoreType.Item] = function() @@ -1114,25 +678,23 @@ function Adv:scoreChange(scoreType, pms) else return end - self.advInfo.score[scoreType] = self.advInfo.score[scoreType] or 0 - self.advInfo.score[scoreType] = self.advInfo.score[scoreType] + score + self.score[scoreType] = self.score[scoreType] or 0 + self.score[scoreType] = self.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] + self.score[AdvScoreType.Level] = math.floor(self.score[AdvScoreType.Level] or 0) + self.score[AdvScoreType.Block] = math.floor(self.score[AdvScoreType.Block] or 0) + self.score[AdvScoreType.Hurt] = math.max(math.floor(self.score[AdvScoreType.Hurt] or 0), - (self.score[AdvScoreType.Level] + self.score[AdvScoreType.Block])) + self.score[AdvScoreType.Kill] = math.floor(self.score[AdvScoreType.Kill] or 0) + self.score[AdvScoreType.Item] = math.floor(self.score[AdvScoreType.Item] or 0) + + return self.score[AdvScoreType.Level] + self.score[AdvScoreType.Block] + self.score[AdvScoreType.Hurt] + + self.score[AdvScoreType.Kill] + self.score[AdvScoreType.Item] end function Adv:popBackEvents() local events = self.backEvents - -- TODO 缓存数据需要分类,防止发错,暂时只有战斗,可以不分 - self.tempBackEvents = events self.backEvents = {} return events end @@ -1142,14 +704,6 @@ 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 \ No newline at end of file diff --git a/src/adv/AdvBattle.lua b/src/adv/AdvBattle.lua index 9b2e734..430852b 100644 --- a/src/adv/AdvBattle.lua +++ b/src/adv/AdvBattle.lua @@ -7,7 +7,7 @@ function Battle:ctor(adv) self.player = nil --玩家 self.isNewPlayer = false self.enemys = {} --怪 - self.tempData = {} -- 临时回合数据 + self.cachePassiveEvent = {} self:initPlayer() self:initEnemys() self:initAfter() @@ -17,9 +17,11 @@ function Battle:ctor(adv) end function Battle:initAfter() - self.player:initAfter(self.adv.advTeam.player) - for _, enemy in pairs(self.enemys) do - enemy:initAfter(self.adv.rooms[enemy.roomId].blocks[enemy.blockId].event.enemy) + self.player:initAfter(self.adv.owner:getProperty("advTeam").player) + for idx, mapEnemys in pairs(self.enemys) do + for _, enemy in ipairs(mapEnemys) do + enemy:initAfter(self.adv:getBlock(enemy.roomId, enemy.blockId, idx).event.enemy) + end end end --[[ @@ -33,12 +35,14 @@ end --]] function Battle:initPlayer() - if not next(self.adv.advTeam.heros) then return end - if not self.adv.advTeam.player then - local player = {} + local advTeam = self.adv.owner:getProperty("advTeam") + if not next(advTeam.heros) then return end + local player = advTeam.player + if not player then + player = {} player.passives = {} local heroLevel = 0 - for slot, heroId in pairs(self.adv.advTeam.heros) do + for slot, heroId in pairs(advTeam.heros) do local hero = self.adv.owner.heros[heroId] if hero then heroLevel = heroLevel + hero:getProperty("level") @@ -48,56 +52,77 @@ function Battle:initPlayer() end end end - player.growth = (self.adv.owner:getRealBattleValue(self.adv.advTeam.heros) / 80) ^ 0.52 + math.floor(heroLevel / 50) / 50 + player.growth = (self.adv.owner:getRealBattleValue(advTeam.heros) / 80) ^ 0.52 + math.floor(heroLevel / 50) / 50 player.level = 1 player.exp = 0 player.sp = 100 local activeRelation = self.adv.owner:getHeroActiveRelation() - local baseAttr = csvdb["adv_unitCsv"][math.floor(self.adv.advInfo.chapter / 100)] + local baseAttr = csvdb["adv_unitCsv"][math.floor(self.adv.chapterId / 100)] for _, attr in pairs(AttsEnumEx) do if baseAttr[attr] then player[attr] = baseAttr[attr] + baseAttr[attr] * player.growth * (player.level - 1) end end player.hpMax = player.hp or 0 - self.adv.advTeam.player = player self.isNewPlayer = true + advTeam.player = player end - self.player = Player.new(self, self.adv.advTeam.player) + self.player = Player.new(self, player) end function Battle:initEnemys() - for _, room in pairs(self.adv.rooms) do - for _, block in pairs(room.blocks) do - self:addEnemy(room, block) + for idx, map in pairs(self.adv.maps) do + self:initMapEnemys(idx) + end +end + +function Battle:initMapEnemys(mapIdx) + self.enemys[mapIdx] = {} + local map = self.adv.maps[mapIdx] + if map then + for _, room in pairs(map.rooms) do + for _, block in pairs(room.blocks) do + self:addEnemy(room, block, mapIdx) + end + end + end + if self.cachePassiveEvent[mapIdx] then + for _, passiveC in ipairs(self.cachePassiveEvent or {}) do + for _, enemy in ipairs(self.enemys[mapIdx]) do + enemy:triggerPassive(passiveC[1], passiveC[2]) + end end end + self.cachePassiveEvent[mapIdx] = nil end -function Battle:addEnemy(room, block) - if block.event and (block.event.etype == AdvEventType.BOSS or block.event.etype == AdvEventType.Monster) then +function Battle:addEnemy(room, block, mapIdx) + mapIdx = mapIdx or self.adv:getCurMapIdx() + + if block:isMonster() then if not block.event.enemy then local enemyCsv = csvdb["event_monsterCsv"][block.event.id] local enemy = {} - enemy.hp = enemyCsv.hp + enemyCsv.levelhp * self.adv.advInfo.level - enemy.atk = enemyCsv.atk + enemyCsv.levelatk * self.adv.advInfo.level - enemy.hit = enemyCsv.hit + enemyCsv.levelhit * self.adv.advInfo.level - enemy.miss = enemyCsv.miss + enemyCsv.levelmiss * self.adv.advInfo.level - enemy.def = enemyCsv.def + enemyCsv.leveldef * self.adv.advInfo.level + enemy.hp = enemyCsv.hp + enemyCsv.levelhp * self.adv.level + enemy.atk = enemyCsv.atk + enemyCsv.levelatk * self.adv.level + enemy.hit = enemyCsv.hit + enemyCsv.levelhit * self.adv.level + enemy.miss = enemyCsv.miss + enemyCsv.levelmiss * self.adv.level + enemy.def = enemyCsv.def + enemyCsv.leveldef * self.adv.level enemy.passives = {} for _, id in ipairs(enemyCsv.mapPassive:toArray(true, "=")) do table.insert(enemy.passives, {id = id}) end block.event.enemy = enemy end - local player = Enemy.new(self, block.event.mId or 999, block.event.id, room.roomId, block.blockId, not block.isOpen, block.event.enemy) - table.insert(self.enemys, player) + local player = Enemy.new(self, block.event.mId or 999, block.event.id, room.roomId, block.blockId, not block.isOpen, block.event.enemy, mapIdx) + table.insert(self.enemys[mapIdx], player) return player end end -function Battle:getEnemy(roomId, blockId) - for _, enemy in ipairs(self.enemys) do +function Battle:getEnemy(roomId, blockId, mapIdx) + mapIdx = mapIdx or self.adv:getCurMapIdx() + for _, enemy in ipairs(self.enemys[mapIdx] or {}) do if enemy.roomId == roomId and enemy.blockId == blockId then return enemy end @@ -105,45 +130,55 @@ function Battle:getEnemy(roomId, blockId) end function Battle:getEnemyById(id) - for _, enemy in ipairs(self.enemys) do - if enemy.id == id then - return enemy + for idx, mapEnemys in pairs(self.enemys) do + for _, enemy in ipairs(mapEnemys) do + if enemy.id == id then + return enemy + end end end end function Battle:getRBByEnemyId(enemyId) local enemy = self:getEnemyById(enemyId) - return enemy.roomId, enemy.blockId + return enemy.roomId, enemy.blockId, enemy.mapIdx end --触发全员被动技能 -function Battle:triggerPassive(condType, params) +function Battle:triggerPassive(condType, params, mapIdx) + mapIdx = mapIdx or self.adv:getCurMapIdx() self.player:triggerPassive(condType, params) - for _, enemy in ipairs(self.enemys) do - enemy:triggerPassive(condType, params) + if not self.enemys[mapIdx] then + -- 缓存一下 + self.cachePassiveEvent[mapIdx] = self.cachePassiveEvent[mapIdx] or {} + table.insert(self.cachePassiveEvent[mapIdx], {condType, params}) + else + for _, enemy in ipairs(self.enemys[mapIdx]) do + enemy:triggerPassive(condType, params) + end end end --回合 function Battle:afterRound() + local mapIdx = self.adv:getCurMapIdx() self.player:afterRound() - table.sort(self.enemys, function(e1, e2) + table.sort(self.enemys[mapIdx], function(e1, e2) return e1.id < e2.id end) - for _, enemy in ipairs(self.enemys) do + for _, enemy in ipairs(self.enemys[mapIdx]) do enemy:afterRound() end self.player:clearRound() - for _, enemy in ipairs(self.enemys) do + for _, enemy in ipairs(self.enemys[mapIdx]) do enemy:clearRound() end - for i = #self.enemys, 1, -1 do - if self.enemys[i].isDead then - self.adv:enemyDead(self.enemys[i].roomId, self.enemys[i].blockId) - self.enemys[i]:clear() - table.remove(self.enemys, i) + for i = #self.enemys[mapIdx], 1, -1 do + if self.enemys[mapIdx][i].isDead then + self.adv:enemyDead(self.enemys[mapIdx][i].roomId, self.enemys[mapIdx][i].blockId) + self.enemys[mapIdx][i]:clear() + table.remove(self.enemys[mapIdx], i) end end @@ -162,17 +197,25 @@ function Battle:battleBegin(roomId, blockId, params) enemy:hurt(enemy.hp, self.player, {hurtType = 5}) self.player:effectBattleBuff() end - self.player:hurt(math.max(0, math.ceil(self.player.hp - player.hp)), enemy, {hurtType = 5}) --战斗血量只会变少 - self.player:changeSp(math.min(0, math.floor(player.sp - self.player.sp)) , 0) --战斗魔力只会变少 + if player.hp > self.player.hp then + self.player:recover(player.hp - self.player.hp, player) + else + self.player:hurt(math.max(0, math.ceil(self.player.hp - player.hp)), enemy, {hurtType = 5}) --战斗血量只会变少 + end + + self.player:changeSp(math.floor(player.sp - self.player.sp) , 0) --战斗魔力只会变少 end --写入数据 -function Battle:getDB() - self.adv.advTeam.player = self.player:getDB() - for _, enemy in ipairs(self.enemys) do - local block = self.adv.rooms[enemy.roomId].blocks[enemy.blockId] - block.event.enemy = enemy:getDB() +function Battle:saveDB() + for idx, mapEnemys in pairs(self.enemys) do + for _, enemy in ipairs(mapEnemys) do + local block = self.adv:getBlock(enemy.roomId, enemy.blockId, idx) + if block and block:isMonster() then + block.event.enemy = enemy:getDB() + end + end end end diff --git a/src/adv/AdvBlock.lua b/src/adv/AdvBlock.lua new file mode 100644 index 0000000..589e520 --- /dev/null +++ b/src/adv/AdvBlock.lua @@ -0,0 +1,108 @@ +--块类型 +local AdvCommon = require "adv.AdvCommon" +local Passive = require "adv.AdvPassive" + +local Block = class("AdvBlock") +function Block:ctor(room, blockId, event, isOpen, trapId) + self.room = room + self.blockId = blockId + self.col, self.row = AdvCommon.getCrById(self.blockId) + + self.isOpen = isOpen and true or false + self.trapId = trapId + + self:updateEvent(event) +end +function Block:isBoss() + return self:getEventType() == AdvEventType.BOSS +end + +function Block:isMonster() + return (self:getEventType() == AdvEventType.BOSS or self:getEventType() == AdvEventType.Monster) +end + +function Block:getEventType() + return self.event and self.event.etype +end + +function Block:updateEvent(event) + self.event = event +end + +function Block:clear() + if self:getEventType() == AdvEventType.Trap then + self.trapId = self.event.id + end + self.event = nil +end + +--事件有需要额外处理的部分 +function Block:open() + local room = self.room + local map = room.map + local adv = map.adv + --如果翻开有数据处理在这里处理 + local randomFunc = {} + --怪 + randomFunc[AdvEventType.Monster] = function() + self.event.mId = adv.lastEnemyId --给怪一个有序id 回合逻辑时使用 + adv.lastEnemyId = adv.lastEnemyId + 1 + local enemy = adv.battle:getEnemy(room.roomId, self.blockId, map.mapIdx) + if enemy then + enemy:unlock(self.event.mId) + else + enemy = adv.battle:addEnemy(room, self, map.mapIdx) + 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() + self:clear() + end + + + if self.event then -- 随机出具体的事件 + if randomFunc[self:getEventType()] then + randomFunc[self:getEventType()]() + end + end + self.isOpen = true +end + +return Block \ No newline at end of file diff --git a/src/adv/AdvCommon.lua b/src/adv/AdvCommon.lua new file mode 100644 index 0000000..d9301af --- /dev/null +++ b/src/adv/AdvCommon.lua @@ -0,0 +1,50 @@ +-- 工具函数--第一象限 < 10000 < 第二象限 < 20000 < 第四象限 < 30000 < 第三象限 + +local AdvCommon = {} + +function AdvCommon.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 + +function AdvCommon.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 +function AdvCommon.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 + +return AdvCommon \ No newline at end of file diff --git a/src/adv/AdvMap.lua b/src/adv/AdvMap.lua new file mode 100644 index 0000000..4e6ee4f --- /dev/null +++ b/src/adv/AdvMap.lua @@ -0,0 +1,383 @@ + +local Room = require "adv.AdvRoom" +local Passive = require "adv.AdvPassive" +local AdvCommon = require "adv.AdvCommon" +-- 一层地图 +local Map = class("AdvMap") +-- 内部方法声明 +local createMap, getEventLib + + +function Map:ctor(adv, mapIdx, mapInfo) + self.adv = adv + if type(mapInfo) == "number" then -- mapInfo 传入 id + mapInfo = createMap(mapInfo, self.adv.chapterId, self.adv.level) -- 生成地图 + end + if not mapInfo then return end + + self.mapIdx = mapIdx + self.mapId = mapInfo.mapId + self.rooms = {} + self:loadRooms(mapInfo.rooms) +end + +function Map:loadRooms(rooms) + local mapData = csvdb["map_" .. csvdb["mapCsv"][self.mapId]["path"] .. "Csv"] + for roomId, roomName in pairs(mapData["rooms"]) do + if roomName == "path" then + self.rooms[roomId] = Room.new(self, roomId, mapData["path"], rooms[roomId], true) + else + roomName = roomName:gsub("/", "_") + self.rooms[roomId] = Room.new(self, roomId, csvdb["room_" .. roomName .. "Csv"], rooms[roomId], false) + end + end +end + +function Map:getDB() + local map = {} + map.mapId = self.mapId + map.rooms = {} + for roomId, room in pairs(self.rooms) do + map.rooms[roomId] = room:getDB() + end + return map +end + +--结束本层的时候调用 +function Map:checkOver() + local mapCsv = csvdb["mapCsv"][self.mapId] + + if mapCsv.clearType == 1 then -- 消耗 + if self.adv:cost(mapCsv.clear:toNumMap()) then return true end + elseif mapCsv.clearType == 2 then -- 杀光 + if #self.adv.battle.player:getTeam(2) == 0 then return true end + elseif mapCsv.clearType == 3 then -- 持有 + if self.adv:cost(mapCsv.clear:toNumMap(), {}, true) then return true end + else + return true + end +end + +--随机一个空的位置生成怪, 如果没有就没有 +function Map: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.adv.chapterId, self.adv.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.adv.lastEnemyId} + self.adv.lastEnemyId = self.adv.lastEnemyId + 1 + event.id = monsterId + block:updateEvent(event) + + self.adv.battle:addEnemy(room, block):triggerPassive(Passive.BORN_ONCE) + + return room, block +end + +-- 随机翻开 num 个 以开放的房间的 地块 +function Map: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 Map: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 + + +--获取,某个位置上的 room 和 block +function Map: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 Map: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 + +-----------------------------随机地图----------------------------- + +createMap = function(mapId, chapterId, level) + local mapInfo = {} + mapInfo.rooms = {} + mapInfo.mapId = mapId + local mapCsvData =csvdb["mapCsv"][mapId] + local mapData = csvdb["map_" .. mapCsvData["path"] .. "Csv"] + if not mapData then + error("mapId " .. mapId .. " dont exist!") + return + end + --事件随机 + local eventLib = getEventLib(chapterId, level) -- 同时记录出现次数 + local monsterEvents = {} --处理钥匙掉落 + local haveBoss = false + + + local function randomEvent(roomId, blockId, eventType) + if mapInfo.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 + --跨层点 + randomFunc[AdvEventType.Layer] = randomCommon + + + if randomFunc[etype] then + if randomFunc[etype]() ~= false then + if mapCsvData.clearType == 1 and etype == AdvEventType.BOSS then + event.item = mapCsvData.clear:toArray(true, "=") + end + mapInfo.rooms[roomId]["event"][blockId] = event + end + end + end + + + local stagePool = {["global"] = {}} + for roomId, roomName in pairs(mapData["rooms"]) do + stagePool[roomId] = {} + mapInfo.rooms[roomId] = {event = {}, open = {}, trap = {}} -- 事件, 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 mapCsvData.clearType == 1 and not haveBoss then + if not next(monsterEvents) then + error("这个地图没有钥匙!!! mapId : " .. mapId) + else + local event = monsterEvents[math.randomInt(1, #monsterEvents)] + event.item = mapCsvData.clear:toArray(true, "=") --掉落钥匙 + end + end + return mapInfo +end + +--关卡事件库 +getEventLib = function(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, + ["event_layerCsv"] = AdvEventType.Layer, + + } + 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 AdvCommon.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 + + + +return Map + + diff --git a/src/adv/AdvPlayer.lua b/src/adv/AdvPlayer.lua index 5fd4eb6..7e24ccf 100644 --- a/src/adv/AdvPlayer.lua +++ b/src/adv/AdvPlayer.lua @@ -327,7 +327,8 @@ function BaseObject:releaseSkill(skillId, target) end --0 全部 1 我方 2 敌方 -function BaseObject:getTeam(nType, noSelf) +function BaseObject:getTeam(nType, noSelf, mapIdx) + mapIdx = mapIdx or self.battle.adv:getCurMapIdx() nType = nType or 0 local team = {} local function addPlayer() @@ -338,7 +339,7 @@ function BaseObject:getTeam(nType, noSelf) end end local function addEnemy() - for _, enemy in pairs(self.battle.enemys) do + for _, enemy in pairs(self.battle.enemys[mapIdx]) do if not noSelf or enemy ~= self then if not enemy.isDead and not enemy.lock then -- 已经翻开的 table.insert(team, enemy) @@ -396,13 +397,14 @@ function BaseObject:changeSp() end local Enemy = class("Enemy", BaseObject) -function Enemy:ctor(battle, mId, monsterId, roomId, blockId, lock, enemy) +function Enemy:ctor(battle, mId, monsterId, roomId, blockId, lock, enemy, mapIdx) Enemy.super.ctor(self, battle) self.id = mId self.monsterId = monsterId --数据id self.roomId = roomId self.blockId = blockId self.lock = lock + self.mapIdx = mapIdx self:initData(enemy) end function Enemy:unlock(id) diff --git a/src/adv/AdvRoom.lua b/src/adv/AdvRoom.lua new file mode 100644 index 0000000..368add4 --- /dev/null +++ b/src/adv/AdvRoom.lua @@ -0,0 +1,93 @@ +-- 房间 + +local AdvCommon = require "adv.AdvCommon" +local Block = require "adv.AdvBlock" +local Passive = require "adv.AdvPassive" + +local Room = class("AdvRoom") +function Room:ctor(map, roomId, csvData, info, isPath) + self.map = map + self.roomId = roomId + self.col, self.row = AdvCommon.getCrById(self.roomId) + self.isPath = isPath + self.isBossRoom = false -- boss房间 --击败boss 以后重置为false + self.isShow = false + + self.blocks = {} + self:loadBlocks(csvData, info) + +end + +function Room:loadBlocks(csvData, info) + for blockId, _ in pairs(csvData["blocks"]) do + self.blocks[blockId] = Block.new(self, blockId, info.event[blockId], info.open == 1 or info.open[blockId], info.trap[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]:getEventType() == AdvEventType.In then -- 开放 + self.isShow = true + self.blocks[blockId].isOpen = true + --入口房间只会在这里首次展示开放 --触发固有技 + self.map.adv:triggerPassive(Passive.ROOM_SHOW, {roomId = self.roomId}) + end + end + end +end + +function Room:getDB() + local room = {event = {}, open = {}, trap = {}} + local allOpen = true + for blockId, block in pairs(self.blocks) do + room["event"][blockId] = block.event + room["open"][blockId] = block.isOpen and 1 or nil + if not block.isOpen then + allOpen = false + end + room["trap"][blockId] = block.trapId + end + if allOpen then + room["open"] = 1 + end + return room +end + +function Room:openBlock(block) + 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() + end + else + block:open() + end + + self.map.adv:scoreChange(AdvScoreType.Block) + + if not self.isShow then + self.isShow = true + --首次展示房间 + self.map.adv:triggerPassive(Passive.ROOM_SHOW, {roomId = self.roomId}) + 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[AdvCommon.getIdByCr(c, r)] +end + + + +return Room \ No newline at end of file diff --git a/src/models/RolePlugin.lua b/src/models/RolePlugin.lua index ca952c8..d0c2184 100644 --- a/src/models/RolePlugin.lua +++ b/src/models/RolePlugin.lua @@ -509,7 +509,6 @@ function RolePlugin.bind(Role) function Role:getAdvData() if not self.advData then self.advData = require("adv.Adv").new(self) - self.advData:initByInfo() end return self.advData end -- libgit2 0.21.2