Path of Exile Wiki

Wiki поддерживается сообществом, поэтому подумайте над тем, чтобы внести свой вклад.

ПОДРОБНЕЕ

Path of Exile Wiki
Нет описания правки
(Switched to the new function from cargo module)
Строка 648: Строка 648:
 
p.table_monster_life_scaling = m_cargo.declare_factory{data=tables.monster_life_scaling}
 
p.table_monster_life_scaling = m_cargo.declare_factory{data=tables.monster_life_scaling}
   
  +
p.store_data = m_cargo.store_from_lua{tables=tables, module='Monster'}
function p.store_data(frame)
 
-- Get args
 
tpl_args = getArgs(frame, {
 
parentFirst = true
 
})
 
frame = m_util.misc.get_frame(frame)
 
 
if tables[tpl_args.tbl] == nil then
 
error(i18n.errors.invalid_table)
 
end
 
-- mw.loadData has some problems...
 
local data = require(string.format('Module:Monster/%s', tpl_args.tbl))
 
 
tpl_args.index_start = tpl_args.index_start or 1
 
tpl_args.index_end = tpl_args.index_end or #data
 
 
for i=tpl_args.index_start, tpl_args.index_end do
 
local row = data[i]
 
if row == nil then
 
break
 
end
 
-- get full table name
 
row._table = tables[tpl_args.tbl].table
 
m_util.cargo.store(frame, row)
 
end
 
 
return string.format('Attempted to store rows %s to %s in "%s" table', tpl_args.index_start, tpl_args.index_end, tpl_args.tbl)
 
end
 
   
 
function p.monster (frame)
 
function p.monster (frame)

Версия от 20:50, 28 июня 2019

-- ----------------------------------------------------------------------------
-- Imports
-- ----------------------------------------------------------------------------
local m_cargo = require('Module:Cargo')
local getArgs = require('Module:Arguments').getArgs
local m_util = require('Module:Util')
local m_game = require('Module:Game')

local p = {}

-- ----------------------------------------------------------------------------
-- Strings
-- ----------------------------------------------------------------------------

local i18n = {
    tooltips = {
        name = 'Название',
        experience_multiplier = 'Базовый множитель опыта', 
        health_multiplier = 'Базовый множитель здоровья',
        damage_multiplier = 'Базовый множитель урона',
        attack_speed = 'Базовая скорость атаки',
        critical_strike_chance = 'Базовый шанс критического удара',
        minimum_attack_distance = 'Минимальное расстояние атаки',
        maximum_attack_distance = 'Максимальное расстояние атаки',
        difficulty = 'Сложность',
        resistances = 'Сопротивления',
        part1 = '[[Акт 1]]-<br>[[Акт 5]]',
        part2 = '[[Акт 5]]-<br>[[Акт 10]]',
        maps = 'После<br>[[Акт 10|10 Акта]]',
        fire = m_game.constants.damage_types.fire.short_upper,
        cold = m_game.constants.damage_types.cold.short_upper,
        lightning = m_game.constants.damage_types.lightning.short_upper,
        chaos = m_game.constants.damage_types.chaos.short_upper,
        stat_text = 'Effects from modifiers',
        size = 'Object size',
        model_size_multiplier = 'Model size multiplier',
        tags = 'Внутренние метки',
        metadata_id = 'Metadata ids',
        areas = 'Areas',
    },
}
-- ----------------------------------------------------------------------------
-- Helpers
-- ----------------------------------------------------------------------------
local h = {}

function h.add_mod_id(tpl_args, frame, value)
    for _, id in ipairs(value or {}) do
        tpl_args._mods[id] = true
    end
end

-- ----------------------------------------------------------------------------
-- Tables
-- ----------------------------------------------------------------------------
local tables = {}

tables.monsters = {
    table = 'monsters',
    order = {'metadata_id', 'tags', 'monster_type_id', 'mod_ids', 'part1_mod_ids', 'part2_mod_ids', 'endgame_mod_ids', 'skill_ids', 'name', 'size', 'minimum_attack_distance', 'maximum_attack_distance', 'model_size_multiplier', 'experience_multiplier', 'damage_multiplier', 'health_multiplier', 'critical_strike_chance', 'attack_speed', 
    'mods'},
    fields = {
        metadata_id = {
            field = 'metadata_id',
            type = 'String',
            func = function (tpl_args, frame, value)
                tpl_args.monster_usages = m_cargo.query(
                    {'areas'},
                    {             
                        'areas.name',
                        'areas.id',
                        'areas.area_level',
                        'areas.boss_monster_ids',
                        'areas.main_page',
                        'areas._pageName',
                    },
                    {
                        where = string.format('areas.boss_monster_ids HOLDS "%s"', value), 
                    }
                )
            end,
        },
        monster_type_id = {
            field = 'monster_type_id',
            type = 'String',
            func = function (tpl_args, frame, value)
                tpl_args.monster_type = m_cargo.query(
                    {'monster_types', 'monster_resistances'},
                    {
                        'monster_types.tags',
                        'monster_types.armour_multiplier',
                        'monster_types.evasion_multiplier',
                        'monster_types.energy_shield_multiplier',
                        'monster_types.damage_spread',
                        'monster_resistances.part1_fire', 
                        'monster_resistances.part1_cold', 
                        'monster_resistances.part1_lightning', 
                        'monster_resistances.part1_chaos', 
                        'monster_resistances.part2_fire', 
                        'monster_resistances.part2_cold', 
                        'monster_resistances.part2_lightning', 
                        'monster_resistances.part2_chaos', 
                        'monster_resistances.maps_fire', 
                        'monster_resistances.maps_cold', 
                        'monster_resistances.maps_lightning', 
                        'monster_resistances.maps_chaos'
                    },
                    {
                        join = 'monster_types.monster_resistance_id = monster_resistances.id',
                        where = string.format('monster_types.id = "%s"', value), 
                    }
                )[1]
                
                for _, tag in ipairs(m_util.string.split(tpl_args.monster_type['monster_types.tags'], ',%s+')) do
                    tpl_args.tags[#tpl_args.tags+1] = tag
                end
            end,
        },
        mod_ids = {
            field = 'mod_ids',
            type = 'List (,) of String',
            func = h.add_mod_id,
        },
        part1_mod_ids = {
            field = 'part1_mod_ids',
            type = 'List (,) of String',
            func = h.add_mod_id,
        },
        part2_mod_ids = {
            field = 'part2_mod_ids',
            type = 'List (,) of String',
            func = h.add_mod_id,
        },
        endgame_mod_ids = {
            field = 'endgame_mod_ids',
            type = 'List (,) of String',
            func = h.add_mod_id,
        },
        tags = {
            field = 'tags',
            type = 'List (,) of String',
        },
        skill_ids = {
            field = 'skill_ids',
            type = 'List (,) of String',
            --TODO
        },
        -- add base type info or just parse it?
        name = {
            field = 'name',
            type = 'String',
        },
        size = {
            field = 'size',
            type = 'Integer',
        },
        minimum_attack_distance = {
            field = 'minimum_attack_distance',
            type = 'Integer',
        },
        maximum_attack_distance = {
            field = 'maximum_attack_distance',
            type = 'Integer',
        },
        model_size_multiplier = {
            field = 'model_size_multiplier',
            type = 'Float',
        },
        experience_multiplier = {
            field = 'experience_multiplier',
            type = 'Float',
        },
        damage_multiplier = {
            field = 'damage_multiplier',
            type = 'Float',
        },
        health_multiplier = {
            field = 'health_multiplier',
            type = 'Float',
        },
        critical_strike_chance = {
            field = 'critical_strike_chance',
            type = 'Float',
        },
        attack_speed = {
            field = 'attack_speed',
            type = 'Float',
        },
        --
        -- Processing fields
        --
        mods = {
            func = function (tpl_args, frame) 
                local mlist = {}
                for key, _ in pairs(tpl_args._mods) do
                    mlist[#mlist+1] = key
                end
                
                tpl_args._mods = m_cargo.array_query{
                    tables={'mods'},
                    fields={'mods.stat_text'},
                    id_field='mods.id',
                    id_array=mlist
                }
            end,
        },
    }
}

tables.monster_types = {
    table = 'monster_types',
    order = {'id', 'tags', 'monster_resistance_id'},
    fields = {
        id = {
            field = 'id',
            type = 'String',
        },
        tags = {
            field = 'tags',
            type = 'List (,) of String',
        },
        monster_resistance_id = {
            field = 'monster_resistance_id',
            type = 'String',
        },
        armour_multiplier = {
            field = 'armour_multiplier',
            type = 'Float',
        },
        evasion_multiplier = {
            field = 'evasion_multiplier',
            type = 'Float',
        },
        energy_shield_multiplier = {
            field = 'energy_shield_multiplier',
            type = 'Float',
        },
        damage_spread = {
            field = 'damage_spread',
            type = 'Float',
        },
    }
}

tables.monster_resistances = {
    table = 'monster_resistances',
    order = {'id', 'part1_fire', 'part1_cold', 'part1_lightning', 'part1_chaos', 'part2_fire', 'part2_cold', 'part2_lightning', 'part2_chaos', 'maps_fire', 'maps_cold', 'maps_lightning', 'maps_chaos'},
    fields = {
        id = {
            field = 'id',
            type = 'String',
        },
        part1_fire = {
            field = 'part1_fire',
            type = 'Integer',
        },
        part1_cold = {
            field = 'part1_cold',
            type = 'Integer',
        },
        part1_lightning = {
            field = 'part1_lightning',
            type = 'Integer',
        },
        part1_chaos = {
            field = 'part1_chaos',
            type = 'Integer',
        },
        part2_fire = {
            field = 'part2_fire',
            type = 'Integer',
        },
        part2_cold = {
            field = 'part2_cold',
            type = 'Integer',
        },
        part2_lightning = {
            field = 'part2_lightning',
            type = 'Integer',
        },
        part2_chaos = {
            field = 'part2_chaos',
            type = 'Integer',
        },
        maps_fire = {
            field = 'maps_fire',
            type = 'Integer',
        },
        maps_cold = {
            field = 'maps_cold',
            type = 'Integer',
        },
        maps_lightning = {
            field = 'maps_lightning',
            type = 'Integer',
        },
        maps_chaos = {
            field = 'maps_chaos',
            type = 'Integer',
        },
    }
}

tables.monster_base_stats = {
    table = 'monster_base_stats',
    order = {'level', 'damage', 'evasion', 'accuracy', 'life', 'experience', 'summon_life'},
    fields = {
        level = {
            field = 'level',
            type = 'Integer',
        },
        damage = {
            field = 'damage',
            type = 'Float',
        },
        evasion = {
            field = 'evasion',
            type = 'Integer',
        },
        accuracy = {
            field = 'accuracy',
            type = 'Integer',
        },
        life = {
            field = 'life',
            type = 'Integer',
        },
        experience = {
            field = 'experience',
            type = 'Integer',
        },
        summon_life = {
            field = 'summon_life',
            type = 'Integer',
        },
        -- whole bunch of other values I have no clue about ...
    }
}

tables.monster_map_multipliers = {
    table = 'monster_map_multipliers',
    order = {'level', 'life', 'damage', 'boss_life', 'boss_damage', 'boss_item_rarity', 'boss_item_quantity'},
    fields = {
        level = {
            field = 'level',
            type = 'Integer',
        },
        life = {
            field = 'life',
            type = 'Integer',
        },
        damage = {
            field = 'damage',
            type = 'Integer',
        },
        boss_life = {
            field = 'boss_life',
            type = 'Integer',
        },
        boss_damage = {
            field = 'boss_damage',
            type = 'Integer',
        },
        boss_item_rarity = {
            field = 'boss_item_rarity',
            type = 'Integer',
        },
        boss_item_quantity = {
            field = 'boss_item_quantity',
            type = 'Integer',
        },
    }
}

tables.monster_life_scaling = {
    table = 'monster_life_scaling',
    order = {'level', 'magic', 'rare'},
    fields = {
        level = {
            field = 'level',
            type = 'Integer',
        },
        magic = {
            field = 'magic',
            type = 'Integer',
        },
        rare = {
            field = 'rare',
            type = 'Integer',
        },
    }
}

-- ----------------------------------------------------------------------------
-- Monster box sections
-- ----------------------------------------------------------------------------

local display = {}
function display.value (args)
    return function (tpl_args, frame)
        local v
        if args.sub then
            v = tpl_args[args.sub][args.arg]
        else
            v = tpl_args[args.arg]
        end
        
        if v and args.fmt then
            return string.format(args.fmt, v)
        else
            return v
       end
    end
end

function display.sub_value (args)
    return function (tpl_args, frame)
        return tpl_args[args.sub][args.arg]
    end
end

local tbl_view = {
    {
        header = i18n.tooltips.name,
        func = display.value{arg='name'},
    },
    {
        header = i18n.tooltips.experience_multiplier,
        func = display.value{arg='experience_multiplier'},
    },
    {
        header = i18n.tooltips.health_multiplier,
        func = display.value{arg='health_multiplier'},
    },
    {
        header = i18n.tooltips.damage_multiplier,
        func = display.value{arg='damage_multiplier'},
    },
    {
        header = i18n.tooltips.attack_speed,
        func = display.value{arg='attack_speed', fmt='%.3fs',},
    },
    {
        header = i18n.tooltips.critical_strike_chance,
        func = display.value{arg='critical_strike_chance', fmt='%.2f%%',},
    },
    {
        header = i18n.tooltips.minimum_attack_distance,
        func = display.value{arg='minimum_attack_distance'},
    },
    {
        header = i18n.tooltips.maximum_attack_distance,
        func = display.value{arg='maximum_attack_distance'},
    },
    {
        header = i18n.tooltips.resistances,
        func = function (tpl_args, frame)
            local tbl = mw.html.create('table')
            tbl
                :attr('class', 'wikitable')
                :tag('tr')
                    :tag('th')
                        :wikitext(i18n.tooltips.difficulty)
                        :attr('rowspan', 2)
                        :done()
                    :tag('th')
                        :wikitext(i18n.tooltips.resistances)
                        :attr('colspan', 4)
                        :done()
                    :done()
                :tag('tr')
                    :tag('th')
                        :wikitext(i18n.tooltips.fire)
                        :done()
                    :tag('th')
                        :wikitext(i18n.tooltips.cold)
                        :done()
                    :tag('th')
                        :wikitext(i18n.tooltips.lightning)
                        :done()
                    :tag('th')
                        :wikitext(i18n.tooltips.chaos)
                        :done()
                    :done()
                    
            for _, k in ipairs({'part1', 'part2', 'maps'}) do
                local tr = tbl:tag('tr')
                tr
                    :tag('th')
                        :wikitext(i18n.tooltips[k])
                        :done()
                for _, element in ipairs({'fire', 'cold', 'lightning', 'chaos'}) do
                    tr
                        :tag('td')
                            :attr('class', 'tc -' .. element)
                            :wikitext(tpl_args.monster_type[string.format('monster_resistances.%s_%s', k, element)])
                            :done()
                end
            end
            
            return tostring(tbl)
        end,
    },
    {
        header = i18n.tooltips.stat_text,
        func = function (tpl_args, frame)
            if #tpl_args._mods == 0 then
                return
            end
            
            local out = {}
            for _, row in ipairs(tpl_args._mods) do
                out[#out+1] = row['mods.stat_text']
            end
            
            return table.concat(out, '<br>')
        end,
    },
    {
        header = i18n.tooltips.size,
        func = display.value{arg='size'},
    },
    {
        header = i18n.tooltips.model_size_multiplier,
        func = display.value{arg='model_size_multiplier'},
    },
    {
        header = i18n.tooltips.tags,
        func = function (tpl_args, frame)
            if tpl_args.tags == nil or #tpl_args.tags == 0 then
                return
            end
            
           return table.concat(tpl_args.tags, '<br>')
        end,
    },
    {
        header = i18n.tooltips.metadata_id,
        func = display.value{arg='metadata_id'},
    },
    {
        header = i18n.tooltips.areas,
        func = function(tpl_args, frame)
            local out = {}
            for i,v in ipairs(tpl_args.monster_usages) do 
                out[#out+1] = string.format(
                    '[[%s|%s]]', 
                    v['areas.main_page'] or v['areas._pageName'], 
                    v['areas.name'] or v['areas.id']
                )
            end
            
            return table.concat(out, ', ')
        end 
    },
    {
        header = 'Life',
        func = function(tpl_args, frame)
            
            -- Get monster level from the area level that 
            local monster_level = {}
            for _, v in ipairs(tpl_args.monster_usages) do
                monster_level[#monster_level+1] = v['areas.area_level'] + 2
            end
            tpl_args.monster_level = tpl_args.monster_level or table.concat(monster_level, ',')
            
            -- Stop if no monster level was found:
            if tpl_args.monster_level == nil or tpl_args.monster_level == '' then
               return nil
            end
            
            tpl_args.monster_level = m_util.string.split(tpl_args.monster_level, ',') 
            
            local results = m_cargo.query(
                {
                    'monster_base_stats', 
                    'monster_life_scaling', 
                    'monster_map_multipliers', 
                    -- 'monster'
                },
                {
                    'monster_base_stats.level',
                    'monster_base_stats.life', 
                    'monster_life_scaling.magic', 
                    'monster_life_scaling.rare',
                    'monster_map_multipliers.life',
                    'monster_map_multipliers.boss_life',
                    -- 'monster.health_multiplier',
                },
                {
                    join='monster_base_stats.level=monster_life_scaling.level, monster_base_stats.level=monster_map_multipliers.level',
                    where=string.format(
                        'monster_base_stats.level IN (%s)', 
                        table.concat(tpl_args.monster_level, ',')
                    ),
                }
            )
            
            local out = {}
            for i, result in ipairs(results) do
                -- Base life:
                local life = result['monster_base_stats.life']
                
                -- TODO no idea how these works!
                -- Available multipliers:
                local multipliers = {
                    1 + (tpl_args.health_multiplier or 0),
                    1 + (result['monster_life_scaling.magic'] or 0)/100, 
                    1 + (result['monster_life_scaling.rare'] or 0)/100,
                    1 + (result['monster_map_multipliers.life'] or 0)/100,
                    1 + (result['monster_map_multipliers.boss_life'] or 0)/100,
                }
                
                -- Calculate the final life:
                for _, v in ipairs(multipliers) do
                    life = life * v
                end
                
                out[i] = m_util.html.abbr(
                    string.format('%0.0f', life), 
                    string.format(
                        'Lvl. %s: %s * %s',
                        tpl_args.monster_level[i],
                        result['monster_base_stats.life'], 
                        table.concat(multipliers, ' * ')
                    )
                )
                end
            
            return table.concat(out, ', ')
        end,
    },
}

local list_view = {
}


-- ----------------------------------------------------------------------------
-- Page views
-- ----------------------------------------------------------------------------

p.table_monsters = m_cargo.declare_factory{data=tables.monsters}
p.table_monster_types = m_cargo.declare_factory{data=tables.monster_types}
p.table_monster_resistances = m_cargo.declare_factory{data=tables.monster_resistances}
p.table_monster_base_stats = m_cargo.declare_factory{data=tables.monster_base_stats}
p.table_monster_map_multipliers = m_cargo.declare_factory{data=tables.monster_map_multipliers}
p.table_monster_life_scaling = m_cargo.declare_factory{data=tables.monster_life_scaling}

p.store_data = m_cargo.store_from_lua{tables=tables, module='Monster'}

function p.monster (frame)
    --[[
    Stores data and display infoboxes of monsters.
    
    Example
    -------
    = p.monster{
        metadata_id='Metadata/Monsters/Bandits/BanditBossHeavyStrike_',
        monster_type_id='BanditBoss',
        tags='red_blood', 
        skill_ids='Melee, MonsterHeavyStrike',
        name='Calaf, Headstaver',
        size=3,
        minimum_attack_distance=4,
        maximum_attack_distance=5,
        model_size_multiplier=1.15,
        experience_multiplier=1.0,
        damage_multiplier=1.0,
        health_multiplier=1.0,
        critical_strike_chance=5.0,
        attack_speed=1.35,
    }
    ]]
    
    -- Get args
    tpl_args = getArgs(frame, {
        parentFirst = true
    })
    frame = m_util.misc.get_frame(frame)
    
    
    tpl_args._mods = {}
    
    -- parse 
    m_cargo.parse_field_arguments{
        tpl_args=tpl_args,
        frame=frame,
        table_map=tables.monsters,
    }
    
    local tbl = mw.html.create('table')
    tbl
        :attr('class', 'wikitable')
        
    for _, data in ipairs(tbl_view) do
        local v = data.func(tpl_args, frame)
        
        if v ~= nil and v ~= '' then
            tbl
                :tag('tr')
                    :tag('th')
                        :wikitext(data.header)
                        :done()
                    :tag('td')
                        :wikitext(v)
                        :done()
                    :done()
        end
    end
    
    out = {tostring(tbl)}
    for _, data in ipairs(list_view) do
        out[#out+1] = data.func(tpl_args, frame)
    end
    
    return table.concat(out)
end

return p