Module:Iteminfo/datagen

From Terraria Wiki
Jump to navigation Jump to search
Lua.svg Documentation The documentation below is transcluded from Module:Iteminfo/datagen/doc. (edit | history)

This helper module is used for generating the item database, Module:Iteminfo/data. See that page for instructions on how to invoke this helper module.

The code of this module reproduces the Terraria.Item.SetDefaults method and its siblings from Terraria's source code, ported from C# to Lua. Various other methods or snippets of methods needed to generate item information are also included. The code is based on version 1.4.4.9.

Some of the data generation functionality is offloaded to submodules of this module. Notably, the SetDefaults<n> methods are each reproduced here in their own submodule, e.g. Module:Iteminfo/datagen/2 for SetDefaults2.

  • As this is a helper module which is only invoked manually, it is not needed in language wikis (and the submodules are not needed either). Only the final item database (Module:Iteminfo/data) is required there.


    local trim = mw.text.trim
    local ItemIdSets = require('Module:Iteminfo/idSets').getValue
    local ProjectileInfo = require('Module:Projectileinfo').getProjectileInfo
    local GameText = require('Module:GameText').getText
    
    ---A cached version of the current frame, the interface to the parser.
    local currentFrame
    
    ---Return a trimmed version of the value of the template parameter with the specified `key`.
    ---Return `nil` if the parameter is empty or unset.
    ---@param key string|number
    ---@return string|nil
    local function getArg(key)
    	local value = currentFrame.args[key]
    	if not value then
    		return nil
    	end
    	value = trim(value)
    	if value == '' then
    		return nil
    	end
    	return value
    end
    
    
    --
    -- In this module and its submodules, Terraria's C# code is reproduced in Lua.
    -- Terraria version: as below (Desktop version)
    --
    
    local terrariaversion = '1.4.4.9'
    
    
    -- import Item, AmmoID, SoundID, etc.
    local extdata = require('Module:Iteminfo/datagen/extdata')
    -- create reverse ItemID
    extdata.ItemInternalName = {}
    for internalname, itemid in pairs(extdata.ItemID) do
    	extdata.ItemInternalName[itemid] = internalname
    end
    for k, v in pairs(extdata) do
    	_G[k] = v
    end
    
    -- from resource file: Terraria.GameContent.Creative.Content.Sacrifices.tsv
    local sacrifices = mw.loadData('Module:Iteminfo/datagen/sacrifices')
    
    -- Terraria.GameContent.Creative.CreativeItemSacrificesCatalog.Initialize()
    local function getSacrificesCount(internalName)
    	if not sacrifices[internalName] then
    		return
    	end
    	local type = string.lower(sacrifices[internalName])
    	if type == "e" then
    		return
    	end
    	local num1
    	if type == "" or type == "a" then
    		num1 = 50;
    	elseif type == "b" then
    		num1 = 25;
    	elseif type == "c" then
    		num1 = 5;
    	elseif type == "d" then
    		num1 = 1;
    	elseif type == "e" then
    		flag = true;
    	elseif type == "f" then
    		num1 = 2;
    	elseif type == "g" then
    		num1 = 3;
    	elseif type == "h" then
    		num1 = 10;
    	elseif type == "i" then
    		num1 = 15;
    	elseif type == "j" then
    		num1 = 30;
    	elseif type == "k" then
    		num1 = 99;
    	elseif type == "l" then
    		num1 = 100;
    	elseif type == "m" then
    		num1 = 200;
    	elseif type == "n" then
    		num1 = 20;
    	elseif type == "o" then
    		num1 = 400;
    	end
    	return num1
    end
    
    --------------------------------
    local this = {}
    
    --Terraria.Item.SetShopValues(ItemRarityColor rarity, int coinValue)
    this.SetShopValues = function(rarity, coinValue)
    	this.rare = rarity;
    	this.value = coinValue;
    end
    
    --Terraria.Item.DefaultToAccessory(int newwidth = 24, int newheight = 24)
    this.DefaultToAccessory = function(newwidth, newheight)
    	newwidth = newwidth or 24
    	newheight = newheight or 24
    	----------
    	this.width = newwidth;
    	this.height = newheight;
    	this.accessory = true;
    end
    
    --Terraria.Item.DefaultToBow(int singleShotTime, float shotVelocity, bool hasAutoReuse = false)
    this.DefaultToBow = function(singleShotTime, shotVelocity, hasAutoReuse)
    	hasAutoReuse = hasAutoReuse or false
    	----------
    	this.DefaultToRangedWeapon(1, AmmoID.Arrow, singleShotTime, shotVelocity, hasAutoReuse);
    	this.width = 14;
    	this.height = 30;
    	this.UseSound = SoundID.Item5;
    end
    
    --Terraria.Item.DefaultToCapturedCritter(short npcIdToSpawnOnUse)
    this.DefaultToCapturedCritter = function(npcIdToSpawnOnUse)
    	this.useStyle = 1;
    	this.autoReuse = true;
    	this.useTurn = true;
    	this.useAnimation = 15;
    	this.useTime = 10;
    	this.maxStack = Item.CommonMaxStack;
    	this.consumable = true;
    	this.width = 12;
    	this.height = 12;
    	this.noUseGraphic = true;
    	this.makeNPC = npcIdToSpawnOnUse;
    end
    
    --Terraria.Item.DefaultToFood(int newwidth, int newheight, int foodbuff, int foodbuffduration, bool useGulpSound = false, int animationTime = 17)
    this.DefaultToFood = function(newwidth, newheight, foodbuff, foodbuffduration, useGulpSound, animationTime)
    	useGulpSound = useGulpSound or false
    	animationTime = animationTime or 17
    	----------
    	if (not useGulpSound) then
    		this.UseSound = SoundID.Item2;
    	else
    		this.UseSound = SoundID.Item3;
    	end
    	if (not useGulpSound) then
    		this.useStyle = 2;
    	else
    		this.useStyle = 9;
    	end
    	this.useTurn = true;
    	local num = animationTime;
    	local num1 = num;
    	this.useTime = num;
    	this.useAnimation = num1;
    	this.maxStack = Item.CommonMaxStack;
    	this.consumable = true;
    	this.width = newwidth;
    	this.height = newheight;
    	this.buffType = foodbuff;
    	this.buffTime = foodbuffduration;
    	this.rare = 1;
    	this.value = Item.buyPrice(0, 0, 20, 0);
    end
    
    --Terraria.Item.DefaultToGolfBall(int projid)
    this.DefaultToGolfBall = function(projid)
    	this.shoot = projid;
    	this.useStyle = 1;
    	this.shootSpeed = 12;
    	this.width = 18;
    	this.height = 20;
    	this.maxStack = 1;
    	this.UseSound = SoundID.Item1;
    	this.useAnimation = 15;
    	this.useTime = 15;
    	this.noUseGraphic = true;
    	this.noMelee = true;
    	this.value = 0;
    	this.accessory = true;
    	this.SetShopValues(ItemRarityColor.Green2, Item.buyPrice(0, 1, 0, 0));
    	this.hasVanityEffects = true;
    end
    
    --Terraria.Item.DefaultToGolfClub(int newwidth, int newheight)
    this.DefaultToGolfClub = function(newwidth, newheight)
    	this.width = newwidth;
    	this.height = newheight;
    	this.channel = true;
    	this.useStyle = 8;
    	this.holdStyle = 4;
    	this.shootSpeed = 6;
    	this.shoot = 722;
    	this.UseSound = null;
    	local num = 12;
    	local num1 = num;
    	this.useTime = num;
    	this.useAnimation = num1;
    	this.noMelee = true;
    end
    
    --Terraria.Item.DefaultToGuitar(int newwidth = 24, int newheight = 24)
    this.DefaultToGuitar = function(newwidth, newheight)
    	newwidth = newwidth or 24
    	newheight = newheight or 24
    	----------
    	this.width = newwidth;
    	this.height = newheight;
    	this.autoReuse = true;
    	this.holdStyle = 5;
    	this.useStyle = 12;
    	local num = 12;
    	local num1 = num;
    	this.useTime = num;
    	this.useAnimation = num1;
    end
    
    --Terraria.Item.DefaultToHeadgear(int newwidth, int newheight, int helmetArtID)
    this.DefaultToHeadgear = function(newwidth, newheight, helmetArtID)
    	this.width = newwidth;
    	this.height = newheight;
    	this.headSlot = helmetArtID;
    end
    
    --Terraria.Item.DefaultToHealingPotion(int newwidth, int newheight, int healingAmount, int animationTime = 17)
    this.DefaultToHealingPotion = function(newwidth, newheight, healingAmount, animationTime)
    	animationTime = animationTime or 17
    	----------
    	this.UseSound = SoundID.Item3;
    	this.useStyle = 9;
    	this.useTurn = true;
    	local num = animationTime;
    	local num1 = num;
    	this.useTime = num;
    	this.useAnimation = num1;
    	this.maxStack = Item.CommonMaxStack;
    	this.consumable = true;
    	this.width = newwidth;
    	this.height = newheight;
    	this.rare = 1;
    	this.value = Item.buyPrice(0, 0, 20, 0);
    	this.potion = true;
    	this.healLife = healingAmount;
    end
    
    --Terraria.Item.DefaultTokite(int projId)
    this.DefaultTokite = function(projId)
    	this.width = 20;
    	this.height = 28;
    	this.DefaultToThrownWeapon(projId, 30, 2, false);
    	this.consumable = false;
    	this.ranged = false;
    	this.noUseGraphic = true;
    	this.maxStack = 1;
    	this.SetShopValues(ItemRarityColor.Blue1, Item.buyPrice(0, 2, 0, 0));
    end
    
    --Terraria.Item.DefaultToLawnMower(int newwidth, int newheight)
    this.DefaultToLawnMower = function(newwidth, newheight)
    	this.width = newwidth;
    	this.height = newheight;
    	this.holdStyle = 1;
    	this.useStyle = 11;
    	this.useAnimation = 30;
    	this.useTime = 10;
    	this.UseSound = SoundID.Item23;
    	this.autoReuse = true;
    end
    
    --Terraria.Item.DefaultToMagicWeapon(int projType, int singleShotTime, float shotVelocity, bool hasAutoReuse = false)
    this.DefaultToMagicWeapon = function(projType, singleShotTime, shotVelocity, hasAutoReuse)
    	hasAutoReuse = hasAutoReuse or false
    	----------
    	this.autoReuse = hasAutoReuse;
    	this.useStyle = 5;
    	this.useAnimation = singleShotTime;
    	this.useTime = singleShotTime;
    	this.shoot = projType;
    	this.shootSpeed = shotVelocity;
    	this.noMelee = true;
    	this.magic = true;
    end
    
    --Terraria.Item.DefaultToMount(int mount)
    this.DefaultToMount = function(mount)
    	this.width = 36;
    	this.height = 26;
    	this.mountType = mount;
    end
    
    --Terraria.Item.DefaultToMusicBox(int style)
    this.DefaultToMusicBox = function(style)
    	this.useStyle = 1;
    	this.useTurn = true;
    	this.useAnimation = 15;
    	this.useTime = 10;
    	this.autoReuse = true;
    	this.consumable = true;
    	this.createTile = 139;
    	this.placeStyle = style;
    	this.width = 24;
    	this.height = 24;
    	this.rare = 4;
    	this.value = 100000;
    	this.accessory = true;
    	this.hasVanityEffects = true;
    end
    
    --Terraria.Item.DefaultToPlaceableTile(ushort tileIDToPlace, int tileStyleToPlace = 0)
    this.DefaultToPlaceableTile = function(tileIDToPlace, tileStyleToPlace)
    	tileStyleToPlace = tileStyleToPlace or 0
    	----------
    	this.createTile = tileIDToPlace;
    	this.placeStyle = tileStyleToPlace;
    	this.width = 14;
    	this.height = 14;
    	this.useStyle = 1;
    	this.useAnimation = 15;
    	this.useTime = 10;
    	this.maxStack = Item.CommonMaxStack;
    	this.useTurn = true;
    	this.autoReuse = true;
    	this.consumable = true;
    end
    
    --Terraria.Item.DefaultToPlaceableWall(ushort wallToPlace)
    this.DefaultToPlaceableWall = function(wallToPlace)
    	this.useStyle = 1;
    	this.useTurn = true;
    	this.useAnimation = 15;
    	this.useTime = 7;
    	this.autoReuse = true;
    	this.maxStack = Item.CommonMaxStack;
    	this.consumable = true;
    	this.createWall = wallToPlace;
    	this.width = 12;
    	this.height = 12;
    end
    
    --Terraria.Item.DefaultToQuestFish()
    this.DefaultToQuestFish = function()
    	this.questItem = true;
    	this.maxStack = 1;
    	this.width = 26;
    	this.height = 26;
    	this.uniqueStack = true;
    	this.rare = -11;
    end
    
    --Terraria.Item.DefaultToRangedWeapon(int baseProjType, int ammoID, int singleShotTime, float shotVelocity, bool hasAutoReuse = false)
    this.DefaultToRangedWeapon = function(baseProjType, ammoID, singleShotTime, shotVelocity, hasAutoReuse)
    	hasAutoReuse = hasAutoReuse or false
    	----------
    	this.autoReuse = hasAutoReuse;
    	this.useStyle = 5;
    	this.useAnimation = singleShotTime;
    	this.useTime = singleShotTime;
    	this.shoot = baseProjType;
    	this.useAmmo = ammoID;
    	this.shootSpeed = shotVelocity;
    	this.noMelee = true;
    	this.ranged = true;
    end
    
    --Terraria.Item.DefaultToSeaShell()
    this.DefaultToSeaShell = function()
    	this.useStyle = 1;
    	this.autoReuse = true;
    	this.useAnimation = 15;
    	this.useTime = 10;
    	this.maxStack = Item.CommonMaxStack;
    	this.consumable = true;
    	this.createTile = 324;
    	this.width = 22;
    	this.height = 22;
    	local num = this.type;
    	if (num == 2626) then
    		this.placeStyle = 1;
    		this.value = Item.sellPrice(0, 0, 10, 0);
    		return;
    	end
    	if num == 4071 then
    		this.placeStyle = 4;
    		this.value = Item.sellPrice(0, 1, 0, 0);
    		return;
    	elseif num == 4072 then
    		this.placeStyle = 2;
    		this.value = Item.sellPrice(0, 0, 20, 0);
    		return;
    	elseif num == 4073 then
    		this.placeStyle = 3;
    		this.value = Item.sellPrice(0, 0, 20, 0);
    		return;
    	end
    	this.value = Item.sellPrice(0, 0, 5, 0);
    end
    
    --Terraria.Item.DefaultToSolution(int projectileId)
    this.DefaultToSolution = function(projectileId)
    	this.shoot = projectileId - 145;
    	this.ammo = AmmoID.Solution;
    	this.width = 10;
    	this.height = 12;
    	this.value = Item.buyPrice(0, 0, 15, 0);
    	this.rare = 3;
    	this.maxStack = Item.CommonMaxStack;
    	this.consumable = true;
    end
    
    --Terraria.Item.DefaultToSpear(int projType, float pushForwardSpeed, int animationTime)
    this.DefaultToSpear = function(projType, pushForwardSpeed, animationTime)
    	this.useStyle = 5;
    	this.useAnimation = 31;
    	this.useTime = 31;
    	this.shootSpeed = pushForwardSpeed;
    	this.width = 32;
    	this.height = 32;
    	this.UseSound = SoundID.Item1;
    	this.shoot = projType;
    	this.noMelee = true;
    	this.noUseGraphic = true;
    	this.melee = true;
    	local num = animationTime;
    	local num1 = num;
    	this.useTime = num;
    	this.useAnimation = num1;
    end
    
    --Terraria.Item.DefaultToStaff(int projType, float pushForwardSpeed, int singleShotTime, int manaPerShot)
    this.DefaultToStaff = function(projType, pushForwardSpeed, singleShotTime, manaPerShot)
    	this.DefaultToMagicWeapon(projType, singleShotTime, pushForwardSpeed, true);
    	this.mana = manaPerShot;
    	this.width = 40;
    	this.height = 40;
    	this.UseSound = SoundID.Item43;
    end
    
    --Terraria.Item.DefaultToThrownWeapon(int baseProjType, int singleShotTime, float shotVelocity, bool hasAutoReuse = false)
    this.DefaultToThrownWeapon = function(baseProjType, singleShotTime, shotVelocity, hasAutoReuse)
    	hasAutoReuse = hasAutoReuse or false
    	----------
    	this.autoReuse = hasAutoReuse;
    	this.useStyle = 1;
    	this.useAnimation = singleShotTime;
    	this.useTime = singleShotTime;
    	this.shoot = baseProjType;
    	this.shootSpeed = shotVelocity;
    	this.noMelee = true;
    	this.ranged = true;
    	this.consumable = true;
    	this.maxStack = Item.CommonMaxStack;
    end
    
    --Terraria.Item.DefaultToTorch(int tileStyleToPlace, bool allowWaterPlacement = false)
    this.DefaultToTorch = function(tileStyleToPlace, allowWaterPlacement)
    	allowWaterPlacement = allowWaterPlacement or false
    	----------
    	this.flame = true;
    	this.noWet = not allowWaterPlacement;
    	this.holdStyle = 1;
    	this.autoReuse = true;
    	this.maxStack = Item.CommonMaxStack;
    	this.consumable = true;
    	this.createTile = 4;
    	this.placeStyle = tileStyleToPlace;
    	this.width = 10;
    	this.height = 12;
    	this.value = 60;
    	this.useStyle = 1;
    	this.useTurn = true;
    	this.useAnimation = 15;
    	this.useTime = 10;
    end
    
    --Terraria.Item.DefaultToVanitypet(int projId, int buffID)
    this.DefaultToVanitypet = function(projId, buffID)
    	this.damage = 0;
    	this.useStyle = 1;
    	this.width = 16;
    	this.height = 30;
    	this.UseSound = SoundID.Item2;
    	this.useAnimation = 20;
    	this.useTime = 20;
    	this.rare = 3;
    	this.noMelee = true;
    	this.value = Item.sellPrice(0, 2, 0, 0);
    	this.buffType = buffID;
    	this.shoot = projId;
    end
    
    --Terraria.Item.DefaultToWhip(int projectileId, int dmg, float kb, float shootspeed, int animationTotalTime = 30)
    this.DefaultToWhip = function(projectileId, dmg, kb, shootspeed, animationTotalTime)
    	animationTotalTime = animationTotalTime or 30
    	----------
    	this.autoReuse = false;
    	this.useStyle = 1;
    	this.useAnimation = animationTotalTime;
    	this.useTime = animationTotalTime;
    	this.width = 18;
    	this.height = 18;
    	this.shoot = projectileId;
    	this.UseSound = SoundID.Item152;
    	this.noMelee = true;
    	this.summon = true;
    	this.noUseGraphic = true;
    	this.damage = dmg;
    	this.knockBack = kb;
    	this.shootSpeed = shootspeed;
    	----------
    	-- crit chance fix for whips:
    	this.crit = 0 -- all whips cannot normally deal critical hits.
    end
    
    --Terraria.Item.SetWeaponValues(int dmg, float knockback, int bonusCritChance = 0)
    this.SetWeaponValues = function(dmg, knockback, bonusCritChance)
    	bonusCritChance = bonusCritChance or 0
    	----------
    	this.damage = dmg;
    	this.knockBack = knockback;
    	this.crit = bonusCritChance;
    end
    
    --Terraria.Item.MakeUsableWithChlorophyteExtractinator()
    this.MakeUsableWithChlorophyteExtractinator = function()
    	this.useStyle = 1;
    	this.useAnimation = 15;
    	this.useTime = 10;
    	this.chlorophyteExtractinatorConsumable = true;
    	this.autoReuse = true;
    	this.consumable = true;
    end
    
    --Terraria.Item.ResetStats(int Type)
    this.ResetStats = function(Type)
    	-- reset all data fields
    	for k, v in pairs(this) do
    		if not (type(v) == 'function' or type(v) == 'table') then
    			this[k] = nil
    		end
    	end
    	----- "const" -----
    	this.shadowOrbPrice = Item.sellPrice(0, 1, 50, 0);
    	this.dungeonPrice = Item.sellPrice(0, 1, 75, 0);
    	this.queenBeePrice = Item.sellPrice(0, 2, 0, 0);
    	this.hellPrice = Item.sellPrice(0, 2, 50, 0);
    	this.eclipsePrice = Item.sellPrice(0, 7, 50, 0);
    	this.eclipsePostPlanteraPrice = Item.sellPrice(0, 10, 0, 0);
    	this.eclipseMothronPrice = Item.sellPrice(0, 12, 50, 0);
    	----------
    	this.tooltipContext = -1
    	--this.BestiaryNotes = null;
    	this.sentry = false
    	this.hasVanityEffects = false
    	this.DD2Summon = false
    	this.shopSpecialCurrency = -1
    	this.shopCustomPrice = false
    	this.expert = false
    	this.isAShopItem = false
    	this.expertOnly = false
    	this.instanced = false
    	this.questItem = false
    	this.fishingPole = 0
    	this.bait = 0
    	this.hairDye = -1
    	this.makeNPC = 0
    	this.dye = 0
    	this.paint = 0
    	this.paintCoating = 0
    	this.tileWand = -1
    	this.notAmmo = false
    	this.netID = 0
    	this.prefix = 0
    	this.crit = 0
    	this.mech = false
    	this.flame = false
    	this.reuseDelay = 0
    	this.melee = false
    	this.magic = false
    	this.ranged = false
    	this.summon = false
    	this.placeStyle = 0
    	this.buffTime = 0
    	this.buffType = 0
    	this.mountType = -1
    	this.cartTrack = false
    	this.material = false
    	this.craftable = false
    	this.noWet = false
    	this.vanity = false
    	this.mana = 0
    	this.wet = false
    	this.wetCount = 0
    	this.lavaWet = false
    	this.channel = false
    	this.manaIncrease = 0
    	--this.timeSinceTheItemHasBeenReservedForSomeone = 0
    	this.noMelee = false
    	this.noUseGraphic = false
    	this.lifeRegen = 0
    	this.shootSpeed = 0
    	this.active = true
    	this.alpha = 0
    	this.ammo = AmmoID.None
    	this.useAmmo = AmmoID.None
    	this.autoReuse = false
    	this.accessory = false
    	this.axe = 0
    	this.healMana = 0
    	this.bodySlot = -1
    	this.legSlot = -1
    	this.headSlot = -1
    	this.potion = false
    	--this.color = new_Color()
    	this.glowMask = -1
    	this.consumable = false
    	this.createTile = -1
    	this.createWall = -1
    	this.damage = -1
    	this.defense = 0
    	this.hammer = 0
    	this.healLife = 0
    	this.holdStyle = 0
    	this.knockBack = 0
    	this.maxStack = 1
    	this.pick = 0
    	this.rare = 0
    	this.scale = 1
    	this.shoot = 0
    	--this.stack = 1
    	--this.ToolTip = null
    	this.tileBoost = 0
    	this.useStyle = 0
    	this.UseSound = ''
    	this.useTime = 100
    	this.useAnimation = 100
    	this.value = 0
    	this.useTurn = false
    	this.buy = false
    	this.handOnSlot = -1
    	this.handOffSlot = -1
    	this.backSlot = -1
    	this.frontSlot = -1
    	this.shoeSlot = -1
    	this.waistSlot = -1
    	this.wingSlot = -1
    	this.shieldSlot = -1
    	this.neckSlot = -1
    	this.faceSlot = -1
    	this.balloonSlot = -1
    	this.beardSlot = -1
    	this.uniqueStack = false
    	--this.favorited = false
    	this.shootsEveryUse = false
    	this.Variant = false
    	----------
    	this.type = Type
    	this.rarity = 0
    	this.height = 0
    	this.width = 0
    	this.stringColor = false
    end
    
    --Terraria.Item.netDefaults(int type)
    this.netDefaults = function(type)
    	if type > 0 then
    		this.SetDefaults(type)
    	end
    	if type <= -1 and type >= -18 then
    		this.SetDefaults(3522 + type)
    	end
    	if type <= -19 and type >= -24 then
    		this.SetDefaults(3745 - type)
    	end
    	if type <= -25 and type >= -48 then
    		this.SetDefaults(3528 + type)
    	end
    end
    
    --Terraria.Item.SetDefaults(int Type, bool noMatCheck = false, ItemVariant variant = null)
    this.SetDefaults = function(Type)
    	if Type < 0 then
    		this.netDefaults(Type)
    		return
    	end
    	-- if (Main.netMode == 1 || Main.netMode == 2)
    	-- {
    	--     this.playerIndexTheItemIsReservedFor = 255;
    	-- }
    	-- else
    	-- {
    	--     this.playerIndexTheItemIsReservedFor = Main.myPlayer;
    	-- }
    	this.ResetStats(Type)
    	if this.type >= ItemID.Count then
    		this.type = 0
    	end
    	-- if (variant == null)
    	-- {
    	--     variant = ItemVariants.SelectVariant(Type);
    	-- }
    	-- else if (!ItemVariants.HasVariant(Type, variant))
    	-- {
    	--     variant = null;
    	-- }
    	this.Variant = null;
    	if this.type == 0 then
    		this.netID = 0
    		this.stack = 0
    	elseif ItemIdSets('IsFood', this.type) then
    		this.SetFoodDefaults(this.type)
    	elseif this.type <= 1000 then
    		this.SetDefaults1(this.type)
    	elseif this.type <= 2001 then
    		this.SetDefaults2(this.type)
    	elseif this.type <= 3000 then
    		this.SetDefaults3(this.type)
    	elseif this.type > 3989 then
    		this.SetDefaults5(this.type)
    	else
    		this.SetDefaults4(this.type)
    	end
    	--this.dye = GetShaderIdFromItemId(this.type)
    	this.dye = ItemIdSets('dyes', this.type) and 1 or 0
    	--if this.hairDye ~= 0 then -- -1 by default
    	--	this.hairDye = GameShaders.Hair.GetShaderIdFromItemId(this.type)
    	--end
    	this.hairDye = ItemIdSets('hairDyes', this.type)
    	if this.type == 2015 then
    		this.value = Item.sellPrice(0, 0, 5, 0)
    	end
    	if this.type == 2016 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 2017 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 5212 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 5300 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 5311 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 5312 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 5313 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 2019 then
    		this.value = Item.sellPrice(0, 0, 5, 0)
    	end
    	if this.type == 2018 then
    		this.value = Item.sellPrice(0, 0, 5, 0)
    	end
    	if this.type == 3563 then
    		this.value = Item.sellPrice(0, 0, 5, 0)
    	end
    	if this.type == 261 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 2205 then
    		this.value = Item.sellPrice(0, 0, 12, 50)
    	end
    	if this.type == 2123 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 2122 then
    		this.value = Item.sellPrice(0, 0, 7, 50)
    	end
    	if this.type == 2003 then
    		this.value = Item.sellPrice(0, 0, 10, 0)
    	end
    	if this.type == 2156 then
    		this.value = Item.sellPrice(0, 0, 15, 0)
    	end
    	if this.type == 2157 then
    		this.value = Item.sellPrice(0, 0, 15, 0)
    	end
    	if this.type == 2121 then
    		this.value = Item.sellPrice(0, 0, 10, 0)
    	end
    	if this.type == 1992 then
    		this.value = Item.sellPrice(0, 0, 3, 0)
    	end
    	if this.type == 2004 then
    		this.value = Item.sellPrice(0, 0, 5, 0)
    	end
    	if this.type == 2002 then
    		this.value = Item.sellPrice(0, 0, 5, 0)
    	end
    	if this.type == 2740 then
    		this.value = Item.sellPrice(0, 0, 2, 50)
    	end
    	if this.type == 2006 then
    		this.value = Item.sellPrice(0, 0, 10, 0)
    	end
    	if this.type == 3191 then
    		this.value = Item.sellPrice(0, 0, 20, 0)
    	end
    	if this.type == 3192 then
    		this.value = Item.sellPrice(0, 0, 2, 50)
    	end
    	if this.type == 3193 then
    		this.value = Item.sellPrice(0, 0, 5, 0)
    	end
    	if this.type == 3194 then
    		this.value = Item.sellPrice(0, 0, 10, 0)
    	end
    	if this.type == 2007 then
    		this.value = Item.sellPrice(0, 0, 50, 0)
    	end
    	if this.type == 2673 then
    		this.value = Item.sellPrice(0, 10, 0, 0)
    	end
    	if this.bait > 0 then
    		if this.bait >= 50 then
    			this.rare = 3
    		elseif this.bait >= 30 then
    			this.rare = 2
    		elseif this.bait >= 15 then
    			this.rare = 1
    		end
    	end
    	if this.type >= 1994 and this.type <= 2001 then
    		local num = this.type - 1994
    		if num == 0 then
    			this.value = Item.sellPrice(0, 0, 5, 0)
    		end
    		if num == 4 then
    			this.value = Item.sellPrice(0, 0, 10, 0)
    		end
    		if num == 6 then
    			this.value = Item.sellPrice(0, 0, 15, 0)
    		end
    		if num == 3 then
    			this.value = Item.sellPrice(0, 0, 20, 0)
    		end
    		if num == 7 then
    			this.value = Item.sellPrice(0, 0, 30, 0)
    		end
    		if num == 2 then
    			this.value = Item.sellPrice(0, 0, 40, 0)
    		end
    		if num == 1 then
    			this.value = Item.sellPrice(0, 0, 75, 0)
    		end
    		if num == 5 then
    			this.value = Item.sellPrice(0, 1, 0, 0)
    		end
    	end
    	if this.type == 2663 or this.type == 1720 or this.type == 2137 or this.type == 2155 or this.type == 2151 or this.type == 1704 or this.type == 2143 or this.type == 1710 or this.type == 2238 or this.type == 2133 or this.type == 2147 or this.type == 2405 or this.type == 1716 or this.type == 1705 then
    		this.value = Item.sellPrice(0, 2, 0, 0)
    	end
    	if ProjectileInfo(this.shoot).aiStyle == 7 then --if Main.projHook[this.shoot] then
    		this.useStyle = 0
    		this.useTime = 0
    		this.useAnimation = 0
    	end
    	if ItemIdSets('IsDrill', this.type) or ItemIdSets('IsChainsaw', this.type) or this.type == 1262 then
    		this.useTime = math.floor(this.useTime * 0.6)
    		if this.useTime < 1 then
    			this.useTime = 1
    		end
    		this.useAnimation = math.floor(this.useAnimation * 0.6)
    		if this.useAnimation < 1 then
    			this.useAnimation = 1
    		end
    		this.tileBoost = this.tileBoost - 1
    	end
    	if ItemIdSets('IsFood', this.type) then
    		this.holdStyle = 1
    	end
    	if this.type >= 1803 and this.type <= 1807 then
    		this.SetDefaults(1533 + this.type - 1803)
    	end
    	if this.dye > 0 then
    		this.maxStack = Item.CommonMaxStack
    	end
    	if this.createTile == 19 then
    		this.maxStack = Item.CommonMaxStack
    	end
    	this.netID = this.type
    	-- this.material = ItemID.Sets.IsAMaterial[this.type]  // use {{recipes}}
    
    	--RebuildTooltip() // use {{itemTooltip}} or {{gameText}}
    	if this.type > 0 and this.type < ItemID.Count and ItemIdSets('Unused', this.type) then
    		this.netID = 0
    		this.type = 0
    		this.stack = 0
    	end
    end
    
    this.SetDefaults1 = require('Module:Iteminfo/datagen/1').factory(this)
    this.SetDefaults2 = require('Module:Iteminfo/datagen/2').factory(this)
    this.SetDefaults3 = require('Module:Iteminfo/datagen/3').factory(this)
    this.SetDefaults5 = require('Module:Iteminfo/datagen/5').factory(this)
    this.SetDefaults4 = require('Module:Iteminfo/datagen/4').factory(this)
    this.SetFoodDefaults = require('Module:Iteminfo/datagen/food').factory(this)
    
    local function export(var)
    	local t = mw.dumpObject(var)
    	t = string.gsub(t, "table#1 ", "")
    	t = string.gsub(t, "metatable = table#2", "")
    	t = string.gsub(t, "  +", "")
    	t = string.gsub(t, "\n+", "\n")
    	return t
    end
    
    this.getInfo = function()
    	local info = {}
    	for k, v in pairs(this) do
    		if not (type(v) == 'table' or type(v) == 'function' or type(v) == 'nil') then
    			info[k] = v
    		end
    	end
    	return info
    end
    
    local function iteminfo(itemid)
    	this.SetDefaults(itemid)
    	local info = this.getInfo()
    	-- other stats:
    	local frame = mw.getCurrentFrame()
    	info.internalName = ItemInternalName[itemid]
    	info.name = GameText('ItemName.' .. info.internalName, 'en', nil, true) or ''
    	info.sacrifices = getSacrificesCount(info.internalName) or 0
    	-- crafting:
    	info.material = (frame:expandTemplate { title = 'recipes/exist', args = { ingredient = info.name } } ~= '')
    	info.craftable = (frame:expandTemplate { title = 'recipes/exist', args = { result = info.name } } ~= '')
    
    	-- DD2shop (Chest.SetupShop)
    	if itemid == 3813 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3818 then
    		info.shopCustomPrice = 5
    	end
    	if itemid == 3824 then
    		info.shopCustomPrice = 5
    	end
    	if itemid == 3832 then
    		info.shopCustomPrice = 5
    	end
    	if itemid == 3829 then
    		info.shopCustomPrice = 5
    	end
    	if itemid == 3819 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3825 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3833 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3830 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3820 then
    		info.shopCustomPrice = 60
    	end
    	if itemid == 3826 then
    		info.shopCustomPrice = 60
    	end
    	if itemid == 3834 then
    		info.shopCustomPrice = 60
    	end
    	if itemid == 3831 then
    		info.shopCustomPrice = 60
    	end
    	if itemid == 3800 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3801 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3802 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3797 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3798 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3799 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3803 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3804 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3805 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3806 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3807 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3808 then
    		info.shopCustomPrice = 15
    	end
    	if itemid == 3871 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3872 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3873 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3874 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3875 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3876 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3877 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3878 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3879 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3880 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3881 then
    		info.shopCustomPrice = 50
    	end
    	if itemid == 3882 then
    		info.shopCustomPrice = 50
    	end
    
    	-- projectile fix: (Player.ItemCheck_Shoot)
    	if (itemid == 682) then
    		info.shoot = 117;
    	end
    	if (itemid == 725) then
    		info.shoot = 120;
    	end
    	if (itemid == 2796) then
    		info.shoot = 442;
    	end
    	if (itemid == 2223) then
    		info.shoot = 357;
    	end
    	if (itemid == 5117) then
    		info.shoot = 968;
    	end
    
    	-- expert item:
    	if itemid ~= 0 then
    		info.rarity = nil
    	end
    	if info.expert then
    		info.rarity = info.rare
    		info.rare = -12
    	end
    	-- crit fix for Morning Star (4679): Whips cannot normally deal critical hits.
    	if (itemid == 4679) then
    		info.crit = 0
    	end
    
    	-- unset unused fields
    	info.expertOnly = nil
    	info.favorited = nil
    	info.stack = nil
    	info.shadowOrbPrice = nil
    	info.dungeonPrice = nil
    	info.queenBeePrice = nil
    	info.hellPrice = nil
    	info.eclipsePrice = nil
    	info.eclipsePostPlanteraPrice = nil
    	info.eclipseMothronPrice = nil
    	info.color = nil -- not really useful
    
    	-- damage adjustments
    	info.damage = info.damage * require('Module:Iteminfo/idSets').getValue('ToolTipDamageMultiplier', itemid)
    
    	return info
    end
    
    
    ---Return a copy of `data` where all keys are removed that have the same value
    ---as the respective keys in `default`. In other words: identify all the non-default
    ---values in `data`.
    ---@param data table
    ---@param default table
    ---@return table
    local function diff(data, default)
    	local nondefaultData = {}
    	for k, v in pairs(data) do
    		if v ~= default[k] then
    			nondefaultData[k] = v
    		end
    	end
    	return nondefaultData
    end
    
    ---------------------------
    
    local p = {
    
    	-- for other modules: get all stats of an item, return them as a table
    	getInfo = iteminfo,
    
    	-- for templates: generate a data slice
    	gen = function(frame)
    		currentFrame = frame -- cache
    		local min = tonumber(getArg(1)) or 0
    		local max = tonumber(getArg(2)) or 0
    
    		local output = ''
    
    		local default = iteminfo(0)
    		-- SetDefaults(0)
    		-- local reset = { name = '', internalName = '' }
    		-- for k,v in pairs(this) do
    		-- 	reset[k] = v
    		-- end
    
    		for itemid = min, max do
    			local data = iteminfo(itemid)
    			local info
    			if itemid ~= 0 then
    				info = diff(data, default)
    			else
    				info = data
    			end
    			info.type = nil
    			output = output .. '\n["' .. itemid .. '"] = ' .. (string.gsub(export(info), '’', "'")) .. ',' -- number index may cause problem in mw.text.jsonEncode()
    		end
    
    		return output
    	end,
    
    	-- for templates: print the "meta" rows with timestamp and Terraria version
    	genMeta = function(frame)
    		local timestamp = os.date('!%Y-%m-%d %H:%M:%S') .. ' (+00:00)' -- the "!" forces UTC
    		return
    			"\n['_terrariaversion'] = '" .. terrariaversion .. "',"
    			.. "\n['_generated'] = '" .. timestamp .. "',"
    	end,
    
    	-- for other modules: return the "extdata"
    	extdata = function()
    		return extdata
    	end,
    	
    	convertToJsonData = function()
    		str = '-'..'- This module contains a database with the statistics of all items, which is queried by Module:Iteminfo.\n' 
    		.. '-'..'- It was generated from Module:Iteminfo/datagen.\n'
    		.. 'return {\n'
    
    		local data = require('Module:Iteminfo/luadata')
    		str = str .. '["data"] = [====='..'[' ..  mw.text.jsonEncode(data) .. ']=====' .. '],\n'
    		local itemInternalNameFromId = {['_dummy']='none'} -- force it to be an object instead of a list.
    		local itemIdFromInternalName = {}
    		local itemNameFromId = {['_dummy']='none'} -- Not actually needed because indexes are not a continuous sequence.
    		local itemIdFromName = {}
    		for id, iteminfo in pairs(data) do
    			local n = tonumber(id)
    			if n and n > 0 then
    				if iteminfo.name then
    					itemNameFromId[id] = iteminfo.name
    					itemIdFromName[iteminfo.name] = id
    				end 
    				if iteminfo.internalName then
    					itemInternalNameFromId[id] = iteminfo.internalName
    					itemIdFromInternalName[iteminfo.internalName] = id
    				end
    			end
    		end
    		str = str .. '["nameDB"] = [====='..'[' .. mw.text.jsonEncode({
    			['itemNameFromId'] = itemNameFromId,
    			['itemIdFromName'] = itemIdFromName,
    			['itemInternalNameFromId'] = itemInternalNameFromId,
    			['itemIdFromInternalName'] = itemIdFromInternalName
    		}) .. ']====='..'],\n}'
    	
    		return str
    	end,
    
    }
    return p