Path of Exile Wiki

Подумайте над тем, чтобы помочь в обновлении Wiki.

ПОДРОБНЕЕ

Path of Exile Wiki
Path of Exile Wiki
50 394
страницы
м (Откат правок Ruba159753 (обсуждение) к версии Kordloperdlo)
Метка: откат
(Infobox formatting: Acquisition "Level" -> "Area level"; Hideout decoration master and favour cost; Prophecy seal cost; "Miscellaneous" -> "Metadata")
 
(не показано 15 промежуточных версий этого же участника)
Строка 1: Строка 1:
  +
-------------------------------------------------------------------------------
-- Cargo reworked item module
 
  +
--
  +
-- Module:Item2
  +
--
  +
-- This module implements Template:Item and Template:Itembox
  +
-------------------------------------------------------------------------------
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
Строка 30: Строка 35:
 
--
 
--
 
-- remove the ul if name_list is not provided
 
-- remove the ul if name_list is not provided
-- maybe smw
 
   
  +
require('Module:No globals')
-- ----------------------------------------------------------------------------
 
  +
local getArgs = require('Module:Arguments').getArgs
-- Imports
 
-- ----------------------------------------------------------------------------
 
 
local m_util = require('Module:Util')
 
local m_util = require('Module:Util')
local getArgs = require('Module:Arguments').getArgs
 
local m_game = require('Module:Game')
 
local m_skill = require('Module:Skill')
 
local m_area = require('Module:Area')
 
 
local m_cargo = require('Module:Cargo')
 
local m_cargo = require('Module:Cargo')
local f_item_link = require('Module:Item link').item_link
 
   
local p = {}
+
local m_game = mw.loadData('Module:Game')
local c = {}
 
c.image_size = 39
 
c.image_size_full = c.image_size * 2
 
c.query_default = 50
 
c.query_max = 200
 
   
  +
-- Should we use the sandbox version of our submodules?
c.lang = mw.language.new('en')
 
  +
local use_sandbox = m_util.misc.maybe_sandbox('Item2')
   
  +
-- Lazy loading
-- ----------------------------------------------------------------------------
 
  +
local f_skill -- require('Module:Skill')._skill
-- Strings
 
  +
local f_item_link -- require('Module:Item link').item_link
-- ----------------------------------------------------------------------------
 
  +
local f_query_area_info -- require('Module:Area').query_area_info
-- This section contains strings used by this module.
 
  +
local f_process_upgraded_from -- require('Module:Item2/upgrade').process_upgraded_from
-- Add new strings here instead of in-code directly, this will help other
 
  +
local f_append_schema -- require('Module:Item2/cargo').append_schema
-- people to correct spelling mistakes easier and help with translation to
 
-- other PoE wikis.
 
--
 
-- TODO: Maybe move this out to a separate sub-page module
 
local i18n = {
 
inventory_icon = 'File:%s inventory icon.png',
 
status_icon = 'File:%s status icon.png',
 
divination_card_art = 'File:%s card art.png',
 
gem_tag_category = '[[:Категория:%s (тег камня)|%s]]',
 
 
misc = {
 
-- used to identify betrayal map series to avoid showing area infobox.
 
betrayal = 'Предательство',
 
upgraded_from_map = 'случайная карта уровнем выше того же региона',
 
},
 
   
  +
-- The cfg table contains all localisable strings and configuration, to make it
categories = {
 
  +
-- easier to port this module to another wiki.
-- maintenance cats
 
  +
local cfg = use_sandbox and mw.loadData('Module:Item2/config/sandbox') or mw.loadData('Module:Item2/config')
improper_modifiers = 'Предметы с неправильными модификаторами',
 
missing_release_version = 'Предметы без версии выпуска',
 
broken_upgraded_from_reference = 'Предметы со сломанными ссылками предметов в параметрах "upgraded_from"',
 
duplicate_upgraded_from_reference = 'Предметы с повторяющимися наборами в параметрах "upgraded_from"',
 
duplicate_query_area_ids = 'Предметы с повторяющимися идентификаторами областей из запросов',
 
base_items = 'Базовые предметы',
 
derived_items = 'Производные предметы',
 
sell_prices_override = 'Предметы с изменёнными ценами продаж',
 
   
  +
local i18n = cfg.i18n
-- regular cats
 
alternate_artwork = 'Предметы с альтернативным внешним видом',
 
   
  +
local core = use_sandbox and require('Module:Item2/core/sandbox') or require('Module:Item2/core')
-- misc
 
gem_tag_affix = '%s (тег камня)',
 
unique_affix = 'Уникальные %s',
 
 
prophecies = 'Пророчества',
 
blight_item = 'Масла',
 
talismans = 'Талисманы',
 
essences = 'Сущности',
 
},
 
   
  +
-- Declare early to avoid errors
stat_skip_patterns = {
 
maps = {
+
local c = {}
'%d+%% увеличение количества найденных предметов в этой области',
 
'%d+%% повышение редкости найденных предметов в этой области',
 
'%+%d+%% увеличение размера групп монстров',
 
-- ranges
 
'%(%d+%-%d+%)%% увеличение количества найденных предметов в этой области',
 
'%(%d+%-%d+%)%% повышение редкости найденных предметов в этой области',
 
'%+%(%d+%-%d+%)%% увеличение размера групп монстров',
 
},
 
jewels = {
 
'Limited to %d+ %(Hidden%)',
 
'Jewel has a radius of %d+ %(Hidden%)',
 
},
 
},
 
 
 
help_text_defaults = {
 
active_gem = 'Для получения умения выберите предмет и поместите камень в гнездо соответствующего цвета. Щелкните ПКМ, чтобы вынуть камень из гнезда.',
 
support_gem = 'Это камень поддержки. Он дает преимущества не герою, а камню умения в связанных гнездах. Вставьте камень поддержки в гнездо, соединенное с гнездом усиливаемого камня активного умения. Щелкните ПКМ, чтобы вынуть камень из гнезда.',
 
jewel = 'Поместите самоцвет в доступное гнездо на дереве пассивных умений. Чтобы вынуть самоцвет, щёлкните по нему правой кнопкой мыши.',
 
},
 
 
-- texts specific to upgraded from
 
upgraded_from_tooltips = {
 
-- formatters
 
f = {
 
random = 'случайный %s',
 
random_2 = 'случайная %s',
 
random_3 = 'случайное %s',
 
random_4 = 'случайные %s',
 
random_corrupted = string.format('случайный %s %%s', m_util.html.poe_color('corrupted', 'осквернённый')),
 
random_corrupted_2 = string.format('случайная %s %%s', m_util.html.poe_color('corrupted', 'осквернённая')),
 
random_corrupted_3 = string.format('случайное %s %%s', m_util.html.poe_color('corrupted', 'осквернённое')),
 
random_corrupted_4 = string.format('случайные %s %%s', m_util.html.poe_color('corrupted', 'осквернённые')),
 
random_unidentified_corrupted = string.format('случайный %s %%s', m_util.html.poe_color('corrupted', 'неопознанный осквернённый')),
 
random_unidentified_corrupted_2 = string.format('случайная %s %%s', m_util.html.poe_color('corrupted', 'неопознанная осквернённая')),
 
random_two_implicit_corrupted = string.format('случайный %s %%s %s', m_util.html.poe_color('corrupted', 'осквернённый'), m_util.html.poe_color('corrupted', 'с двумя собственными свойствами')),
 
random_item_level_x = 'случайный %s %s уровня',
 
random_item_level_x_2 = 'случайная %s %s уровня',
 
random_item_level_x_3 = 'случайное %s %s уровня',
 
random_item_level_x_4 = 'случайные %s %s уровня',
 
random_x_link = 'случайный %s с %s связанными гнёздами',
 
random_x_link_item_level_y = 'случайный %s с %s связанными гнёздами %s уровня',
 
random_x_link_item_level_y_random_influenced = 'случайный %s с %s связанными гнёздами %s уровня и случайным влиянием',
 
random_x_amount = 'случайный %s (%s шт.)',
 
random_x_amount_2 = 'случайная %s (%s шт.)',
 
random_x_amount_3 = 'случайное %s (%s шт.)',
 
random_x_amount_4 = 'случайные %s (%s шт.)',
 
random_influenced = 'случайный предмет %s с влиянием',
 
random_two_influenced = 'случайная %s с двойным влиянием',
 
random_two_influenced_x_2 = 'случайная %s с двойным влиянием %s уровня',
 
random_two_influenced_x_3 = 'случайное %s с двойным влиянием %s уровня',
 
random_shaper = 'случайный %s с влиянием Создателя',
 
random_shaper_item_level_x = 'случайный %s с влиянием Создателя %s уровня',
 
random_shaper_item_level_x_2 = 'случайная %s с влиянием Создателя %s уровня',
 
random_shaper_item_level_x_3 = 'случайное %s с влиянием Создателя %s уровня',
 
random_shaper_item_level_x_4 = 'случайные %s с влиянием Создателя %s уровня',
 
random_shaper_hunter_item_level_x = 'случайный %s с влиянием Создателя и Охотника %s уровня',
 
random_shaper_hunter_item_level_x_2 = 'случайная %s с влиянием Создателя и Охотника %s уровня',
 
random_shaper_hunter_item_level_x_3 = 'случайное %s с влиянием Создателя и Охотника %s уровня',
 
random_shaper_hunter_item_level_x_4 = 'случайные %s с влиянием Создателя и Охотника %s уровня',
 
random_elder_item_level_x = 'случайный %s с влиянием Древнего %s уровня',
 
random_elder_item_level_x_2 = 'случайная %s с влиянием Древнего %s уровня',
 
random_elder_item_level_x_3 = 'случайное %s с влиянием Древнего %s уровня',
 
random_elder_item_level_x_4 = 'случайные %s с влиянием Древнего %s уровня',
 
random_eternal_labyrinth_enchantment = string.format('случайный %%s со случайным %s', m_util.html.poe_color('enchanted', 'зачарованием Вечного Лабиринта')),
 
random_veiled = 'случайный %s с завуалированным свойством',
 
random_two_veiled = 'случайный %s с двумя завуалированными свойствами',
 
random_primordial = string.format('случайный %s %%s', m_util.html.poe_color('magic', 'Первородный')),
 
random_map_level = 'случайная %s, осквернённая и %s уровня',
 
 
tier_x_map = 'карта %s уровня',
 
level_x_gem = 'камень %s уровня',
 
level_x_y_gem = 'камень с меткой "%s" %s уровня',
 
superior_gem_q_x = 'камень с качеством %s',
 
superior_x_gem_q_y = 'камень с меткой "%s" и качеством %s',
 
superior_level_x_y_gem_q_z = 'камень с меткой "%s" %s уровня и качеством %s',
 
superior_skill_gem = 'камень умения случайного качества',
 
superior_level_x_skill_gem_q_y = 'камень умения %s уровня и качеством %s',
 
superior_level_x_support_plus_gem_q_y = 'пробужденный камень поддержки %s уровня и качеством %s',
 
 
x_item = 'предмет %s',
 
},
 
 
-- items / rewards not covered by module game
 
agate_amulet = 'амулет с агатом',
 
unset_ring = 'кольцо без камня',
 
gold_ring = 'золотое кольцо',
 
prismatic_ring = 'радужное кольцо',
 
two_stone_ring = 'кольцо с двумя камнями',
 
crystal_sceptre = 'кристальный скипетр',
 
nightmare_bascinet = 'кошмарный бацинет',
 
rustic_sash = 'кушак',
 
talisman = 'талисман',
 
tier_1_talisman = 'талисман 1 уровня',
 
breachstone_splinter = 'осколок Разлома',
 
breachstone = 'камень Разлома',
 
pure_breachstone = 'очищенный камень Разлома',
 
scarab = 'скарабей',
 
gilded_scarab = 'золочёный скарабей',
 
divination_card = 'гадальная карта',
 
quality_currency = 'валюта, повышающая качество',
 
essence = 'сущность',
 
deafening_essence = 'оглушающая сущность',
 
shrieking_essence = 'визжащая сущность',
 
fossil = 'ископаемое',
 
fragment = 'фрагмент',
 
sacrifice_fragment = 'фрагмент жертвы',
 
mortal_fragment = 'смертный фрагмент',
 
uber_elder_fragment = 'фрагмент убер-Древнего',
 
harbinger_fragment = 'фрагмент Предвестника',
 
body_armour = 'нательный доспех',
 
shield = 'щит',
 
map = 'карта',
 
belt = 'пояс',
 
armour = 'доспех',
 
helmet = 'шлем',
 
weapon = 'оружие',
 
jewel = 'самоцвет',
 
timeless_jewel = 'вневременной самоцвет',
 
jewellery = 'бижутерия',
 
one_hand_weapon = 'одноручное оружие',
 
two_hand_weapon = 'двуручное оружие',
 
sword = 'меч',
 
axe = 'топор',
 
flask = 'флакон',
 
granite_flask = 'гранитный флакон',
 
amulet = 'амулет',
 
ring = 'кольцо',
 
league_specific_item = 'предмет из лиги',
 
item = 'предмет',
 
fated_item = 'пророчество на судьбоносный уникальный предмет',
 
 
-- prefix
 
life = 'со здоровьем',
 
 
--
 
-- used within essences
 
--
 
essence_plus_one_level = string.format('+1 уровень в результате %s' ,m_util.html.poe_color('corrupted', 'осквернения')),
 
essence_type_change = string.format('изменение типа в результате %s' ,m_util.html.poe_color('corrupted', 'осквернения')),
 
},
 
 
-- Used by the item info box
 
tooltips = {
 
corrupted = m_util.html.poe_color('corrupted', 'Осквернено'),
 
support_icon = 'Изображение: %s',
 
radius = 'Радиус: %s',
 
mana_reserved = 'Удержано маны: %s',
 
mana_cost = 'Расход маны: %s',
 
mana_multiplier = 'Множитель маны: %s',
 
vaal_souls_per_use = 'Разовый расход душ: %s',
 
stored_uses = 'Максимум зарядов: %s',
 
vaal_soul_gain_prevention_time = 'Нельзя получать души: %s',
 
cooldown_time = 'Перезарядка: %s',
 
cast_time = 'Время применения: %s',
 
critical_strike_chance = 'Шанс критического удара: %s',
 
attack_speed_multiplier = 'Скорость атаки: %s',
 
attack_speed_multiplier_fmt = '%i%% от базовой',
 
damage_effectiveness = 'Эффективность добавленного урона: %s',
 
projectile_speed = 'Скорость снаряда: %s',
 
quality = 'Качество: %s',
 
physical_damage = 'Физический урон: %s',
 
elemental_damage = 'Урон от стихий: %s',
 
chaos_damage = 'Урон хаосом: %s',
 
attacks_per_second = 'Атак в секунду: %s',
 
weapon_range = 'Дальность оружия: %s',
 
map_level = 'Уровень области: %s',
 
map_tier = 'Уровень карты: %s',
 
map_guild_character = m_util.html.abbr('Редактор тега гильдии', 'При редактировании тега гильдии эта карта может быть использована для данного символа') .. ': %s',
 
item_quantity = 'Количество предметов: %s',
 
item_rarity = 'Редкость предметов: %s',
 
monster_pack_size = 'Размер групп монстров: %s',
 
limited_to = 'Максимум: %s',
 
flask_mana_recovery = 'Восстанавливает маны: %s за %s сек.',
 
flask_life_recovery = 'Восстанавливает здоровья: %s за %s сек.',
 
flask_duration = 'Длится %s сек.',
 
flask_charges_per_use = 'Расходует %s из %s зарядов при использовании',
 
chance_to_block = 'Шанс заблокировать удар: %s',
 
armour = 'Броня: %s',
 
evasion = 'Уклонение: %s',
 
energy_shield = 'Энерг. щит: %s',
 
movement_speed = 'Скорость передвижения: %s',
 
talisman_tier = 'Уровень талисмана: %s',
 
stack_size = 'Размер стопки: %s',
 
essence_level = 'Уровень сущности: %s',
 
blight_item_tier = 'Уровень масла: %s',
 
requires = 'Требуется %s',
 
level_inline = 'Уровень %s',
 
level = 'Уровень: %s',
 
gem_quality = 'За 1% качества:',
 
gem_quality_1 = 'По умолчанию',
 
gem_quality_2 = 'Аномальный',
 
gem_quality_3 = 'Искривлённый',
 
gem_quality_4 = 'Фантомный',
 
variation_singular = 'Изменений:',
 
variation_plural = 'Изменений:',
 
favour_cost = 'Цена расположения: %s',
 
seal_cost = 'Стоимость печати: <br>%s',
 
cannot_be_traded_or_modified = 'Этот предмет нельзя отдать или изменить',
 
 
-- harvest seeds
 
 
seed_tier = 'Уровень семени: %s',
 
seed_monster = 'При сборе появляется монстр ? уровня',
 
seed_lifeforce_gained = 'При сборе даёт ? едениц(-ы) чистой %s жизненной силы',
 
seed_growth_cycles = 'Можно собрать после %s циклов роста',
 
 
seed_lifeforce_consumed = 'Потребляет (%s%%) единиц(-ы) конденсированной %s жизненной силы из распылителя за цикл роста',
 
seed_required_seeds = 'Для роста требует соседства %s %s растений как минимум %s уровня',
 
 
-- harvest plant boosters, not used at the moment
 
plant_booster_extra_chances = 'Seeds in radius give the rarest of %s chosen Crafting Options when Harvested',
 
plant_booster_lifeforce = 'Seeds in radius produce %s more Lifeforce when Harvested',
 
plant_booster_additional_crafting_optioons = 'Seeds in radius have %s chance to generate additional Crafting Options when Harvested',
 
 
 
-- heist
 
heist_required_npc = 'Этот предмет могут использовать: %s',
 
heist_required_job = 'Требуется %s %s уровня',
 
heist_any_job = 'Любая роль',
 
 
-- ClientStrings.dat -> WeaponClassDisplayName.*
 
item_class_map = {
 
['Staff'] = 'Посох',
 
['Bow'] = 'Лук',
 
['Wand'] = 'Жезл',
 
['Two Hand Axe'] = 'Двуручный топор',
 
['Two Hand Sword'] = 'Двуручный меч',
 
['Two Hand Mace'] = 'Двуручная булава',
 
['Warstaff'] = 'Воинский посох',
 
['Sceptre'] = 'Скипетр',
 
['One Hand Mace'] = 'Одноручная булава',
 
['One Hand Axe'] = 'Одноручный топор',
 
['One Hand Sword'] = 'Одноручный меч',
 
['Thrusting One Hand Sword'] = 'Одноручный меч',
 
['Claw'] = 'Когти',
 
['Dagger'] = 'Кинжал',
 
['Rune Dagger'] = 'Рунический кинжал',
 
['FishingRod'] = 'Удочка',
 
['HideoutDoodad'] = 'Предмет для убежища',
 
},
 
 
random_mod = '&lt;&lt;случайное свойство %s&gt;&gt;',
 
 
--
 
-- secondary infobox
 
--
 
extra_info = 'Дополнительная информация',
 
header_overall = 'Диаграмма улучшения области',
 
header_upgrades = 'Уровень улучшения',
 
header_map_tier = 'Уровень карты',
 
header_map_level = 'Уровень области',
 
header_connections = 'Соединения',
 
 
drop_restrictions = 'Получение',
 
league_restriction = m_util.html.abbr('Лига(-и):', 'Предмет может быть получен только в Лиге(-ах)') .. ' %s',
 
drop_disabled = 'НЕ ВЫПАДАЕТ',
 
 
purchase_costs = m_util.html.abbr('Стоимость покупки', 'Стоимость покупки предмета такого типа у торгующих NPC. Это не означает, действительно ли NPC продаст вам этот предмет.'),
 
sell_price = m_util.html.abbr('Цена продажи', 'Товары или валюта, полученные при продаже этого товара у торгующих NPC. Некоторые рецепты торговцев могут переопределить это значение.'),
 
 
damage_per_second = 'УВС Оружия',
 
physical_dps = m_game.constants.damage_types.physical.short_upper,
 
fire_dps = m_game.constants.damage_types.fire.short_upper,
 
cold_dps = m_game.constants.damage_types.cold.short_upper,
 
lightning_dps = m_game.constants.damage_types.lightning.short_upper,
 
chaos_dps = m_game.constants.damage_types.chaos.short_upper,
 
elemental_dps = 'Стихийный',
 
poison_dps = 'Физ+Хаос',
 
dps = 'Общий',
 
 
misc = 'Прочее',
 
item_class = 'Класс предмета: %s',
 
metadata_id = 'Metadata ID: %s',
 
},
 
 
item_class_infobox = {
 
page = '[[Класс предметов]]',
 
info = m_util.html.abbr('(?)', 'Классы предметов помогают классифицировать предметы. Классы в основном используются для разграничения предметов или камней умений по определенному классу или для создания фильтров предметов.'),
 
also_referred_to_as = 'Также упоминается как:',
 
},
 
 
debug = {
 
base_item_field_not_found = 'Base item property not found: %s.%s',
 
field_value_mismatch = 'Value for argument "%s" is set to something else then default: %s',
 
},
 
 
errors = {
 
missing_base_item = 'Rarity is set to above normal, but base item is not set. A base item for rarities above normal is required!',
 
missing_rarity = 'Base item parameter is set, but rarity is set to normal. A rarity above normal is required!',
 
missing_amount = 'Item amount is missing or not a number (%s)',
 
upgraded_from_broken_reference = 'Item reference in %s is broken (value: %s)',
 
upgraded_from_duplicate = 'Automatic upgraded from entry is duplicated on page in upgraded_from_set%s',
 
duplicate_base_items = 'More then one result found for the specified base item. Consider using base_item_page or base_item_id to narrow down the results.',
 
base_item_not_found = 'Базовый предмет не найден в базе данных. Проверьте орфографические ошибки или наличие страницы базового предмета на вики. Если страница базового предмета существует на вики, но не может быть найдена, пожалуйста, отредактируйте страницу.',
 
invalid_league = '%s не распознаётся как "лига"',
 
invalid_tag = '%s не является допустимым тегом',
 
generic_argument_parameter = 'Unrecognized %s parameter "%s"',
 
generic_required_parameter = 'Parameter "%s" must be specified for this item type.',
 
non_unique_flag = 'Only unique items can are egible for the flag "%s".',
 
duplicate_area_id_from_query = 'Query found duplicate area ids that do not need to be set on the item. Duplicate ids: "%s"',
 
duplicate_metadata = 'Дубликат metadata_id "%s" на странице "%s"',
 
invalid_influence = 'The influence "%s" is invalid. Acceptable values are "shaper", "elder", "crusader", "redeemer", "hunter" and "warlord".',
 
invalid_class = 'The item class name "%s" is invalid.',
 
invalid_class_id = 'Данный class_id не верный "%s". Для правильной работы модуля Item2 и шаблона, необходимо использовать правильный идентификатор.',
 
invalid_rarity_id = 'Недопустимый rarity_id "%s". Допустимые значения: "normal", "magic", "rare" и "unique".',
 
invalid_region_upgrade_count = 'atlas_connection%s_tier: Invalid amount (%s) of connections, only 5 are allowed',
 
},
 
}
 
   
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
-- Other stuff
+
-- Helper functions
 
-- ----------------------------------------------------------------------------
 
-- ----------------------------------------------------------------------------
   
 
local h = {}
 
local h = {}
   
  +
-- Lazy loading for Module:Skill
function h.debug(tpl_args, func)
 
if tpl_args.debug == nil then
+
function h.skill(tpl_args, frame)
return
+
if not f_skill then
  +
f_skill = use_sandbox and require('Module:Skill/sandbox')._skill or require('Module:Skill')._skill
 
end
 
end
  +
return f_skill(tpl_args, frame)
func()
 
 
end
 
end
   
  +
-- Lazy loading for Module:Item link
function h.na_or_val(tr, value, func)
 
  +
function h.item_link(args)
if value == nil then
 
  +
if not f_item_link then
tr:wikitext(m_util.html.td.na())
 
  +
f_item_link = require('Module:Item link').item_link
else
 
local raw_value = value
 
if func ~= nil then
 
value = func(value)
 
end
 
tr
 
:tag('td')
 
:attr('data-sort-value', raw_value)
 
:wikitext(value)
 
:done()
 
 
end
 
end
  +
return f_item_link(args)
 
end
 
end
   
  +
-- Lazy loading for Module:Item link
-- helper to loop over the range variables easier
 
  +
function h.query_area_info(args)
h.range_map = {
 
  +
if not f_query_area_info then
min = {
 
  +
f_query_area_info = require('Module:Area').query_area_info
var = '_range_minimum',
 
},
+
end
  +
return f_query_area_info(args)
max = {
 
var = '_range_maximum',
 
},
 
avg = {
 
var = '_range_average',
 
},
 
}
 
 
h.range_fields = {
 
{
 
field = '_range_minimum',
 
type = nil,
 
},
 
{
 
field = '_range_maximum',
 
type = nil,
 
},
 
{
 
field = '_range_average',
 
type = nil,
 
},
 
{
 
field = '_range_text',
 
type = 'Text',
 
},
 
{
 
field = '_range_colour',
 
type = 'String',
 
},
 
{
 
field = '_html',
 
type = 'Text',
 
},
 
 
}
 
 
function h.handle_range_args(tpl_args, frame, argument_key, field, value, fmt_options)
 
fmt_options = mw.clone(fmt_options)
 
fmt_options.return_color = true
 
local html, colour = m_util.html.format_value(tpl_args, frame, value, fmt_options)
 
tpl_args[argument_key .. '_html'] = html
 
tpl_args[field .. '_html'] = html
 
tpl_args[field .. '_range_colour'] = colour
 
 
fmt_options = mw.clone(fmt_options)
 
fmt_options.no_color = true
 
tpl_args[field .. '_range_text'] = m_util.html.format_value(tpl_args, frame, value, fmt_options)
 
 
end
 
end
   
  +
-- Lazy loading for Module:Item2/cargo
function h.stats_update(tpl_args, id, value, modid, key)
 
  +
function h.append_schema(tpl_args, frame, tables)
if tpl_args[key][id] == nil then
 
  +
if not f_append_schema then
tpl_args[key][id] = {
 
  +
f_append_schema = use_sandbox and require('Module:Item2/cargo/sandbox').append_schema or require('Module:Item2/cargo').append_schema
references = {modid},
 
min = value.min,
 
max = value.max,
 
avg = value.avg,
 
}
 
else
 
if modid ~= nil then
 
table.insert(tpl_args[key][id].references, modid)
 
end
 
tpl_args[key][id].min = tpl_args[key][id].min + value.min
 
tpl_args[key][id].max = tpl_args[key][id].max + value.max
 
tpl_args[key][id].avg = tpl_args[key][id].avg + value.avg
 
 
end
 
end
  +
return f_append_schema(tpl_args, frame, tables)
 
end
 
end
   
  +
-- Lazy loading for Module:Item2/upgrade
h.stat = {}
 
function h.stat.add (value, stat_cached)
+
function h.process_upgraded_from(tpl_args, frame)
  +
if not f_process_upgraded_from then
value.min = value.min + stat_cached.min
 
  +
f_process_upgraded_from = use_sandbox and require('Module:Item2/upgrade/sandbox').process_upgraded_from or require('Module:Item2/upgrade').process_upgraded_from
value.max = value.max + stat_cached.max
 
end
 
 
function h.stat.more (value, stat_cached)
 
value.min = value.min * (1 + stat_cached.min / 100)
 
value.max = value.max * (1 + stat_cached.max / 100)
 
end
 
 
function h.stat.more_inverse (value, stat_cached)
 
value.min = value.min / (1 + stat_cached.min / 100)
 
value.max = value.max / (1 + stat_cached.max / 100)
 
end
 
 
-- ----------------------------------------------------------------------------
 
-- core
 
-- ----------------------------------------------------------------------------
 
 
local core = {}
 
 
function core.build_cargo_data(tpl_args, frame)
 
for _, table_name in ipairs(core.item_classes[tpl_args.class_id].tables) do
 
-- Need to clone the table here because we'll be changing the table as we run though
 
-- TODO: Optimize this?
 
for k, _ in pairs(mw.clone(core.cargo[table_name].fields)) do
 
field_data = core.cargo[table_name].fields[k]
 
field_data.table = table_name
 
for _, stat_data in pairs(core.stat_map) do
 
if stat_data.field == k then
 
for _, range_field in ipairs(h.range_fields) do
 
local field_name = stat_data.field .. range_field.field
 
 
local data = {
 
no_copy = true,
 
table = table_name,
 
field = field_name,
 
-- if the type is nil, use the parent type
 
-- this is set integer/float values correctly
 
type = range_field.type or field_data.type,
 
}
 
 
core.cargo[table_name].fields[field_name] = data
 
core.map[field_name] = data
 
end
 
break
 
end
 
end
 
if table_name == 'weapons' then
 
for _, dps_data in ipairs(core.dps_map) do
 
for _, range_field in ipairs(h.range_fields) do
 
local field_name = dps_data.field .. range_field.field
 
 
local data = {
 
no_copy = true,
 
table = table_name,
 
field = field_name,
 
-- dps values are floating points
 
type = range_field.type or 'Float',
 
}
 
 
core.cargo[table_name].fields[field_name] = data
 
core.map[field_name] = data
 
end
 
end
 
end
 
end
 
 
end
 
end
  +
return f_process_upgraded_from(tpl_args, frame)
 
end
 
end
   
function core.validate_mod(tpl_args, frame, args)
+
function h.validate_mod(tpl_args, frame, args)
 
-- args:
 
-- args:
 
-- key - implict or explicit
 
-- key - implict or explicit
Строка 588: Строка 117:
 
local prefix = args.key .. args.i
 
local prefix = args.key .. args.i
 
local value = tpl_args[prefix]
 
local value = tpl_args[prefix]
  +
local is_implicit = args.key == 'implicit'
 
local out = {
 
local out = {
 
result=nil,
 
result=nil,
Строка 593: Строка 123:
 
id=nil,
 
id=nil,
 
stat_text=nil,
 
stat_text=nil,
is_implicit=(args.key == 'implicit'),
+
is_implicit=is_implicit,
 
is_random=nil,
 
is_random=nil,
 
}
 
}
 
 
  +
local mods_table = is_implicit and tpl_args._defined_implicit_mods or tpl_args._mods
 
if value ~= nil then
 
if value ~= nil then
 
out.id = value
 
out.id = value
 
out.stat_text = tpl_args[prefix .. '_text']
 
out.stat_text = tpl_args[prefix .. '_text']
 
out.is_random = false
 
out.is_random = false
table.insert(tpl_args._mods, out)
+
table.insert(mods_table, out)
 
 
 
return true
 
return true
Строка 608: Строка 139:
 
value = m_util.string.split(tpl_args[prefix .. '_random_list'], ',%s*')
 
value = m_util.string.split(tpl_args[prefix .. '_random_list'], ',%s*')
 
for _, mod_id in ipairs(value) do
 
for _, mod_id in ipairs(value) do
table.insert(tpl_args._mods, {
+
table.insert(mods_table, {
 
result = nil,
 
result = nil,
 
id = mod_id,
 
id = mod_id,
 
stat_text = tpl_args[prefix .. '_text'] or string.format(i18n.tooltips.random_mod, args.i),
 
stat_text = tpl_args[prefix .. '_text'] or string.format(i18n.tooltips.random_mod, args.i),
is_implicit = (args.key == 'implicit'),
+
is_implicit = is_implicit,
 
is_random = true,
 
is_random = true,
 
})
 
})
Строка 624: Строка 155:
 
out.stat_text = value
 
out.stat_text = value
 
out.is_random = false
 
out.is_random = false
table.insert(tpl_args._mods, out)
+
table.insert(mods_table, out)
 
 
 
return true
 
return true
Строка 632: Строка 163:
 
end
 
end
   
function core.process_smw_mods(tpl_args, frame)
+
function h.handle_range_args(tpl_args, frame, argument_key, field, value, fmt_options)
  +
fmt_options = mw.clone(fmt_options)
if #tpl_args._mods > 0 then
 
  +
fmt_options.return_color = true
local mods = {}
 
  +
local html, colour = m_util.html.format_value(tpl_args, frame, value, fmt_options)
local mod_ids = {}
 
  +
tpl_args[argument_key .. '_html'] = html
local non_random_mod_ids = {}
 
  +
tpl_args[field .. '_html'] = html
for _, mod_data in ipairs(tpl_args._mods) do
 
  +
tpl_args[field .. '_range_colour'] = colour
if mod_data.result == nil then
 
  +
mods[mod_data.id] = mod_data
 
  +
fmt_options = mw.clone(fmt_options)
mod_ids[#mod_ids+1] = mod_data.id
 
  +
fmt_options.no_color = true
if not mod_data.is_random then
 
  +
tpl_args[field .. '_range_text'] = m_util.html.format_value(tpl_args, frame, value, fmt_options)
table.insert(non_random_mod_ids, mod_data.id)
 
end
 
end
 
tpl_args._subobjects[#tpl_args._subobjects+1] = {
 
_table = 'item_mods',
 
id = mod_data.id,
 
text = mod_data.stat_text,
 
is_implicit = mod_data.is_implicit,
 
is_random = mod_data.is_random,
 
}
 
end
 
 
local results = m_cargo.array_query{
 
tables={'mods'},
 
fields={'mods._pageName', 'mods.id', 'mods.required_level', 'mods.stat_text'},
 
id_field='mods.id',
 
id_array=mod_ids,
 
}
 
 
for _, data in ipairs(results) do
 
local mod_data = mods[data['mods.id']]
 
mod_data.result = data
 
 
if mod_data.is_random == false then
 
-- update item level requirement
 
local keys = {'required_level_final'}
 
-- only update base item requirement if this is an implicit
 
if mod_data.key == 'implicit' then
 
keys[#keys+1] = 'required_level'
 
end
 
 
for _, key in ipairs(keys) do
 
local req = math.floor(tonumber(data['mods.required_level']) * 0.8)
 
if req > tpl_args[key] then
 
tpl_args[key] = req
 
end
 
end
 
end
 
end
 
 
-- fetch stats
 
 
results = m_cargo.query(
 
{'mods', 'mod_stats'},
 
{'mods.id', 'mod_stats.id', 'mod_stats.min', 'mod_stats.max'},
 
{
 
join='mods._pageID=mod_stats._pageID',
 
where=string.format('mod_stats.id IS NOT NULL AND mods.id IN ("%s")', table.concat(mod_ids, '", "')),
 
}
 
)
 
for _, data in ipairs(results) do
 
-- Stat subobject
 
local mod_data = mods[data['mods.id']]
 
if mod_data.result.stats == nil then
 
mod_data.result.stats = {data, }
 
else
 
mod_data.result.stats[#mod_data.result.stats+1] = data
 
end
 
 
local id = data['mod_stats.id']
 
local value = {
 
min = tonumber(data['mod_stats.min']),
 
max = tonumber(data['mod_stats.max']),
 
}
 
value.avg = (value.min+value.max)/2
 
 
local prefix = ''
 
if mod_data.is_random then
 
prefix = '_random'
 
end
 
h.stats_update(tpl_args, id, value, mod_data.result['mods.id'], prefix .. '_stats')
 
if mod_data.is_implicit then
 
h.stats_update(tpl_args, id, value, mod_data.result['mods.id'], prefix .. '_implicit_stats')
 
else
 
h.stats_update(tpl_args, id, value, mod_data.result['mods.id'], prefix .. '_explicit_stats')
 
end
 
end
 
 
if tpl_args._flags.sell_prices_override ~= true then
 
-- fetch sell prices
 
results = m_cargo.query(
 
{'mods', 'mod_sell_prices'},
 
{'mods.id', 'mod_sell_prices.amount', 'mod_sell_prices.name'},
 
{
 
join='mods._pageID=mod_sell_prices._pageID',
 
-- must be non random mods to avoid accumulating sell prices of randomized modifiers
 
where=string.format('mod_sell_prices.amount IS NOT NULL AND mods.id IN ("%s")', table.concat(non_random_mod_ids, '", "')),
 
}
 
)
 
 
for _, data in ipairs(results) do
 
local mod_data = mods[data['mods.id']]
 
if not mod_data.is_implicit then
 
local values = {
 
name = data['mod_sell_prices.name'],
 
amount = tonumber(data['mod_sell_prices.amount']),
 
}
 
-- sell_prices is defined in tpl_args.sell_prices_override
 
tpl_args.sell_prices[values.name] = (tpl_args.sell_prices[values.name] or 0) + values.amount
 
end
 
end
 
end
 
end
 
if tpl_args._flags.sell_prices_override ~= true then
 
local missing_sell_price = true
 
for _, _ in pairs(tpl_args.sell_prices) do
 
missing_sell_price = false
 
break
 
end
 
 
if missing_sell_price then
 
tpl_args.sell_prices['Обрывок свитка'] = 1
 
end
 
 
-- Set sell price on page
 
for name, amount in pairs(tpl_args.sell_prices) do
 
-- sell_price_order is defined in tpl_args.sell_prices_override
 
tpl_args.sell_price_order[#tpl_args.sell_price_order+1] = name
 
tpl_args._subobjects[#tpl_args._subobjects+1] = {
 
_table = 'item_sell_prices',
 
amount = amount,
 
name = name,
 
}
 
end
 
table.sort(tpl_args.sell_price_order)
 
end
 
 
end
 
end
   
  +
h.stat = {}
function core.process_base_item(tpl_args, frame, args)
 
  +
function h.stat.add(value, stat_cached)
local where
 
  +
value.min = value.min + stat_cached.min
if tpl_args.base_item_id ~= nil then
 
  +
value.max = value.max + stat_cached.max
where = string.format('items.metadata_id="%s"', tpl_args.base_item_id)
 
elseif tpl_args.base_item_page ~= nil then
 
where = string.format('items._pageName="%s"' , tpl_args.base_item_page)
 
elseif tpl_args.base_item ~= nil then
 
where = string.format('items.name="%s"' , tpl_args.base_item)
 
elseif tpl_args.rarity_id ~= 'normal' then
 
error(m_util.html.error{msg=i18n.errors.missing_base_item})
 
else
 
return
 
end
 
 
if where ~= nil and tpl_args.rarity_id == 'normal' and not tpl_args._flags.is_prophecy then
 
error(m_util.html.error{msg=i18n.errors.missing_rarity})
 
end
 
 
where = string.format('%s AND items.class_id="%s" AND items.rarity_id="normal"', where, tpl_args.class_id)
 
 
local join = {}
 
 
for _, table_name in ipairs(core.item_classes[tpl_args.class_id].tables) do
 
if table_name ~= 'items' then
 
join[#join+1] = string.format('items._pageID=%s._pageID', table_name)
 
end
 
end
 
 
local fields = {
 
'items._pageName',
 
'items.name',
 
'items.metadata_id',
 
}
 
 
for _, k in ipairs(tpl_args._base_item_args) do
 
local data = core.map[k]
 
if data.field ~= nil then
 
fields[#fields+1] = string.format('%s.%s', data.table, data.field)
 
end
 
end
 
 
local result = m_cargo.query(
 
core.item_classes[tpl_args.class_id].tables,
 
fields,
 
{
 
where=where,
 
join=table.concat(join, ','),
 
groupBy='items._pageID',
 
}
 
)
 
 
if #result > 1 then
 
error(m_util.html.error{msg=i18n.errors.duplicate_base_items})
 
-- TODO be more explicit in the error?
 
elseif #result == 0 then
 
error(m_util.html.error{msg=i18n.errors.base_item_not_found})
 
end
 
 
result = result[1]
 
 
tpl_args.base_item_data = result
 
core.process_arguments(tpl_args, frame, {array={'base_item', 'base_item_page', 'base_item_id'}})
 
 
--Copy values..
 
for _, k in ipairs(tpl_args._base_item_args) do
 
local data = core.map[k]
 
if data.field ~= nil and data.func_fetch == nil then
 
local value = result[string.format('%s.%s', data.table, data.field)]
 
-- I can just use data.default since it will be nil if not provided (nil == nil). Neat! ;)
 
if value ~= nil and (tpl_args[k] == data.default or type(data.default) == 'function') then
 
tpl_args[k] = value
 
if data.func ~= nil then
 
data.func(tpl_args, frame)
 
end
 
if data.func_copy ~= nil then
 
data.func_copy(tpl_args, frame)
 
end
 
elseif value == nil and not data.debug_ignore_nil then
 
h.debug(tpl_args, function ()
 
error(string.format(i18n.debug.base_item_field_not_found, data.table, data.field))
 
end)
 
elseif tpl_args[k] ~= data.default then
 
h.debug(tpl_args, function ()
 
error(string.format(i18n.debug.field_value_mismatch, k, tostring(tpl_args[k])))
 
end)
 
end
 
elseif data.func_fetch ~= nil then
 
data.func_fetch(tpl_args, frame)
 
end
 
end
 
 
end
 
end
   
function core.process_arguments(tpl_args, frame, args)
+
function h.stat.more(value, stat_cached)
  +
value.min = value.min * (1 + stat_cached.min / 100)
for _, k in ipairs(args.array) do
 
  +
value.max = value.max * (1 + stat_cached.max / 100)
local data = core.map[k]
 
if data == nil then
 
error(string.format('Invalid key or missing data for "%s"', k))
 
end
 
if data.no_copy == nil then
 
table.insert(tpl_args._base_item_args, k)
 
end
 
if data.func ~= nil then
 
data.func(tpl_args, frame)
 
--[[local status, err = pcall(data.func)
 
-- an error was raised, return the error string instead of the template
 
if not status then
 
return err
 
end
 
]]--
 
end
 
if tpl_args[k] == nil then
 
if tpl_args.class_id and core.item_classes[tpl_args.class_id].defaults ~= nil and core.item_classes[tpl_args.class_id].defaults[k] ~= nil then
 
tpl_args[k] = core.item_classes[tpl_args.class_id].defaults[k]
 
elseif data.default ~= nil then
 
if type(data.default) == 'function' then
 
tpl_args[k] = data.default(tpl_args, frame)
 
else
 
tpl_args[k] = data.default
 
end
 
end
 
end
 
end
 
end
 
 
function core.process_mod_stats(tpl_args, args)
 
local lines = {}
 
 
local skip = core.class_specifics[tpl_args.class_id]
 
if skip then
 
skip = skip.skip_stat_lines
 
end
 
 
local random_mods = {}
 
 
for _, modinfo in ipairs(tpl_args._mods) do
 
if modinfo.is_implicit == args.is_implicit then
 
if modinfo.is_random == true then
 
if random_mods[modinfo.stat_text] then
 
table.insert(random_mods[modinfo.stat_text], modinfo)
 
else
 
random_mods[modinfo.stat_text] = {modinfo}
 
end
 
else
 
if modinfo.id == nil then
 
table.insert(lines, modinfo.result)
 
-- Allows the override of the SMW fetched mod texts for this modifier via <modtype><id>_text parameter
 
elseif modinfo.text ~= nil then
 
table.insert(lines, modinfo.text)
 
else
 
for _, line in ipairs(m_util.string.split(modinfo.result['mods.stat_text'] or '', '<br>')) do
 
if line ~= '' then
 
if skip == nil then
 
table.insert(lines, line)
 
else
 
local skipped = false
 
for _, pattern in ipairs(skip) do
 
if string.match(line, pattern) then
 
skipped = true
 
break
 
end
 
end
 
if not skipped then
 
table.insert(lines, line)
 
end
 
end
 
end
 
end
 
end
 
end
 
end
 
end
 
 
for stat_text, modinfo_list in pairs(random_mods) do
 
local text = {}
 
for _, modinfo in ipairs(modinfo_list) do
 
table.insert(text, modinfo.result['mods.stat_text'])
 
end
 
 
local tbl = mw.html.create('table')
 
tbl
 
:attr('class', 'random-modifier-stats mw-collapsed')
 
:attr('style', 'text-align: left')
 
:tag('tr')
 
:tag('th')
 
:attr('class', 'mw-customtoggle-31')
 
:wikitext(stat_text)
 
:done()
 
:done()
 
:tag('tr')
 
:attr('class', 'mw-collapsible mw-collapsed')
 
:attr('id', 'mw-customcollapsible-31')
 
:tag('td')
 
:wikitext(table.concat(text, '<hr style="width: 20%">'))
 
:done()
 
:done()
 
table.insert(lines, tostring(tbl))
 
end
 
 
if #lines == 0 then
 
return
 
else
 
return table.concat(lines, '<br>')
 
end
 
 
end
 
end
   
function core.process_quest_rewards(tpl_args, frame)
+
function h.stat.more_inverse(value, stat_cached)
  +
value.min = value.min / (1 + stat_cached.min / 100)
local rid = 1
 
  +
value.max = value.max / (1 + stat_cached.max / 100)
local continue
 
tpl_args.quest_rewards = {}
 
tpl_args.vendor_rewards = {}
 
repeat
 
continue = true
 
local prefix = string.format('quest_reward%s_', rid)
 
 
local input_args = {
 
shared = {
 
['type'] = true,
 
['quest'] = false,
 
['quest_id'] = false,
 
['act'] = true,
 
['class_ids'] = false,
 
},
 
vendor = {
 
['npc'] = true,
 
},
 
quest = {
 
['sockets'] = false,
 
['item_level'] = false,
 
['rarity_id'] = false,
 
['notes'] = false,
 
},
 
}
 
 
local rdata = {}
 
 
for key, is_required in pairs(input_args.shared) do
 
rdata[key] = tpl_args[prefix .. key]
 
if is_required then
 
if rdata[key] == nil then
 
continue = false
 
break
 
end
 
end
 
end
 
 
if rdata.quest == nil or rdata.quest_id == nil then
 
continue = false
 
end
 
 
if continue and rdata.type == 'vendor' or rdata.type == 'quest' then
 
for key, is_required in pairs(input_args[rdata.type]) do
 
rdata[key] = tpl_args[prefix .. key]
 
if is_required then
 
if rdata[key] == nil then
 
continue = false
 
break
 
end
 
end
 
end
 
else
 
continue = false
 
end
 
 
if continue then
 
rdata.classes = {}
 
if rdata.class_ids ~= nil then
 
rdata.class_ids = m_util.string.split(rdata.class_ids, ',%s*')
 
for index, class_id in ipairs(rdata.class_ids) do
 
local class = m_game.constants.characters[class_id]
 
if class == nil then
 
error(string.format('Class id %s is invalid', class_id))
 
else
 
rdata.class_ids[index] = class.str_id
 
rdata.classes[index] = class.name
 
end
 
end
 
end
 
 
 
if rdata.item_level then
 
rdata.item_level = m_util.cast.number(rdata.item_level)
 
end
 
 
if rdata.rarity_id then
 
if m_game.constants.rarities[rdata.rarity_id] == nil then
 
error(string.format(i18n.errors.invalid_rarity_id, tostring(rdata.rarity_id)))
 
end
 
end
 
 
rdata._table = rdata.type .. '_rewards'
 
rdata.type = nil
 
 
tpl_args[rdata._table] = rdata
 
 
m_cargo.store(frame, rdata)
 
 
-- TODO: Verify quests and quest ids?
 
end
 
 
rid = rid + 1
 
until continue == false
 
 
end
 
end
   
  +
--
  +
-- Processing
  +
--
   
function core.process_upgraded_from(tpl_args, frame)
+
function h.process_arguments(tpl_args, frame, params)
  +
tpl_args._processed_args = tpl_args._processed_args or {}
local query_data = {
 
id = {},
+
for _, k in ipairs(params) do
name = {},
+
local data = core.map[k]
page = {},
+
if data == nil then
  +
if tpl_args.debug then
}
 
  +
error(string.format(i18n.debug.invalid_argument_key, k))
local sets = {}
 
 
-- ------------------------------------------------------------------------
 
-- Manual data
 
-- ------------------------------------------------------------------------
 
local setid = #sets + 1
 
local set
 
repeat
 
local prefix = string.format('upgraded_from_set%s_', setid)
 
local groupid = 1
 
local group
 
set = {
 
groups = {},
 
text = m_util.cast.text(tpl_args[prefix .. 'text']),
 
automatic = false,
 
}
 
repeat
 
local group_prefix = string.format('%sgroup%s_', prefix, groupid)
 
group = {
 
item_name = tpl_args[group_prefix .. 'item_name'],
 
item_id = tpl_args[group_prefix .. 'item_id'],
 
item_page = tpl_args[group_prefix .. 'item_page'],
 
amount = tonumber(tpl_args[group_prefix .. 'amount']),
 
notes = m_util.cast.text(tpl_args[group_prefix .. 'notes']),
 
}
 
 
if group.item_name ~= nil or group.item_id ~= nil or group.item_page ~= nil then
 
if group.amount == nil then
 
error(string.format(i18n.errors.missing_amount, group_prefix .. 'amount'))
 
else
 
for key, array in pairs(query_data) do
 
local value = group['item_' .. key]
 
if value then
 
if array[value] then
 
table.insert(array[value], {setid, groupid})
 
else
 
array[value] = {{setid, groupid}, }
 
end
 
end
 
end
 
set.groups[#set.groups+1] = group
 
end
 
 
end
 
end
 
groupid = groupid + 1
 
until group.item_name == nil and group.item_id == nil and group.item_page == nil
 
 
-- set was empty, can terminate safely
 
if #set.groups == 0 then
 
set = nil
 
 
else
 
else
setid = setid + 1
+
if data.inherit ~= false then
  +
table.insert(tpl_args._base_item_args, k)
sets[#sets+1] = set
 
end
 
until set == nil
 
-- ------------------------------------------------------------------------
 
-- Automatic
 
-- ------------------------------------------------------------------------
 
 
--
 
-- maps
 
--
 
local automatic_index = #sets + 1
 
-- TODO: 3.9.0 Unsure how this works yet, so disabled for now
 
--[[if tpl_args.atlas_connections and tpl_args.rarity_id == "normal" then
 
local results = m_cargo.query(
 
{'items', 'maps'},
 
{'items._pageName', 'items.name'},
 
{
 
join='items._pageID=maps._pageID',
 
where=string.format('items.class_id = "Map" AND items.rarity_id = "normal" AND maps.tier < %s AND items._pageName IN ("%s")', tpl_args.map_tier, table.concat(tpl_args.atlas_connections, '", "')),
 
}
 
)
 
for _, row in ipairs(results) do
 
sets[#sets+1] = {
 
text = i18n.misc.upgraded_from_map,
 
groups = {
 
{
 
item_name = row['items.name'],
 
item_page = row['items._pageName'],
 
amount = 3,
 
notes = nil,
 
},
 
},
 
automatic = true,
 
}
 
end
 
end]]
 
 
--
 
-- oils
 
--
 
if tpl_args._flags.is_blight_item and tpl_args.blight_item_tier > 1 then
 
local results = m_cargo.query(
 
{'items', 'blight_items'},
 
{'items._pageName', 'items.name'},
 
{
 
join='items._pageID=blight_items._pageID',
 
where=string.format('blight_items.tier = %s', tpl_args.blight_item_tier - 1),
 
}
 
)
 
for _, row in ipairs(results) do
 
sets[#sets+1] = {
 
text = nil,
 
groups = {
 
{
 
item_name = row['items.name'],
 
item_page = row['items._pageName'],
 
amount = 3,
 
notes = nil,
 
},
 
},
 
automatic = true,
 
}
 
end
 
end
 
 
 
--
 
-- essences
 
--
 
 
-- exclude remnant of corruption via type
 
if tpl_args.is_essence and tpl_args.essence_type > 0 then
 
local results = m_cargo.query(
 
{'items', 'essences'},
 
{
 
'items._pageName',
 
'items.name',
 
'items.metadata_id',
 
'essences.category',
 
'essences.type',
 
},
 
{
 
join='items._pageID=essences._pageID',
 
where=string.format([[
 
(essences.category="%s" AND essences.level = %s)
 
OR (essences.type = %s AND essences.level = %s)
 
OR items.metadata_id = 'Metadata/Items/Currency/CurrencyCorruptMonolith'
 
OR (%s = 6 AND essences.type = 5 AND essences.level >= 5)
 
]],
 
tpl_args.essence_category, tpl_args.essence_level - 1,
 
tpl_args.essence_type - 1, tpl_args.essence_level,
 
-- special case for corruption only essences
 
tpl_args.essence_type
 
),
 
orderBy='essences.level ASC, essences.type ASC',
 
}
 
)
 
 
local remnant = results[1]
 
if remnant['items.metadata_id'] ~= 'Metadata/Items/Currency/CurrencyCorruptMonolith' then
 
error(string.format('Something went seriously wrong here. Got results: %s', mw.dumpObject(results)))
 
end
 
for i=2, #results do
 
local row = results[i]
 
if row['essences.category'] == tpl_args.essence_category then
 
-- 3 to 1 recipe
 
sets[#sets+1] = {
 
automatic = true,
 
text = nil,
 
groups = {
 
{
 
item_id = row['items.metadata_id'],
 
item_page = row['items._pageName'],
 
item_name = row['items.name'],
 
amount = 3,
 
},
 
},
 
}
 
-- corruption +1
 
sets[#sets+1] = {
 
automatic = true,
 
text = i18n.upgraded_from_tooltips.essence_plus_one_level,
 
groups = {
 
{
 
item_id = row['items.metadata_id'],
 
item_page = row['items._pageName'],
 
item_name = row['items.name'],
 
amount = 1,
 
},
 
{
 
item_id = remnant['items.metadata_id'],
 
item_page = remnant['items._pageName'],
 
item_name = remnant['items.name'],
 
amount = 1,
 
},
 
},
 
}
 
elseif tonumber(row['essences.type']) == tpl_args.essence_type - 1 then
 
-- corruption type change
 
sets[#sets+1] = {
 
automatic = true,
 
text = i18n.upgraded_from_tooltips.essence_type_change,
 
groups = {
 
{
 
item_id = row['items.metadata_id'],
 
item_page = row['items._pageName'],
 
item_name = row['items.name'],
 
amount = 1,
 
},
 
{
 
item_id = remnant['items.metadata_id'],
 
item_page = remnant['items._pageName'],
 
item_name = remnant['items.name'],
 
amount = 1,
 
},
 
},
 
}
 
 
end
 
end
end
+
if data.func ~= nil then
  +
tpl_args[k] = data.func(tpl_args, frame, tpl_args[k])
end
 
 
-- data based on mapping
 
if tpl_args.drop_enabled and not tpl_args.upgraded_from_disabled then
 
for _, data in ipairs(core.automatic_upgraded_from) do
 
data.defaults = data.defaults or {}
 
local continue = true
 
for key, value in pairs(core.automatic_upgraded_from_defaults) do
 
local func
 
local v = data.defaults[key]
 
if v == false then
 
-- check is disabled specifically, continue
 
elseif v == nil then
 
func = value
 
elseif type(v) == 'function' then
 
func = v
 
else
 
error(string.format('Invalid value for defaults at data %s', mw.dumpObject(data)))
 
end
 
if func then
 
continue = func(tpl_args, frame) and continue
 
if not continue then
 
break
 
end
 
end
 
 
end
 
end
for _, condition in ipairs(data.condition) do
+
if tpl_args[k] == nil then
continue = condition(tpl_args, frame) and continue
+
if tpl_args.class_id and tpl_args._item_config.defaults ~= nil and tpl_args._item_config.defaults[k] ~= nil then
if not continue then
+
-- Item defaults
break
+
tpl_args[k] = tpl_args._item_config.defaults[k]
end
+
elseif data.default ~= nil then
end
+
-- Generic defaults
  +
if type(data.default) == 'function' then
 
  +
tpl_args[k] = data.default(tpl_args, frame)
if continue then
 
sets[#sets+1] = {
 
automatic = true,
 
text = data.text(tpl_args, frame),
 
groups = data.groups,
 
}
 
for groupid, row in ipairs(data.groups) do
 
if query_data['id'][row.item_id] then
 
table.insert(query_data['id'][row.item_id], {#sets, groupid})
 
 
else
 
else
query_data['id'][row.item_id] = {{#sets, groupid}, }
+
tpl_args[k] = data.default
 
end
 
end
 
end
 
end
 
end
 
end
  +
tpl_args._processed_args[k] = true
end
 
end
 
 
if #sets == 0 then
 
return
 
end
 
--
 
-- Fetch item data in a single query to sacrifice database load with a lot of upgraded_from references
 
--
 
local query_data_array = {
 
id = {},
 
name = {},
 
page = {},
 
}
 
local query_fields = {
 
id = 'items.metadata_id',
 
page = 'items._pageName',
 
name = 'items.name',
 
}
 
local where = {}
 
local expected_count = 0
 
for key, thing_array in pairs(query_data) do
 
for thing, _ in pairs(thing_array) do
 
table.insert(query_data_array[key], thing)
 
end
 
if #query_data_array[key] > 0 then
 
expected_count = expected_count + #query_data_array[key]
 
local q_data = table.concat(query_data_array[key], '", "')
 
table.insert(where, string.format('%s IN ("%s")', query_fields[key], q_data))
 
end
 
end
 
local results = m_cargo.query(
 
{'items'},
 
{'items._pageName', 'items.name', 'items.metadata_id'},
 
{
 
where=table.concat(where, ' OR '),
 
}
 
)
 
 
for _, row in ipairs(results) do
 
for key, thing_array in pairs(query_data) do
 
local set_groups = thing_array[row[query_fields[key]]]
 
if set_groups then
 
for _, set_group in ipairs(set_groups) do
 
local entry = sets[set_group[1]].groups[set_group[2]]
 
for entry_key, data_key in pairs(query_fields) do
 
-- metadata_id may be nil, since we don't know them for unique items
 
if row[data_key] then
 
entry['item_' .. entry_key] = row[data_key]
 
end
 
end
 
end
 
-- set this to nil for error checking in later step
 
thing_array[row[query_fields[key]]] = nil
 
end
 
end
 
end
 
 
-- sbow the broken references if needed
 
if #results ~= expected_count then
 
-- query data was pruned of existing keys earlier, so only broken keys remain
 
for key, array in pairs(query_data) do
 
for thing, set_groups in pairs(array) do
 
for _, set_group in ipairs(set_groups) do
 
tpl_args._flags.broken_upgraded_from_reference = true
 
tpl_args._errors[#tpl_args._errors+1] = string.format(i18n.errors.upgraded_from_broken_reference, string.format('upgraded_from_set%s_group%s_item_%s', set_group[1], set_group[2], key), thing)
 
end
 
end
 
end
 
end
 
 
--
 
-- Check for duplicates
 
--
 
local delete_sets = {}
 
for i=automatic_index, #sets do
 
for j=1, automatic_index-1 do
 
if #sets[i].groups == #sets[j].groups then
 
local match = true
 
for row_id, row in ipairs(sets[i].groups) do
 
-- Only the fields from the database query are matched since we can be sure they're correct. Other fields may be subject to user error.
 
for _, key in ipairs({'item_id', 'item_name', 'item_page'}) do
 
match = match and (row[key] == sets[j].groups[row_id][key])
 
end
 
end
 
if match then
 
tpl_args._flags.duplicate_upgraded_from_reference = true
 
tpl_args._errors[#tpl_args._errors+1] = string.format(i18n.errors.upgraded_from_duplicate, j)
 
delete_sets[#delete_sets+1] = j
 
end
 
end
 
end
 
end
 
 
for offset, index in ipairs(delete_sets) do
 
table.remove(sets, index-(offset-1))
 
end
 
--
 
-- Set data
 
--
 
tpl_args.upgrade_from_sets = sets
 
 
-- set upgraded_from data
 
for i, set in ipairs(sets) do
 
tpl_args._subobjects[#tpl_args._subobjects+1] = {
 
_table = 'upgraded_from_sets',
 
set_id = i,
 
text = set.text,
 
automatic = set.automatic,
 
}
 
 
for j, group in ipairs(set.groups) do
 
tpl_args._subobjects[#tpl_args._subobjects+1] = {
 
_table = 'upgraded_from_groups',
 
group_id = j,
 
set_id = i,
 
item_name = group.item_name,
 
item_id = group.item_id,
 
item_page = group.item_page,
 
amount = group.amount,
 
notes = group.notes,
 
}
 
 
end
 
end
 
end
 
end
Строка 1465: Строка 230:
   
 
--
 
--
  +
-- Display
-- function factory
 
 
--
 
--
core.factory = {}
 
   
  +
function h.strip_random_stats(tpl_args, frame, stat_text, container_type)
function core.factory.cast_text(k, args)
 
  +
if tpl_args._flags.random_mods and container_type == 'inline' then
args = args or {}
 
  +
repeat
return function (tpl_args, frame)
 
  +
local text = string.match(stat_text, '<th class="mw%-customtoggle%-31">(.+)</th>')
tpl_args[args.key_out or k] = m_util.cast.text(tpl_args[k])
 
  +
if text ~= nil then
  +
stat_text = string.gsub(stat_text, '<table class="random%-modifier%-stats.+</table>', text, 1)
  +
end
  +
until text == nil
 
end
 
end
  +
return stat_text
 
end
 
end
   
  +
function h.add_to_container_from_map(tpl_args, frame, container, mapping, container_type)
function core.factory.display_value(args)
 
  +
local statcont = mw.html.create('span')
-- args:
 
  +
statcont
-- type: Type of the keys (nil = regular, gem = skill gems, stat = stats)
 
  +
:attr('class', 'item-stats')
-- options<Array>:
 
-- key: key to use
+
:done()
  +
local count = 0 -- Number of groups in container
-- allow_zero: allow zero values
 
  +
for _, group in ipairs(mapping) do
-- hide_default: hide the value if this is set
 
  +
local lines = {}
-- hide_default_key: key to use if it isn't equal to the key parameter
 
-- -- from m_util.html.format_value --
+
if group.func == nil then
-- fmt: formatter to use for the value instead of valfmt
+
for _, line in ipairs(group) do
-- fmt_range: formatter to use for the range values. Default: (%s to %s)
+
local show = true
  +
if container_type == 'inline' and line.inline == false then -- TODO: This is not used currently. Need to address what is hidden in inline view.
-- insert: insert results into this object
 
-- func: Function to adjust the value with before output
+
show = false
  +
elseif line.show == false then
-- color: colour code for m_util.html.poe_color, overrides mod colour
 
-- no_color: set to true to ingore colour entirely
+
show = false
  +
elseif type(line.show) == 'function' then
-- truncate: set to true to truncate the line
 
  +
show = line.show(tpl_args, frame, container_type)
 
for k, default in pairs({options = {}}) do
 
if args[k] == nil then
 
args[k] = default
 
end
 
end
 
 
return function (tpl_args, frame)
 
local base_values = {}
 
local temp_values = {}
 
if args.type == 'gem' then
 
if not core.class_groups.gems.keys[tpl_args.class_id] then
 
return
 
end
 
for i, data in ipairs(args.options) do
 
local value = tpl_args.skill_levels[0][data.key]
 
if value ~= nil then
 
base_values[#base_values+1] = value
 
temp_values[#temp_values+1] = {value={min=value,max=value}, index=i}
 
else
 
value = {
 
min=tpl_args.skill_levels[1][data.key],
 
max=tpl_args.skill_levels[tpl_args.max_level][data.key],
 
}
 
if value.min == nil or value.max == nil then
 
else
 
base_values[#base_values+1] = value.min
 
temp_values[#temp_values+1] = {value=value, index=i}
 
end
 
 
end
 
end
end
+
if show then
  +
lines[#lines+1] = line.func(tpl_args, frame, container_type)
elseif args.type == 'stat' then
 
for i, data in ipairs(args.options) do
 
local value = tpl_args._stats[data.key]
 
if value ~= nil then
 
base_values[i] = value.min
 
temp_values[#temp_values+1] = {value=value, index=i}
 
 
end
 
end
 
end
 
end
 
else
 
else
for i, data in ipairs(args.options) do
+
lines = group.func(tpl_args, frame, container_type)
base_values[i] = tpl_args[data.key]
 
local value = {}
 
if tpl_args[data.key .. '_range_minimum'] ~= nil then
 
value.min = tpl_args[data.key .. '_range_minimum']
 
value.max = tpl_args[data.key .. '_range_maximum']
 
elseif tpl_args[data.key] ~= nil then
 
value.min = tpl_args[data.key]
 
value.max = tpl_args[data.key]
 
end
 
if value.min == nil then
 
else
 
temp_values[#temp_values+1] = {value=value, index=i}
 
end
 
end
 
 
end
 
end
+
if #lines > 0 then
local final_values = {}
+
count = count + 1
for i, data in ipairs(temp_values) do
+
local heading = ''
local opt = args.options[data.index]
+
if group.heading == nil then
local insert = false
+
elseif type(group.heading) == 'function' then
if opt.hide_default == nil then
+
heading = group.heading()
insert = true
 
elseif opt.hide_default_key == nil then
 
local v = data.value
 
if opt.hide_default ~= v.min and opt.hide_default ~= v.max then
 
insert = true
 
end
 
 
else
 
else
local v = {
+
heading = string.format('<em class="header">%s</em><br>', group.heading)
min = tpl_args[opt.hide_default_key .. '_range_minimum'],
 
max = tpl_args[opt.hide_default_key .. '_range_maximum'],
 
}
 
if v.min == nil or v.max == nil then
 
if opt.hide_default ~= tpl_args[opt.hide_default_key] then
 
insert = true
 
end
 
elseif opt.hide_default ~= v.min and opt.hide_default ~= v.max then
 
insert = true
 
end
 
end
 
 
if insert == true then
 
table.insert(final_values, data)
 
 
end
 
end
end
+
statcont
+
:tag('span')
  +
:attr('class', 'group ' .. (group.class or ''))
-- all zeros = dont display and return early
 
  +
:wikitext(heading .. table.concat(lines, '<br>'))
if #final_values == 0 then
 
return nil
+
:done()
end
 
 
local out = {}
 
 
for i, data in ipairs(final_values) do
 
local value = data.value
 
value.base = base_values[data.index]
 
 
local options = args.options[data.index]
 
 
if options.color == nil and args.type == 'gem' then
 
value.color = 'value'
 
end
 
if options.truncate then
 
options.class = 'u-truncate-line'
 
end
 
 
out[#out+1] = m_util.html.format_value(tpl_args, frame, value, options)
 
end
 
 
if args.inline then
 
return m_util.html.poe_color(args.color or 'default', string.format(args.inline, unpack(out)))
 
else
 
return table.concat(out, '')
 
 
end
 
end
 
end
 
end
end
 
   
  +
-- Add groups to container
function core.factory.display_value_only(key)
 
  +
if count > 0 then
return function(tpl_args, frame)
 
return tpl_args[key]
+
container:node(statcont)
 
end
 
end
 
end
 
end
   
  +
function h.make_main_container(tpl_args, frame, container_type)
function core.factory.descriptor_value(args)
 
-- Arguments:
 
-- key
 
-- tbl
 
args = args or {}
 
return function (tpl_args, frame, value)
 
args.tbl = args.tbl or tpl_args
 
if args.tbl[args.key] then
 
value = m_util.html.abbr(value, args.tbl[args.key])
 
end
 
return value
 
end
 
end
 
 
function core.factory.damage_html(args)
 
return function(tpl_args, frame)
 
if args.key ~= 'physical' then
 
args.color = args.key
 
args.no_color = true
 
end
 
local keys = {
 
min=args.key .. '_damage_min',
 
max=args.key .. '_damage_max',
 
}
 
local value = {}
 
 
for ktype, key in pairs(keys) do
 
value[ktype] = core.factory.display_value{options={ [1] = {
 
key = key,
 
no_color = args.no_color,
 
hide_default = 0
 
}}}(tpl_args, frame)
 
end
 
 
if value.min and value.max then
 
value = value.min .. '&ndash;' .. value.max
 
if args.color ~= nil then
 
value = m_util.html.poe_color(args.color, value)
 
end
 
tpl_args[args.key .. '_damage_html'] = value
 
end
 
end
 
end
 
 
--
 
-- Display
 
--
 
core.display = {}
 
 
function core.display.make_main_container(tpl_args, frame, container_type)
 
 
local container = mw.html.create('span')
 
local container = mw.html.create('span')
 
:attr('class', 'item-box -' .. tpl_args.frame_type)
 
:attr('class', 'item-box -' .. tpl_args.frame_type)
Строка 1705: Строка 333:
 
else
 
else
 
local header_css
 
local header_css
  +
local line_type
 
if tpl_args.base_item and tpl_args.rarity_id ~= 'normal' then
 
if tpl_args.base_item and tpl_args.rarity_id ~= 'normal' then
 
line_type = 'double'
 
line_type = 'double'
Строка 1749: Строка 378:
 
:done()
 
:done()
 
 
core.display.add_to_container_from_map(tpl_args, frame, container, core.item_display_groups, container_type)
+
h.add_to_container_from_map(tpl_args, frame, container, c.item_infobox_groups, container_type)
 
end
 
end
 
 
Строка 1759: Строка 388:
 
end
 
end
   
  +
--
function core.display.add_to_container_from_map(tpl_args, frame, container, mapping, container_type)
 
  +
-- Factory
local grpcont
 
  +
--
local valid
 
local statcont = mw.html.create('span')
 
statcont
 
:attr('class', 'item-stats')
 
:done()
 
 
local count = 0
 
 
for _, group in ipairs(mapping) do
 
grpcont = {}
 
if group.func == nil then
 
for _, disp in ipairs(group) do
 
valid = true
 
if container_type == 'inline' and disp.inline == false then
 
valid = false
 
else
 
-- No args to verify which means always valid
 
if disp.args == nil then
 
elseif type(disp.args) == 'table' then
 
for _, key in ipairs(disp.args) do
 
if tpl_args[key] == nil then
 
valid = false
 
break
 
end
 
end
 
elseif type(disp.args) == 'function' then
 
valid = disp.args(tpl_args, frame, container_type)
 
end
 
end
 
if valid then
 
grpcont[#grpcont+1] = disp.func(tpl_args, frame, container_type)
 
end
 
end
 
else
 
grpcont = group.func(tpl_args, frame, container_type)
 
end
 
 
if #grpcont > 0 then
 
count = count + 1
 
local header = ''
 
if group.header == nil then
 
elseif type(group.header) == 'function' then
 
header = group.header()
 
else
 
header = string.format('<em class="header">%s</em><br>', group.header)
 
end
 
statcont
 
:tag('span')
 
:attr('class', 'group ' .. (group.css_class or ''))
 
:wikitext(header .. table.concat(grpcont, '<br>'))
 
:done()
 
end
 
end
 
 
-- Don't add empty containers
 
if count > 0 then
 
container:node(statcont)
 
end
 
end
 
   
  +
h.factory = {}
function core.display.strip_random_stats(tpl_args, frame, stat_text, container_type)
 
if tpl_args._flags.random_mods and container_type == 'inline' then
 
repeat
 
local text = string.match(stat_text, '<th class="mw%-customtoggle%-31">(.+)</th>')
 
if text ~= nil then
 
stat_text = string.gsub(stat_text, '<table class="random%-modifier%-stats.+</table>', text, 1)
 
end
 
until text == nil
 
end
 
return stat_text
 
end
 
   
  +
function h.factory.maybe_show_infobox_line(args)
--
 
  +
-- Verifies that a list of keys are present in tpl_args and that the item
-- argument mapping
 
  +
-- should use those keys. Returns true if all conditions are met, otherwise
--
 
  +
-- returns false.
-- format:
 
  +
return function (tpl_args)
-- tpl_args key = {
 
  +
local keys = args.keys or {}
-- no_copy = true or nil -- When loading an base item, dont copy this key
 
  +
local conditions = args.conditions or {}
-- property = 'prop', -- Property associated with this key
 
  +
if #keys == 0 then
-- property_func = function or nil -- Function to unpack the property into a native lua value.
 
-- If not specified, func is used.
 
-- If neither is specified, value is copied as string
 
-- func = function or nil -- Function to unpack the argument into a native lua value and validate it.
 
-- If not specified, value will not be set.
 
-- default = object -- Default value if the parameter is nil
 
-- }
 
core.map = {
 
-- special params
 
html = {
 
no_copy = true,
 
field = 'html',
 
type = 'Text',
 
func = nil,
 
},
 
html_extra = {
 
no_copy = true,
 
field = 'html_extra',
 
type = 'Text',
 
func = nil,
 
},
 
implicit_stat_text = {
 
field = 'implicit_stat_text',
 
type = 'Text',
 
func = function(tpl_args, frame)
 
tpl_args.implicit_stat_text = core.process_mod_stats(tpl_args, {is_implicit=true})
 
end,
 
},
 
explicit_stat_text = {
 
field = 'explicit_stat_text',
 
type = 'Text',
 
func = function(tpl_args, frame)
 
tpl_args.explicit_stat_text = core.process_mod_stats(tpl_args, {is_implicit=false})
 
 
if tpl_args.is_talisman or tpl_args.is_corrupted then
 
if tpl_args.explicit_stat_text == nil or tpl_args.explicit_stat_text == '' then
 
tpl_args.explicit_stat_text = i18n.tooltips.corrupted
 
else
 
tpl_args.explicit_stat_text = (tpl_args.explicit_stat_text or '') .. '<br>' .. i18n.tooltips.corrupted
 
end
 
end
 
end,
 
},
 
stat_text = {
 
field = 'stat_text',
 
type = 'Text',
 
func = function(tpl_args, frame)
 
local sep = ''
 
if tpl_args.implicit_stat_text and tpl_args.explicit_stat_text then
 
sep = string.format('<span class="item-stat-separator -%s"></span>', tpl_args.frame_type)
 
end
 
local text = (tpl_args.implicit_stat_text or '') .. sep .. (tpl_args.explicit_stat_text or '')
 
 
if string.len(text) > 0 then
 
tpl_args.stat_text = text
 
end
 
end,
 
},
 
class = {
 
no_copy = true,
 
field = 'class',
 
type = 'String',
 
func = function (tpl_args, frame)
 
tpl_args.class = m_game.constants.item.classes[tpl_args.class_id]['long_upper']
 
-- Avoids errors with empty item class names later on
 
if tpl_args.class == '' then
 
tpl_args.class = nil
 
end
 
end,
 
},
 
-- processed in core.build_item_classes
 
class_id = {
 
no_copy = true,
 
field = 'class_id',
 
type = 'String',
 
func = function (tpl_args, frame)
 
if m_game.constants.item.classes[tpl_args.class_id] == nil then
 
error(string.format(i18n.errors.invalid_class_id, tostring(tpl_args.class_id)))
 
end
 
end
 
},
 
-- generic
 
rarity_id = {
 
no_copy = true,
 
field = 'rarity_id',
 
type = 'String',
 
func = function (tpl_args, frame)
 
if m_game.constants.rarities[tpl_args.rarity_id] == nil then
 
error(string.format(i18n.errors.invalid_rarity_id, tostring(tpl_args.rarity_id)))
 
end
 
end
 
},
 
rarity = {
 
no_copy = true,
 
field = 'rarity',
 
type = 'String',
 
func = function(tpl_args, frame)
 
tpl_args.rarity = m_game.constants.rarities[tpl_args.rarity_id]['long_upper']
 
end
 
},
 
name = {
 
no_copy = true,
 
field = 'name',
 
type = 'String',
 
func = nil,
 
},
 
size_x = {
 
field = 'size_x',
 
type = 'Integer',
 
func = m_util.cast.factory.number('size_x'),
 
},
 
size_y = {
 
field = 'size_y',
 
type = 'Integer',
 
func = m_util.cast.factory.number('size_y'),
 
},
 
drop_rarities_ids = {
 
no_copy = true,
 
field = 'drop_rarity_ids',
 
type = 'List (,) of Text',
 
func = function(tpl_args, frame)
 
tpl_args.drop_rarities_ids = nil
 
if true then return end
 
-- Drop rarities only matter for base items.
 
if tpl_args.rarity_id ~= 'normal' then
 
return
 
end
 
 
if tpl_args.drop_rarities_ids == nil then
 
tpl_args.drop_rarities_ids = {}
 
return
 
end
 
 
tpl_args.drop_rarities_ids = m_util.string.split(tpl_args.drop_rarities_ids, ',%s*')
 
for _, rarity_id in ipairs(tpl_args.drop_rarities_ids) do
 
if m_game.constants.rarities[rarity_id] == nil then
 
error(string.format(i18n.errors.invalid_rarity_id, tostring(rarity_id)))
 
end
 
end
 
end,
 
},
 
drop_rarities = {
 
no_copy = true,
 
field = nil,
 
type = 'List (,) of Text',
 
func = function(tpl_args, frame)
 
tpl_args.drop_rarities = nil
 
if true then return end
 
-- Drop rarities only matter for base items.
 
if tpl_args.rarity_id ~= 'normal' then
 
return
 
end
 
 
local rarities = {}
 
for _, rarity_id in ipairs(tpl_args.drop_rarities_ids) do
 
rarities[#rarities+1] = m_game.constants.rarities[rarity_id].full
 
end
 
tpl_args.drop_rarities = rarities
 
end,
 
},
 
drop_enabled = {
 
no_copy = true,
 
field = 'drop_enabled',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('drop_enabled'),
 
default = true,
 
},
 
drop_level = {
 
no_copy = true,
 
field = 'drop_level',
 
type = 'Integer',
 
func = m_util.cast.factory.number('drop_level'),
 
},
 
drop_level_maximum = {
 
no_copy = true,
 
field = 'drop_level_maximum',
 
type = 'Integer',
 
func = m_util.cast.factory.number('drop_level_maximum'),
 
},
 
drop_leagues = {
 
no_copy = true,
 
field = 'drop_leagues',
 
type = 'List (,) of String',
 
func = m_util.cast.factory.assoc_table('drop_leagues', {tbl=m_game.constants.leagues, errmsg=i18n.errors.invalid_league}),
 
},
 
drop_areas = {
 
no_copy = true,
 
field = 'drop_areas',
 
type = 'List (,) of String',
 
func = function(tpl_args, frame)
 
if tpl_args.drop_areas ~= nil then
 
tpl_args.drop_areas = m_util.string.split(tpl_args.drop_areas, ',%s*')
 
tpl_args.drop_areas_data = m_cargo.array_query{
 
tables={'areas'},
 
fields={'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'},
 
id_field='areas.id',
 
id_array=tpl_args.drop_areas,
 
query={limit=5000},
 
}
 
end
 
 
-- find areas based on item tags for atlas bases
 
local query_data
 
for _, tag in ipairs(tpl_args.tags or {}) do
 
query_data = nil
 
if string.match(tag, '[%w_]*atlas[%w_]*') ~= nil and tag ~= 'atlas_base_type' then
 
query_data = m_cargo.query(
 
{'atlas_maps', 'maps', 'areas', 'atlas_base_item_types'},
 
{'areas._pageName', 'areas.id', 'areas.name', 'areas.main_page'},
 
{
 
join='atlas_maps._pageID=maps._pageID, maps.area_id=areas.id, atlas_maps.region_id=atlas_base_item_types.region_id',
 
where=string.format([[
 
atlas_base_item_types.tag = "%s"
 
AND atlas_base_item_types.weight > 0
 
AND (
 
atlas_maps.map_tier0 >= tier_min AND atlas_maps.map_tier0 <= atlas_base_item_types.tier_max
 
OR atlas_maps.map_tier1 >= tier_min AND atlas_maps.map_tier1 <= atlas_base_item_types.tier_max
 
OR atlas_maps.map_tier2 >= tier_min AND atlas_maps.map_tier2 <= atlas_base_item_types.tier_max
 
OR atlas_maps.map_tier3 >= tier_min AND atlas_maps.map_tier3 <= atlas_base_item_types.tier_max
 
OR atlas_maps.map_tier4 >= tier_min AND atlas_maps.map_tier4 <= atlas_base_item_types.tier_max
 
)]],
 
tag),
 
groupBy='areas.id',
 
}
 
)
 
end
 
 
if query_data ~= nil then
 
-- in case no manual drop areas have been set
 
if tpl_args.drop_areas == nil then
 
tpl_args.drop_areas = {}
 
tpl_args.drop_areas_data = {}
 
end
 
local drop_areas_assoc = {}
 
for _, id in ipairs(tpl_args.drop_areas) do
 
drop_areas_assoc[id] = true
 
end
 
 
local duplicates = {}
 
 
for _, row in ipairs(query_data) do
 
if drop_areas_assoc[row['areas.id']] == nil then
 
tpl_args.drop_areas[#tpl_args.drop_areas+1] = row['areas.id']
 
tpl_args.drop_areas_data[#tpl_args.drop_areas_data+1] = row
 
else
 
duplicates[#duplicates+1] = row['areas.id']
 
end
 
end
 
 
if #duplicates > 0 then
 
tpl_args._errors[#tpl_args._errors+1] = string.format(i18n.errors.duplicate_area_id_from_query, table.concat(duplicates, ', '))
 
tpl_args._flags.duplicate_query_area_ids = true
 
end
 
end
 
end
 
end,
 
},
 
drop_monsters = {
 
no_copy = true,
 
field = 'drop_monsters',
 
type = 'List (,) of Text',
 
func = function (tpl_args, frame)
 
if tpl_args.drop_monsters ~= nil then
 
tpl_args.drop_monsters = m_util.string.split(tpl_args.drop_monsters, ',%s*')
 
end
 
end,
 
},
 
drop_text = {
 
no_copy = true,
 
field = 'drop_text',
 
type = 'Text',
 
func = core.factory.cast_text('drop_text'),
 
},
 
required_level = {
 
field = 'required_level_base',
 
type = 'Integer',
 
func = m_util.cast.factory.number('required_level'),
 
default = 1,
 
},
 
required_level_final = {
 
field = 'required_level',
 
type = 'Integer',
 
func = function(tpl_args, frame)
 
tpl_args.required_level_final = tpl_args.required_level
 
end,
 
default = 1,
 
},
 
required_dexterity = {
 
field = 'required_dexterity',
 
type = 'Integer',
 
func = m_util.cast.factory.number('required_dexterity'),
 
default = 0,
 
},
 
required_strength = {
 
field = 'required_strength',
 
type = 'Integer',
 
func = m_util.cast.factory.number('required_strength'),
 
default = 0,
 
},
 
required_intelligence = {
 
field = 'required_intelligence',
 
type = 'Integer',
 
func = m_util.cast.factory.number('required_intelligence'),
 
default = 0,
 
},
 
inventory_icon = {
 
no_copy = true,
 
field = 'inventory_icon',
 
type = 'String',
 
func = function(tpl_args, frame)
 
if tpl_args.class_id == 'DivinationCard' then
 
tpl_args.inventory_icon = tpl_args.inventory_icon or 'Divination card'
 
end
 
tpl_args.inventory_icon_id = tpl_args.inventory_icon or tpl_args.name
 
tpl_args.inventory_icon = string.format(i18n.inventory_icon, tpl_args.inventory_icon_id)
 
end,
 
},
 
-- note: this must be called after inventory item to work correctly as it depends on tpl_args.inventory_icon_id being set
 
alternate_art_inventory_icons = {
 
no_copy = true,
 
field = 'alternate_art_inventory_icons',
 
type = 'List (,) of String',
 
func = function(tpl_args, frame)
 
local icons = {}
 
if tpl_args.alternate_art_inventory_icons ~= nil then
 
local names = m_util.string.split(tpl_args.alternate_art_inventory_icons, ',%s*')
 
 
for _, name in ipairs(names) do
 
icons[#icons+1] = string.format(i18n.inventory_icon, string.format('%s %s', tpl_args.inventory_icon_id, name))
 
end
 
end
 
tpl_args.alternate_art_inventory_icons = icons
 
end,
 
default = function (tpl_args, frame) return {} end,
 
},
 
cannot_be_traded_or_modified = {
 
no_copy = true,
 
field = 'cannot_be_traded_or_modified',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('cannot_be_traded_or_modified'),
 
default = false,
 
},
 
help_text = {
 
debug_ignore_nil = true,
 
field = 'help_text',
 
type = 'Text',
 
func = core.factory.cast_text('help_text'),
 
},
 
flavour_text = {
 
no_copy = true,
 
field = 'flavour_text',
 
type = 'Text',
 
func = core.factory.cast_text('flavour_text'),
 
},
 
flavour_text_id = {
 
no_copy = true,
 
field = 'flavour_text_id',
 
type = 'String',
 
func = nil,
 
},
 
tags = {
 
field = 'tags',
 
type = 'List (,) of String',
 
func = m_util.cast.factory.assoc_table('tags', {
 
tbl = m_game.constants.tags,
 
errmsg = i18n.errors.invalid_tag,
 
}),
 
},
 
metadata_id = {
 
no_copy = true,
 
field = 'metadata_id',
 
type = 'String',
 
--type = 'String(unique; size=200)',
 
func = function(tpl_args, frame)
 
if tpl_args.metadata_id == nil then
 
return
 
end
 
local results = m_cargo.query(
 
{'items'},
 
{'items._pageName'},
 
{
 
where=string.format('items.metadata_id="%s" AND items._pageName != "%s"', tpl_args.metadata_id, mw.title.getCurrentTitle().fullText)
 
}
 
)
 
if #results > 0 and tpl_args.debug_id == nil and not tpl_args.debug then
 
error(string.format(i18n.errors.duplicate_metadata, tpl_args.metadata_id, results[1]['items._pageName']))
 
end
 
end,
 
},
 
influences = {
 
no_copy = true,
 
field = 'influences',
 
type = 'List (,) of String',
 
func = m_util.cast.factory.assoc_table('influences', {
 
tbl = m_game.constants.influences,
 
errmsg = i18n.errors.invalid_influence,
 
}),
 
},
 
is_fractured = {
 
no_copy = true,
 
field = 'is_fractured',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('is_fractured'),
 
default = false,
 
},
 
is_synthesised = {
 
no_copy = true,
 
field = 'is_synthesised',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('is_synthesised'),
 
default = false,
 
},
 
is_veiled = {
 
no_copy = true,
 
field = 'is_veiled',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('is_veiled'),
 
default = false,
 
},
 
is_replica = {
 
no_copy = true,
 
field = 'is_replica',
 
type = 'Boolean',
 
func = function(tpl_args, frame)
 
m_util.cast.factory.boolean('is_replica')(tpl_args, frame)
 
if tpl_args.is_replica == true and tpl_args.rarity_id ~= 'unique' then
 
error(string.format(i18n.errors.non_unique_flag, 'is_replica'))
 
end
 
end,
 
default = false,
 
},
 
is_corrupted = {
 
no_copy = true,
 
field = 'is_corrupted',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('is_corrupted'),
 
default = false,
 
},
 
is_relic = {
 
no_copy = true,
 
field = 'is_relic',
 
type = 'Boolean',
 
func = function(tpl_args, frame)
 
m_util.cast.factory.boolean('is_relic')(tpl_args, frame)
 
if tpl_args.is_relic == true and tpl_args.rarity_id ~= 'unique' then
 
error(string.format(i18n.errors.non_unique_flag, 'is_relic'))
 
end
 
end,
 
default = false,
 
},
 
is_fated = {
 
no_copy = true,
 
field = 'is_fated',
 
type = 'Boolean',
 
func = function(tpl_args, frame)
 
m_util.cast.factory.boolean('is_fated')(tpl_args, frame)
 
if tpl_args.is_fated == true and tpl_args.rarity_id ~= 'unique' then
 
error(string.format(i18n.errors.non_unique_flag, 'is_fated'))
 
end
 
end,
 
default = false,
 
},
 
is_prophecy = {
 
no_copy = true,
 
field = nil,
 
type = nil,
 
func = function(tpl_args, frame)
 
tpl_args._flags.is_prophecy = (tpl_args.metadata_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy' or tpl_args.base_item == 'Пророчество' or tpl_args.base_item_page == 'Пророчество' or tpl_args.base_item_id == 'Metadata/Items/Currency/CurrencyItemisedProphecy')
 
end
 
},
 
is_blight_item = {
 
no_copy = true,
 
field = nil,
 
type = nil,
 
func = function(tpl_args, frame)
 
tpl_args._flags.is_blight_item = (tpl_args.blight_item_tier ~= nil)
 
end
 
},
 
is_drop_restricted = {
 
no_copy = true,
 
field = 'is_drop_restricted',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('is_drop_restricted'),
 
default = function(tpl_args, frame)
 
-- Generally items that are obtained only from specific monsters can't be obtained via cards or other means unless specifically specified
 
for _, var in ipairs({'is_talisman', 'is_fated', 'is_relic', 'drop_monsters'}) do
 
if tpl_args[var] then
 
return true
 
end
 
end
 
for _, flag in ipairs({'is_prophecy', 'is_blight_item'}) do
 
if tpl_args._flags[flag] then
 
return true
 
end
 
end
 
 
return false
 
return false
end,
 
},
 
purchase_costs = {
 
func = function(tpl_args, frame)
 
local purchase_costs = {}
 
for _, rarity_id in ipairs(m_game.constants.rarity_order) do
 
local rtbl = {}
 
local prefix = string.format('purchase_cost_%s', rarity_id)
 
local i = 1
 
while i ~= -1 do
 
local iprefix = prefix .. i
 
local values = {
 
name = tpl_args[iprefix .. '_name'],
 
amount = tonumber(tpl_args[iprefix .. '_amount']),
 
rarity = rarity_id,
 
}
 
if values.name ~= nil and values.amount ~= nil then
 
rtbl[#rtbl+1] = values
 
i = i + 1
 
 
tpl_args._subobjects[#tpl_args._subobjects+1] = {
 
_table = 'item_purchase_costs',
 
amount = values.amount,
 
name = values.name,
 
rarity = values.rarity,
 
}
 
else
 
i = -1
 
end
 
end
 
 
purchase_costs[rarity_id] = rtbl
 
end
 
 
tpl_args.purchase_costs = purchase_costs
 
end,
 
func_fetch = function(tpl_args, frame)
 
if tpl_args.rarity_id ~= 'unique' then
 
return
 
end
 
 
local results = m_cargo.query(
 
{'items' ,'item_purchase_costs'},
 
{'item_purchase_costs.amount', 'item_purchase_costs.name', 'item_purchase_costs.rarity'},
 
{
 
join = 'items._pageID=item_purchase_costs._pageID',
 
where = string.format('items._pageName="%s" AND item_purchase_costs.rarity="unique"', tpl_args.base_item_page),
 
}
 
)
 
 
for _, row in ipairs(results) do
 
local values = {
 
rarity = row['item_purchase_costs.rarity'],
 
name = row['item_purchase_costs.name'],
 
amount = tonumber(row['item_purchase_costs.amount']),
 
}
 
local datavar = tpl_args.purchase_costs[string.lower(values.rarity)]
 
datavar[#datavar+1] = values
 
 
tpl_args._subobjects[#tpl_args._subobjects+1] = {
 
_table = 'item_purchase_costs',
 
amount = values.amount,
 
name = values.name,
 
rarity = values.rarity,
 
}
 
end
 
end,
 
},
 
sell_prices_override = {
 
no_copy = true,
 
func = function(tpl_args, frame)
 
-- these variables are also used by mods when setting automatic sell prices
 
tpl_args.sell_prices = {}
 
tpl_args.sell_price_order = {}
 
 
 
local name
 
local amount
 
local i = 0
 
repeat
 
i = i + 1
 
name = tpl_args[string.format('sell_price%s_name', i)]
 
amount = tpl_args[string.format('sell_price%s_amount', i)]
 
 
if name ~= nil and amount ~= nil then
 
tpl_args.sell_price_order[#tpl_args.sell_price_order+1] = name
 
tpl_args.sell_prices[name] = amount
 
tpl_args._subobjects[#tpl_args._subobjects+1] = {
 
_table = 'item_sell_prices',
 
amount = amount,
 
name = name,
 
}
 
end
 
until name == nil or amount == nil
 
 
-- if sell prices are set, the override is active
 
for _, _ in pairs(tpl_args.sell_prices) do
 
tpl_args._flags.sell_prices_override = true
 
break
 
end
 
end,
 
},
 
--
 
-- specific section
 
--
 
 
-- Most item classes
 
quality = {
 
no_copy = true,
 
field = 'quality',
 
type = 'Integer',
 
-- Can be set manually, but default to Q20 for unique weapons/body armours
 
-- Also must copy to stat for the stat adjustments to work properly
 
func = function(tpl_args, frame)
 
local quality = tonumber(tpl_args.quality)
 
--
 
if quality == nil then
 
if tpl_args.rarity_id ~= 'unique' then
 
quality = 0
 
elseif core.class_groups.weapons.keys[tpl_args.class_id] or core.class_groups.armor.keys[tpl_args.class_id] then
 
quality = 20
 
else
 
quality = 0
 
end
 
end
 
 
tpl_args.quality = quality
 
 
local stat = {
 
min = quality,
 
max = quality,
 
avg = quality,
 
}
 
 
h.stats_update(tpl_args, 'quality', stat, nil, '_stats')
 
 
if tpl_args.class_id == 'UtilityFlask' or tpl_args.class_id == 'UtilityFlaskCritical' then
 
h.stats_update(tpl_args, 'quality_flask_duration', stat, nil, '_stats')
 
-- quality is added to quantity for maps
 
elseif tpl_args.class_id == 'Map' then
 
h.stats_update(tpl_args, 'map_item_drop_quantity_+%', stat, nil, '_stats')
 
end
 
end,
 
},
 
-- amulets
 
is_talisman = {
 
field = 'is_talisman',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('is_talisman'),
 
default = false,
 
},
 
 
talisman_tier = {
 
field = 'talisman_tier',
 
type = 'Integer',
 
func = m_util.cast.factory.number('talisman_tier'),
 
},
 
 
-- flasks
 
charges_max = {
 
field = 'charges_max',
 
type = 'Integer',
 
func = m_util.cast.factory.number('charges_max'),
 
},
 
charges_per_use = {
 
field = 'charges_per_use',
 
type = 'Integer',
 
func = m_util.cast.factory.number('charges_per_use'),
 
},
 
flask_mana = {
 
field = 'mana',
 
type = 'Integer',
 
func = m_util.cast.factory.number('flask_mana'),
 
},
 
flask_life = {
 
field = 'life',
 
type = 'Integer',
 
func = m_util.cast.factory.number('flask_life'),
 
},
 
flask_duration = {
 
field = 'duration',
 
type = 'Float',
 
func = m_util.cast.factory.number('flask_duration'),
 
},
 
buff_id = {
 
field = 'id',
 
type = 'String',
 
func = nil,
 
},
 
buff_values = {
 
field = 'buff_values',
 
type = 'List (,) of Integer',
 
func = function(tpl_args, frame)
 
local values = {}
 
local i = 0
 
repeat
 
i = i + 1
 
local key = 'buff_value' .. i
 
values[i] = tonumber(tpl_args[key])
 
tpl_args[key] = nil
 
until values[i] == nil
 
 
-- needed so the values copyied from unique item base isn't overriden
 
if #values >= 1 then
 
tpl_args.buff_values = values
 
end
 
end,
 
func_copy = function(tpl_args, frame)
 
tpl_args.buff_values = m_util.string.split(tpl_args.buff_values, ',%s*')
 
end,
 
default = function (tpl_args, frame) return {} end,
 
},
 
buff_stat_text = {
 
field = 'stat_text',
 
type = 'String',
 
func = nil,
 
},
 
buff_icon = {
 
field = 'icon',
 
type = 'String',
 
func = function(tpl_args, frame)
 
tpl_args.buff_icon = string.format(i18n.status_icon, tpl_args.name)
 
end,
 
},
 
 
-- weapons
 
critical_strike_chance = {
 
field = 'critical_strike_chance',
 
type = 'Float',
 
func = m_util.cast.factory.number('critical_strike_chance'),
 
},
 
attack_speed = {
 
field = 'attack_speed',
 
type = 'Float',
 
func = m_util.cast.factory.number('attack_speed'),
 
},
 
weapon_range = {
 
field = 'weapon_range',
 
type = 'Integer',
 
func = m_util.cast.factory.number('weapon_range'),
 
},
 
physical_damage_min = {
 
field = 'physical_damage_min',
 
type = 'Integer',
 
func = m_util.cast.factory.number('physical_damage_min'),
 
},
 
physical_damage_max = {
 
field = 'physical_damage_max',
 
type = 'Integer',
 
func = m_util.cast.factory.number('physical_damage_max'),
 
},
 
fire_damage_min = {
 
field = 'fire_damage_min',
 
type = 'Integer',
 
func = m_util.cast.factory.number('fire_damage_min'),
 
default = 0,
 
},
 
fire_damage_max = {
 
field = 'fire_damage_max',
 
type = 'Integer',
 
func = m_util.cast.factory.number('fire_damage_max'),
 
default = 0,
 
},
 
cold_damage_min = {
 
field = 'cold_damage_min',
 
type = 'Integer',
 
func = m_util.cast.factory.number('cold_damage_min'),
 
default = 0,
 
},
 
cold_damage_max = {
 
field = 'cold_damage_max',
 
type = 'Integer',
 
func = m_util.cast.factory.number('cold_damage_max'),
 
default = 0,
 
},
 
lightning_damage_min = {
 
field = 'lightning_damage_min',
 
type = 'Integer',
 
func = m_util.cast.factory.number('lightning_damage_min'),
 
default = 0,
 
},
 
lightning_damage_max = {
 
field = 'lightning_damage_max',
 
type = 'Integer',
 
func = m_util.cast.factory.number('lightning_damage_max'),
 
default = 0,
 
},
 
chaos_damage_min = {
 
field = 'chaos_damage_min',
 
type = 'Integer',
 
func = m_util.cast.factory.number('chaos_damage_min'),
 
default = 0,
 
},
 
chaos_damage_max = {
 
field = 'chaos_damage_max',
 
type = 'Integer',
 
func = m_util.cast.factory.number('chaos_damage_max'),
 
default = 0,
 
},
 
-- armor-type stuff
 
armour = {
 
field = 'armour',
 
type = 'Integer',
 
func = m_util.cast.factory.number('armour'),
 
default = 0,
 
},
 
energy_shield = {
 
field = 'energy_shield',
 
type = 'Integer',
 
func = m_util.cast.factory.number('energy_shield'),
 
default = 0,
 
},
 
evasion = {
 
field = 'evasion',
 
type = 'Integer',
 
func = m_util.cast.factory.number('evasion'),
 
default = 0,
 
},
 
-- This is the inherent penality from the armour piece if any
 
movement_speed = {
 
field = 'movement_speed',
 
type = 'Integer',
 
func = m_util.cast.factory.number('movement_speed'),
 
default = 0,
 
},
 
-- shields
 
block = {
 
field = 'block',
 
type = 'Integer',
 
func = m_util.cast.factory.number('block'),
 
},
 
-- skill gem stuff
 
gem_description = {
 
field = 'gem_description',
 
type = 'Text',
 
func = core.factory.cast_text('gem_description'),
 
},
 
dexterity_percent = {
 
field = 'dexterity_percent',
 
type = 'Integer',
 
func = m_util.cast.factory.percentage('dexterity_percent'),
 
},
 
strength_percent = {
 
field = 'strength_percent',
 
type = 'Integer',
 
func = m_util.cast.factory.percentage('strength_percent'),
 
},
 
intelligence_percent = {
 
field = 'intelligence_percent',
 
type = 'Integer',
 
func = m_util.cast.factory.percentage('intelligence_percent'),
 
},
 
primary_attribute = {
 
field = 'primary_attribute',
 
type = 'String',
 
func = function(tpl_args, frame)
 
for _, attr in ipairs(m_game.constants.attribute_order) do
 
local val = tpl_args[attr .. '_percent']
 
if val and val >= 60 then
 
tpl_args['primary_attribute'] = attr
 
return
 
end
 
end
 
tpl_args['primary_attribute'] = 'none'
 
end,
 
},
 
gem_tags = {
 
field = 'gem_tags',
 
type = 'List (,) of String',
 
-- TODO: default rework
 
func = function(tpl_args, frame)
 
if tpl_args.gem_tags then
 
tpl_args.gem_tags = m_util.string.split(tpl_args.gem_tags, ',%s*')
 
end
 
end,
 
default = function (tpl_args, frame) return {} end,
 
},
 
-- Support gems only
 
support_gem_letter = {
 
field = 'support_gem_letter',
 
type = 'String(size=1)',
 
func = nil,
 
},
 
support_gem_letter_html = {
 
field = 'support_gem_letter_html',
 
type = 'Text',
 
func = function(tpl_args, frame)
 
if tpl_args.support_gem_letter == nil then
 
return
 
end
 
 
-- TODO replace this with a loop possibly
 
local css_map = {
 
strength = 'red',
 
intelligence = 'blue',
 
dexterity = 'green',
 
}
 
local id
 
for k, v in pairs(css_map) do
 
k = string.format('%s_percent', k)
 
if tpl_args[k] and tpl_args[k] > 50 then
 
id = v
 
break
 
end
 
end
 
 
if id ~= nil then
 
local container = mw.html.create('span')
 
container
 
:attr('class', string.format('support-gem-id-%s', id))
 
:wikitext(tpl_args.support_gem_letter)
 
:done()
 
tpl_args.support_gem_letter_html = tostring(container)
 
end
 
end,
 
},
 
--
 
-- Maps
 
--
 
map_tier = {
 
field = 'tier',
 
type = 'Integer',
 
func = m_util.cast.factory.number('map_tier'),
 
},
 
map_guild_character = {
 
field = 'guild_character',
 
type = 'String(size=1)',
 
func = nil,
 
},
 
map_area_id = {
 
field = 'area_id',
 
type = 'String',
 
func = nil, -- TODO: Validate against a query?
 
},
 
map_area_level = {
 
field = 'area_level',
 
type = 'Integer',
 
func = m_util.cast.factory.number('map_area_level'),
 
},
 
unique_map_guild_character = {
 
field = 'unique_guild_character',
 
type = 'String(size=1)',
 
func_copy = function(tpl_args, frame)
 
tpl_args.map_guild_character = tpl_args.unique_map_guild_character
 
end,
 
func = nil,
 
},
 
unique_map_area_id = {
 
field = 'unique_area_id',
 
type = 'String',
 
func = nil, -- TODO: Validate against a query?
 
func_copy = function(tpl_args, frame)
 
tpl_args.map_area_id = tpl_args.unique_map_area_id
 
end,
 
},
 
unique_map_area_level = {
 
field = 'unique_area_level',
 
type = 'Integer',
 
func = m_util.cast.factory.number('unique_map_area_level'),
 
func_copy = function(tpl_args, frame)
 
tpl_args.map_area_level = tpl_args.unique_map_area_level
 
end,
 
},
 
map_series = {
 
field = 'series',
 
type = 'String',
 
func = function(tpl_args, frame)
 
if tpl_args.rarity == 'normal' and tpl_args.map_series == nil then
 
error(string.format(i18n.errors.generic_required_parameter, 'map_series'))
 
end
 
end,
 
},
 
-- atlas info is only for the current map series
 
atlas_x = {
 
field = 'x',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_x'),
 
},
 
atlas_y = {
 
field = 'y',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_y'),
 
},
 
atlas_region_id = {
 
field = 'region_id',
 
type = 'String',
 
func = nil,
 
},
 
atlas_region_minimum = {
 
field = 'region_minimum',
 
type = 'Integer',
 
func = m_util.cast.factory.number('atlas_region_minimum'),
 
},
 
atlas_x0 = {
 
field = 'x0',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_x0'),
 
},
 
atlas_x1 = {
 
field = 'x1',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_x1'),
 
},
 
atlas_x2 = {
 
field = 'x2',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_x2'),
 
},
 
atlas_x3 = {
 
field = 'x3',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_x3'),
 
},
 
atlas_x4 = {
 
field = 'x4',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_x4'),
 
},
 
atlas_y0 = {
 
field = 'y0',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_0'),
 
},
 
atlas_y1 = {
 
field = 'y1',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_y1'),
 
},
 
atlas_y2 = {
 
field = 'y2',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_y2'),
 
},
 
atlas_y3 = {
 
field = 'y3',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_y3'),
 
},
 
atlas_y4 = {
 
field = 'y4',
 
type = 'Float',
 
func = m_util.cast.factory.number('atlas_y4'),
 
},
 
atlas_map_tier0 = {
 
field = 'map_tier0',
 
type = 'Integer',
 
func = m_util.cast.factory.number('atlas_map_tier0'),
 
},
 
atlas_map_tier1 = {
 
field = 'map_tier1',
 
type = 'Integer',
 
func = m_util.cast.factory.number('atlas_map_tier1'),
 
},
 
atlas_map_tier2 = {
 
field = 'map_tier2',
 
type = 'Integer',
 
func = m_util.cast.factory.number('atlas_map_tier2'),
 
},
 
atlas_map_tier3 = {
 
field = 'map_tier3',
 
type = 'Integer',
 
func = m_util.cast.factory.number('atlas_map_tier3'),
 
},
 
atlas_map_tier4 = {
 
field = 'map_tier4',
 
type = 'Integer',
 
func = m_util.cast.factory.number('atlas_map_tier4'),
 
},
 
atlas_connections = {
 
field = nil,
 
type = nil,
 
func = function(tpl_args, frame)
 
tpl_args.atlas_connections = {}
 
 
local cont = true
 
local i = 1
 
while cont do
 
local prefix = string.format('atlas_connection%s_', i)
 
local regions = tpl_args[prefix .. 'tier']
 
local data = {
 
_table = 'atlas_connections',
 
map1 = string.format('%s (%s)', tpl_args.name, tpl_args.map_series or ''),
 
map2 = tpl_args[prefix .. 'target'],
 
}
 
 
if regions and data.map2 then
 
regions = m_util.string.split(regions, ',%s*')
 
if #regions ~= 5 then
 
error(string.format(i18n.errors.invalid_region_upgrade_count, i, #regions))
 
end
 
for index, value in ipairs(regions) do
 
data['region' .. (index - 1)] = m_util.cast.boolean(value)
 
end
 
 
tpl_args.atlas_connections[data.map2] = data
 
table.insert(tpl_args._subobjects, data)
 
else
 
cont = false
 
if i == 1 then
 
tpl_args.atlas_connections = nil
 
end
 
end
 
 
i = i + 1
 
end
 
end,
 
default = nil,
 
},
 
--
 
-- Currency-like items
 
--
 
stack_size = {
 
field = 'stack_size',
 
type = 'Integer',
 
func = m_util.cast.factory.number('stack_size'),
 
},
 
stack_size_currency_tab = {
 
field = 'stack_size_currency_tab',
 
type = 'Integer',
 
func = m_util.cast.factory.number('stack_size_currency_tab'),
 
},
 
description = {
 
field = 'description',
 
type = 'Text',
 
func = core.factory.cast_text('description'),
 
},
 
cosmetic_type = {
 
field = 'cosmetic_type',
 
type = 'String',
 
func = core.factory.cast_text('cosmetic_type'),
 
},
 
-- for essences
 
is_essence = {
 
field = nil,
 
func = m_util.cast.factory.boolean('is_essence'),
 
default = false,
 
},
 
essence_level_restriction = {
 
field = 'level_restriction',
 
type = 'Integer',
 
func = m_util.cast.factory.number('essence_level_restriction'),
 
},
 
essence_level = {
 
field = 'level',
 
type = 'Integer',
 
func = m_util.cast.factory.number('essence_level'),
 
},
 
essence_type = {
 
field = 'type',
 
type = 'Integer',
 
func = m_util.cast.factory.number('essence_type'),
 
},
 
essence_category = {
 
field = 'category',
 
type = 'String',
 
func = nil,
 
},
 
-- blight crafting items (i.e. oils)
 
blight_item_tier = {
 
field = 'tier',
 
type = 'Integer',
 
func = m_util.cast.factory.number('blight_item_tier'),
 
},
 
-- harvest seeds
 
seed_type_id = {
 
field = 'type_id',
 
type = 'String',
 
},
 
seed_type = {
 
field = 'type',
 
type = 'String',
 
func = function (tpl_args, frame)
 
if tpl_args.seed_type_id ~= 'none' or tpl_args.seed_type_id ~= nil then
 
tpl_args.seed_type = m_game.seed_types[tpl_args.seed_type_id]
 
end
 
 
end
 
end
  +
for _, k in ipairs(keys) do
},
 
  +
if tpl_args[k] == nil then
seed_type_html = {
 
field = nil,
+
return false
type = nil,
 
func = function (tpl_args, frame)
 
if tpl_args.seed_type ~= nil then
 
tpl_args.seed_type_html = m_util.html.poe_color(tpl_args.seed_type_id, tpl_args.seed_type)
 
 
end
 
end
end
+
local t = type(tpl_args[k])
  +
if (t == 'table' or t == 'string') and #tpl_args[k] == 0 then
},
 
  +
return false
seed_effect = {
 
field = 'effect',
 
type = 'Text',
 
},
 
seed_tier = {
 
field = 'tier',
 
type = 'Integer',
 
func = m_util.cast.factory.number('seed_tier'),
 
},
 
seed_growth_cycles = {
 
field = 'growth_cycles',
 
type = 'Integer',
 
func = m_util.cast.factory.number('seed_growth_cycles'),
 
},
 
seed_required_nearby_seed_tier = {
 
field = 'required_nearby_seed_tier',
 
type = 'Integer',
 
func = m_util.cast.factory.number('seed_required_nearby_seed_tier'),
 
},
 
seed_required_nearby_seed_amount = {
 
field = 'required_nearby_seed_amount',
 
type = 'Integer',
 
func = m_util.cast.factory.number('seed_required_nearby_seed_amount'),
 
},
 
seed_consumed_wild_lifeforce_percentage = {
 
field = 'consumed_wild_lifeforce_percentage',
 
type = 'Integer',
 
func = m_util.cast.factory.number('seed_consumed_wild_lifeforce_percentage'),
 
default = 0,
 
},
 
seed_consumed_vivid_lifeforce_percentage = {
 
field = 'consumed_vivid_lifeforce_percentage',
 
type = 'Integer',
 
func = m_util.cast.factory.number('seed_consumed_vivid_lifeforce_percentage'),
 
default = 0,
 
},
 
seed_consumed_primal_lifeforce_percentage = {
 
field = 'consumed_primal_lifeforce_percentage',
 
type = 'Integer',
 
func = m_util.cast.factory.number('seed_consumed_primal_lifeforce_percentage'),
 
default = 0,
 
},
 
seed_granted_craft_option_ids = {
 
field = 'granted_craft_option_ids',
 
type = 'List (,) of String',
 
func = m_util.cast.factory.number('seed_grandted_craft_option_ids'),
 
default = 0,
 
},
 
--
 
-- harvest planet boosters
 
--
 
plant_booster_radius = {
 
field = 'radius',
 
type = 'Integer',
 
func = m_util.cast.factory.number('plant_booster_radius'),
 
},
 
plant_booster_lifeforce = {
 
field = 'lifeforce',
 
type = 'Integer',
 
func = m_util.cast.factory.number('plant_booster_lifeforce'),
 
},
 
plant_booster_additional_crafting_options = {
 
field = 'additional_crafting_options',
 
type = 'Integer',
 
func = m_util.cast.factory.number('plant_booster_additional_crafting_options'),
 
},
 
plant_booster_extra_chances = {
 
field = 'extra_chances',
 
type = 'Integer',
 
func = m_util.cast.factory.number('plant_booster_extra_chances'),
 
},
 
--
 
-- Heist properties
 
--
 
heist_required_job_id = {
 
field = 'required_job_id',
 
type = 'String',
 
func = core.factory.cast_text('heist_required_job_id'),
 
},
 
heist_required_job_level = {
 
field = 'required_job_level',
 
type = 'Integer',
 
func = m_util.cast.factory.number('heist_required_job_level'),
 
},
 
heist_data = {
 
func = function (tpl_args, frame)
 
if tpl_args.heist_required_job_level then
 
if tpl_args.heist_required_job_id then
 
local results = m_cargo.query(
 
{'heist_jobs', 'heist_npcs', 'heist_npc_skills'},
 
{'heist_npcs.name', 'heist_jobs.name'},
 
{
 
join = 'heist_npc_skills.job_id=heist_jobs.id, heist_npc_skills.npc_id=heist_npcs.id',
 
where = string.format('heist_npc_skills.job_id = "%s" AND heist_npc_skills.level >= %s', tpl_args.heist_required_job_id, tpl_args.heist_required_job_level),
 
}
 
)
 
 
local npcs = {}
 
 
for _, row in ipairs(results) do
 
npcs[#npcs+1] = row['heist_npcs.name']
 
end
 
 
tpl_args.heist_required_npcs = table.concat(npcs, ', ')
 
tpl_args.heist_required_job = results[1]['heist_jobs.name']
 
else
 
tpl_args.heist_required_job = i18n.tooltips.heist_any_job
 
end
 
 
end
 
end
  +
if conditions.processed == true and tpl_args._processed_args[k] == nil then
end,
 
  +
return false
},
 
--
 
-- hideout doodads (HideoutDoodads.dat)
 
--
 
is_master_doodad = {
 
field = 'is_master_doodad',
 
type = 'Boolean',
 
func = m_util.cast.factory.boolean('is_master_doodad'),
 
},
 
master = {
 
field = 'master',
 
type = 'String',
 
-- todo validate against list of master names
 
func = m_util.cast.factory.table('master', {key='full', tbl=m_game.constants.masters}),
 
},
 
master_level_requirement = {
 
field = 'level_requirement',
 
type = 'Integer',
 
func = m_util.cast.factory.number('master_level_requirement'),
 
},
 
master_favour_cost = {
 
field = 'favour_cost',
 
type = 'Integer',
 
func = m_util.cast.factory.number('master_favour_cost'),
 
},
 
variation_count = {
 
field = 'variation_count',
 
type = 'Integer',
 
func = m_util.cast.factory.number('variation_count'),
 
},
 
-- Propehcy
 
prophecy_id = {
 
field = 'prophecy_id',
 
type = 'String',
 
func = nil,
 
},
 
prediction_text = {
 
field = 'prediction_text',
 
type = 'Text',
 
func = core.factory.cast_text('prediction_text'),
 
},
 
seal_cost = {
 
field = 'seal_cost',
 
type = 'Integer',
 
func = m_util.cast.factory.number('seal_cost'),
 
},
 
prophecy_reward = {
 
field = 'reward',
 
type = 'Text',
 
func = core.factory.cast_text('prophecy_reward'),
 
},
 
prophecy_objective = {
 
field = 'objective',
 
type = 'Text',
 
func = core.factory.cast_text('prophecy_objective'),
 
},
 
-- Divination cards
 
card_art = {
 
field = 'card_art',
 
type = 'Page',
 
func = function(tpl_args, frame)
 
tpl_args.card_art = string.format(i18n.divination_card_art, tpl_args.card_art or tpl_args.name)
 
end,
 
},
 
-- ------------------------------------------------------------------------
 
-- derived stats
 
-- ------------------------------------------------------------------------
 
 
-- For rarity != normal, rarity already verified
 
base_item = {
 
no_copy = true,
 
field = 'base_item',
 
type = 'String',
 
func = function(tpl_args, frame)
 
tpl_args.base_item = tpl_args.base_item_data['items.name']
 
end,
 
},
 
base_item_id = {
 
no_copy = true,
 
field = 'base_item_id',
 
type = 'String',
 
func = function(tpl_args, frame)
 
tpl_args.base_item_id = tpl_args.base_item_data['items.metadata_id']
 
end,
 
},
 
base_item_page = {
 
no_copy = true,
 
field = 'base_item_page',
 
type = 'Page',
 
func = function(tpl_args, frame)
 
tpl_args.base_item_page = tpl_args.base_item_data['items._pageName']
 
end,
 
},
 
name_list = {
 
no_copy = true,
 
field = 'name_list',
 
type = 'List (�) of String',
 
func = function(tpl_args, frame)
 
if tpl_args.name_list ~= nil then
 
tpl_args.name_list = m_util.string.split(tpl_args.name_list, ',%s*')
 
tpl_args.name_list[#tpl_args.name_list+1] = tpl_args.name
 
else
 
tpl_args.name_list = {tpl_args.name}
 
end
 
end,
 
},
 
frame_type = {
 
no_copy = true,
 
field = 'frame_type',
 
type = 'String',
 
property = nil,
 
func = function(tpl_args, frame)
 
if tpl_args._flags.is_prophecy then
 
tpl_args.frame_type = 'prophecy'
 
return
 
end
 
 
local var = core.class_specifics[tpl_args.class_id]
 
if var ~= nil and var.frame_type ~= nil then
 
tpl_args.frame_type = var.frame_type
 
return
 
end
 
 
if tpl_args.is_relic then
 
tpl_args.frame_type = 'relic'
 
return
 
end
 
 
tpl_args.frame_type = tpl_args.rarity_id
 
end,
 
},
 
--
 
-- args populated by mod validation
 
--
 
mods = {
 
default = function (tpl_args, frame) return {} end,
 
func_fetch = function (tpl_args, frame)
 
local results = m_cargo.query(
 
{'items' ,'item_mods'},
 
{'item_mods.id', 'item_mods.is_implicit', 'item_mods.is_random', 'item_mods.text'},
 
{
 
join = 'items._pageID=item_mods._pageID',
 
where = string.format('items._pageName="%s" AND item_mods.is_implicit=1', tpl_args.base_item_page),
 
}
 
)
 
for _, row in ipairs(results) do
 
-- Handle text-only mods
 
local result
 
if row['item_mods.id'] == nil then
 
result = row['item_mods.text']
 
end
 
tpl_args._mods[#tpl_args._mods+1] = {
 
result=result,
 
id=row['item_mods.id'],
 
stat_text=row['item_mods.text'],
 
is_implicit=m_util.cast.boolean(row['item_mods.is_implicit']),
 
is_random=m_util.cast.boolean(row['item_mods.is_random']),
 
}
 
end
 
end,
 
},
 
physical_damage_html = {
 
no_copy = true,
 
field = 'physical_damage_html',
 
type = 'Text',
 
func = core.factory.damage_html{key='physical'},
 
},
 
fire_damage_html = {
 
no_copy = true,
 
field = 'fire_damage_html',
 
type = 'Text',
 
func = core.factory.damage_html{key='fire'},
 
},
 
cold_damage_html = {
 
no_copy = true,
 
field = 'cold_damage_html',
 
type = 'Text',
 
func = core.factory.damage_html{key='cold'},
 
},
 
lightning_damage_html = {
 
no_copy = true,
 
field = 'lightning_damage_html',
 
type = 'Text',
 
func = core.factory.damage_html{key='lightning'},
 
},
 
chaos_damage_html = {
 
no_copy = true,
 
field = 'chaos_damage_html',
 
type = 'Text',
 
func = core.factory.damage_html{key='chaos'},
 
},
 
damage_avg = {
 
no_copy = true,
 
field = 'damage_avg',
 
type = 'Text',
 
func = function(tpl_args, frame)
 
local dmg = {min=0, max=0}
 
for key, _ in pairs(dmg) do
 
for _, dkey in ipairs(m_game.constants.damage_type_order) do
 
dmg[key] = dmg[key] + tpl_args[string.format('%s_damage_%s_range_average', dkey, key)]
 
end
 
end
 
 
dmg = (dmg.min + dmg.max) / 2
 
 
tpl_args.damage_avg = dmg
 
end,
 
},
 
damage_html = {
 
no_copy = true,
 
field = 'damage_html',
 
type = 'Text',
 
func = function(tpl_args, frame)
 
local text = {}
 
for _, dkey in ipairs(m_game.constants.damage_type_order) do
 
local value = tpl_args[dkey .. '_damage_html']
 
if value ~= nil then
 
text[#text+1] = value
 
end
 
end
 
if #text > 0 then
 
tpl_args.damage_html = table.concat(text, '<br>')
 
end
 
end,
 
},
 
item_limit = {
 
no_copy = true,
 
field = 'item_limit',
 
type = 'Integer',
 
func = m_util.cast.factory.number('item_limit'),
 
},
 
jewel_radius_html = {
 
no_copy = true,
 
field = 'radius_html',
 
type = 'Text',
 
func = function(tpl_args, frame)
 
local radius = tpl_args._stats.local_jewel_effect_base_radius
 
if radius then
 
radius = radius.min
 
tpl_args.jewel_radius_html = string.format('%s (%i)', (m_game.constants.item.jewel_radius_to_size[radius] or '?'), radius)
 
end
 
end,
 
},
 
incubator_effect = {
 
no_copy = true,
 
field = 'effect',
 
type = 'Text',
 
func = nil,
 
},
 
drop_areas_html = {
 
no_copy = true,
 
field = 'drop_areas_html',
 
type = 'Text',
 
func = function(tpl_args, frame)
 
if tpl_args.drop_areas_data == nil then
 
return
 
end
 
 
if tpl_args.drop_areas_html ~= nil then
 
return
 
end
 
 
local areas = {}
 
for _, data in pairs(tpl_args.drop_areas_data) do
 
-- skip legacy maps in the drop html listing
 
if not string.match(data['areas.id'], '^Map.*') or string.match(data['areas.id'], '^MapWorlds.*') or string.match(data['areas.id'], '^MapAtziri.*') then
 
areas[#areas+1] = string.format('[[%s|%s]]', data['areas.main_page'] or data['areas._pageName'], data['areas.main_page'] or data['areas.name'])
 
end
 
end
 
 
tpl_args.drop_areas_html = table.concat(areas, ' • ')
 
end,
 
},
 
release_version = {
 
no_copy = true,
 
field = 'release_version',
 
type = 'String'
 
},
 
removal_version = {
 
no_copy = true,
 
field = 'removal_version',
 
type = 'String',
 
},
 
--
 
-- args governing use of the template itself
 
--
 
suppress_improper_modifiers_category = {
 
no_copy = true,
 
field = nil,
 
func = m_util.cast.factory.boolean('suppress_improper_modifiers_category'),
 
default = false,
 
},
 
upgraded_from_disabled = {
 
no_copy = true,
 
field = nil,
 
func = m_util.cast.factory.boolean('upgraded_from_disabled'),
 
default = false,
 
},
 
}
 
 
core.stat_map = {
 
required_level_final = {
 
field = 'required_level',
 
stats_add = {
 
'local_level_requirement_+',
 
},
 
stats_override = {
 
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=1, max=1},
 
},
 
minimum = 1,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
weapon_range = {
 
field = 'weapon_range',
 
stats_add = {
 
'local_weapon_range_+',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
physical_damage_min = {
 
field = 'physical_damage_min',
 
stats_add = {
 
'local_minimum_added_physical_damage',
 
},
 
stats_increased = {
 
'local_physical_damage_+%',
 
'quality',
 
},
 
stats_override = {
 
['local_weapon_no_physical_damage'] = {min=0, max=0},
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
physical_damage_max = {
 
field = 'physical_damage_max',
 
stats_add = {
 
'local_maximum_added_physical_damage',
 
},
 
stats_increased = {
 
'local_physical_damage_+%',
 
'quality',
 
},
 
stats_override = {
 
['local_weapon_no_physical_damage'] = {min=0, max=0},
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
fire_damage_min = {
 
field = 'fire_damage_min',
 
stats_add = {
 
'local_minimum_added_fire_damage',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
color = 'fire',
 
fmt = '%i',
 
},
 
},
 
fire_damage_max = {
 
field = 'fire_damage_max',
 
stats_add = {
 
'local_maximum_added_fire_damage',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
color = 'fire',
 
fmt = '%i',
 
},
 
},
 
cold_damage_min = {
 
field = 'cold_damage_min',
 
stats_add = {
 
'local_minimum_added_cold_damage',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
color = 'cold',
 
fmt = '%i',
 
},
 
},
 
cold_damage_max = {
 
field = 'cold_damage_max',
 
stats_add = {
 
'local_maximum_added_cold_damage',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
color = 'cold',
 
fmt = '%i',
 
},
 
},
 
lightning_damage_min = {
 
field = 'lightning_damage_min',
 
stats_add = {
 
'local_minimum_added_lightning_damage',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
color = 'lightning',
 
fmt = '%i',
 
},
 
},
 
lightning_damage_max = {
 
field = 'lightning_damage_max',
 
stats_add = {
 
'local_maximum_added_lightning_damage',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
color = 'lightning',
 
fmt = '%i',
 
},
 
},
 
chaos_damage_min = {
 
field = 'chaos_damage_min',
 
stats_add = {
 
'local_minimum_added_chaos_damage',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
color = 'chaos',
 
fmt = '%i',
 
},
 
},
 
chaos_damage_max = {
 
field = 'chaos_damage_max',
 
stats_add = {
 
'local_maximum_added_chaos_damage',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
color = 'chaos',
 
fmt = '%i',
 
},
 
},
 
critical_strike_chance = {
 
field = 'critical_strike_chance',
 
stats_add = {
 
'local_critical_strike_chance',
 
},
 
stats_increased = {
 
'local_critical_strike_chance_+%',
 
},
 
stats_override = {
 
['local_weapon_always_crit'] = {min=100, max=100},
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%.2f%%',
 
},
 
},
 
attack_speed = {
 
field = 'attack_speed',
 
stats_increased = {
 
'local_attack_speed_+%',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%.2f',
 
},
 
},
 
flask_life = {
 
field = 'life',
 
stats_add = {
 
'local_flask_life_to_recover',
 
},
 
stats_increased = {
 
'local_flask_life_to_recover_+%',
 
'local_flask_amount_to_recover_+%',
 
'quality',
 
},
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
flask_mana = {
 
field = 'mana',
 
stats_add = {
 
'local_flask_mana_to_recover',
 
},
 
stats_increased = {
 
'local_flask_mana_to_recover_+%',
 
'local_flask_amount_to_recover_+%',
 
'quality',
 
},
 
},
 
flask_duration = {
 
field = 'duration',
 
stats_increased = {
 
'local_flask_duration_+%',
 
-- regular quality isn't used here because it doesn't increase duration of life/mana/hybrid flasks
 
'quality_flask_duration',
 
},
 
stats_increased_inverse = {
 
'local_flask_recovery_speed_+%',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%.2f',
 
},
 
},
 
charges_per_use = {
 
field = 'charges_per_use',
 
stats_increased = {
 
'local_charges_used_+%',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
charges_max = {
 
field = 'charges_max',
 
stats_add = {
 
'local_extra_max_charges',
 
},
 
stats_increased = {
 
'local_max_charges_+%',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
block = {
 
field = 'block',
 
stats_add = {
 
'local_additional_block_chance_%',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i%%',
 
},
 
},
 
armour = {
 
field = 'armour',
 
stats_add = {
 
'local_base_physical_damage_reduction_rating',
 
},
 
stats_increased = {
 
'local_physical_damage_reduction_rating_+%',
 
'local_armour_and_energy_shield_+%',
 
'local_armour_and_evasion_+%',
 
'local_armour_and_evasion_and_energy_shield_+%',
 
'quality',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
evasion = {
 
field = 'evasion',
 
stats_add = {
 
'local_base_evasion_rating',
 
'local_evasion_rating_and_energy_shield',
 
},
 
stats_increased = {
 
'local_evasion_rating_+%',
 
'local_evasion_and_energy_shield_+%',
 
'local_armour_and_evasion_+%',
 
'local_armour_and_evasion_and_energy_shield_+%',
 
'quality',
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
energy_shield = {
 
field = 'energy_shield',
 
stats_add = {
 
'local_energy_shield',
 
'local_evasion_rating_and_energy_shield',
 
},
 
stats_increased = {
 
'local_energy_shield_+%',
 
'local_armour_and_energy_shield_+%',
 
'local_evasion_and_energy_shield_+%',
 
'local_armour_and_evasion_and_energy_shield_+%',
 
'quality',
 
},
 
stats_override = {
 
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0},
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
required_dexterity = {
 
field = 'required_dexterity',
 
stats_add = {
 
'local_dexterity_requirement_+'
 
},
 
stats_increased = {
 
'local_dexterity_requirement_+%',
 
'local_attribute_requirements_+%',
 
},
 
stats_override = {
 
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0},
 
['local_no_attribute_requirements'] = {min=0, max=0},
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
required_intelligence = {
 
field = 'required_intelligence',
 
stats_add = {
 
'local_intelligence_requirement_+'
 
},
 
stats_increased = {
 
'local_intelligence_requirement_+%',
 
'local_attribute_requirements_+%',
 
},
 
stats_override = {
 
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0},
 
['local_no_attribute_requirements'] = {min=0, max=0},
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
required_strength = {
 
field = 'required_strength',
 
stats_add = {
 
'local_strength_requirement_+'
 
},
 
stats_increased = {
 
'local_strength_requirement_+%',
 
'local_attribute_requirements_+%',
 
},
 
stats_override = {
 
['local_unique_tabula_rasa_no_requirement_or_energy_shield'] = {min=0, max=0},
 
['local_no_attribute_requirements'] = {min=0, max=0},
 
},
 
minimum = 0,
 
html_fmt_options = {
 
fmt = '%i',
 
},
 
},
 
map_area_level = {
 
field = 'map_area_level',
 
stats_override = {
 
['map_item_level_override'] = true,
 
},
 
},
 
}
 
 
core.dps_map = {
 
{
 
name = 'physical_dps',
 
field = 'physical_dps',
 
damage_args = {'physical_damage', },
 
label_infobox = i18n.tooltips.physical_dps,
 
html_fmt_options = {
 
color = 'value',
 
fmt = '%.1f',
 
},
 
},
 
{
 
name = 'fire_dps',
 
field = 'fire_dps',
 
damage_args = {'fire_damage'},
 
label_infobox = i18n.tooltips.fire_dps,
 
html_fmt_options = {
 
color = 'fire',
 
fmt = '%.1f',
 
},
 
},
 
{
 
name = 'cold_dps',
 
field = 'cold_dps',
 
damage_args = {'cold_damage'},
 
label_infobox = i18n.tooltips.cold_dps,
 
html_fmt_options = {
 
color = 'cold',
 
fmt = '%.1f',
 
},
 
},
 
{
 
name = 'lightning_dps',
 
field = 'lightning_dps',
 
damage_args = {'lightning_damage'},
 
label_infobox = i18n.tooltips.lightning_dps,
 
html_fmt_options = {
 
color = 'lightning',
 
fmt = '%.1f',
 
},
 
},
 
{
 
name = 'chaos_dps',
 
field = 'chaos_dps',
 
damage_args = {'chaos_damage'},
 
label_infobox = i18n.tooltips.chaos_dps,
 
html_fmt_options = {
 
color = 'chaos',
 
fmt = '%.1f',
 
},
 
},
 
{
 
name = 'elemental_dps',
 
field = 'elemental_dps',
 
damage_args = {'fire_damage', 'cold_damage', 'lightning_damage'},
 
label_infobox = i18n.tooltips.elemental_dps,
 
html_fmt_options = {
 
color = 'value',
 
fmt = '%.1f',
 
},
 
},
 
{
 
name = 'poison_dps',
 
field = 'poison_dps',
 
damage_args = {'physical_damage', 'chaos_damage'},
 
label_infobox = i18n.tooltips.poison_dps,
 
html_fmt_options = {
 
color = 'value',
 
fmt = '%.1f',
 
},
 
},
 
{
 
name = 'dps',
 
field = 'dps',
 
damage_args = {'physical_damage', 'fire_damage', 'cold_damage', 'lightning_damage', 'chaos_damage'},
 
label_infobox = i18n.tooltips.dps,
 
html_fmt_options = {
 
color = 'value',
 
fmt = '%.1f',
 
},
 
},
 
}
 
 
core.cargo = {}
 
core.cargo.items = {
 
table = 'items',
 
fields = {
 
html = core.map.html,
 
html_extra = core.map.html_extra,
 
implicit_stat_text = core.map.implicit_stat_text,
 
explicit_stat_text = core.map.explicit_stat_text,
 
stat_text = core.map.stat_text,
 
class = core.map.class,
 
class_id = core.map.class_id,
 
rarity = core.map.rarity,
 
rarity_id = core.map.rarity_id,
 
name = core.map.name,
 
size_x = core.map.size_x,
 
size_y = core.map.size_y,
 
drop_enabled = core.map.drop_enabled,
 
drop_level = core.map.drop_level,
 
drop_level_maximum = core.map.drop_level_maximum,
 
drop_leagues = core.map.drop_leagues,
 
drop_areas = core.map.drop_areas,
 
drop_areas_html = core.map.drop_areas_html,
 
drop_monsters = core.map.drop_monsters,
 
drop_text = core.map.drop_text,
 
-- sightly different because of strange DB issues
 
drop_rarity_ids = core.map.drop_rarities_ids,
 
required_level = core.map.required_level,
 
required_level_final = core.map.required_level_final,
 
required_dexterity = core.map.required_dexterity,
 
required_strength = core.map.required_strength,
 
required_intelligence = core.map.required_intelligence,
 
inventory_icon = core.map.inventory_icon,
 
alternate_art_inventory_icons = core.map.alternate_art_inventory_icons,
 
buff_icon = core.map.buff_icon,
 
cannot_be_traded_or_modified = core.map.cannot_be_traded_or_modified,
 
help_text = core.map.help_text,
 
flavour_text = core.map.flavour_text,
 
flavour_text_id = core.map.flavour_text_id,
 
tags = core.map.tags,
 
metadata_id = core.map.metadata_id,
 
influences = core.map.influences,
 
is_fractured = core.map.is_fractured,
 
is_synthesised = core.map.is_synthesised,
 
is_veiled = core.map.is_veiled,
 
is_replica = core.map.is_replica,
 
is_corrupted = core.map.is_corrupted,
 
is_relic = core.map.is_relic,
 
is_fated = core.map.is_fated,
 
is_drop_restricted = core.map.is_drop_restricted,
 
quality = core.map.quality,
 
base_item = core.map.base_item,
 
base_item_id = core.map.base_item_id,
 
base_item_page = core.map.base_item_page,
 
frame_type = core.map.frame_type,
 
name_list = core.map.name_list,
 
description = core.map.description,
 
release_version = core.map.release_version,
 
removal_version = core.map.removal_version,
 
},
 
}
 
 
core.cargo.item_sell_prices = {
 
table = 'item_sell_prices',
 
fields = {
 
amount = {
 
field = 'amount',
 
type = 'Integer',
 
},
 
name = {
 
field = 'name',
 
type = 'String',
 
},
 
},
 
}
 
 
 
core.cargo.item_purchase_costs = {
 
table = 'item_purchase_costs',
 
fields = {
 
amount = {
 
field = 'amount',
 
type = 'Integer',
 
},
 
name = {
 
field = 'name',
 
type = 'String',
 
},
 
rarity = {
 
field = 'rarity',
 
type = 'String',
 
},
 
},
 
}
 
 
core.cargo.item_mods = {
 
table = 'item_mods',
 
fields = {
 
id = {
 
field = 'id',
 
type = 'String',
 
},
 
stat_text = {
 
field = 'text',
 
type = 'Text',
 
},
 
is_implicit = {
 
field = 'is_implicit',
 
type = 'Boolean',
 
},
 
is_random = {
 
field = 'is_random',
 
type = 'Boolean',
 
},
 
},
 
}
 
 
core.cargo.item_stats = {
 
table = 'item_stats',
 
fields = {
 
id = {
 
field = 'id',
 
type = 'String',
 
},
 
min = {
 
field = 'min',
 
type = 'Integer',
 
},
 
max = {
 
field = 'max',
 
type = 'Integer',
 
},
 
avg = {
 
field = 'avg',
 
type = 'Integer',
 
},
 
is_implicit = {
 
field = 'is_implicit',
 
type = 'Boolean',
 
},
 
is_random = {
 
field = 'is_random',
 
type = 'Boolean',
 
},
 
},
 
}
 
 
-- There probably will be a table named "buffs" in the future, so "item_buffs" is the best solution here
 
core.cargo.item_buffs = {
 
table = 'item_buffs',
 
fields = {
 
id = core.map.buff_id,
 
buff_values = core.map.buff_values,
 
stat_text = core.map.buff_stat_text,
 
icon = core.map.buff_icon,
 
},
 
}
 
 
core.cargo.upgraded_from_sets = {
 
table = 'upgraded_from_sets',
 
fields = {
 
set_id = {
 
field = 'set_id',
 
type = 'Integer',
 
},
 
text = {
 
field = 'text',
 
type = 'Text',
 
},
 
automatic = {
 
field = 'automatic',
 
type = 'Boolean',
 
},
 
}
 
}
 
 
core.cargo.upgraded_from_groups = {
 
table = 'upgraded_from_groups',
 
fields = {
 
group_id = {
 
field = 'group_id',
 
type = 'Integer',
 
},
 
set_id = {
 
field = 'set_id',
 
type = 'Integer',
 
},
 
item_id = {
 
field = 'item_id',
 
type = 'String',
 
},
 
item_name = {
 
field = 'item_name',
 
type = 'String',
 
},
 
item_page = {
 
field = 'item_page',
 
type = 'Page',
 
},
 
integer = {
 
field = 'amount',
 
type = 'Integer',
 
},
 
notes = {
 
field = 'notes',
 
type = 'Text',
 
},
 
}
 
}
 
 
core.cargo.amulets = {
 
table = 'amulets',
 
fields = {
 
is_talisman = core.map.is_talisman,
 
talisman_tier = core.map.talisman_tier,
 
},
 
}
 
 
core.cargo.flasks = {
 
table = 'flasks',
 
fields = {
 
-- All flasks
 
duration = core.map.flask_duration,
 
charges_max = core.map.charges_max,
 
charges_per_use = core.map.charges_per_use,
 
-- Life/Mana/Hybrid flasks
 
life = core.map.flask_life,
 
mana = core.map.flask_mana,
 
},
 
}
 
 
core.cargo.weapons = {
 
table = 'weapons',
 
fields = {
 
critical_strike_chance = core.map.critical_strike_chance,
 
attack_speed = core.map.attack_speed,
 
weapon_range = core.map.weapon_range,
 
physical_damage_min = core.map.physical_damage_min,
 
physical_damage_max = core.map.physical_damage_max,
 
physical_damage_html = core.map.physical_damage_html,
 
fire_damage_html = core.map.fire_damage_html,
 
cold_damage_html = core.map.cold_damage_html,
 
lightning_damage_html = core.map.lightning_damage_html,
 
chaos_damage_html = core.map.chaos_damage_html,
 
damage_avg = core.map.damage_avg,
 
damage_html = core.map.damage_html,
 
 
-- Values added via stat population
 
fire_damage_min = core.map.fire_damage_min,
 
fire_damage_max = core.map.fire_damage_max,
 
cold_damage_min = core.map.cold_damage_min,
 
cold_damage_max = core.map.cold_damage_max,
 
lightning_damage_min = core.map.lightning_damage_min,
 
lightning_damage_max = core.map.lightning_damage_max,
 
chaos_damage_min = core.map.chaos_damage_min,
 
chaos_damage_max = core.map.chaos_damage_max,
 
},
 
}
 
 
core.cargo.armours = {
 
table = 'armours',
 
fields = {
 
armour = core.map.armour,
 
energy_shield = core.map.energy_shield,
 
evasion = core.map.evasion,
 
movement_speed = core.map.movement_speed,
 
},
 
}
 
 
core.cargo.shields = {
 
table = 'shields',
 
fields = {
 
block = core.map.block,
 
}
 
}
 
 
core.cargo.skill_gems = {
 
table = 'skill_gems',
 
fields = {
 
gem_description = core.map.gem_description,
 
dexterity_percent = core.map.dexterity_percent,
 
strength_percent = core.map.strength_percent,
 
intelligence_percent = core.map.intelligence_percent,
 
primary_attribute = core.map.primary_attribute,
 
gem_tags = core.map.gem_tags,
 
-- Support Skill Gems
 
support_gem_letter = core.map.support_gem_letter,
 
support_gem_letter_html = core.map.support_gem_letter_html,
 
},
 
}
 
 
core.cargo.maps = {
 
table = 'maps',
 
fields = {
 
tier = core.map.map_tier,
 
guild_character = core.map.map_guild_character,
 
unique_guild_character = core.map.unique_map_guild_character,
 
area_id = core.map.map_area_id,
 
unique_area_id = core.map.unique_map_area_id,
 
series = core.map.map_series,
 
 
-- REMOVE?
 
area_level = core.map.map_area_level,
 
unique_area_level = core.map.unique_map_area_level,
 
},
 
}
 
 
core.cargo.atlas_maps = {
 
table = 'atlas_maps',
 
fields = {
 
x = core.map.atlas_x,
 
y = core.map.atlas_y,
 
region_id = core.map.atlas_region_id,
 
region_minimum = core.map.atlas_region_minimum,
 
x0 = core.map.atlas_x0,
 
x1 = core.map.atlas_x1,
 
x2 = core.map.atlas_x2,
 
x3 = core.map.atlas_x3,
 
x4 = core.map.atlas_x4,
 
y0 = core.map.atlas_y0,
 
y1 = core.map.atlas_y1,
 
y2 = core.map.atlas_y2,
 
y3 = core.map.atlas_y3,
 
y4 = core.map.atlas_y4,
 
map_tier0 = core.map.atlas_map_tier0,
 
map_tier1 = core.map.atlas_map_tier1,
 
map_tier2 = core.map.atlas_map_tier2,
 
map_tier3 = core.map.atlas_map_tier3,
 
map_tier4 = core.map.atlas_map_tier4,
 
},
 
}
 
 
core.cargo.atlas_connections = {
 
table = 'atlas_connections',
 
fields = {
 
map1 = {
 
field = 'map1',
 
type = 'String',
 
},
 
map2 = {
 
field = 'map2',
 
type = 'String',
 
},
 
region0 = {
 
field = 'region0',
 
type = 'Boolean',
 
},
 
region1 = {
 
field = 'region1',
 
type = 'Boolean',
 
},
 
region2 = {
 
field = 'region2',
 
type = 'Boolean',
 
},
 
region3 = {
 
field = 'region3',
 
type = 'Boolean',
 
},
 
region4 = {
 
field = 'region4',
 
type = 'Boolean',
 
},
 
},
 
}
 
 
core.cargo.stackables = {
 
table = 'stackables',
 
fields = {
 
stack_size = core.map.stack_size,
 
stack_size_currency_tab = core.map.stack_size_currency_tab,
 
cosmetic_type = core.map.cosmetic_type,
 
},
 
}
 
 
core.cargo.essences = {
 
table = 'essences',
 
fields = {
 
level_restriction = core.map.essence_level_restriction,
 
level = core.map.essence_level,
 
type = core.map.essence_type,
 
category = core.map.essence_category,
 
},
 
}
 
 
core.cargo.blight_items = {
 
table = 'blight_items',
 
fields = {
 
tier = core.map.blight_item_tier,
 
},
 
}
 
 
core.cargo.hideout_doodads = {
 
table = 'hideout_doodads',
 
fields = {
 
is_master_doodad = core.map.is_master_doodad,
 
master = core.map.master,
 
master_level_requirement = core.map.master_level_requirement,
 
master_favour_cost = core.map.master_favour_cost,
 
variation_count = core.map.variation_count,
 
},
 
}
 
 
core.cargo.prophecies = {
 
table = 'prophecies',
 
fields = {
 
prophecy_id = core.map.prophecy_id,
 
prediction_text = core.map.prediction_text,
 
seal_cost = core.map.seal_cost,
 
objective = core.map.prophecy_objective,
 
reward = core.map.prophecy_reward,
 
},
 
}
 
 
core.cargo.divination_cards = {
 
table = 'divination_cards',
 
fields = {
 
card_art = core.map.card_art,
 
},
 
}
 
 
core.cargo.jewels = {
 
table = 'jewels',
 
fields = {
 
item_limit = core.map.item_limit,
 
radius_html = core.map.jewel_radius_html,
 
},
 
}
 
 
core.cargo.incubators = {
 
table = 'incubators',
 
fields = {
 
effect = core.map.incubator_effect,
 
},
 
}
 
 
core.cargo.harvest_seeds = {
 
table = 'harvest_seeds',
 
fields = {
 
effect = core.map.seed_effect,
 
type_id = core.map.seed_type_id,
 
type = core.map.seed_type,
 
tier = core.map.seed_tier,
 
growth_cycles = core.map.seed_growth_cycles,
 
required_nearby_seed_tier = core.map.seed_required_nearby_seed_tier,
 
required_nearby_seed_amount = core.map.seed_required_nearby_seed_amount,
 
consumed_wild_lifeforce_percentage = core.map.seed_consumed_wild_lifeforce_percentage,
 
consumed_vivid_lifeforce_percentage = core.map.seed_consumed_vivid_lifeforce_percentage,
 
consumed_primal_lifeforce_percentage = core.map.seed_consumed_primal_lifeforce_percentage,
 
granted_craft_option_ids = core.map.seed_granted_craft_option_ids,
 
},
 
}
 
 
core.cargo.harvest_plant_boosters = {
 
table = 'harvest_plant_boosters',
 
fields = {
 
radius = core.map.plant_booster_radius,
 
lifeforce = core.map.plant_booster_lifeforce,
 
additional_crafting_options = core.map.plant_booster_additional_crafting_options,
 
extra_chances = core.map.plant_booster_extra_chances,
 
},
 
}
 
 
core.cargo.heist_equipment = {
 
table = 'heist_equipment',
 
fields = {
 
required_job_id = core.map.heist_required_job_id,
 
required_job_level = core.map.heist_required_job_level,
 
},
 
}
 
 
core.cargo.quest_rewards = {
 
table = 'quest_rewards',
 
fields = {
 
quest = {
 
field = 'quest',
 
type = 'String',
 
},
 
quest_id = {
 
field = 'quest_id',
 
type = 'String',
 
},
 
-- still needed?
 
act = {
 
field = 'act',
 
type = 'Integer',
 
},
 
classes = {
 
field = 'classes',
 
type = 'List (,) of String',
 
},
 
class_ids = {
 
field = 'class_ids',
 
type = 'List (,) of String',
 
},
 
sockets = {
 
field = 'sockets',
 
type = 'Integer',
 
},
 
item_level = {
 
field = 'item_level',
 
type = 'Integer',
 
},
 
rarity = {
 
field = 'rarity',
 
type = 'String',
 
},
 
notes = {
 
field = 'notes',
 
type = 'Text',
 
},
 
},
 
}
 
 
core.cargo.vendor_rewards = {
 
table = 'vendor_rewards',
 
fields = {
 
quest = {
 
field = 'quest',
 
type = 'String',
 
},
 
quest_id = {
 
field = 'quest_id',
 
type = 'String',
 
},
 
act = {
 
field = 'act',
 
type = 'Integer',
 
},
 
npc = {
 
field = 'npc',
 
type = 'String',
 
},
 
classes = {
 
field = 'classes',
 
type = 'List (,) of String',
 
},
 
class_ids = {
 
field = 'class_ids',
 
type = 'List (,) of String',
 
},
 
}
 
}
 
 
-- TODO: Second pass for i18n item classes
 
-- base item is default, but will be validated later
 
-- Notes:
 
-- inventory_icon must always be before alternate_art_inventory_icons
 
-- drop_areas after tags
 
-- is_relic after rarity
 
core.default_args = {
 
'rarity_id', 'rarity', 'name', 'name_list', 'size_x', 'size_y',
 
'drop_rarities_ids', 'drop_rarities', 'drop_enabled', 'drop_level', 'drop_level_maximum', 'drop_leagues', 'drop_text', 'required_level', 'required_level_final',
 
'inventory_icon', 'alternate_art_inventory_icons', 'flavour_text', 'flavour_text_id',
 
'cannot_be_traded_or_modified', 'help_text', 'tags', 'metadata_id', 'influences', 'is_fractured', 'is_synthesised', 'is_veiled', 'is_replica', 'is_corrupted', 'is_relic', 'is_fated', 'purchase_costs', 'sell_prices_override', 'mods',
 
'drop_areas', 'drop_areas_html', 'drop_monsters',
 
 
'upgraded_from_disabled',
 
'suppress_improper_modifiers_category',
 
 
'is_prophecy', 'is_blight_item',
 
 
'class',
 
'is_drop_restricted',
 
}
 
-- frame_type is needed in stat_text
 
core.late_args = {'frame_type', 'implicit_stat_text', 'explicit_stat_text', 'stat_text'}
 
core.prophecy_args = {'prophecy_id', 'prediction_text', 'seal_cost', 'prophecy_objective', 'prophecy_reward'}
 
core.tables = {'items'}
 
core.class_groups = {
 
flasks = {
 
tables = {'flasks'},
 
keys = {['LifeFlask'] = true, ['ManaFlask'] = true, ['HybridFlask'] = true, ['UtilityFlask'] = true, ['UtilityFlaskCritical'] = true},
 
args = {'quality', 'flask_duration', 'charges_max', 'charges_per_use'},
 
},
 
weapons = {
 
tables = {'weapons'},
 
keys = {['Claw'] = true, ['Dagger'] = true, ['Wand'] = true, ['One Hand Sword'] = true, ['Thrusting One Hand Sword'] = true, ['One Hand Axe'] = true, ['One Hand Mace'] = true, ['Bow'] = true, ['Staff'] = true, ['Two Hand Sword'] = true, ['Two Hand Axe'] = true, ['Two Hand Mace'] = true, ['Sceptre'] = true, ['FishingRod'] = true, ['Rune Dagger'] = true, ['Warstaff'] = true},
 
args = {'quality', 'required_dexterity', 'required_intelligence', 'required_strength', 'critical_strike_chance', 'attack_speed', 'physical_damage_min', 'physical_damage_max', 'lightning_damage_min', 'lightning_damage_max', 'cold_damage_min', 'cold_damage_max', 'fire_damage_min', 'fire_damage_max', 'chaos_damage_min', 'chaos_damage_max', 'weapon_range'},
 
late_args = {'physical_damage_html', 'fire_damage_html', 'cold_damage_html', 'lightning_damage_html', 'chaos_damage_html', 'damage_avg', 'damage_html'},
 
},
 
gems = {
 
tables = {'skill_gems'},
 
keys = {['Active Skill Gem'] = true, ['Support Skill Gem'] = true},
 
args = {'dexterity_percent', 'strength_percent', 'intelligence_percent', 'primary_attribute', 'gem_tags'},
 
},
 
armor = {
 
tables = {'armours'},
 
keys = {['Gloves'] = true, ['Boots'] = true, ['Body Armour'] = true, ['Helmet'] = true, ['Shield'] = true},
 
args = {'quality', 'required_dexterity', 'required_intelligence', 'required_strength', 'armour', 'energy_shield', 'evasion', 'movement_speed'},
 
},
 
stackable = {
 
tables = {'stackables'},
 
keys = {['Currency'] = true, ['StackableCurrency'] = true, ['HideoutDoodad'] = true, ['Microtransaction'] = true, ['DivinationCard'] = true, ['DelveSocketableCurrency'] = true, ['DelveStackableSocketableCurrency'] = true, ['Incubator'] = true, ['HarvestSeed'] = true, ['HarvestPlantBooster'] = true},
 
args = {'stack_size', 'stack_size_currency_tab', 'description', 'cosmetic_type'},
 
},
 
heist_equipment = {
 
tables = {'heist_equipment'},
 
keys = {['HeistEquipmentWeapon'] = true, ['HeistEquipmentTool'] = true, ['HeistEquipmentUtility'] = true, ['HeistEquipmentReward'] = true},
 
args = {'heist_required_job_id', 'heist_required_job_level', 'heist_data'},
 
},
 
}
 
 
core.class_specifics = {
 
['Amulet'] = {
 
tables = {'amulets'},
 
args = {'is_talisman', 'talisman_tier'},
 
},
 
['LifeFlask'] = {
 
args = {'flask_life'},
 
},
 
['ManaFlask'] = {
 
args = {'flask_mana'},
 
},
 
['HybridFlask'] = {
 
args = {'flask_life', 'flask_mana'},
 
},
 
['UtilityFlask'] = {
 
tables = {'item_buffs'},
 
args = {'buff_id', 'buff_values', 'buff_stat_text', 'buff_icon'},
 
},
 
['UtilityFlaskCritical'] = {
 
tables = {'item_buffs'},
 
args = {'buff_id', 'buff_values', 'buff_stat_text', 'buff_icon'},
 
},
 
['Active Skill Gem'] = {
 
defaults = {
 
help_text = i18n.help_text_defaults.active_gem,
 
size_x = 1,
 
size_y = 1,
 
},
 
frame_type = 'gem',
 
},
 
['Support Skill Gem'] = {
 
args = {'support_gem_letter', 'support_gem_letter_html'},
 
defaults = {
 
help_text = i18n.help_text_defaults.support_gem,
 
size_x = 1,
 
size_y = 1,
 
},
 
frame_type = 'gem',
 
},
 
['Shield'] = {
 
tables = {'shields'},
 
args = {'block'},
 
},
 
['Map'] = {
 
tables = {'maps', 'atlas_maps'},
 
args = {
 
'quality',
 
 
'map_tier',
 
'map_guild_character',
 
'map_area_id',
 
'map_area_level',
 
'unique_map_area_id',
 
'unique_map_area_level',
 
'unique_map_guild_character',
 
'map_series',
 
 
'atlas_x',
 
'atlas_y',
 
'atlas_region_id',
 
'atlas_x0',
 
'atlas_x1',
 
'atlas_x2',
 
'atlas_x3',
 
'atlas_x4',
 
'atlas_y0',
 
'atlas_y1',
 
'atlas_y2',
 
'atlas_y3',
 
'atlas_y4',
 
'atlas_map_tier0',
 
'atlas_map_tier1',
 
'atlas_map_tier2',
 
'atlas_map_tier3',
 
'atlas_map_tier4',
 
'atlas_connections', -- pseudo to fill connections table
 
},
 
skip_stat_lines = i18n.stat_skip_patterns.maps,
 
},
 
['Currency'] = {
 
frame_type = 'currency',
 
},
 
['StackableCurrency'] = {
 
tables = {'essences', 'prophecies', 'blight_items'},
 
args = {'is_essence', 'essence_level_restriction', 'essence_level', 'essence_type', 'essence_category', 'blight_item_tier'},
 
frame_type = 'currency',
 
},
 
['Microtransaction'] = {
 
frame_type = 'currency',
 
},
 
['HideoutDoodad'] = {
 
tables = {'hideout_doodads'},
 
args = {'is_master_doodad', 'master', 'master_level_requirement', 'master_favour_cost', 'variation_count'},
 
frame_type = 'currency',
 
},
 
['Jewel'] = {
 
tables = {'jewels'},
 
late_args = {'item_limit', 'jewel_radius_html'},
 
defaults = {
 
help_text = i18n.help_text_defaults.jewel,
 
},
 
skip_stat_lines = i18n.stat_skip_patterns.jewels,
 
},
 
['AbyssJewel'] = {
 
tables = {'jewels'},
 
late_args = {'item_limit', 'jewel_radius_html'},
 
skip_stat_lines = i18n.stat_skip_patterns.jewels,
 
},
 
['QuestItem'] = {
 
args = {'description'},
 
frame_type = 'quest',
 
},
 
['DivinationCard'] = {
 
tables = {'divination_cards'},
 
args = {'card_art',},
 
frame_type = 'divicard',
 
},
 
['LabyrinthItem'] = {
 
frame_type = 'currency',
 
},
 
['LabyrinthTrinket'] = {
 
tables = {'item_buffs'},
 
args = {'description', 'buff_icon'},
 
frame_type = 'currency',
 
},
 
['PantheonSoul'] = {
 
defaults = {
 
cannot_be_traded_or_modified = true,
 
},
 
},
 
['IncursionItem'] = {
 
frame_type = 'currency',
 
},
 
['Incubator'] = {
 
tables = {'incubators'},
 
args = {'incubator_effect'},
 
frame_type = 'currency',
 
},
 
['HarvestSeed'] = {
 
tables = {'harvest_seeds'},
 
args = {'seed_effect', 'seed_type_id', 'seed_effect', 'seed_type', 'seed_type_html', 'seed_tier', 'seed_growth_cycles', 'seed_required_nearby_seed_tier', 'seed_required_nearby_seed_amount', 'seed_consumed_wild_lifeforce_percentage', 'seed_consumed_vivid_lifeforce_percentage', 'seed_consumed_primal_lifeforce_percentage', 'seed_granted_craft_option_ids'},
 
frame_type = 'currency',
 
},
 
['HarvestPlantBooster'] = {
 
tables = {'harvest_plant_boosters'},
 
args = {'plant_booster_radius', 'plant_booster_lifeforce', 'plant_booster_additional_crafting_options', 'plant_booster_extra_chances'},
 
frame_type = 'currency',
 
},
 
['HeistObjective'] = {
 
frame_type = 'currency',
 
},
 
}
 
 
-- add defaults from class specifics and class groups
 
core.item_classes = {}
 
core.item_classes_extend = {'tables', 'args', 'late_args'}
 
function core.build_item_classes(tpl_args, frame)
 
core.map.class.func(tpl_args, frame)
 
 
core.item_classes[tpl_args.class_id] = {
 
tables = {},
 
args = {},
 
late_args = {},
 
defaults = {},
 
}
 
 
for _, table_name in ipairs(core.tables) do
 
table.insert(core.item_classes[tpl_args.class_id].tables, table_name)
 
end
 
 
for _, row in pairs(core.class_groups) do
 
for class, _ in pairs(row.keys) do
 
if class == tpl_args.class_id then
 
for _, k in ipairs(core.item_classes_extend) do
 
if row[k] ~= nil then
 
for _, value in ipairs(row[k]) do
 
table.insert(core.item_classes[tpl_args.class_id][k], value)
 
end
 
end
 
end
 
break
 
 
end
 
end
 
end
 
end
end
+
return true
 
local class_specifics = core.class_specifics[tpl_args.class_id]
 
if class_specifics then
 
for _, k in ipairs(core.item_classes_extend) do
 
if class_specifics[k] ~= nil then
 
for _, value in ipairs(class_specifics[k]) do
 
table.insert(core.item_classes[tpl_args.class_id][k], value)
 
end
 
end
 
end
 
if class_specifics.defaults ~= nil then
 
for key, value in pairs(class_specifics.defaults) do
 
core.item_classes[tpl_args.class_id].defaults[key] = value
 
end
 
end
 
 
end
 
end
 
end
 
end
   
  +
function h.factory.display_raw_value(key)
-- GroupTable -> RowTable -> formatter function
 
  +
return function(tpl_args, frame)
--
 
  +
return tpl_args[key]
--
 
 
h.conditions = {}
 
h.conditions.factory = {}
 
 
function h.conditions.factory.arg (args)
 
-- Обязательно:
 
-- arg: Аргумент для проверки (The argument to check against)
 
-- Один должен быть указан (One must be specified)
 
-- value: проверяет, равен ли аргумент этому значению (check whether the argument equals this value)
 
-- values: проверяет, находится ли аргумент в этом списке значений (check whether the argument is in this list of values)
 
-- values_assoc: проверяет, находится ли аргумент в этой ассоциативной таблице (check whether the argument is in this associative table)
 
--
 
-- Опционально:
 
-- negate: отрицает проверку против значения, т.е. не равно ли значение или нет в списке/таблице (negates the check against the value, i.e. whether the value is not equal or not in the list/table).
 
if args.negate == nil then
 
args.negate = false
 
 
end
 
end
 
-- Inner type of function depending on whether to check a single value, a list of values or an associative list of values
 
local inner
 
if args.value ~= nil then
 
inner = function (tpl)
 
return tpl == args.value
 
end
 
elseif args.values ~= nil then
 
inner = function (tpl)
 
for _, value in ipairs(args.values) do
 
if tpl == value then
 
return true
 
end
 
end
 
return false
 
end
 
elseif args.values_assoc ~= nil then
 
inner = function(tpl)
 
return args.values_assoc[tpl] ~= nil
 
end
 
else
 
error(string.format('Missing inner comparision function. Args: %s', mw.dumpObject(args)))
 
end
 
 
-- Внешний тип функции в зависимости от того, следует ли проверять одно значение или сверяться с таблицей (Outer type of function depending on whether to check a single value or against a table)
 
return function (tpl_args, frame)
 
local tpl_value = tpl_args[args.arg]
 
local rtr
 
if type(tpl_value) == 'table' then
 
rtr = false
 
for key, value in pairs(tpl_value) do
 
if type(key) == 'number' then
 
rtr = rtr or inner(value)
 
else
 
rtr = rtr or inner(key)
 
end
 
end
 
 
else
 
rtr = inner(tpl_value)
 
end
 
 
if args.negate then
 
rtr = not rtr
 
end
 
 
return rtr
 
end
 
 
end
 
end
   
function h.conditions.factory.league (args)
+
function h.factory.descriptor_value(args)
  +
-- Arguments:
return function (tpl_args, frame)
 
  +
-- key
for _, league in ipairs(tpl_args.drop_leagues or {}) do
 
  +
-- tbl
if league == args.league then
 
return true
+
args = args or {}
  +
return function (tpl_args, frame, value)
end
 
  +
args.tbl = args.tbl or tpl_args
  +
if args.tbl[args.key] then
  +
value = m_util.html.abbr(value, args.tbl[args.key])
 
end
 
end
return false
+
return value
 
end
 
end
 
end
 
end
   
  +
-- ----------------------------------------------------------------------------
h.conditions.normal = h.conditions.factory.arg{arg='rarity_id', value='normal'}
 
  +
-- Additional configuration
h.conditions.unique = h.conditions.factory.arg{arg='rarity_id', value='unique'}
 
  +
-- ----------------------------------------------------------------------------
   
  +
-- helper to loop over the range variables easier
-- По умолчанию для всех записей, но может быть отключен для определенных (Default for all entries, but can be disabled by specific ones).
 
  +
c.range_map = {
core.automatic_upgraded_from_defaults = {
 
  +
min = {
is_drop_restricted = h.conditions.factory.arg{arg='is_drop_restricted', value=false},
 
  +
var = '_range_minimum',
is_corrupted = h.conditions.factory.arg{arg='is_corrupted', value=false},
 
}
 
-- Порядок имеет значение (Order matters)
 
-- Поставьте наиболее конкретный результат вверху и наименее конкретный внизу (Put most specific outcome at the topic and the least specific at the bottom)
 
core.automatic_upgraded_from = {
 
--[[
 
{
 
defaults = {
 
arg_key = function (tpl_args, frame) end,
 
},
 
condition = {
 
function (tpl_args, frame) end,
 
},
 
text = '',
 
groups = {
 
{
 
name = '',
 
item_id = '',
 
amount = 0,
 
notes = '',
 
},
 
},
 
 
},
 
},
]]
+
max = {
  +
var = '_range_maximum',
--
 
-- Item base specific
 
--
 
{
 
defaults = {
 
is_corrupted = false,
 
},
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Amulets/Amulet9'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random_corrupted, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.agate_amulet))
 
end,
 
groups = {
 
{
 
-- Передышка Лисы
 
item_id = "Metadata/Items/DivinationCards/DivinationCardLysahsRespite",
 
amount = 6,
 
},
 
},
 
 
},
 
},
{
+
avg = {
condition = {
+
var = '_range_average',
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Rings/Ring15'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random_3, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.unset_ring))
 
end,
 
groups = {
 
{
 
-- Кающийся
 
item_id = "Metadata/Items/DivinationCards/DivinationCardThePenitent",
 
amount = 5,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Rings/Ring4'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random_3, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.gold_ring))
 
end,
 
groups = {
 
{
 
-- Проблеск надежды
 
item_id = "Metadata/Items/DivinationCards/DivinationCardGlimmerOfHope",
 
amount = 8,
 
},
 
},
 
},
 
{
 
defaults = {
 
is_corrupted = false,
 
},
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Rings/Ring8'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random_corrupted_3, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.prismatic_ring))
 
end,
 
groups = {
 
{
 
-- Надежда
 
item_id = "Metadata/Items/DivinationCards/DivinationCardHope",
 
amount = 5,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.normal,
 
h.conditions.factory.arg{arg='metadata_id', values={'Metadata/Items/Rings/Ring12', 'Metadata/Items/Rings/Ring13', 'Metadata/Items/Rings/Ring14'}},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random_3, m_util.html.poe_color('rare', i18n.upgraded_from_tooltips.two_stone_ring))
 
end,
 
groups = {
 
{
 
-- Утраченная любовь Лантадора
 
item_id = "Metadata/Items/DivinationCards/DivinationCardLantadorsLostLove",
 
amount = 7,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', values={'Metadata/Items/Rings/Ring12', 'Metadata/Items/Rings/Ring13', 'Metadata/Items/Rings/Ring14'}},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random_3, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.two_stone_ring))
 
end,
 
groups = {
 
{
 
-- Гетерохромия
 
item_id = "Metadata/Items/DivinationCards/DivinationCardHeterochromia",
 
amount = 2,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Weapons/OneHandWeapons/OneHandMaces/Sceptre11'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.crystal_sceptre))
 
end,
 
groups = {
 
{
 
-- Свет и правда
 
item_id = "Metadata/Items/DivinationCards/DivinationCardLightAndTruth",
 
amount = 2,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Flasks/FlaskUtility5'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.granite_flask))
 
end,
 
groups = {
 
{
 
-- Пьющий землю
 
item_id = "Metadata/Items/DivinationCards/DivinationCardEarthDrinker",
 
amount = 5,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Armours/Helmets/HelmetStrDex10'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.nightmare_bascinet))
 
end,
 
groups = {
 
{
 
-- Гладиатор
 
item_id = "Metadata/Items/DivinationCards/DivinationCardTheGladiator",
 
amount = 5,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Belts/Belt1'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.rustic_sash))
 
end,
 
groups = {
 
{
 
-- Противоборство
 
item_id = "Metadata/Items/DivinationCards/DivinationCardTheStandoff",
 
amount = 3,
 
},
 
},
 
},
 
{
 
defaults = {
 
is_drop_restricted = false,
 
},
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='base_item_id', value='Metadata/Items/Jewels/JewelTimeless'},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.timeless_jewel))
 
end,
 
groups = {
 
{
 
-- Безмятежные минуты
 
item_id = "Metadata/Items/DivinationCards/DivinationCardPeacefulMoments",
 
amount = 5,
 
},
 
},
 
},
 
{
 
defaults = {
 
is_corrupted = false,
 
},
 
condition = {
 
h.conditions.normal,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Карта храма ваал')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(m_util.html.poe_color('rare', string.format('Карта храма ваал')))
 
end,
 
groups = {
 
{
 
-- Пережитки прошлого
 
item_id = "Metadata/Items/DivinationCards/DivinationCardLingeringRemnants",
 
amount = 16,
 
},
 
},
 
},
 
{
 
defaults = {
 
is_corrupted = false,
 
},
 
condition = {
 
h.conditions.normal,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Карта террасы')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(m_util.html.poe_color('rare', string.format('Карта террасы')))
 
end,
 
groups = {
 
{
 
-- Лёгкая прогулка
 
item_id = "Metadata/Items/DivinationCards/DivinationCardTheEasyStroll",
 
amount = 2,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.normal,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Карта колизея')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(m_util.html.poe_color('normal', string.format('Карта колизея')))
 
end,
 
groups = {
 
{
 
-- Чемпион Арены
 
item_id = "Metadata/Items/DivinationCards/DivinationCardTheArenaChampion",
 
amount = 10,
 
},
 
},
 
},
 
--
 
-- Even more specific stuff
 
--
 
{
 
defaults = {
 
is_drop_restricted = false,
 
is_corrupted = false,
 
},
 
condition = {
 
h.conditions.normal,
 
h.conditions.factory.arg{arg='is_talisman', value=true},
 
h.conditions.factory.arg{arg='talisman_tier', value=1},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random_corrupted, m_util.html.poe_color('rare', i18n.upgraded_from_tooltips.tier_1_talisman))
 
end,
 
groups = {
 
{
 
-- Призыв Первых
 
item_id = "Metadata/Items/DivinationCards/DivinationCardCallToTheFirstOnes",
 
amount = 5,
 
},
 
},
 
},
 
{
 
defaults = {
 
is_drop_restricted = false,
 
is_corrupted = false,
 
},
 
condition = {
 
h.conditions.factory.arg{arg='is_talisman', value=true},
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, i18n.upgraded_from_tooltips.talisman)
 
end,
 
groups = {
 
{
 
-- Первобытный инкубатор
 
item_id = "Metadata/Items/Currency/CurrencyIncubationTalismans",
 
amount = 1,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Атзири')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', string.format(i18n.upgraded_from_tooltips.f.x_item, 'Атзири')))
 
end,
 
groups = {
 
{
 
-- Поклонник
 
item_id = "Metadata/Items/DivinationCards/DivinationCardTheAdmirer",
 
amount = 9,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Доэдре')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', string.format(i18n.upgraded_from_tooltips.f.x_item, 'Доэдре')))
 
end,
 
groups = {
 
{
 
-- Безумие Доэдре
 
item_id = "Metadata/Items/DivinationCards/DivinationCardDoedresMadness",
 
amount = 9,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Шавронн')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', string.format(i18n.upgraded_from_tooltips.f.x_item, 'Шавронн')))
 
end,
 
groups = {
 
{
 
-- Эстет
 
item_id = "Metadata/Items/DivinationCards/DivinationCardTheAesthete",
 
amount = 8,
 
},
 
},
 
},
 
{
 
defaults = {
 
is_drop_restricted = false,
 
},
 
condition = {
 
h.conditions.unique,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Ригвальда')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', string.format(i18n.upgraded_from_tooltips.f.x_item, 'Ригвальда')))
 
end,
 
groups = {
 
{
 
-- Волк
 
item_id = "Metadata/Items/DivinationCards/DivinationCardTheWolf",
 
amount = 5,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Львиного глаза')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', string.format(i18n.upgraded_from_tooltips.f.x_item, 'Львиного глаза')))
 
end,
 
groups = {
 
{
 
-- Лев
 
item_id = "Metadata/Items/DivinationCards/DivinationCardTheLion",
 
amount = 5,
 
},
 
},
 
},
 
{
 
defaults = {
 
is_drop_restricted = false,
 
},
 
condition = {
 
h.conditions.unique,
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Фаррул')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random, m_util.html.poe_color('unique', string.format(i18n.upgraded_from_tooltips.f.x_item, 'Фаррул')))
 
end,
 
groups = {
 
{
 
-- Кошачий совет
 
item_id = "Metadata/Items/DivinationCards/DivinationCardCouncilOfCats",
 
amount = 4,
 
},
 
},
 
},
 
{
 
condition = {
 
h.conditions.unique,
 
h.conditions.factory.arg{arg='class_id', value='Jewel'},
 
function (tpl_args, frame)
 
return string.find(tpl_args.name, 'Первородн')
 
end,
 
},
 
text = function (tpl_args, frame)
 
return string.format(i18n.upgraded_from_tooltips.f.random_primordial, m_util.html.poe_color('unique', i18n.upgraded_from_tooltips.jewel))
 
end,
 
groups = {
 
{
 
-- Первородный
 
item_id = "Metadata/Items/DivinationCards/DivinationCardThePrimordial",
 
amount = 5,
 
},
 
},
 
},
 
{
 
defaults = {
 
is_drop_restricted = false,
 
is_corrupted = false,