Module:Items

From Fractured Wiki
Jump to navigation Jump to search
Documentation

Module Structure

Description

This Module will be used for items.

Use: Module:Items/Data, Module:Items/Data/Crafted, Module:Items/Data/Edible, Module:Items/Data/Equipment, Module:Items/Data/Reagents


local TableTools = require("Module:TableTools")
local Utils = require("Module:Utils")
local Pagelist = require("Module:Pagelist")
local List = require("Module:List")
local mw = mw

local gsub = string.gsub
local tinsert = table.insert

local pagelist = Pagelist._main
local keysToList = TableTools.keysToList
local shallowClone = TableTools.shallowClone
local table_size = TableTools.size
local sortedPairs = TableTools.sortedPairs
local formatNum = Utils.formatNum
local pageExists = Utils.pageExists
local sprintf = Utils.sprintf
local strlen = Utils.strlen
local upper = Utils.upper
local tableSort = Utils.tableSort
local makeList = List.makeList

--[[------------------------------------------------]]
--[[--------------- MODULE FUNCTIONS ---------------]]
--[[------------------------------------------------]]
local p = require("Module:BaseModule"):newModule()
local module_data = p:getModuleData("Module:Items/Data")

local main_args = {
    parentFirst = true,
    wrappers = {
        "Template:ItemTable",
        "Template:ItemHeader",
        "Template:ItemRecipeTable",
        "Template:ItemIngredientOf",
        "Template:EquipmentByAttribute",
        "Template:CookingList",
    }
}

p.makeItemTable = p:makeInvokeFunc("_makeItemTable", main_args)
p.makeItemRecipeTable = p:makeInvokeFunc("_makeItemRecipeTable", main_args)
p.getItemHeader = p:makeInvokeFunc("_getItemHeader", main_args)
p.listItemIngredientOf = p:makeInvokeFunc("_listItemIngredientOf", main_args)
p.tableEquipmentByAttribute = p:makeInvokeFunc("_tableEquipmentByAttribute", main_args)
p.listCooking = p:makeInvokeFunc("_listCooking", main_args)
p.generateLootMobTable = p:makeInvokeFunc('_generateLootMobTable', main_args)
p.generateReagentTable = p:makeInvokeFunc("_generate_reagent_table", main_args)


p.ItemIcon = p:makeInvokeFunc("_ItemIcon", main_args)
p.ItemWeight = p:makeInvokeFunc("_ItemWeight", main_args)

--[[------------------------------------------------]]
--[[---------------- PAGE FUNCTIONS ----------------]]
--[[------------------------------------------------]]

----------------------------
-- Make Item Recipe table
----------------------------
function p._makeItemRecipeTable(args, frame) -- luacheck: ignore
    local item_name = args[1]
    local item_crafted_data = p:getModuleData("Module:Items/Data/Crafted", item_name)
    local item_equipment_data = p:getModuleData("Module:Items/Data/Equipment", item_name)

    if item_crafted_data == nil then
        return sprintf("ERROR: '''%s''' doesn't exist in the [[Module:Items/Data/Crafted|Crafted]] data module!", item_name)
    end

    local item_material_stats = item_equipment_data and item_equipment_data["Material Stats"] or {}
    local item_materials_needed = item_crafted_data["Materials Needed"] or {}

    local num_material_stats = table_size(item_material_stats)

    local quantity_crafted = item_crafted_data["Quantity Crafted"] or "??"
    local time_required = item_crafted_data["Time Required"] or "??"

    local stations = shallowClone(item_crafted_data["Station"])

    if #stations > 0 then
        stations["conjunction"] = " or "
        stations["nspace"] = "all"
        stations = gsub(pagelist(stations), "%[%[:Hand|Hand%]%]", "Hand")
    else
        stations = "UNKNOWN"
    end

    local recipeWikitext = mw.html.create("p"):wikitext(sprintf("%s is crafted via %s.<br><br>", item_name, stations))

    local craftingStatsTable = mw.html.create("table")
        :addClass("wikitable")
        :cssText("text-align: center")
        :tag("tr")
            :tag("th")
                :cssText("text-align: left; width: 130px")
                :wikitext("Quantity Crafted")
            :done()
            :tag("td")
                :cssText("width: 20px")
                :wikitext(quantity_crafted)
            :done()
        :done()
        :tag("tr")
            :tag("th")
                :cssText("text-align: left; width: 130px")
                :wikitext("Time Required")
            :done()
            :tag("td")
                :cssText("width: 20px")
                :wikitext(time_required)
            :done()
        :done()
    :done()

    local itemsNode
    local itemsNode_leftCellCss = "width:75%;"
    local itemsNode_rightCellCss = "width:25%;"
    local bonusStatsNode
    local stats
    local num_stats
    local count
    local name
    local row
    local itemTable_leftCellCss = "text-align: left; width: 100%"
    local itemTable_rightCellCss = "text-align: center"
    local itemTableWidth = "300px"

    if num_material_stats > 0 then
        itemsNode_leftCellCss = "width:50%;"
        itemsNode_rightCellCss = "width:50%;"

        itemTable_leftCellCss = "text-align: left; width: 65%"
        itemTableWidth = "550px"
    end

    local itemTable = mw.html.create("table")
        :addClass("wikitable")
        :cssText(sprintf("width: %s", itemTableWidth))
        :tag("caption")
            :addClass("game-item-table")
            :cssText("caption-side:bottom; font-size:90%; text-align:left; font-weight:normal; padding-left:5px")
            :wikitext("*One recipe per row")
        :done()

    local itemTableHeaderRow = mw.html.create("tr")
        :tag("th")
            :cssText(itemTable_leftCellCss)
            :wikitext("Recipes")
        :done()

    if num_material_stats > 0 then
        itemTableHeaderRow
            :tag("th")
                :cssText(itemTable_rightCellCss)
                :wikitext("Bonus Stats")
            :done()
    end

    itemTable:node(itemTableHeaderRow:done())

    for idx, recipe in ipairs(item_materials_needed) do
        -- Create wikitext for recipe items and bonus stats
        itemsNode = mw.html.create("table"):cssText("width: 100%")
        bonusStatsNode = mw.html.create("div"):cssText("text-align: center")

        for _, item in ipairs(recipe) do
            name = item["name"]

            itemsNode:tag("tr")
                :tag("td")
                    :cssText(sprintf("text-align: left; background-color:inherit; border:none;%s", itemsNode_leftCellCss))
                    :wikitext(sprintf("[[%s]]", name))
                :done()
                :tag("td")
                    :cssText(sprintf("text-align: center; background-color:inherit; border:none;%s", itemsNode_rightCellCss))
                    :tag("div")
                        :cssText("display: inline-block; vertical-align: middle; margin-right: 4px")
                        :wikitext(item["quantity"])
                    :done()
                    :tag("div")
                        :cssText("display: inline-block")
                        :wikitext(sprintf("[[File:%s|20px|alt=%s|link=]]", item["image"], name))
                    :done()
                :done()
            :done()
        end

        -- Get material stats
        stats = item_material_stats[idx] or {}
        num_stats = table_size(stats)
        count = 1

        for k, v in pairs(stats) do
            k = pageExists(k) and sprintf("[[%s]]", k) or k

            bonusStatsNode:tag("div")
                :cssText("display: inline-block; vertical-align: middle; margin-right: 4px")
                :wikitext(k)
            :done()

            bonusStatsNode:tag("div")
                :cssText("display: inline-block")
                :wikitext(v)
            :done()

            if count < num_stats then
                bonusStatsNode:wikitext("<br>")
            end

            count = count + 1
        end

        itemsNode:done()
        bonusStatsNode:done()

        row = mw.html.create("tr")
            :tag("td")
                :cssText("vertical-align:middle")
                :node(itemsNode)
            :done()

        if num_material_stats > 0 then
            row:tag("td")
                :cssText("vertical-align:middle")
                :node(bonusStatsNode)
            :done()
        end

        itemTable:node(row:done())
    end

    recipeWikitext
        :node(craftingStatsTable)
        :wikitext("<br>")
        :node(itemTable:done())

    return sprintf("%s", tostring(recipeWikitext:allDone()))
end


    ------------------------
    -- Make horizontal table
    ------------------------
    local function make_htable(targetTable)
    local horizontalTable = mw.html.create("table")
        :addClass("wikitable")
        :attr("style"," margin-left: auto; margin-right: auto")
        :cssText("text-align: center")
        :tag("tr")

        for k, v in sortedPairs(targetTable) do
                horizontalTable
                  :tag("th")
                  :wikitext(k)
                  :done()
        end
       horizontalTable
         :tag("tr")
        for k, v in sortedPairs(targetTable) do
                horizontalTable
                  :tag("td")
                  :wikitext(v)
                  :done()
        end
        horizontalTable
          :done()
       return sprintf("%s", tostring(horizontalTable:allDone()))
    end



----------------------------
-- Make Item Table
----------------------------
function p._makeItemTable(args, frame) -- luacheck: ignore
    local item_name = args[1]
    local item_data = module_data[item_name]
    local item_image = ""
    
    if item_data == nil then
    	--local helpstring = ""
    	--for k,v in pairs(mw.title.getCurrentTitle()) do
--    		helpstring = string.format("%s, %s -> %s", helpstring, tostring(k), tostring(v))
    	--end
    	item_name = tostring(mw.title.getCurrentTitle()["basePageTitle"])
    	item_data = module_data[item_name]
		
    	if item_data == nil then
    		--return sprintf("<br>%s<br>%s<br>ERROR: %s HAS NO HEADER! [[Category:Item HAS NO HEADER]]", t, helpstring, item_name)
    		return sprintf("<br>ERROR: %s HAS NO TABLE! [[Category:Item HAS NO TABLE]]", item_name)
		else
			item_image = item_data["image"]
		end
        
    else
   	    item_image = item_data["image"]
    end

    if item_data == nil or strlen(item_data) == 0 then
        return sprintf("%s DOES NOT EXIST!", item_name)
    end

    if item_image == nil or strlen(item_image) == 0 or not pageExists(sprintf("File:%s", item_image)) then
        item_image = "Icon Unknown.jpg"
    end

    -- Need to modify values for formatting consistency
    item_data = shallowClone(item_data)

    -- CSS is set below after the local functions
    local itemTable = mw.html.create("table")

    -- CSS for left and right table columns
    local leftCellCss = "text-align:center; width:50%"
    local rightCellCss = leftCellCss

    -- Each section can order its own keys
    local data_key_order

    -- Adds a section header to table row
    local function add_section_header(name)
        itemTable
            :tag("tr")
                :tag("th")
                    :attr("class", "section-header")
                    :attr("colspan", "2")
                    :attr("style", "background-color:DimGrey; padding: 2px 0")
                    :cssText("text-align: center;")
                    :wikitext(sprintf("%s", name))
                :done()
            :done()
    end

    -- Add a common table row to table
    local function add_basic_row(left_data, right_data)
        if pageExists(left_data) then
            left_data = sprintf("[[%s]]", left_data)
        end      
        if type(right_data) == "table" then
        itemTable
            :tag("tr")
                :tag("th")
                    :cssText(leftCellCss)
                    :wikitext(left_data)
                :done()
                :tag("td")
                    :cssText(rightCellCss)
                    :wikitext(make_htable(right_data))
                :done()
            :done()
        else
        itemTable
            :tag("tr")
                :tag("th")
                    :cssText(leftCellCss)
                    :wikitext(left_data)
                :done()
                :tag("td")
                    :cssText(rightCellCss)
                    :wikitext(right_data)
                :done()
            :done()
       end
    end

    -- Add a common table row to table without Link
    local function add_basic_row_nolink(left_data, right_data)
        if type(right_data) == "table" then
        itemTable
            :tag("tr")
                :tag("th")
                    :cssText(leftCellCss)
                    :wikitext(left_data)
                :done()
                :tag("td")
                    :cssText(rightCellCss)
                    :wikitext(make_htable(right_data))
                :done()
            :done()
        else
        itemTable
            :tag("tr")
                :tag("th")
                    :cssText(leftCellCss)
                    :wikitext(left_data)
                :done()
                :tag("td")
                    :cssText(rightCellCss)
                    :wikitext(right_data)
                :done()
            :done()
       end
    end

    -- Add several common table rows to table
    local function add_basic_rows(key_order, row_data)
        local right_data
        for _, left_data in ipairs(key_order) do
            right_data = row_data[left_data]

            if right_data ~= nil then
                add_basic_row(left_data, right_data)
            end
        end
    end

    -- Name header, Image
    itemTable
        :attr("class", "game-item-table")
        :cssText("float: left; background-color:inherit; border: 2px solid dimgrey; border-collapse: separate; border-radius: 25px; width: 350px; margin-left: 15px; margin-right: 15px;")
        :done()
        :tag("tr")
            :tag("th")
                :attr("colspan", "2")
                :cssText("color:#fff; text-align: center; font-size: 18px; font-weight: bold; font-style: italic; width: 110%")
                :wikitext(sprintf("[[%s]]", item_name))
            :done()
        :done()
        :tag("tr")
            :tag("td")
                :attr("colspan", "2")
                :wikitext(sprintf("[[File:%s|frameless|center|class=section-header]]", item_image))
            :done()
        :done()

    -- Some editors may use a comma and others a dot for number decimals
    -- Replace comma with dot to avoid tonumber() and lang.formatNum issues
    if item_data["Weight"] ~= nil then
        item_data["Weight"] = sprintf("%s kg", formatNum(item_data["Weight"]))
    end

    -- Enforce order of keys for base data
    data_key_order = {"Source", "Max Stack", "Weight"}
    add_basic_rows(data_key_order, item_data)

    -- Guarantee the order these appear in the table for consistency
    local item_edible_data = p:getModuleData("Module:Items/Data/Edible", item_name)
    local item_reagent_data = p:getModuleData("Module:Items/Data/Reagents", item_name)
    local item_equipment_data = p:getModuleData("Module:Items/Data/Equipment", item_name)

    -- Process Edible data
    if item_edible_data ~= nil then
        add_section_header("[[Edible]]")
        
        for k, v in pairs(item_edible_data) do
            add_basic_row(k, v)
        end
    end

    -- Process Enchanting Reagent data
    if item_reagent_data ~= nil then
        add_section_header("[[:Category:Reagents|Enchanting Reagent]]")

        for _, name in ipairs(keysToList(item_reagent_data)) do
            for _, ele in ipairs(item_reagent_data[name]) do
                add_basic_row_nolink(name, ele)
            end
        end
    end

    -- Process Equipment stats
    if item_equipment_data ~= nil then
        add_section_header("[[:Category:Game_mechanics|Stats]]")

        data_key_order = {
            "Armor Type", "Weapon Type", "Durability", "Slot", "Physical Armor", "Magical Armor", "Slash Armor", "Pierce Armor", "Crush Armor", "Magic Resistance", "Cold Resistance", "Poison Resistance", "Acid Resistance", "Fire Resistance", "Shock Resistance", "Cold Insulation", "Heat Insulation", "Encumbrance", 
            "Damage Type", "Damage Attribute", "Versatile", "Attack Speed", "Accuracy", "Evasion", "Range", 
            "Physical Damage Increase", "Shock Damage Increase", "Acid Damage Increase", "Spell Damage Increase", "Ice Damage Increase", "Energy Damage Increase", "Fire Damage Increase", 
            "Corrosion Stacks On Hit", "Warm Stacks On Hit", "Chilled Stacks On Hit", "Poison Stacks On Hit", "Shocked Stacks On Hit", 
            "Weapon Damage", "Spell Damage",  "Luck", "Willpower", "Fortitude", "Health", "Mana Regeneration", "Health Regeneration",
            "Strength", "Intelligence", "Dexterity", "Perception", "Charisma","Constitution",
            "Damage"
        }
        add_basic_rows(data_key_order, item_equipment_data)
    end

    -- Native properties
    ------
    data_key_order = {
       "Armor Penetration", "Bashing", "Block Chance", "Cooldown Reduction", "Critical Damage", "Lower Mana Cost", "Poison Chance", "Special Properties", "Critical Chance"
    }
    -- Check if equipment has native properties
    local nativeCheck = false
    if item_equipment_data ~= nil then
       for stat, data in pairs(item_equipment_data) do
          for key, nativeProperty in pairs(data_key_order) do
             if stat == nativeProperty then nativeCheck = true end
             if nativeCheck == true then break end
          end
          if nativeCheck == true then break end
       end
    -- create section header and rows with data
       if nativeCheck == true then
           add_section_header("Native properties")
           add_basic_rows(data_key_order, item_equipment_data)
       end
    end
 
    return sprintf("%s", tostring(itemTable:allDone()))
end

----------------------------
-- Get Item Header
----------------------------
function p._getItemHeader(args, frame) -- luacheck: ignore
    local item_name = args[1]
    local item_data = module_data[item_name]

--  Removed Item Image Link in front of Description, because Item Image is in the Item Info Box
	--local item_image = ""
	
    if item_data == nil then
    	--local helpstring = ""
    	--for k,v in pairs(mw.title.getCurrentTitle()) do
--    		helpstring = string.format("%s, %s -> %s", helpstring, tostring(k), tostring(v))
    	--end
    	item_name = tostring(mw.title.getCurrentTitle()["basePageTitle"])
    	item_data = module_data[item_name]
		
    	if item_data == nil then
    		--return sprintf("<br>%s<br>%s<br>ERROR: %s HAS NO HEADER! [[Category:Item HAS NO HEADER]]", t, helpstring, item_name)
    		return sprintf("<br>ERROR: %s HAS NO HEADER! [[Category:Item HAS NO HEADER]]", item_name)
		--else
			--item_image = item_data["image"]
		end
        
    --else
   	    --item_image = item_data["image"]
    end

    --if item_image == nil or strlen(item_image) == 0 or not pageExists(sprintf("File:%s", item_image)) then
    --    item_image = "Icon Unknown.jpg"
    --end

    local res = {}
    local description = item_data["description"]
    --local image = item_data["envImage"]
    
    --if image ~= nil then
    --    if strlen(image) > 0 and pageExists(sprintf("File:%s", image)) then
    --        table.insert(res, sprintf('[[File:%s|left|200px]]\n', image))
    --    else
    --        table.insert(res, sprintf('[[File:%s|left|200px]]\n', item_image))
    --    end
    --end

    if description ~= nil and strlen(description) > 0 then
    	local desc_linky = string.gsub(description, "<style=gold>", "[[")
    	desc_linky = string.gsub(desc_linky, "</style>", "]]")
        table.insert(res,sprintf('%s\n', desc_linky))
    else
        table.insert(res,sprintf("[[Category:Items with missing Description]]", item_name))
    end

    return table.concat(res,'')
end

----------------------------
-- Return items where args is an ingredient
----------------------------
function p._listItemIngredientOf(args, frame) -- luacheck: ignore
    local item_name = args[1]
    local item_crafted_data = p:getModuleData("Module:Items/Data/Crafted")
    local list = {}
    local res = {}

    for name, _ in pairs(item_crafted_data) do
        local item_data = item_crafted_data[name]
        local recipe_list = item_data["Materials Needed"]
        for _, materials_info in ipairs(recipe_list) do
            for _, item_info in ipairs(materials_info) do
                if item_info["name"] == item_name then
                    list[#list + 1] = name
                end
            end
        end
    end

    if #list ~= 0 then
        table.insert(res, sprintf("%s is used in the following recipes:\n",item_name))
        for _, v in pairs(TableTools.removeDuplicates(Utils.tableSort(list))) do
            table.insert(res,sprintf('* [[%s]]\n',v))
        end
    else
        table.insert(res,"There are no known recipes, which this item is part of.")
    end

    return table.concat(res,'')
end

----------------------------
-- Return items that go in a given character slot (i.e. Head, Chest, Hands)
----------------------------
local function getEquipmentInSlot(slot)
    local item_equipment_data = p:getModuleData("Module:Items/Data/Equipment")
    local data

    if not slot then
        data = item_equipment_data
    else
        data = {}

        for item_name, item_data in pairs(item_equipment_data) do
            if upper(slot) == upper(item_data["Slot"]) then
                data[item_name] = item_data
            end
        end
    end

    return data
end

----------------------------
-- Return items where args is a property (i.e. Evasion, Melee Damage)
----------------------------
function p._tableEquipmentByAttribute(args, frame) -- luacheck: ignore
    local item_attribute = args[1]
    local item_equipment_data = getEquipmentInSlot(args[2])
    local item_crafted_data = p:getModuleData("Module:Items/Data/Crafted")
    local found_items = false

    local itemTable = mw.html.create("table")
        :addClass("wikitable sortable")
        :cssText("text-align: center; width: 50%")

    itemTable
        :tag("tr")
            :tag("th"):wikitext("Item Name"):done()
            :tag("th"):wikitext("Slot"):done()
            :tag("th"):wikitext(item_attribute):done()
            :tag("th"):wikitext(sprintf("%s from Recipes", item_attribute)):done()
        :done()

    local slot
    local material_stats_data
    local material_stats_value
    local item_crafted
    local materials_needed_data
    local armor_types = {"Physical Armor","Slash Armor", "Pierce Armor", "Crush Armor"}
    local physical_armor_value
    local slash_armor_value
    local pierce_armor_value
    local crush_armor_value

    for item_name, item_attributes in sortedPairs(item_equipment_data) do
        local attribute_value = ""
        local materials_needed_names = {}
        slot = item_attributes["Slot"]
        material_stats_data = item_attributes["Material Stats"]
        item_crafted = item_crafted_data[item_name]
        
        physical_armor_value = item_attributes["Physical Armor"]
        slash_armor_value = item_attributes["Slash Armor"]
        pierce_armor_value = item_attributes["Pierce Armor"]
        crush_armor_value = item_attributes["Crush Armor"]

        -- Special case for Armor to get all types
        if item_attribute == "Armor" and ((physical_armor_value and physical_armor_value ~= 0) or (slash_armor_value and slash_armor_value ~= 0) or (pierce_armor_value and pierce_armor_value ~= 0) or (crush_armor_value and crush_armor_value ~= 0)) then
            local armor_type_values = {
            	physical_armor_value or 0,
                slash_armor_value or 0,
                pierce_armor_value or 0,
                crush_armor_value or 0,
            }

            for idx, armor_type_value in ipairs(armor_type_values) do
                if armor_type_value > 0 then
                    attribute_value = sprintf("%s<br>[[%s]]: %s", attribute_value, armor_types[idx], armor_type_value)
                end
            end

            -- remove leading and trailing line breaks
            attribute_value = gsub(attribute_value, "^<br>", "")
            attribute_value = gsub(attribute_value, "<br>$", "")
        else
            attribute_value = item_attributes[item_attribute]
        end

        -- Check if any recipes offer the attribute we're looking for
        local armorString = " "
        if material_stats_data ~= nil then
            for idx, stats in ipairs(material_stats_data) do
                for k, v in pairs(stats) do
                    if (k == item_attribute) or (item_attribute == "Armor" and (k == "Physical Armor" or k == "Slash Armor" or k == "Pierce Armor" or k == "Crush Armor")) then
                        -- Get the value for the attribute
                        material_stats_value = v
                        armorString = " " .. k .. " "

                        -- Find what materials are needed to acquire the attribute on the item
                        materials_needed_data = item_crafted and item_crafted["Materials Needed"]

                        if materials_needed_data ~= nil then
                            local materials_needed_idx = materials_needed_data[idx] or {}

                            for _, craft_items in ipairs(materials_needed_idx) do
                                tinsert(materials_needed_names, craft_items["name"])
                            end
                        end
                    end
                end
            end
        end

        -- Check if the item itself has the attribute
        if attribute_value ~= nil or #materials_needed_names > 0 then
            local recipe_str = "----"

            if material_stats_value ~= nil and #materials_needed_names > 0 then
                recipe_str = sprintf("%s%sif made with %s", material_stats_value, armorString, pagelist(materials_needed_names))
            end

            if type(attribute_value) == "table" then
            itemTable
                :tag("tr")
                    :tag("td"):wikitext(sprintf("[[%s]]", item_name)):done()
                    :tag("td"):wikitext(slot or ""):done()
                    :tag("td"):wikitext(make_htable(attribute_value)):done()
                    :tag("td"):wikitext(recipe_str):done()
                :done()
            else
            itemTable
                :tag("tr")
                    :tag("td"):wikitext(sprintf("[[%s]]", item_name)):done()
                    :tag("td"):wikitext(slot or ""):done()
                    :tag("td"):wikitext(attribute_value or "----"):done()
                    :tag("td"):wikitext(recipe_str):done()
                :done()
            end

            found_items = true
        end

    end

    if found_items == false then
        itemTable
            :tag("tr")
                :tag("td")
                    :attr("colspan", "4")
                    :wikitext(sprintf("No items with [[%s]] found", item_attribute))
                :done()
            :done()
    end

    return sprintf("%s", tostring(itemTable:allDone()))
end


----------------------------

------------------------------------------
----- Cooking - list
------------------------------------------
function p._listCooking(args, frame) -- luacheck: ignore
   local module_crafted = p:getModuleData("Module:Items/Data/Crafted")
   local module_edible = p:getModuleData("Module:Items/Data/Edible")

   local cookingList = {}

   for craftedName,_ in pairs(module_crafted) do
      if module_edible[craftedName] ~= nil then
         cookingList[#cookingList + 1] = sprintf("[[%s]]", craftedName)
      end
   end

return makeList("bulleted",tableSort(cookingList))
end
--[[------------------------------------------------]]
--[[------------- Item Page Functions --------------]]
--[[------------------------------------------------]]
function p._ItemIcon(args, frame) -- luacheck: ignore
	if module_data[args[1]] == nil or module_data[args[1]]['image'] == nil then return "ERROR: NOT FOUND" end
	if module_data[args[1]]['image'] == "" then return "Icon Unknown.jpg" else return module_data[args[1]]['image'] end
end

function p._ItemWeight(args, frame) -- luacheck: ignore
	if module_data[args[1]] == nil or module_data[args[1]]['Weight'] == nil then return "ERROR: NOT FOUND" else return module_data[args[1]]['Weight'] end
end


function dict_to_sorted_list(data)
    local result = {}

    for entry_name,_ in pairs(data) do
        table.insert(result, entry_name)
    end

    table.sort(result)

    return result
end

function get_icon(item_table, item_name)
    local reagent_entry = item_table[item_name]

    if reagent_entry == nil then
        return nil
    end

    local reagent_icon = reagent_entry["image"]

    if strlen(reagent_icon) > 0 and pageExists(string.format("File:%s", reagent_icon)) then
        return reagent_icon
    else
        return nil
    end
end

local SandBoxTools = require("Module:Sandbox/Maltos")


local reagent_table = p:getModuleData("Module:Items/Data/Reagents")
local item_table = p:getModuleData("Module:Items/Data")

function p._generate_reagent_table(args, frame) -- luacheck: ignore
--function generate_reagent_table(args, frame) -- luacheck: 

    local rare_icon_str = string.format("[[File:RarityIcon.png|16px|link=]]")

    local aspect_dict = {}

    for reagent_name, reagent_aspects in pairs(reagent_table) do
        for aspect_name, aspect_value in pairs(reagent_aspects) do
            aspect_dict[aspect_name] = true
        end
    end

    aspect_dict["Rarity"] = nil

    local aspect_list = dict_to_sorted_list(aspect_dict)

    local reagent_list = dict_to_sorted_list(reagent_table)


    local result_entries = {}

    for _, reagent_name in pairs(reagent_list) do

        local reagent_aspects = reagent_table[reagent_name]

        local reagent_aspect_data = {}
        for aspect_idx, aspect_name in pairs(aspect_list) do
            reagent_aspect_entry = reagent_aspects[aspect_name]

            if reagent_aspect_entry == nil then
                reagent_aspect_entry = ""
            else
                reagent_aspect_entry = reagent_aspect_entry[1]
            end

            table.insert(reagent_aspect_data, reagent_aspect_entry)

        end

        result_entries[reagent_name] = reagent_aspect_data
    end
    
    local aspect_list_icons = {}
    for _, aspect_name in pairs(aspect_list) do
        local aspect_entry_icon = string.format("[[File:Icon_Aspects_%s.png|30px|alt=%s|link=]]", aspect_name, aspect_name)
        local aspect_entry_header_html = string.format("<th><div class='tooltip'>%s<span class='tooltiptext'>%s</span></div></th>", aspect_entry_icon, aspect_name)
        table.insert(aspect_list_icons, aspect_entry_header_html)
    end

    local table_header = "<table id='reagentTable' class='wikitable sortable' style='text-align: center><tr><th>Reagent</th><th>Mobs</th><th>Rarity</th>" .. table.concat(aspect_list_icons) .. "</tr>"
    local table_data_list = {}
    local table_footer = "</table>"

    for _, reagent_name in pairs(reagent_list) do
        local reagent_data = result_entries[reagent_name]

        local reagent_rarity = reagent_table[reagent_name]["Rarity"][1]

        local reagent_icon = get_icon(item_table, reagent_name)
        
        -- local reagent_source_table = SandBoxTools.generateLootMobTable({reagent_name})
        --local reagent_source_table = SandBoxTools.generateLootMobTable("Animal Bones")
        local reagent_source_table = p._generateLootMobTable({reagent_name},{})
        -- dummy data to test memory consumption
        --local reagent_source_table = "dummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumptiondummy data to test memory consumption"
        --local reagent_source_table = "Animal Bones"

        local reagent_icon_string = ""
        if reagent_icon ~= nil then
            reagent_icon_string = string.format("[[File:%s|30px|alt=%s|class=smoothBorderImage]]", reagent_icon, reagent_name)
        end

        --table.insert(reagent_data, 1, string.format("[[%s]]", reagent_name))

        --for x,y in pairs(reagent_data) do
        --    print(string.format("%s %s %s",reagent_name,aspect_list[x], y))
        --end
        --print(reagent_data)
        local row_id = string.gsub(reagent_name, "%s+", "")
        row_id = string.gsub(reagent_name, "'", "")
        local title = string.gsub(reagent_name, "'", "")

        local reagent_aspect_entries = {}
        for i,aspect_value in pairs(reagent_data) do

            local reagent_aspect_cell_html = ""

            if aspect_value ~= "" then
                local aspect_tooltip_entries = {}
                for reagent_aspect_idx, av in pairs(reagent_data) do
                    if av ~= "" then
                        local aspect_tooltip_entry = string.format("%s %s", av, aspect_list[reagent_aspect_idx])
                        table.insert(aspect_tooltip_entries, aspect_tooltip_entry)
                    end
                end

                local reagent_tooltip_aspect_description = table.concat(aspect_tooltip_entries, "<br>")

                reagent_aspect_cell_html = string.format("<td><div class='tooltip'>%s<span class='tooltiptext'>%s<br>%s<br>%s %s<br>%s</span></div></td>", aspect_value, reagent_icon_string, reagent_name, rare_icon_str, reagent_rarity, reagent_tooltip_aspect_description)
            else
                reagent_aspect_cell_html = string.format("<td>%s</td>",aspect_value)
            end
            table.insert(reagent_aspect_entries, reagent_aspect_cell_html)
        end

        local reagent_entry_line = string.format("<tr style='white-space: nowrap;' id='%s'><td>[[%s]] %s</td><td>%s</td><td>%s</td>", row_id, reagent_name, reagent_icon_string, reagent_source_table, reagent_rarity) .. table.concat(reagent_aspect_entries) .. "</tr>"
        --local reagent_entry_line = string.format("<tr style='white-space: nowrap;' id='%s' title='%s'><td>[[%s]] %s</td><td>", row_id, title, reagent_name, reagent_icon_string) .. table.concat(reagent_data, "</td><td>") .. "</td></tr>"

        table.insert(table_data_list, reagent_entry_line)
    end

    local table_string = table_header .. table.concat(table_data_list) .. table_footer

    --print(table_string)

    --return table_string
    return mw.getCurrentFrame():preprocess(table_string)
end


local data_module_creature = p:getModuleData("Module:Creature/data")
local data_module_creature_loot = p:getModuleData("Module:Creature/data/Loot")

function check_mob_as_loot(mob_name, loot_name) -- luacheck: ignore
	local mob_loot = data_module_creature_loot[mob_name]
	if mob_loot == nil then
		return false
	end
	
	local has_loot = false
	
	for idx, loot_entry in mob_loot["Item Drops"] do
		local loot_entry_name = loot_entry["Item Name"]
		if loot_entry_name ~= nil and loot_entry_name == loot_name then
			has_loot = true
		end
	end
	
	return has_loot
end

function p._generateLootMobTable(args, frame) -- luacheck: ignore
	
	local reagent_name = args[1]

	local gem_types = {"Chipped", "Fine", "Flawless"}
	local gem_names = {"Amethyst", "Diamond", "Ruby", "Emerald", "Sapphire", "Topaz"}

	local loot_dict = {}
	
	loot_dict["Gold"] = {}
	
	for mob_entry_idx, mob_entry in pairs(data_module_creature_loot) do
		local mob_name = mob_entry["Monster Name"]
		if mob_name ~= nil and #mob_name > 3 then
			
			--if reagent_name == nil or reagent_name == "" or check_mob_as_loot(mob_name, reagent_name) then
			if true then
				-- different loot items
				for loot_entry_idx, loot_entry in pairs(mob_entry["Item Drops"]) do
					local loot_name = loot_entry["Item Name"]
	
					if loot_name ~= nil and #loot_name > 2 then
						if loot_dict[loot_name] == nil then
							loot_dict[loot_name] = {}
						end
						
						-- shouldnt happen
						--if loot_dict[loot_name][mob_name] ~= nil then
						--	loot_dict[loot_name][mob_name] = {}
						--end
	
						local mob_loot_entry = {}
						mob_loot_entry["Minimum Quantity"] = loot_entry["Minimum Quantity"]
						mob_loot_entry["Maximum Quantity"] = loot_entry["Maximum Quantity"]
						mob_loot_entry["Drop Probability"] = loot_entry["Drop Probability"]
						
						loot_dict[loot_name][mob_name] = mob_loot_entry
			
					end
				end
		
				-- gold here
				if tonumber(mob_entry["Minimum Gold"]) > 0 then
					local gold_entry = {}
					gold_entry["Minimum Quantity"] = mob_entry["Minimum Gold"]
					gold_entry["Maximum Quantity"] = mob_entry["Maximum Gold"]
					gold_entry["Drop Probability"] = "1.0"
					loot_dict["Gold"][mob_name] = gold_entry
				end
				
				-- gems here
				for gem_name_idx=1,#gem_names do
					local gem_name = gem_names[gem_name_idx]
					if mob_entry["Drops " .. gem_name] == "True" then
						for gem_type_idx=1,#gem_types do
							gem_type = gem_types[gem_type_idx]
							gem_prob = mob_entry[gem_type .. " Chance"]
							if gem_prob ~= "0" then
								gem_entry = {}
								gem_entry["Minimum Quantity"] = 0
								gem_entry["Maximum Quantity"] = mob_entry["Maximum Gems"]
								gem_entry["Drop Probability"] = gem_prob
								if loot_dict[gem_type .. " " .. gem_name] == nil then
									loot_dict[gem_type .. " " .. gem_name] = {}
								end
								loot_dict[gem_type .. " " .. gem_name][mob_name] = gem_entry
							end
						end
					end
				end
			end
		end
	end

	-- generate the table rows
	local res = {}
	
	if reagent_name ~= nil and reagent_name ~= "" then
		local loot_data = loot_dict[reagent_name]
		
		if loot_data == nil then
			return ""
		end
		
		local loot_name = reagent_name
		
		local small_table_string = "<table class='wikitable sortable mw-collapsible mw-collapsed mw-collapsible-toggle-default' id='loot_" .. loot_name .. "' style='margin: auto; text-align: center;'><caption></caption><tr style='background-color: #1c3464;'><th data-sort-type=text>Mob Name</th><th data-sort-type=text>Mob CR</th><th data-sort-type=number>Loot Min</th><th data-sort-type=number>Loot Max</th><th data-sort-type=number>Loot Probability</th></tr>"
				
		for mob_name, loot_details in pairs(loot_data) do
			local mob_cr = data_module_creature[mob_name]["ChallengeRating"]
			small_table_string = small_table_string .. sprintf("<tr><td>[[%s]]</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>", mob_name, mob_cr, loot_details["Minimum Quantity"], loot_details["Maximum Quantity"], loot_details["Drop Probability"])
		end

		small_table_string = small_table_string .. "</table>"
		return small_table_string
	end
	
	for loot_name, loot_data in pairs(loot_dict) do
		
		local loot_string = "<tr><td>" .. sprintf("<span id=\"%s\">[[%s]]</span>", loot_name, loot_name) .."</td><td><table class='wikitable sortable' id='loot_" .. loot_name .. "' style='margin: auto; text-align: center;'><tr style='background-color: #1c3464;'><th data-sort-type=text>Mob Name</th><th data-sort-type=text>Mob CR</th><th data-sort-type=number>Loot Min</th><th data-sort-type=number>Loot Max</th><th data-sort-type=number>Loot Probability</th></tr>"
	
		for mob_name, loot_details in pairs(loot_data) do
			mob_cr = data_module_creature[mob_name]["ChallengeRating"]
			loot_string = loot_string .. sprintf("<tr><td>[[%s]]</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>", mob_name, mob_cr, loot_details["Minimum Quantity"], loot_details["Maximum Quantity"], loot_details["Drop Probability"])
		end
		loot_string = loot_string .. "</table></tr>"
		table.insert(res, loot_string)

	end
	--if true then
	--	return string.format("end of loop for: '%s'", reagent_name)
	--end
	return mw.getCurrentFrame():preprocess("<table class='wikitable sortable' id='lootMobTable' style='margin: auto; text-align: center;'><caption>Loot Mob Listing</caption><tr style='background-color: #1c3464;'><th data-sort-type=text>Loot Name</th><th>Monster Data</th></tr>" .. table.concat(res,"") .. "</table>")
end


------------------------------------------
return p