ItemStats/Filters

* do not use NULL on item stats as it prevents searching for an amount of 0 (except for stats that certain items just cant have)
 * fix stats from spells granting spell power and spell healing separately
 * define and use some item subclasses
This commit is contained in:
Sarjuuk
2024-09-10 14:44:11 +02:00
parent a62f24b97c
commit c1eecb4c22
6 changed files with 265 additions and 76 deletions

View File

@@ -842,6 +842,75 @@ define('ITEM_CLASS_PERMANENT', 14);
define('ITEM_CLASS_MISC', 15);
define('ITEM_CLASS_GLYPH', 16);
// ItemSubClass - Consumable (0)
define('ITEM_SUBCLASS_CONSUMABLE', 0);
define('ITEM_SUBCLASS_POTION', 1);
define('ITEM_SUBCLASS_ELIXIR', 2);
define('ITEM_SUBCLASS_FLASK', 3);
define('ITEM_SUBCLASS_SCROLL', 4);
define('ITEM_SUBCLASS_FOOD', 5);
define('ITEM_SUBCLASS_ITEM_ENHANCEMENT', 6);
define('ITEM_SUBCLASS_BANDAGE', 7);
define('ITEM_SUBCLASS_MISC_CONSUMABLE', 8);
// ItemSubClass - Container (1)
define('ITEM_SUBCLASS_BAG', 0);
define('ITEM_SUBCLASS_SOUL_BAG', 1);
define('ITEM_SUBCLASS_HERB_BAG', 2);
define('ITEM_SUBCLASS_ENCHANTING_BAG', 3);
define('ITEM_SUBCLASS_ENGINEERING_BAG', 4);
define('ITEM_SUBCLASS_GEM_BAG', 5);
define('ITEM_SUBCLASS_MINING_BAG', 6);
define('ITEM_SUBCLASS_LEATHERWORKING_BAG', 7);
define('ITEM_SUBCLASS_INSCRIPTION_BAG', 8);
// ItemSubClass - Weapon (2)
define('ITEM_SUBCLASS_1H_AXE', 0);
define('ITEM_SUBCLASS_2H_AXE', 1);
define('ITEM_SUBCLASS_BOW', 2);
define('ITEM_SUBCLASS_GUN', 3);
define('ITEM_SUBCLASS_1H_MACE', 4);
define('ITEM_SUBCLASS_2H_MACE', 5);
define('ITEM_SUBCLASS_POLEARM', 6);
define('ITEM_SUBCLASS_1H_SWORD', 7);
define('ITEM_SUBCLASS_2H_SWORD', 8);
define('ITEM_SUBCLASS_OBSOLETE', 9);
define('ITEM_SUBCLASS_STAFF', 10);
define('ITEM_SUBCLASS_1H_EXOTIC', 11);
define('ITEM_SUBCLASS_2H_EXOTIC', 12);
define('ITEM_SUBCLASS_FIST_WEAPON', 13);
define('ITEM_SUBCLASS_MISC_WEAPON', 14);
define('ITEM_SUBCLASS_DAGGER', 15);
define('ITEM_SUBCLASS_THROWN', 16);
define('ITEM_SUBCLASS_SPEAR', 17);
define('ITEM_SUBCLASS_CROSSBOW', 18);
define('ITEM_SUBCLASS_WAND', 19);
define('ITEM_SUBCLASS_FISHING_POLE', 20);
// ItemSubClass - Gem (3)
define('ITEM_SUBCLASS_RED_GEM', 0);
define('ITEM_SUBCLASS_BLUE_GEM', 1);
define('ITEM_SUBCLASS_YELLOW_GEM', 2);
define('ITEM_SUBCLASS_PURPLE_GEM', 3);
define('ITEM_SUBCLASS_GREEN_GEM', 4);
define('ITEM_SUBCLASS_ORANGE_GEM', 5);
define('ITEM_SUBCLASS_META_GEM', 6);
define('ITEM_SUBCLASS_SIMPLE_GEM', 7);
define('ITEM_SUBCLASS_PRISMATIC_GEM', 8);
// ItemSubClass - Armor (4)
define('ITEM_SUBCLASS_MISC_ARMOR', 0);
define('ITEM_SUBCLASS_CLOTH_ARMOR', 1);
define('ITEM_SUBCLASS_LETHER_ARMOR', 2);
define('ITEM_SUBCLASS_MAIL_ARMOR', 3);
define('ITEM_SUBCLASS_PLATE_ARMOR', 4);
define('ITEM_SUBCLASS_BUCKLER', 5);
define('ITEM_SUBCLASS_SHIELD', 6);
define('ITEM_SUBCLASS_LIBRAM', 7);
define('ITEM_SUBCLASS_IDOL', 8);
define('ITEM_SUBCLASS_TOTEM', 9);
define('ITEM_SUBCLASS_SIGIL', 10);
// ItemFlags
define('ITEM_FLAG_CONJURED', 0x00000002);
define('ITEM_FLAG_OPENABLE', 0x00000004);

View File

@@ -403,6 +403,10 @@ class StatsContainer
if (!$spell)
return $this;
// if spells grant an equal, non-zero amount of SPELL_DAMAGE and SPELL_HEALING, combine them to SPELL_POWER
// this probably does not affect enchantments
$tmpStore = [];
for ($i = 1; $i <= 3; $i++)
{
$eff = $spell['effect'.$i.'Id'];
@@ -414,9 +418,18 @@ class StatsContainer
$this->fromEnchantment($relE);
else
foreach ($this->convertSpellEffect($aura, $mVal, $amt) as $idx)
Util::arraySumByKey($this->store, [$idx => $amt]);
$tmpStore[] = [$idx => $amt];
}
if (!empty($tmpStore[Stat::HEALING_SPELL_POWER]) && !empty($tmpStore[Stat::DAMAGE_SPELL_POWER]) && $tmpStore[Stat::HEALING_SPELL_POWER] == $tmpStore[Stat::DAMAGE_SPELL_POWER])
{
$tmpStore[] = [Stat::SPELL_POWER => $tmpStore[Stat::HEALING_SPELL_POWER]];
unset($tmpStore[Stat::HEALING_SPELL_POWER]);
unset($tmpStore[Stat::DAMAGE_SPELL_POWER]);
}
Util::arraySumByKey($this->store, $tmpStore);
return $this;
}
@@ -600,9 +613,9 @@ class StatsContainer
if ($miscValue == (1 << SPELL_SCHOOL_NORMAL))
return [Stat::WEAPON_DAMAGE];
// full magic mask, also counts towards healing
// full magic mask
if ($miscValue == SPELL_MAGIC_SCHOOLS)
return [Stat::SPELL_POWER, Stat::DAMAGE_SPELL_POWER, Stat::HEALING_SPELL_POWER];
return [Stat::DAMAGE_SPELL_POWER];
// HolySpellpower (deprecated; still used in randomproperties)
if ($miscValue & (1 << SPELL_SCHOOL_HOLY))

View File

@@ -1429,7 +1429,7 @@ class ItemList extends BaseType
if ($dps <= 54.8)
return 0.0;
$subClasses = [14]; // Misc Weapons
$subClasses = [ITEM_SUBCLASS_MISC_WEAPON];
$weaponTypeMask = DB::Aowow()->selectCell('SELECT `weaponTypeMask` FROM ?_classes WHERE `id` = ?d', log(CLASS_DRUID, 2) + 1);
if ($weaponTypeMask)
for ($i = 0; $i < 21; $i++)
@@ -1443,6 +1443,14 @@ class ItemList extends BaseType
return round(($dps - 54.8) * 14);
}
public function isRangedWeapon() : bool
{
if ($this->curTpl['class'] != ITEM_CLASS_WEAPON)
return false;
return in_array($this->curTpl['subClassBak'], [ITEM_SUBCLASS_BOW, ITEM_SUBCLASS_GUN, ITEM_SUBCLASS_THROWN, ITEM_SUBCLASS_CROSSBOW, ITEM_SUBCLASS_WAND]);
}
private function formatRating(int $statId, int $itemMod, int $qty, bool $interactive = false, bool &$scaling = false) : string
{
// clamp level range
@@ -1716,7 +1724,7 @@ class ItemList extends BaseType
$json['speed'] = round($this->curTpl['delay'] / 1000, 2);
$json['dps'] = $json['speed'] ? round(($json['dmgmin1'] + $json['dmgmax1']) / (2 * $json['speed']), 1) : 0;
if (in_array($subclass, [2, 3, 18, 19]))
if ($this->isRangedWeapon())
{
$json['rgddmgmin'] = $json['dmgmin1'];
$json['rgddmgmax'] = $json['dmgmax1'];
@@ -2015,7 +2023,7 @@ class ItemListFilter extends Filter
foreach ($classes as $cId => [$weaponTypeMask, $armorTypeMask])
{
// preselect misc subclasses
$this->ubFilter[$cId] = [ITEM_CLASS_WEAPON => [14], ITEM_CLASS_ARMOR => [0]];
$this->ubFilter[$cId] = [ITEM_CLASS_WEAPON => [ITEM_SUBCLASS_MISC_WEAPON], ITEM_CLASS_ARMOR => [ITEM_SUBCLASS_MISC_ARMOR]];
for ($i = 0; $i < 21; $i++)
if ($weaponTypeMask & (1 << $i))
@@ -2284,7 +2292,7 @@ class ItemListFilter extends Filter
$set['name'] = Util::localizedString($randIds[$set['ench']], 'name', true);
}
// only enhance search results if enchantment by name is unique (implies only one enchantment per item is availabel)
// only enhance search results if enchantment by name is unique (implies only one enchantment per item is available)
if (count(array_unique(array_column($randIds, 'name_loc0'))) == 1)
$this->extraOpts['relEnchant'] = $tplIds;
@@ -2567,7 +2575,7 @@ class ItemListFilter extends Filter
if (!isset($this->enums[$cr[0]][$cr[1]]))
return false;
$_ = $this->enums[$cr[0]][$cr[1]];
$_ = $this->enums[$cr[0]][$cr[1]];
if ($_ === null)
return false;
@@ -2667,7 +2675,7 @@ class ItemListFilter extends Filter
return in_array($v, $sl);
// consumables - any; perm / temp item enhancements
else if ($c[0] == 0 && (!isset($c[1]) || in_array($c[1], [-3, 6])))
else if ($c[0] == ITEM_CLASS_CONSUMABLE && (!isset($c[1]) || in_array($c[1], [-3, 6])))
return in_array($v, $sl);
// weapons - always
@@ -2675,7 +2683,7 @@ class ItemListFilter extends Filter
return in_array($v, $sl);
// armor - any; any armor
else if ($c[0] == ITEM_CLASS_ARMOR && (!isset($c[1]) || in_array($c[1], [1, 2, 3, 4])))
else if ($c[0] == ITEM_CLASS_ARMOR && (!isset($c[1]) || in_array($c[1], [ITEM_SUBCLASS_CLOTH_ARMOR, ITEM_SUBCLASS_LETHER_ARMOR, ITEM_SUBCLASS_MAIL_ARMOR, ITEM_SUBCLASS_PLATE_ARMOR])))
return in_array($v, $sl);
return false;

View File

@@ -1104,7 +1104,7 @@ DROP TABLE IF EXISTS `aowow_item_stats`;
CREATE TABLE `aowow_item_stats` (
`type` smallint(5) unsigned NOT NULL,
`typeId` mediumint(8) NOT NULL,
`nsockets` tinyint(3) unsigned NULL,
`nsockets` tinyint(3) unsigned NOT NULL DEFAULT 0,
`dps` float(8,2) NULL,
`damagetype` tinyint(4) NULL,
`dmgmin1` mediumint(5) unsigned NULL,
@@ -1118,71 +1118,71 @@ CREATE TABLE `aowow_item_stats` (
`rgddmgmin` mediumint(5) unsigned NULL,
`rgddmgmax` mediumint(5) unsigned NULL,
`rgdspeed` float(8,2) NULL,
`dmg` float(8,2) NULL,
`mana` mediumint(6) NULL,
`health` mediumint(6) NULL,
`agi` mediumint(6) NULL,
`str` mediumint(6) NULL,
`int` mediumint(6) NULL,
`spi` mediumint(6) NULL,
`sta` mediumint(6) NULL,
`energy` mediumint(6) NULL,
`rage` mediumint(6) NULL,
`focus` mediumint(6) NULL,
`runic` mediumint(6) NULL,
`defrtng` mediumint(6) NULL,
`dodgertng` mediumint(6) NULL,
`parryrtng` mediumint(6) NULL,
`blockrtng` mediumint(6) NULL,
`mlehitrtng` mediumint(6) NULL,
`rgdhitrtng` mediumint(6) NULL,
`splhitrtng` mediumint(6) NULL,
`mlecritstrkrtng` mediumint(6) NULL,
`rgdcritstrkrtng` mediumint(6) NULL,
`splcritstrkrtng` mediumint(6) NULL,
`_mlehitrtng` mediumint(6) NULL,
`_rgdhitrtng` mediumint(6) NULL,
`_splhitrtng` mediumint(6) NULL,
`_mlecritstrkrtng` mediumint(6) NULL,
`_rgdcritstrkrtng` mediumint(6) NULL,
`_splcritstrkrtng` mediumint(6) NULL,
`mlehastertng` mediumint(6) NULL,
`rgdhastertng` mediumint(6) NULL,
`splhastertng` mediumint(6) NULL,
`hitrtng` mediumint(6) NULL,
`critstrkrtng` mediumint(6) NULL,
`_hitrtng` mediumint(6) NULL,
`_critstrkrtng` mediumint(6) NULL,
`resirtng` mediumint(6) NULL,
`hastertng` mediumint(6) NULL,
`exprtng` mediumint(6) NULL,
`atkpwr` mediumint(6) NULL,
`mleatkpwr` mediumint(6) NULL,
`rgdatkpwr` mediumint(6) NULL,
`feratkpwr` mediumint(6) NULL,
`splheal` mediumint(6) NULL,
`spldmg` mediumint(6) NULL,
`manargn` mediumint(6) NULL,
`armorpenrtng` mediumint(6) NULL,
`splpwr` mediumint(6) NULL,
`healthrgn` mediumint(6) NULL,
`splpen` mediumint(6) NULL,
`block` mediumint(6) NULL,
`mastrtng` mediumint(6) NULL,
`armor` mediumint(6) NULL,
`dmg` float(8,2) NOT NULL DEFAULT 0,
`mana` mediumint(6) NOT NULL DEFAULT 0,
`health` mediumint(6) NOT NULL DEFAULT 0,
`agi` mediumint(6) NOT NULL DEFAULT 0,
`str` mediumint(6) NOT NULL DEFAULT 0,
`int` mediumint(6) NOT NULL DEFAULT 0,
`spi` mediumint(6) NOT NULL DEFAULT 0,
`sta` mediumint(6) NOT NULL DEFAULT 0,
`energy` mediumint(6) NOT NULL DEFAULT 0,
`rage` mediumint(6) NOT NULL DEFAULT 0,
`focus` mediumint(6) NOT NULL DEFAULT 0,
`runic` mediumint(6) NOT NULL DEFAULT 0,
`defrtng` mediumint(6) NOT NULL DEFAULT 0,
`dodgertng` mediumint(6) NOT NULL DEFAULT 0,
`parryrtng` mediumint(6) NOT NULL DEFAULT 0,
`blockrtng` mediumint(6) NOT NULL DEFAULT 0,
`mlehitrtng` mediumint(6) NOT NULL DEFAULT 0,
`rgdhitrtng` mediumint(6) NOT NULL DEFAULT 0,
`splhitrtng` mediumint(6) NOT NULL DEFAULT 0,
`mlecritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`rgdcritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`splcritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`_mlehitrtng` mediumint(6) NOT NULL DEFAULT 0,
`_rgdhitrtng` mediumint(6) NOT NULL DEFAULT 0,
`_splhitrtng` mediumint(6) NOT NULL DEFAULT 0,
`_mlecritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`_rgdcritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`_splcritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`mlehastertng` mediumint(6) NOT NULL DEFAULT 0,
`rgdhastertng` mediumint(6) NOT NULL DEFAULT 0,
`splhastertng` mediumint(6) NOT NULL DEFAULT 0,
`hitrtng` mediumint(6) NOT NULL DEFAULT 0,
`critstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`_hitrtng` mediumint(6) NOT NULL DEFAULT 0,
`_critstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`resirtng` mediumint(6) NOT NULL DEFAULT 0,
`hastertng` mediumint(6) NOT NULL DEFAULT 0,
`exprtng` mediumint(6) NOT NULL DEFAULT 0,
`atkpwr` mediumint(6) NOT NULL DEFAULT 0,
`mleatkpwr` mediumint(6) NOT NULL DEFAULT 0,
`rgdatkpwr` mediumint(6) NOT NULL DEFAULT 0,
`feratkpwr` mediumint(6) NOT NULL DEFAULT 0,
`splheal` mediumint(6) NOT NULL DEFAULT 0,
`spldmg` mediumint(6) NOT NULL DEFAULT 0,
`manargn` mediumint(6) NOT NULL DEFAULT 0,
`armorpenrtng` mediumint(6) NOT NULL DEFAULT 0,
`splpwr` mediumint(6) NOT NULL DEFAULT 0,
`healthrgn` mediumint(6) NOT NULL DEFAULT 0,
`splpen` mediumint(6) NOT NULL DEFAULT 0,
`block` mediumint(6) NOT NULL DEFAULT 0,
`mastrtng` mediumint(6) NOT NULL DEFAULT 0,
`armor` mediumint(6) NOT NULL DEFAULT 0,
`armorbonus` mediumint(6) NULL,
`firres` mediumint(6) NULL,
`frores` mediumint(6) NULL,
`holres` mediumint(6) NULL,
`shares` mediumint(6) NULL,
`natres` mediumint(6) NULL,
`arcres` mediumint(6) NULL,
`firsplpwr` mediumint(6) NULL,
`frosplpwr` mediumint(6) NULL,
`holsplpwr` mediumint(6) NULL,
`shasplpwr` mediumint(6) NULL,
`natsplpwr` mediumint(6) NULL,
`arcsplpwr` mediumint(6) NULL,
`firres` mediumint(6) NOT NULL DEFAULT 0,
`frores` mediumint(6) NOT NULL DEFAULT 0,
`holres` mediumint(6) NOT NULL DEFAULT 0,
`shares` mediumint(6) NOT NULL DEFAULT 0,
`natres` mediumint(6) NOT NULL DEFAULT 0,
`arcres` mediumint(6) NOT NULL DEFAULT 0,
`firsplpwr` mediumint(6) NOT NULL DEFAULT 0,
`frosplpwr` mediumint(6) NOT NULL DEFAULT 0,
`holsplpwr` mediumint(6) NOT NULL DEFAULT 0,
`shasplpwr` mediumint(6) NOT NULL DEFAULT 0,
`natsplpwr` mediumint(6) NOT NULL DEFAULT 0,
`arcsplpwr` mediumint(6) NOT NULL DEFAULT 0,
PRIMARY KEY (`type`,`typeId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

View File

@@ -47,7 +47,19 @@ class ItemStatSetup extends ItemList
// fromItem: itemMods, spell, enchants from template - fromJson: calculated stats (feralAP, dps, ...)
if ($stats = (new StatsContainer($this->relSpells, $this->relEnchants))->fromItem($curTpl)->fromJson($this->json[$id])->toJson(Stat::FLAG_ITEM | Stat::FLAG_SERVERSIDE))
DB::Aowow()->query('INSERT INTO ?_item_stats (?#) VALUES (?a)', array_merge(['type', 'typeId'], array_keys($stats)), array_merge([Type::ITEM, $this->id], array_values($stats)));
{
// manually set stats 0 if empty to distinguish from items that cant have them
$shared = ['dps' => 0, 'dmgmin1' => 0, 'dmgmax1' => 0, 'speed' => 0];
if ($this->getField('class') == ITEM_CLASS_WEAPON)
$stats += $shared + ($this->isRangedWeapon() ? ['rgddps' => 0, 'rgddmgmin' => 0, 'rgddmgmax' => 0, 'rgdspeed' => 0] : ['mledps' => 0, 'mledmgmin' => 0, 'mledmgmax' => 0, 'mlespeed' => 0]);
else if ($this->getField('class') == ITEM_CLASS_ARMOR)
$stats += ['armorbonus' => 0]; //ArmorDamageModifier only valid on armor(?)
// apply PK
$stats += ['type' => Type::ITEM, 'typeId' => $this->id];
DB::Aowow()->query('INSERT INTO ?_item_stats (?#) VALUES (?a)', array_keys($stats), array_values($stats));
}
}
}
}

View File

@@ -0,0 +1,87 @@
DROP TABLE IF EXISTS `aowow_item_stats`;
CREATE TABLE `aowow_item_stats` (
`type` smallint(5) unsigned NOT NULL,
`typeId` mediumint(8) NOT NULL,
`nsockets` tinyint(3) unsigned NOT NULL DEFAULT 0,
`dps` float(8,2) NULL,
`damagetype` tinyint(4) NULL,
`dmgmin1` mediumint(5) unsigned NULL,
`dmgmax1` mediumint(5) unsigned NULL,
`speed` float(8,2) NULL,
`mledps` float(8,2) NULL,
`mledmgmin` mediumint(5) unsigned NULL,
`mledmgmax` mediumint(5) unsigned NULL,
`mlespeed` float(8,2) NULL,
`rgddps` float(8,2) NULL,
`rgddmgmin` mediumint(5) unsigned NULL,
`rgddmgmax` mediumint(5) unsigned NULL,
`rgdspeed` float(8,2) NULL,
`dmg` float(8,2) NOT NULL DEFAULT 0,
`mana` mediumint(6) NOT NULL DEFAULT 0,
`health` mediumint(6) NOT NULL DEFAULT 0,
`agi` mediumint(6) NOT NULL DEFAULT 0,
`str` mediumint(6) NOT NULL DEFAULT 0,
`int` mediumint(6) NOT NULL DEFAULT 0,
`spi` mediumint(6) NOT NULL DEFAULT 0,
`sta` mediumint(6) NOT NULL DEFAULT 0,
`energy` mediumint(6) NOT NULL DEFAULT 0,
`rage` mediumint(6) NOT NULL DEFAULT 0,
`focus` mediumint(6) NOT NULL DEFAULT 0,
`runic` mediumint(6) NOT NULL DEFAULT 0,
`defrtng` mediumint(6) NOT NULL DEFAULT 0,
`dodgertng` mediumint(6) NOT NULL DEFAULT 0,
`parryrtng` mediumint(6) NOT NULL DEFAULT 0,
`blockrtng` mediumint(6) NOT NULL DEFAULT 0,
`mlehitrtng` mediumint(6) NOT NULL DEFAULT 0,
`rgdhitrtng` mediumint(6) NOT NULL DEFAULT 0,
`splhitrtng` mediumint(6) NOT NULL DEFAULT 0,
`mlecritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`rgdcritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`splcritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`_mlehitrtng` mediumint(6) NOT NULL DEFAULT 0,
`_rgdhitrtng` mediumint(6) NOT NULL DEFAULT 0,
`_splhitrtng` mediumint(6) NOT NULL DEFAULT 0,
`_mlecritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`_rgdcritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`_splcritstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`mlehastertng` mediumint(6) NOT NULL DEFAULT 0,
`rgdhastertng` mediumint(6) NOT NULL DEFAULT 0,
`splhastertng` mediumint(6) NOT NULL DEFAULT 0,
`hitrtng` mediumint(6) NOT NULL DEFAULT 0,
`critstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`_hitrtng` mediumint(6) NOT NULL DEFAULT 0,
`_critstrkrtng` mediumint(6) NOT NULL DEFAULT 0,
`resirtng` mediumint(6) NOT NULL DEFAULT 0,
`hastertng` mediumint(6) NOT NULL DEFAULT 0,
`exprtng` mediumint(6) NOT NULL DEFAULT 0,
`atkpwr` mediumint(6) NOT NULL DEFAULT 0,
`mleatkpwr` mediumint(6) NOT NULL DEFAULT 0,
`rgdatkpwr` mediumint(6) NOT NULL DEFAULT 0,
`feratkpwr` mediumint(6) NOT NULL DEFAULT 0,
`splheal` mediumint(6) NOT NULL DEFAULT 0,
`spldmg` mediumint(6) NOT NULL DEFAULT 0,
`manargn` mediumint(6) NOT NULL DEFAULT 0,
`armorpenrtng` mediumint(6) NOT NULL DEFAULT 0,
`splpwr` mediumint(6) NOT NULL DEFAULT 0,
`healthrgn` mediumint(6) NOT NULL DEFAULT 0,
`splpen` mediumint(6) NOT NULL DEFAULT 0,
`block` mediumint(6) NOT NULL DEFAULT 0,
`mastrtng` mediumint(6) NOT NULL DEFAULT 0,
`armor` mediumint(6) NOT NULL DEFAULT 0,
`armorbonus` mediumint(6) NULL,
`firres` mediumint(6) NOT NULL DEFAULT 0,
`frores` mediumint(6) NOT NULL DEFAULT 0,
`holres` mediumint(6) NOT NULL DEFAULT 0,
`shares` mediumint(6) NOT NULL DEFAULT 0,
`natres` mediumint(6) NOT NULL DEFAULT 0,
`arcres` mediumint(6) NOT NULL DEFAULT 0,
`firsplpwr` mediumint(6) NOT NULL DEFAULT 0,
`frosplpwr` mediumint(6) NOT NULL DEFAULT 0,
`holsplpwr` mediumint(6) NOT NULL DEFAULT 0,
`shasplpwr` mediumint(6) NOT NULL DEFAULT 0,
`natsplpwr` mediumint(6) NOT NULL DEFAULT 0,
`arcsplpwr` mediumint(6) NOT NULL DEFAULT 0,
PRIMARY KEY (`type`,`typeId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
UPDATE `aowow_dbversion` SET `sql` = CONCAT(IFNULL(`sql`, ''), ' stats');