AdvMap.lua 11.1 KB

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(self, mapInfo)  -- 生成地图
	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, 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(self, mapId)
	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(self)  -- 同时记录出现次数
	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
		--层级任务
		randomFunc[AdvEventType.Task] = 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(self, needEventType) -- needEventType  需要的事件
	local  chapterId, level = self.adv.chapterId, self.adv.level
	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 = {}

	local advEventOpenStatus = self.adv.owner:advEventOpenStatus()

	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
				local etype = type(eventType) == "table" and eventType[data.type] or eventType
				
				if data.levelchapter == chapter and (data.unlockType == 0 or (advEventOpenStatus[etype] or {})[data.unlockType]) then
					if AdvCommon.checkIsIn(level, data.leveltype, data.levellimit) then
						eventLib[etype][data.BlockEventType] = eventLib[etype][data.BlockEventType] or {}
						eventLib[etype][data.BlockEventType][id] = {showup = data.showup, limit = data.limit}
					end
				end
			end
			if needEventType then
				break
			end
		end
	end
	return eventLib
end



return Map