Difference between revisions of "Module:Weapon"

From BTAWiki
Jump to navigation Jump to search
 
Line 359: Line 359:
 
   -- template that we don't want to pass into the cargo_store. instead, we
 
   -- template that we don't want to pass into the cargo_store. instead, we
 
   -- iterate through the fields in p.cargo.weapons and look for field names
 
   -- iterate through the fields in p.cargo.weapons and look for field names
   local cargo_data = {}
+
   local cargo_data = {_table = p.cargo.weapons.table}
 
   for _, field in pairs(p.cargo.weapons.fields) do
 
   for _, field in pairs(p.cargo.weapons.fields) do
 
     local arg = tpl_args[field.field]
 
     local arg = tpl_args[field.field]

Latest revision as of 22:37, 14 January 2021

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

-- Module for handling information related to weapons

-- p for "package". This is the interface returned by the module. it starts as
-- a blank table, to which we add all of the modules functions. the module ends
-- with "return p"
local p = {}

--
-- imports
--

local cargo = mw.ext.cargo
local getArgs = require('Module:Arguments').getArgs

--
-- cargo
--
-- this is the code for managing connecting the weapons definitions to the
-- cargo database.

p.cargo = {}

-- p.cargo.weapons defines the schema of the Weapons table
-- TODO(rust dev): currently missing a few complex fields:
--   * The whole "Custom" map
--   * BonusValueA and BonusValueB
--   * statusEffects
--   * ComponentTags
-- TODO(rust dev): we can probably define a generic schema for all items and
-- reuse it for defining both weapons and equipment.
p.cargo.weapons = {
  -- table defines the name of the cargo table
  table = 'Weapons',
  -- fields contains the schema of all of the fields of a weapon; that is, all
  -- of the columns of the database table. the 'Field' element is the name of
  -- the cargo field, and is the same as the key in the json object.
  fields = {
      category = {
        -- TODO(rust dev): category is probably an enum, and we can do some
        -- special handling for it.
        field = 'Category',
        type = 'String',
      },
      type = {
        field = 'Type',
        type = 'String',
      },
      weaponSubType = {
        field = 'WeaponSubType',
        type = 'String',
      },
      minRange = {
        field = 'MinRange',
        type = 'Integer',
      },
      maxRange = {
        field = 'MaxRange',
        type = 'Integer',
      },
      rangeSplit = {
        field = 'RangeSplit',
        -- rangeSplit is special. it stores a list of integers which represent
        -- the ranges. in this case, it's comma separated.
        type = 'List (,) of Integer',
        -- TODO(rust dev): add code to parse RangeSplit into a native lua
        -- array.
      },
      ammoCategory = {
        field = 'AmmoCategory',
        type = 'String',
      },
      startingAmmoCapacity = {
        field = 'StartingAmmoCapacity',
        type = 'Integer',
      },
      heatGenerated = {
        field = 'HeatGenerated',
        type = 'Integer',
      },
      damage = {
        field = 'Damage',
        type = 'Integer',
      },
      overheatedDamageMultiplier = {
        field = 'OverheatedDamageMultiplier',
        type = 'Integer',
      },
      evasiveDamageMultiplier = {
        field = 'EvasiveDamageMultiplier',
        type = 'Integer',
      },
      evasionPipsIgnored = {
        field = 'EvasionPipsIgnored',
        type = 'Integer',
      },
      damageVariance = {
        field = 'DamageVariance',
        type = 'Integer',
      },
      heatDamage = {
        field = 'HeatDamage',
        type = 'Integer',
      },
      accuracyModifier = {
        field = 'AccuracyModifier',
        type = 'Integer',
      },
      criticalChanceMultiplier = {
        field = 'CriticalChanceMultiplier',
        type = 'Integer',
      },
      aoeCapable = {
        field = 'AOECapable',
        type = 'Boolean',
      },
      indirectFireCapable = {
        field = 'IndirectFireCapable',
        type = 'Boolean',
      },
      refireModifier = {
        field = 'RefireModifier',
        type = 'Integer',
      },
      shotsWhenFire = {
        field = 'ShotsWhenFired',
        type = 'Integer',
      },
      projectilesPerShot = {
        field = 'ProjectilesPerShot',
        type = 'Integer',
      },
      attackRecoil = {
        field = 'AttackRecoil',
        type = 'Integer',
      },
      instability = {
        field = 'Instability',
        type = 'Integer',
      },
      weaponEffectID = {
        field = 'WeaponEffectId',
        type = 'String',
      },
      cost = {
        field = 'Cost',
        type = 'Integer',
      },
      rarity = {
        field = 'Rarity',
        type = 'Integer',
      },
      purchasable = {
        field = 'Purchasable',
        type = 'Boolean',
      },
      manufacturer = {
        field = 'Manufacturer',
        type = 'String',
      },
      model = {
        field = 'Model',
        type = 'String',
      },
      uiName = {
        field = 'UIName',
        type = 'String',
      },
      id = {
        field = 'Id',
        type = 'String',
      },
      name = {
        field = 'Name',
        type = 'String',
      },
      details = {
        field = 'Details',
        -- details is a text type. this is different from a String type because
        -- a Text type is un-indexed, and meant for longer-form text.
        -- TODO(rust dev): maybe this should be Wikitext? Details can have some
        -- markup in them.
        type = 'Text',
      },
      icon = {
        field = 'Icon',
        type = 'String',
      },
      componentType = {
        field = 'ComponentType',
        type = 'String',
      },
      componentSubType = {
        field = 'ComponentSubType',
        type = 'String',
      },
      prefabIdentifier = {
        field = 'PrefabIdentifier',
        type = 'String',
      },
      battleValue = {
        field = 'BattleValue',
        type = 'Integer',
      },
      inventorySize = {
        field = 'InventorySize',
        type = 'Integer',
      },
      tonnage = {
        field = 'Tonnage',
        -- tonnage can be in half-ton increments, so use a float
        type = 'Float',
      },
      allowedLocations = {
        field = 'AllowedLocations',
        -- AllowedLocations is a comma separated list in the json, not an
        -- actual array of strings. nevertheless, it will be more convenient
        -- for us to treat it as a list.
        -- TODO(rust dev): write code to unpack this to a native lua list.
        type = 'List (,) of String',
      },
      disallowedLocations = {
        field = 'DisallowedLocations',
        type = 'List (,) of String',
      },
      criticalComponent = {
        field = 'CriticalComponent',
        type = 'Boolean',
      }
  }
}

-- cargo_store stores items into cargo.
-- taken from the Path of Exile wiki's Module:Cargo
function cargo_store(frame, values)
  for kv, v in pairs(values) do
    if type(v) == 'table' then
      if #v == 0 then
        values[k] = nil
      else
        values[k] = table.concat(v, ',')
      end
    elseif
      type(v) == 'boolean' then
      if v == true then
        v = '1'
      else
        v = '0'
      end
      values[k] = v
    end
  end

  return frame:callParserFunction('#cargo_store:', values)
end

-- cargo_declare is a function which returns another function. The return value
-- is evaluated to declare the cargo table.
-- 
-- this is taken in large part from the Path of Exile wiki's Item2 module.
-- 
-- TODO(rust dev): define this in a separate module for reuse
function cargo_declare (data)
  return function (frame)
    if frame == nil then
      frame = mw.getCurrentFrame()
    end

    -- dcl_args are the arguments we will be passing to #cargo_declare
    local dcl_args = {}

    -- set the table name
    dcl_args._table = data.table
    
    -- for every field, we create an argument mapping the field name to its
    -- type.
    for k, field_data in pairs(data.fields) do
      if field_data then 
        dcl_args[field_data.field] = field_data.type
      end
    end

    -- call #cargo_declare to declare the table before ending the function.
    frame:callParserFunction('#cargo_declare:', dcl_args)
  end
end

-- to declare the weapons table, call table_weapons from a template.
p.table_weapons = cargo_declare(p.cargo.weapons)

--
-- Template:Weapon
--
--
-- weapon_full_name returns the full name of a given weapon
function weapon_full_name(tpl_args)
  return string.format(
    '%s %s %s', 
    tpl_args[p.cargo.weapons.fields.manufacturer.field], 
    tpl_args[p.cargo.weapons.fields.model.field],
    tpl_args[p.cargo.weapons.fields.name.field]
  )
end


function p.infobox (frame)
  tpl_args = getArgs(frame, {
    -- parentFirst tells us to prefer args from the parent page (the template
    -- that calls #invoke
    parentFirst = true
  })

  -- build the infobox
  -- TODO(rust dev): this is just a test infobox, so it's not the final thing.
  -- don't use tables
  local weaponTable = mw.html.create('table')
  weaponTable:addClass('wikitable')
  
  weaponTable:tag('tr')
    :tag('th')
      :wikitext('Manufacturer')
    :done()
    :tag('td')
      :wikitext(tpl_args[p.cargo.weapons.fields.manufacturer.field])

  weaponTable:tag('tr')
    :tag('th')
      :wikitext('Model')
    :done()
    :tag('td')
      :wikitext(tpl_args[p.cargo.weapons.fields.model.field])

  weaponTable:tag('tr')
    :tag('th')
      :wikitext('Name')
    :done()
    :tag('td')
      :wikitext(tpl_args[p.cargo.weapons.fields.name.field])

  weaponTable:tag('tr')
    :tag('th')
      :wikitext('Category')
    :done()
    :tag('td')
      :wikitext(tpl_args[p.cargo.weapons.fields.category.field])

  weaponTable:tag('tr')
    :tag('th')
      :wikitext('Type')
    :done()
    :tag('td')
      :wikitext(tpl_args[p.cargo.weapons.fields.type.field])

  -- attach the weapons table. we declare the weapons table in a separate
  -- template, and to use it, we need to attach it here.
  -- frame:callParserFunction('#cargo_attach:', {_table = p.cargo.weapons.table})

  -- store the data in cargo
  -- we don't simply send in the argument verbatim. there may be options to the
  -- template that we don't want to pass into the cargo_store. instead, we
  -- iterate through the fields in p.cargo.weapons and look for field names
  local cargo_data = {_table = p.cargo.weapons.table}
  for _, field in pairs(p.cargo.weapons.fields) do
    local arg = tpl_args[field.field]
    if arg ~= nil then
      cargo_data[field.field] = arg
    end
  end

  local debug_cargo_output = mw.html.create('pre')
  debug_cargo_output:wikitext(mw.dumpObject(cargo_data))

  cargo_store(frame, cargo_data)

  return tostring(weaponTable) .. tostring(debug_cargo_output)
end

-- return the module as we have constructed it.
return p