Module:Mazunki/Dungeons

From Melvor Idle

Documentation for this module may be created at Module:Mazunki/Dungeons/doc

local pm = require("Module:CombatAreas/AreaTables")
local p = {}

local AreaData = mw.loadData('Module:CombatAreas/data')
local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Icons = require('Module:Icons')
local Items = require('Module:Items')
local Monsters = require('Module:Monsters')
local CombatAreas = require('Module:CombatAreas')
local Pets = require('Module:Pets')

function p.getDungeonTable(frame)
	local result = '{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|-class="headerRow-0"'
	result = result..'\r\n!Icon!!Dungeon!!Monsters!!Boss Level!!Total HP!!Min DR (melee)!!Min DR (ranged)!!Min DR (magic)!!Reward(s)!!Boss Pet'

	for i, dungIdx in ipairs(AreaData.displayOrder.dungeons) do
		local dung = CombatAreas.getAreaByID('dungeon', dungIdx)
		result = result..'\r\n|-'
		result = result..'\r\n|data-sort-value="'..dung.name..'"|'..Icons.Icon({dung.name, type='dungeon', size='50', notext=true})
		result = result..'||'..Icons.Icon({dung.name, type='dungeon', noicon=true})
		result = result..'||'..Shared.tableCount(dung.monsters)

		local boss = Monsters.getMonsterByID(dung.monsters[Shared.tableCount(dung.monsters)])
		result = result..'||'..Monsters._getMonsterCombatLevel(boss)
		result = result..'||'..p._getDungeonTotalHP(dung, true) -- accountForEnemyDR = true
		
		local minDR = p._getDungeonMinDR(dung, 1000, 0.4)
		result = result..'||'..minDR["Melee"].."%"
		result = result..'||'..minDR["Ranged"].."%"
		result = result..'||'..minDR["Magic"].."%"

		result = result..'||'..pm._getDungeonRewards(dung, false)
		if dung.petID ~= nil then
			local pet = Pets.getPetByID(dung.petID)
			result = result..'||data-sort-value="'..pet.name..'"|'..Icons.Icon({pet.name, type='pet'})
		else
			result = result..'|| '
		end
	end

	result = result..'\r\n|}'
	return result
end

function p._getMaxHitPerMonsterStyle(dung)
	local maxHitsPerMonsterStyle = { Melee = 0, Ranged = 0, Magic = 0 }
	for i, monsterID in Shared.skpairs(dung.monsters) do
		local monster = Monsters.getMonsterByID(monsterID)
		if monster == nil and monsterID == -1 then
			for _, id in Shared.skpairs(AreaData.itm.monsters) do
				local monster = Monsters.getMonsterByID(id)
				local styleName = Constants.getCombatStyleName(monster.attackType)
				local maxHit = Monsters._getMonsterMaxHit(monster, true) -- doStuns = true
		
				if styleName == "Random" then
					for randomStyle, value in Shared.skpairs(maxHitsPerMonsterStyle) do
						if maxHit > value then
							maxHitsPerMonsterStyle[randomStyle] = maxHit
						end
					end
				else
					if maxHit > maxHitsPerMonsterStyle[styleName] then
						maxHitsPerMonsterStyle[styleName] = maxHit
					end
				end
			end
		else
			local styleName = Constants.getCombatStyleName(monster.attackType)
			local maxHit = Monsters._getMonsterMaxHit(monster, true) -- doStuns = true
			if styleName == "Random" then
				for randomStyle, value in Shared.skpairs(maxHitsPerMonsterStyle) do
					if maxHit > value then
						maxHitsPerMonsterStyle[randomStyle] = maxHit
					end
				end
			else
				if maxHit > maxHitsPerMonsterStyle[styleName] then
					maxHitsPerMonsterStyle[styleName] = maxHit
				end
			end
		end
	end
	return maxHitsPerMonsterStyle
end

function p._getDRRequiredPerPlayerStyle(dung, playerStyle, autoEatTreshold, enemyMaxHitsPerStyle, mode)
	local _mode = mode or "Hardcore" -- default to hardcore if mode is nil
	maxStyleDR = 0
	for enemyStyle, styleHit in Shared.skpairs(enemyMaxHitsPerStyle) do
		if styleHit > 0 and styleHit > autoEatTreshold then
			local styleDR = math.ceil((1 - (autoEatTreshold / styleHit)) * 100)
			styleDR = math.ceil(styleDR / Constants.getTriangleDRModifier(playerStyle, enemyStyle, _mode))
			maxStyleDR = math.max(maxStyleDR, styleDR)
		end
	end
	return maxStyleDR
end

function p._getDungeonMinDR(dung, maxHP, autoEatTresholdPercentage)
	--This is the highest DR to list as possible. Value might be slightly off right now, currently just setting up value for testing
	local MaxViableDR = 81
	--This is the highest DR row shown. This should be higher than MaxViableDR
	local MaxVisibleDR = 85
	
	local autoEatTreshold = math.floor(maxHP * autoEatTresholdPercentage)
	local enemyMaxHitsPerStyle = p._getMaxHitPerMonsterStyle(dung)
	-- mw.logObject(enemyMaxHitsPerStyle)
	-- mw.log("ae: "..autoEatTreshold)
	
	local reductionRequiredPerPlayerStyle = { Melee = 0, Ranged = 0, Magic = 0 }
	
	for playerStyle, dr in pairs(reductionRequiredPerPlayerStyle) do
		reductionRequiredPerPlayerStyle[playerStyle] = p._getDRRequiredPerPlayerStyle(dung, playerStyle, autoEatTreshold, enemyMaxHitsPerStyle)
	end
	
	return reductionRequiredPerPlayerStyle
end

function p._testing()
	local dung = CombatAreas.getArea("Into the Mist")
	local maxHp = 1120
	local ae = 0.4
	
	--return p._getDungeonTotalHP(dung, true)
	return p._getDungeonMinDR(dung, maxHp, ae)
end

function p._getDungeonDrTable(dung, gamemode, maxHP)
	local AutoEatVals = { T1 = 0.2, T2 = 0.3, T3 = 0.4, T3W = 0.45 } -- W = wasteful ring

	--Finally, build the table using those starting points
	local StyleHeader = "Melee!!Ranged!!Magic"
	StyleHeader = StyleHeader..'!!'..StyleHeader..'!!'..StyleHeader..'!!'..StyleHeader

	local result = '{| class="wikitable stickyHeader"'
	result = result..'\r\n|-class="headerRow-0"'
	result = result..'\r\n!Pre-Triangle DR!!colspan=3|AE T3 + Wasteful!!colspan=3|Auto Eat Tier 3!!colspan=3|Auto Eat Tier 2!!colspan=3|Auto Eat Tier 1'
	result = result..'\r\n|-class="headerRow-0"'
	result = result..'\r\n!DR %!!'..StyleHeader

	for tier, aevalue in Shared.skpairs(AutoEatValues) do
		--mw.log(aevalue)
	end

	result = result..'\r\n|}'

	return result
end

function p._getStrongestAfflicted()
	local maxHitsPerMonsterStyle = { Melee = 0, Ranged = 0, Magic = 0 }
	
	for _, id in Shared.skpairs(AreaData.itm.monsters) do
		local monster = Monsters.getMonsterByID(id)
		local styleName = Constants.getCombatStyleName(monster.attackType)
		
		local maxHit = Monsters._getMonsterMaxHit(monster, true) -- doStuns = true
		if styleName == "Random" then
			for randomStyle, value in Shared.skpairs(maxHitsPerMonsterStyle) do
				if maxHit > value then
					maxHitsPerMonsterStyle[randomStyle] = maxHit
				end
			end
		else
			if maxHit > maxHitsPerMonsterStyle[styleName] then
				maxHitsPerMonsterStyle[styleName] = maxHit
			end
		end
	end
	return maxHitsPerMonsterStyle
end

function p._getAfflictedAverageHP()
	local totalHp = 0
	local afflicted = AreaData.itm.monsters
	for _, id in Shared.skpairs(afflicted) do
		local monster = Monsters.getMonsterByID(id)
		totalHp = totalHp + Monsters._getMonsterHP(monster)
	end
	return math.ceil(totalHp / Shared.tableCount(afflicted))
end

function p._getDungeonTotalHP(dung, accountForEnemyDR)
	local calculateDr = accountForEnemyDR or false
	local totalHp = 0
	for i, monsterID in Shared.skpairs(dung.monsters) do
		local dr = 0
		local monsterHp = 0
		
		local monster = Monsters.getMonsterByID(monsterID)
		if monster == nil and monsterID == -1 then
			monsterHp = p._getAfflictedAverageHP()
			dr = 0.2 -- afflicted always have +20% dr
		else 
			monsterHp = Monsters._getMonsterHP(monster)
			dr = 0
		end
		
		if calculateDR then
			for i, eq in Shared.skpairs(monster.equipmentStats) do
				if eq.key == "damageReduction" then
					dr = dr + eq.value/100
				end
			end
		else
			dr = 0
		end
		
		local monsterPostReductionHP = math.floor(monsterHp / (1-dr))
		totalHp = totalHp + monsterPostReductionHP
	end
	return totalHp
end

return p