Modul:Weapon info

Z Minecraft Wiki
Přejít na: navigace, hledání
[create | history | purge]Documentation
This module has no documentation. If you know how to use this module, please create it.
local p = {};

local function materialPlus( n )
    return {
        Wooden = n + 0,
        Stone = n + 1,
        Iron = n + 2,
        Diamond = n + 3,
        Gold = n + 0,
    };
end

-- This is the value of the generic.attackSpeed attribute modifier.
-- Translate from the value shown in the tooltip by subtracting 4.
local attackSpeed = {
    Sword = -2.4,
    Shovel = -3.0,
    Pickaxe = -2.8,
    Axe = {
        Wooden = -3.2,
        Stone = -3.2,
        Iron = -3.1,
        Diamond = -3.0,
        Gold = -3.0,
    },
    Hoe = materialPlus( -3 ),
    Other = 0,
};

-- This is the value of the generic.attackDamage attribute modifier.
-- Translate from the value shown in the tooltip by subtracting 1.
local attackDamage = {
    Sword = materialPlus( 3 ),
    Shovel = materialPlus( 1.5 ),
    Pickaxe = materialPlus( 1.0 ),
    Axe = {
        Wooden = 6,
        Stone = 8,
        Iron = 8,
        Diamond = 8,
        Gold = 6,
    },
    Hoe = 0,
    Other = 0,
};

local allTools = 'Sword;Shovel;Pickaxe;Axe;Hoe;Other';
local allMaterials = { 'Wooden', 'Stone', 'Iron', 'Diamond', 'Gold' };
local dpsNote = '<ref group="note" name="dpsLimit%g">Against a single target, DPS is effectively limited to %g due to [[Damage#Damage immunity|damage immunity]].</ref>';

local function parseInfoArg( what, arg )
    local ret = arg;

    if type( ret ) == 'string' then
        local vals = mw.text.split( ret, '%s*,%s*' );
        if #vals == 1 then
            ret = tonumber( vals[1] );
            if not ret then
                error( 'Value for ' .. what .. ' must be either a single number or five numbers separated by commas', 3 );
            end
        elseif #vals == 5 then
            ret = {}
            for i, v in ipairs( vals ) do
                v = tonumber( v );
                if not v then
                    error( 'Value for ' .. what .. ' must be either a single number or five numbers separated by commas', 3 );
                end
                ret[allMaterials[i]] = v;
            end
        else
            error( 'Value for ' .. what .. ' must be either a single number or five numbers separated by commas', 3 );
        end
    end

    if type( ret ) == 'number' then
        ret = { same = ret }
        for _, material in ipairs( allMaterials ) do
            ret[material] = ret.same;
        end
    end

    return ret;
end


function p.infoTableRow( frame )
    local r = {};
    local args = frame.args or frame;
    local tool = args.tool or error( 'Tool must be specified', 2 );
    local speed = attackSpeed[tool] or attackSpeed.Other;

    if args.showname then
        if tool == 'Other' then
            table.insert( r, '! Other' );
        else
            table.insert( r, '! [[' .. tool .. ']]' );
        end
    end

    local speed = parseInfoArg( 'speed', args.speed or attackSpeed[tool] or attackSpeed.Other );
    if speed.same then
        table.insert( r, '|colspan=5| ' .. speed.same + 4 );
    else
        for _, material in ipairs( allMaterials ) do
            table.insert( r, '| {{ItemSprite|' .. material .. ' ' .. tool .. '}} ' .. speed[material] + 4 );
        end
    end

    local damage = parseInfoArg( 'damage', args.damage or attackDamage[tool] or attackDamage.Other );
    if damage.same then
        table.insert( r, '|colspan=5| {{hp|' .. damage.same + 1 .. '}}' );
    else
        for _, material in ipairs( allMaterials ) do
            table.insert( r, '| {{ItemSprite|' .. material .. ' ' .. tool .. '}} {{hp|' .. damage[material] + 1 .. '}}' );
        end
    end

    if speed.same and damage.same then
        local c = '|colspan=5| ' .. ( damage.same + 1 ) * ( speed.same + 4 );
        if speed.same > -2 then
            local d = ( damage.same + 1 ) * 2;
            c = c .. string.format( dpsNote, d, d );
        end
        table.insert( r, c );
    else
        for _, material in ipairs( allMaterials ) do
            local c = '| {{ItemSprite|' .. material .. ' ' .. tool .. '}} ' .. ( damage[material] + 1 ) * ( speed[material] + 4 );
            if speed[material] > -2 then
                local d = ( damage[material] + 1 ) * 2;
                c = c .. string.format( dpsNote, d, d );
            end
            table.insert( r, c );
        end
    end

    r = table.concat( r, '\n' );
    if type( frame.preprocess ) == 'function' then
        r = frame:preprocess( r );
    end
    return r;
end

local function makeInfoTableHeader( t, showname )
    table.insert( t, '{| class="wikitable" style="text-align:center"' );
    table.insert( t, '|-' );
    if showname then
        table.insert( t, '! Tool ' );
    end
    table.insert( t, '!colspan=5| Attack speed !!colspan=5| Attack damage !!colspan=5| Damage/Second (DPS)' );
end

function p.infoTableHeader( frame )
    local t = {};
    local showname = frame.args.showname or false

    makeInfoTableHeader( t, showname );

    return frame:preprocess( table.concat( t, '\n' ) );
end

function p.infoTable( frame )
    local t = {};
    local tools = frame.args.tools or allTools;
    local showname = frame.args.showname or string.find( tools, ';', 0, true )
    
    makeInfoTableHeader( t, showname );

    for tool in mw.text.gsplit( tools, '%s*;%s*' ) do
        table.insert( t, '|-' );
        table.insert( t, p.infoTableRow{ tool = tool, showname = showname } );
    end

    table.insert( t, '|}' );

    return frame:preprocess( table.concat( t, '\n' ) );
end

function p.damageReductionTable( frame )
    local formula;
    if frame.args.enchantment then
        formula = function ( t, speed )
            return ( ( t + 0.5 ) * ( 4 + speed ) / 20 );
        end;
    else
        formula = function ( t, speed )
            return 0.2 + ( ( t + 0.5 ) * ( 4 + speed ) / 20 ) ^ 2 * 0.8;
        end;
    end

    local tools = frame.args.tools or allTools;
    local minSpeed = 0;
    local rows = {};
    for tool in mw.text.gsplit( tools, '%s*;%s*' ) do
        local speeds = attackSpeed[tool] or attackSpeed.Other;
        if type( speeds ) == 'table' then
            local materials = {};
            local rowSpeeds = {};
            for _, material in ipairs( allMaterials ) do
                local speed = speeds[material];
                if not materials[speed] then
                    materials[speed] = '';
                    table.insert( rowSpeeds, speed );
                    minSpeed = math.min( minSpeed, speed );
                end
                materials[speed] = materials[speed] .. '{{ItemSprite|' .. material .. ' ' .. tool .. '}}';
            end
            table.insert( rows, { tool, materials, rowSpeeds } );
        else
            table.insert( rows, { tool, nil, { speeds } } );
            minSpeed = math.min( minSpeed, speeds );
        end
    end

    local maxTicks = 0;
    if frame.args.maxTicks then
        maxTicks = tonumber( frame.args.maxTicks ) or error( 'Value for maxTicks must be a number', 2 )
        maxTicks = math.ceil( maxTicks );
    else
        maxTicks = 20 / ( 4 + minSpeed );
        while formula( maxTicks, minSpeed ) < 0.99995 do
            maxTicks = maxTicks + 1;
        end
    end

    local t = {};

    table.insert( t, '{| class="wikitable" style="text-align:center"' );
    table.insert( t, '|-' );
    table.insert( t, '!rowspan=2 colspan=2| Item' );
    table.insert( t, '!colspan=' .. maxTicks + 1 .. '| Time (seconds)' );
    table.insert( t, '|-' );
    for i = 0, maxTicks do
        table.insert( t, string.format('! %.2f', i / 20 ) );
    end

    for _, row in ipairs( rows ) do
        local tool, materials, speeds = unpack( row );
        for _, speed in ipairs( speeds ) do
            table.insert( t, '|-' );
            if tool then
                if tool ~= 'Other' then
                    tool = '[[' .. tool .. ']]';
                end
                if materials then
                    table.insert( t, '|rowspan=' .. #speeds .. '| ' .. tool );
                else
                    table.insert( t, '|colspan=2| ' .. tool );
                end
                tool = nil;
            end
            if materials then
                table.insert( t, '|style="white-space:nowrap"| ' .. materials[speed] );
            end
            for i = 0, maxTicks do
                local v = formula( i, speed );
                if v >= 0.99995 then
                    table.insert( t, string.format('|colspan=%d style="text-align:left"| 100%%', maxTicks - i + 1 ) );
                    break;
                else
                    table.insert( t, string.format('| %.2f%%', v * 100 ) );
                end
            end
        end
    end

    table.insert( t, '|}' );

    return frame:preprocess( table.concat( t, '\n' ) );
end

return p;