Dead by Daylight Wiki
Register
Advertisement

local p = {}
local data = require("Module:Datatable")
local sosData = require("Module:Datatable/SoS")
local utils = require("Module:Utils")
local frame = mw.getCurrentFrame()
local nl = "\n"
local ntl = "|-" -- new table line
local inception = {year = 2016, month = 10, day = 26}
local week = 7 * 24 * 60 * 60
local _soSCountTableColumns = 6
local inceptionColor = "3bg" --clr template value

local strings = {
	dateOccWIP = "This is Experimental/WIP feature. Dates may be wrong"
}

function sos.last()
	return sos[#sos]	
end

function p.AssembleSoSTable(sosWeek)
	utils.sortTable(sosWeek)
	return frame:expandTemplate{title = "sos", args = {sosWeek[1], sosWeek[2], sosWeek[3], sosWeek[4]}}
end

function p.SoS(index)
	return p.AssembleSoSTable(sos[#sos - tonumber(index.args[1])])
end

function SoS(index)
	return p.AssembleSoSTable(sos[index])
end

function p.CurrentSoS()
	return p.AssembleSoSTable(sos[1])
end

function p.ManualSoS(args)
	args = args.args
	return frame:expandTemplate{title = "sos", args = {args[1], args[2], args[3], args[4]}}
end

--ISO: https://en.wikipedia.org/wiki/ISO_week_date
--If 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in W01. If it is on a Friday, it is part of W53 of the previous year.
--If it is on a Saturday, it is part of the last week of the previous year which is numbered W52 in a common year and W53 in a leap year.
--If it is on a Sunday, it is part of W52 of the previous year.
function GetWeekNumber(dateStamp)
	firstWeekDayOfYear = tonumber(os.date("%w", os.time({year = os.date("%Y", dateStamp), month = 1, day = 1})))
	firstWeekOfYear = tonumber(os.date("%W", os.time({year = os.date("%Y", dateStamp), month = 1, day = 1})))
	
	-- ATTENTION as per description above some years have first week 01
	-- because all first weeks of year that starts with Sunday, Saturday, Friday or Thursday must be shifted
	if firstWeekDayOfYear > 0 and firstWeekDayOfYear < 4  and firstWeekOfYear == 0 then
		return tonumber(os.date("%W", dateStamp)) + 1
	else
		return tonumber(os.date("%W", dateStamp))
	end
end

function GetEmptyPerkTable(emptyTables)
	local result = {}
	if not emptyTable then for i = 1, #perks do result[i] = 0 end  --make empty table with 0 values for every perk in sos table
	else for i = 1, #perks do result[i] = {} end end
	return result
end

function GetCountOfPerks(year)
	local perkList = GetEmptyPerkTable()

	for i, sosWeek in ipairs(sos) do
		for j, sosPerk in ipairs(sosWeek) do
			if type(sosPerk) ~= "table" then
				if perkList[sosPerk] == nil then --sosPerk, the perk ID will be an index of perkList table. Due to Lua logic there must not be a nil between items (that's why there is getEmptyPerkTable())
					perkList[sosPerk] = 1 --DEV TODO check if possible to remove it
				else
					perkList[sosPerk] = perkList[sosPerk] + 1
				end
			end
		end
	end
	return perkList
end

function p.AssembleSoSPerkCountTable()
	local SoSPerkCountTable = GetCountOfPerks()
	local result = ""
	local maxOccurrence = math.max(unpack(SoSPerkCountTable))
	local number
	utils.sortItemsByName(perks)
	
	result = result .. "{| class=\"wikitable unsortable\"" .. nl

	for i, perk in ipairs(perks) do
		if (i - 1) % _soSCountTableColumns == 0 then
			result = result .. ntl .. nl
		end
		number = SoSPerkCountTable[perk.id]
		result = result .. "! [[File:Teachable " .. utils.FirstLetterLower(utils.resolveFileName(perk.name)) .. ".png|64px|center]]" .. nl
		result = result .. "! [[" .. perk.name .. "]]" .. nl
		if number ~= 0 then
			result = result .. "<div class='noticeText' title='" .. strings.dateOccWIP .. "'>Last occ: " .. GetLastPerkOccurrenceByOldId(perk.id) .. "</div>" .. nl
		end
		result = result .. "| <center>'''" .. GetColoredOccurrenceNumber(number) ..  "'''</center>" .. nl
	end
	
	result = result .. "|}"
	--mw.log(mw.dumpObject(result))
	mw.log(maxOccurrence)
	return result
end

function GetColoredOccurrenceNumber(number)
	if number == maxOccurrence then number = frame:expandTemplate{title = "clr", args = {3, SoSPerkCountTable[perk.id]}}
	elseif number == 0 then number = frame:expandTemplate{title = "clr", args = {8, SoSPerkCountTable[perk.id]}}
	elseif number == 1 then number = frame:expandTemplate{title = "clr", args = {2, SoSPerkCountTable[perk.id]}}
	end
end

--Old ID is the ID that occurs in old Perk table in Datatable (not in Datatable/Perks)
function GetLastPerkOccurrenceByOldId(id)
	local perksNew = require("Module:Datatable/Perks")
	--id = id + _nonUniquePerks --as the table will be converted to new IDs then this will be needed (if the sos week table remains with same IDs)
	offset = 0

	for i, sosWeek in ipairs(sos) do
		--mw.log(mw.dumpObject(sosWeek))
		for j, perk in ipairs(sosWeek) do
			if j <= 4 then
				if perk == id then
					mw.log("Last Occ: " .. GetDateFromSoSIndex(i + offset))
					return GetDateFromSoSIndex(i + offset) --since you find the first occurrence from present it means we found the latest occurrence
				end
			else
				if perk.offset ~= nil then
					offset = offset + perk.offset
				end
			end
		end
	end
	--mw.log(mw.dumpObject(perks[id]))
	return "Never"
end

--sosIndex should be a number of how many weeks ago the perk occurred
function GetDateFromSoSIndex(sosIndex)
	return os.date("%d.%m.%Y", os.time() - (sosIndex - 1) * week)
	--mw.log("sosIndex: " .. sosIndex)
	--mw.log("Current Week: " .. GetWeekNumber(tonumber(os.date())))
	--mw.log("test: " .. week)
	--mw.log("current: " .. currentWeek * week)
	--mw.log("indexed: " .. sosIndex * week)
	--mw.log("now: " .. os.time())
	--mw.log("date: " .. os.date("%d.%m.%Y", os.time() - sosIndex * week))
	--mw.log("date: " .. os.date("%x", currentWeek * week))
	--mw.log("date: " .. os.date("%x", sosIndex * week))
end

function GetIndexesOfPeriod(year)
	local currentWeekDate = os.time(inception)
	local currentYear
	local index = #sos
	local perkList = GetEmptyPerkTable()
	local result = {}

	for i, sosWeek in ipairs(sos) do
		currentYear = tonumber(os.date("%Y", currentWeekDate))
		if year == nil or year == currentYear then
			if result[1] == nil then 
				result[1] = index
			end
			--mw.log("[" .. index .. "] Week " ..GetWeekNumber(currentWeekDate) .. ", Year: " .. os.date("%Y", currentWeekDate) .. ": {" .. sos[index][1] .. ", " .. sos[index][2] .. ", " .. sos[index][3] .. ", " .. sos[index][4] .. "} (" .. os.date("%d. %m. %Y",currentWeekDate) .. ")")
			result[2] = index
		end
		
		-------------------------------
		index = #sos - i -- INDEX SHIFT
		if sos[index] ~= nil and sos[index][5] ~= nil and sos[index][5].offset ~= nil then --need to reorder logic instructions
			currentWeekDate = currentWeekDate + (week * (sos[index][5].offset + 1))
		else
			currentWeekDate = currentWeekDate + week
		end
	end
	--mw.log(mw.dumpObject(result))
	return result
end

function ResolveYearParam(year)
	if type(year) == "table" and year.args[1] ~= nil then
		return tonumber(year.args[1])
	elseif type(year) == "number" then
		return year
	else
		return os.date("%Y")
	end
end

function SoSArchiveCalendar(year)
	local currentWeekDate = os.time(inception)
	local perkList = GetEmptyPerkTable()
	local pStart, pEnd = unpack(GetIndexesOfPeriod(year)) --Period Start and Period End
	local offset = 0
	local offset2016 = 0
	local notices = {}
	local week
	local color
	local index
	
	if year == 2016 then
		offset2016 = tonumber(os.date("%W", os.time(inception))) - 1 --setting offset by 43 weeks
	end
	
	for i = pStart, pEnd, -1 do
		week = (pStart - i + 1 + offset2016)
		if sos[i][5] ~= nil and type(sos[i][5]) == "table" then
			offset = offset + (sos[i][5].offset or 0) --offset must be global because we need to shift the rest of all weeks as well
			color  = sos[i][5].color
			notices[week] = sos[i][5].notice
		else
			color = nil
		end
		for j, sosPerk in ipairs(sos[i]) do --sosPerk = individual perk in sos Week row, goes 4x - 5x
			if type(sosPerk) ~= "table" then
				if sosPerk ~= 0 then
					if perkList[sosPerk] == 0 then --sosPerk, the perk ID will be an index of perkList table. Due to Lua logic there must not be a nil between items (that's why there is getEmptyPerkTable())
						perkList[sosPerk] = {{week = week + offset}}
						if color ~= nil then 
							perkList[sosPerk][1].color = color
						end
					else
						perkList[sosPerk][#perkList[sosPerk] + 1] = {week = week + offset, color = color} 
					end
				end
			end
		end
	end
	return {perkList, notices} -- sorting: perkList[perks.id] gives you weeks of appropriate perk
end

function GetGlobalOffsetInYear(pStart, pEnd)
	local offset = 0
	for i = pStart, pEnd, -1 do
		if sos[i][5] ~= nil and type(sos[i][5]) == "table" then
			offset = offset + (sos[i][5].offset or 0)
		end
	end
	mw.log("Week Offset: " .. offset)
	return tonumber(offset)
end

function GetPerksInception(year)
	local charTable
	local dlcDate
	local weekOffset
	local result = GetEmptyPerkTable()
	for i, perk in ipairs(perks) do
		if perk.character ~= nil then --if Perk has associated character that means it's a unique perk
			if		perk.charType == 'S' then charTable = survivors
			elseif	perk.charType == 'K' then charTable = killers
			else	return -1
			end
			if charTable[perk.character].dlc ~= nil then
				dlcDate = utils.GetDatetime(dlcs[charTable[perk.character].dlc].rDate)
				if tonumber(year) == tonumber(dlcDate.year) then
					weekOffset = tonumber(os.date("%W", os.time({year = dlcDate.year, month = 1, day = 1}))) --check if the year starts with W0 or W1 - see #48 (documentation of GetWeekNumber())
					releaseWeek = tonumber(os.date("%W", os.time(dlcDate))) - weekOffset + 1 -- +1 because week indexing start at 0
					
					result[perk.id] = {week = releaseWeek, color = inceptionColor, inception = true}
						
					mw.log("Perk " .. perk.name .. " was released at week " .. releaseWeek .. "(+" .. weekOffset .. ")")
				end
			end
		end
	end
	return result
end

function mergePerkListWithInceptionList(perkList, perkInception)
	local merged = GetEmptyPerkTable()
	
	for i = 1, #perkList do --perkList as I would to keep dependency on the logic that's used when creating perkList variable due to potential later changes
		if perkInception[i] ~= 0 then
			if perkList[i] == 0 then
				perkList[i] = {perkInception[i]}
			else
				perkList[i][#perkList[i] + 1] = perkInception[i]
			end
		end
	end
	
	--mw.log(mw.dumpObject(perkList))
	return perkList
end

function ResolvePerkOccurence(perkOccurenceList)
	local result = 0
	for _, perkOcc in ipairs(perkOccurenceList) do
		if perkOcc.inception == true then
		else
			result = result + 1
		end
	end
	return result
end

function p.AssembleSoSCalendarTable(year)
	year = ResolveYearParam(year)
	local pStart, pEnd = unpack(GetIndexesOfPeriod(year))
	local perkList, weekNames = unpack(SoSArchiveCalendar(year))
	local perkInception = GetPerksInception(year)
	perkList = mergePerkListWithInceptionList(perkList, perkInception)
	local result = ""
	local currentWeekDate = 1
	local startWeekDate = 1
	local weekFound
	local hideable
	if year == 2016 then
		currentWeekDate = tonumber(os.date("%W", os.time(inception)))
		startWeekDate = tonumber(os.date("%W", os.time(inception)))
	end
	local globalOffset = GetGlobalOffsetInYear(pStart, pEnd)
	local lastWeekNumber = currentWeekDate + (pStart - pEnd + globalOffset)
	local numberOfWeeksInYear = pStart - pEnd + 1 + globalOffset
	
	if perkInception == -1 then return "Error: There's invalid CharType in [[Module:DataTable]] - table perks" end
	
	result = result .. "<div id=\"inceptionPerks" .. year .."\" class=\"inceptionSwitch\"></div>" .. nl --Show/Hide Switch
	result = result .. "{| class=\"wikitable unsortable\"" .. nl
	result = result .. "! Icon !! Name !! colspan = " .. numberOfWeeksInYear .. "| Weeks of " .. year .. "!! Shrine Count" .. nl
	result = result .. ntl .. nl
	result = result .. "! colspan = 2" .. "| " .. nl
	mw.log(mw.dumpObject(weekNames))
	
	for i = 1, numberOfWeeksInYear do -- Weeks Header
		if i ~= 1 then
			result = result .. " || class = \"week-cell\" | "
		else
			result = result .. "| class = \"week-cell\" | "
		end
		result = result ..  (weekNames[currentWeekDate] or currentWeekDate)
		currentWeekDate = currentWeekDate + 1
	end
	result = result .. nl .. "!" .. nl
	
	utils.sortItemsByName(perks)
	mw.log("pStart: " .. pStart)
	mw.log("pEnd: " .. pEnd)
	mw.log(numberOfWeeksInYear)
	mw.log(lastWeekNumber)
	mw.log(lastWeekNumber - (pStart - pEnd))
	mw.log(43)
	for i, perk in ipairs(perks) do
		if perkList[perk.id] ~= 0 then
			for j, perkOcc in ipairs(perkList[perk.id]) do
				hideable = false
				if perkOcc.inception == true and (j == 1 and #perkList[perk.id] == 1) then
					hideable = true
					break
				end
			end
			result = result .. ntl
			if hideable then
				result = result .. " class=\"inception-row" .. year .. "\" style=\"display: none;\" " 
			end
			result = result .. nl .. "! [[File:Teachable " .. utils.FirstLetterLower(utils.resolveFileName(perk.name)) .. ".png|32px]] !! " .. perk.name .. nl .. "|"
			
			for j = startWeekDate, lastWeekNumber do --going through week in year
				weekFound = false
				for k, perkOcc in ipairs(perkList[perk.id]) do --perkOcc = Perk Occurrence
					if perk.id == 30 then mw.log("Perk " .. perk.name .. ": " .. perk.id .. ", weekOcc:" .. perkOcc.week .. ", j: " .. j) end
					if perkOcc.week == j then
						local color = frame:expandTemplate{title = "clr", args = {perkOcc.color or "white"}}

						result = result .. "style=\"background-color: #" .. color .. ";\" title = \"Week " .. perkOcc.week .. "\" | " --[[File:nothing.png]]
						weekFound = true
						break
					end
				end
				if j ~= lastWeekNumber then --if it's not occurence in last week then add delimeters
					result = result .. " ||"
				end
			end
			result = result .. nl .. "! " .. ResolvePerkOccurence(perkList[perks[i].id]) .. nl
		end
	end
	
	result = result .. "|}"
	
	mw.log(result)
	return result
end

function p.AssembleSoSYearPage(year)
	year = ResolveYearParam(year)
	local pStart, pEnd = unpack(GetIndexesOfPeriod(year))
	local result = ""
	local currentWeekDate = 1
	local startWeekDate = 1
	local sosIndex = 0
	local header
	if year == 2016 then
		currentWeekDate = tonumber(os.date("%W", os.time(inception))) --43
		startWeekDate = tonumber(os.date("%W", os.time(inception))) --52
	end
	local currentOffset = 0
	local lastWeekNumber = currentWeekDate + (pStart - pEnd)

	if perkInception == -1 then return "Error: There's invalid CharType in [[Module:DataTable]] - table perks" end
	
	utils.sortItemsByName(perks)
	mw.log("pStart: " .. pStart)
	mw.log("pEnd: " .. pEnd)
	mw.log("lastWeekNumber: " .. lastWeekNumber)
	mw.log("lastWeekNumber CALC: " .. lastWeekNumber - (pStart - pEnd))
	mw.log("startWeekDate: " .. startWeekDate)
	for i = startWeekDate, lastWeekNumber do --going through week in year
		sosIndex = pStart + startWeekDate - i
		if sos[sosIndex][5] ~= nil then --If there's a table after 4 perks then retrieve data
			if sos[sosIndex][5].header ~= nil then
				header = sos[sosIndex][5].header
			elseif sos[sosIndex][5].offset ~= nil then
				currentOffset = currentOffset - 1
				header = "Week " .. (i + currentOffset)
				if sos[sosIndex][5].hideVersion ~= true then
					header = header .. " v." .. (1 - sos[sosIndex][5].offset)
				end
			else
				header = "Week " .. i + currentOffset
			end
			text = sos[sosIndex][5].text or ""
		else
			header = "Week " .. i + currentOffset
			text = ""
		end
		--result = sos[sosIndex][1] .. ", " .. sos[sosIndex][2] .. ", " .. sos[sosIndex][3] .. ", " .. sos[sosIndex][4] .. nl .. nl .. result
		--result = ("i: " .. i .. "| Index: " .. sosIndex .. "| lastWeekNumber - currentOffset: " .. lastWeekNumber - currentOffset) .. nl .. result
		result = SoS(sosIndex) .. nl .. nl .. result
		result = text .. nl .. result
		result = "== " .. header .. " ==" ..nl .. result

	end
	
	mw.log(result)
	return result
end

return p
Advertisement