AdvBattle.lua 8.69 KB
local Player, Enemy = table.unpack(require "adv.AdvPlayer")
local Buff = require "adv.AdvBuff"
local Passive = require "adv.AdvPassive"
local Battle = class("Battle")
function Battle:ctor(adv)
	self.adv = adv
	self.player = nil --玩家
	self.isNewPlayer = false
	self.enemys = {} --怪
	self.builds = {} -- 建筑
	self.cachePassiveEvent = {}
	self:initPlayer()
	self:initEnemys()
	self:initAfter()
	if self.isNewPlayer then
		self.player:triggerPassive(Passive.BORN_ONCE)
		self.player:addExp((self.adv.level - 1) * 40)
	end
end

function Battle:initAfter()
	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	
	for idx, mapBuilds in pairs(self.builds) do
		for _, build in ipairs(mapBuilds) do
			build:initAfter(self.adv:getBlock(build.roomId, build.blockId, idx).event.build)
		end
	end
end
--[[
队伍总属性 = 基础属性 + 等级 × 成长率 	
	基础属性:	固定属性,与章节、队伍够成、养成无关,由策划给出	
	等级:	根据进入时的关卡,获得一个【初始等级】;消灭怪物获得经验后,累计N点会提升等级	
	羁绊加成:	加成条件与“战斗”相同,加成目标改为【冒险队】	
			
	成长率:	由【队伍总生存力】决定	
			成长率 =(总生存力 / 80)^0.52 + INT(总角色等级 / 50)* 1
--]]

local function getAdvLvAttrUp(upAttrs, attrName, baseAttr)
	-- 1=冒险队属性;1=点数/百分比=属性枚举=参数;属性枚举(1=生命上限/2=魔法上限/3=攻击/4=防御);点数/百分比(0=点数/1=百分比)
	local Enem = {
		hp = 1,
		sp = 2,
		atk = 3,
		def = 4,
	}
	if not Enem[attrName] then return baseAttr end
	return baseAttr + (upAttrs[Enem[attrName]] or 0)
end

function Battle:initPlayer()
	local advTeam = self.adv.owner:getProperty("advTeam")
	if not next(advTeam.heros) then return end
	local leaderPassive = {}
	local player = advTeam.player
	if not player then
		local advAddAttrs = self.adv.owner:getAdvLvAddAttrs()

		player = {}
		player.level = 1
		player.exp = 0
		player.sp = getAdvLvAttrUp(advAddAttrs, "sp", 100)
		player.growth = {}
		player.passives = {}

		for slot, heroId in pairs(advTeam.heros) do
			if heroId == advTeam.leader or heroId == advTeam.leader2 then
				local hero = self.adv.owner.heros[heroId]
				if hero then
					local unit = csvdb["unitCsv"][self.adv.owner.heros[heroId]:getProperty("type")]
					if unit.advCaptain ~= 0 then
						table.insert(player.passives, {id = unit.advCaptain, level = 1})
					end
				end
			end
		end

		local attrs = self.adv.owner:getTeamBattleInfo(advTeam).heros


		for attrName, _ in pairs(AdvAttsEnum) do
			for _, hero in pairs(attrs) do
				player[attrName] = (player[attrName] or 0) + hero[attrName]
			end
			player[attrName] = getAdvLvAttrUp(advAddAttrs, attrName, player[attrName])
			player.growth[attrName] = player[attrName] * 0.025
		end

		player.hpMax = player.hp or 0
		self.isNewPlayer = true
		advTeam.player = player
	end
	self.player = Player.new(self, player)
end

function Battle:initEnemys()
	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

			for _, build in ipairs(self.builds[mapIdx]) do
				build:triggerPassive(passiveC[1], passiveC[2])
			end
		end
	end
	self.cachePassiveEvent[mapIdx] = nil
end

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 = {}
			local curFloorData = self.adv:getCurFloorData() or {}
			for attrName, _ in pairs(AdvAttsEnum) do
				enemy[attrName] = enemyCsv[attrName] * curFloorData[attrName]
			end
			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, mapIdx)
		table.insert(self.enemys[mapIdx], player)
		return player
	elseif block:isBuild() then
		if not block.event.build then
			local buildCsv = csvdb["event_buildCsv"][block.event.id]
			local build = {}
			build.passives = {}
			for _, id in ipairs(buildCsv.passive:toArray(true, "=")) do
				table.insert(build.passives, {id = id})
			end
			block.event.build = build
		end
		local player = Build.new(self, block.event.id, room.roomId, block.blockId, not block.isOpen, block.event.build, mapIdx)
		table.insert(self.builds[mapIdx], player)
		return player
	end 
end

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
	end
end

function Battle:getBuild(roomId, blockId, mapIdx)
	mapIdx = mapIdx or self.adv:getCurMapIdx()
	for _, build in ipairs(self.builds[mapIdx] or {}) do
		if build.roomId == roomId and build.blockId == blockId then
			return build
		end
	end
end

function Battle:getEnemyById(id)
	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, enemy.mapIdx
end


--触发全员被动技能
function Battle:triggerPassive(condType, params, mapIdx)
	mapIdx = mapIdx or self.adv:getCurMapIdx()
	self.player: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
		for _, build in ipairs(self.builds[mapIdx]) do
			build:triggerPassive(condType, params)
		end
	end
end

-- 只是从战斗中移除  从地图中移除 在外面操作
function Battle:removeEnemyById(id)
	local mapIdx = self.adv:getCurMapIdx()
	for i = #self.enemys[mapIdx], 1, -1 do
		if self.enemys[mapIdx][i].id == id then
			local enemy = table.remove(self.enemys[mapIdx], i)
			enemy:clear()
			break
		end
	end
end

--回合
function Battle:afterRound()
	local mapIdx = self.adv:getCurMapIdx()
	self.player:afterRound()
	table.sort(self.enemys[mapIdx], function(e1, e2)
		return e1.id < e2.id
	end)
	for _, enemy in ipairs(self.enemys[mapIdx]) do
		enemy:afterRound()
	end
	self.player:clearRound()
	for _, enemy in ipairs(self.enemys[mapIdx]) do
		enemy:clearRound()
	end
	for _, build in ipairs(self.builds[mapIdx]) do
		build:clearRound()
	end
	for i = #self.enemys[mapIdx], 1, -1 do
		if self.enemys[mapIdx][i].isDead then
			local enemy = table.remove(self.enemys[mapIdx], i)
			self.adv:enemyDead(enemy, enemy.isDead == 1)
			enemy:clear()
		end
	end
	for i = #self.builds[mapIdx], 1, -1 do
		if self.builds[mapIdx][i].isDead then
			local build = table.remove(self.builds[mapIdx], i)
			build:clear()
		end
	end

	self.player:triggerPassive(Passive.AFTER_ROUND)

	if self.player.isDead then
		self.adv:over(false)
	end
end


function Battle:battleBegin(roomId, blockId, params)
	local enemy = self:getEnemy(roomId, blockId)
	if not enemy then return end
	local player = params.player
	-- 玩家没死就是怪死了
	if player.hp > 0 then
		enemy:hurt(enemy.hp, self.player, {hurtType = 5})
		self.player:effectBattleBuff()

		self.adv.owner:checkTaskEnter("AdvBattleWin", {id = self.adv.chapterId})
		if params.bySkill then
			self.player:triggerPassive(Passive.SKILL_KILL)
		end
	end
	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: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

return Battle