mirror of
https://github.com/araxiaonline/wow-item-generator.git
synced 2026-06-13 03:02:22 -04:00
added high level item lookups, full refactors of database side of things and regernated end game items
This commit is contained in:
114
cmd/fetch-highlevel-items/main.go
Normal file
114
cmd/fetch-highlevel-items/main.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
"github.com/joho/godotenv"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type EndGameItem struct {
|
||||
Entry int `db:"entry"`
|
||||
Class int `db:"class"`
|
||||
Subclass int `db:"subclass"`
|
||||
StatsList string `db:"stats_list"`
|
||||
}
|
||||
|
||||
func createItemsTable(db *sql.DB) {
|
||||
createItems := `CREATE TABLE IF NOT EXISTS items (
|
||||
entry int unsigned NOT NULL DEFAULT '0',
|
||||
class tinyint unsigned NOT NULL DEFAULT '0',
|
||||
name varchar(250) NOT NULL DEFAULT '',
|
||||
Quality int unsigned NOT NULL DEFAULT '0',
|
||||
itemLevel int unsigned NOT NULL DEFAULT '0',
|
||||
subclass tinyint unsigned NOT NULL DEFAULT '0',
|
||||
stats_list varchar(250) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (entry)
|
||||
)`
|
||||
|
||||
_, err := db.Exec(createItems)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertIntSliceToString(slice []int) string {
|
||||
sliceStr := make([]string, len(slice))
|
||||
for i, v := range slice {
|
||||
sliceStr[i] = strconv.Itoa(v)
|
||||
}
|
||||
|
||||
return strings.Join(sliceStr, ",")
|
||||
}
|
||||
|
||||
func main() {
|
||||
godotenv.Load("../../.env")
|
||||
liteDb, err := sql.Open("sqlite3", "./items.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
mysqlDb, err := mysql.Connect(&mysql.MySqlConfig{
|
||||
Host: os.Getenv("DB_HOST"),
|
||||
User: os.Getenv("DB_USER"),
|
||||
Password: os.Getenv("DB_PASSWORD"),
|
||||
Database: os.Getenv("DB_NAME"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer liteDb.Close()
|
||||
defer mysqlDb.Close()
|
||||
|
||||
// create the items table if it doesnt exist
|
||||
createItemsTable(liteDb)
|
||||
|
||||
// create the endgames items lookup table locally for items 200 and above
|
||||
var dbItems []mysql.DbItem
|
||||
sql := `
|
||||
SELECT ` + mysql.GetItemFields("") + `
|
||||
from acore_world.item_template
|
||||
where ItemLevel >= 200 and Quality >= 3 and ItemLevel < 290
|
||||
AND name NOT LIKE 'NPC Equip%' and name NOT LIKE 'OLD%'
|
||||
AND name NOT LIKE '%(test)%' AND name NOT LIKE '%Deprecated%'
|
||||
AND name NOT LIKE '%Monster - %'
|
||||
AND ((class = 2 and subclass IN(0,1,2,3,4,5,6,7,8,10,11,12,13,15,16,17,18,19)) or ((class = 4 AND subclass IN (0,1,2,3,4,6))))
|
||||
`
|
||||
err = mysqlDb.Select(&dbItems, sql)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get items: %v", err)
|
||||
}
|
||||
|
||||
for _, dbItem := range dbItems {
|
||||
item := items.ItemFromDbItem(dbItem)
|
||||
var statsList []int
|
||||
for i := 1; i <= 10; i++ {
|
||||
val, _ := item.GetField(fmt.Sprintf("StatValue%v", i))
|
||||
statId, _ := item.GetField(fmt.Sprintf("StatType%v", i))
|
||||
if val != 0 {
|
||||
statsList = append(statsList, statId)
|
||||
}
|
||||
}
|
||||
slices.Sort(statsList)
|
||||
statsListStr := ConvertIntSliceToString(statsList)
|
||||
log.Printf("StatList %s for Item %v", statsListStr, item.Name)
|
||||
_, err = liteDb.Exec("INSERT OR IGNORE INTO items (entry, class, name, Quality, itemLevel, subclass, stats_list) VALUES (?, ?, ?, ?, ?,?,?)", item.Entry, *item.Class, item.Name, *item.Quality, *item.ItemLevel, *item.Subclass, statsListStr)
|
||||
if err != nil {
|
||||
log.Printf("Failed to insert item %v: %v", item.Entry, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.Printf("Items: %v", len(dbItems))
|
||||
}
|
||||
BIN
data/items.db
Normal file
BIN
data/items.db
Normal file
Binary file not shown.
BIN
endgame-item-generator
Executable file
BIN
endgame-item-generator
Executable file
Binary file not shown.
@@ -86,7 +86,7 @@ var StatModifiers = map[int]float64{
|
||||
42: 0.5, // ITEM_MOD_SPELL_DAMAGE_DONE
|
||||
43: 2.5, // ITEM_MOD_MANA_REGENERATION
|
||||
44: 1.0, // ITEM_MOD_ARMOR_PENETRATION_RATING
|
||||
45: 0.5, // ITEM_MOD_SPELL_POWER
|
||||
45: 0.50, // ITEM_MOD_SPELL_POWER
|
||||
46: 1.0, // ITEM_MOD_HEALTH_REGEN
|
||||
47: 2.0, // ITEM_MOD_SPELL_PENETRATION
|
||||
48: 0.65, // ITEM_MOD_BLOCK_VALUE
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package creatures
|
||||
|
||||
type Boss struct {
|
||||
Entry int
|
||||
Name string
|
||||
ScriptName string `db:"ScriptName"`
|
||||
ExperienceModifier int `db:"ExperienceModifier"`
|
||||
}
|
||||
@@ -3,18 +3,22 @@ package mysql
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/creatures"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
)
|
||||
|
||||
func (db *MySqlDb) GetBosses(mapId int) ([]creatures.Boss, error) {
|
||||
type Boss struct {
|
||||
Entry int
|
||||
Name string
|
||||
ScriptName string `db:"ScriptName"`
|
||||
ExperienceModifier int `db:"ExperienceModifier"`
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetBosses(mapId int) ([]Boss, error) {
|
||||
|
||||
if mapId == 0 {
|
||||
return nil, errors.New("mapId cannot be 0")
|
||||
}
|
||||
|
||||
bosses := []creatures.Boss{}
|
||||
bosses := []Boss{}
|
||||
var sql string
|
||||
|
||||
// 540 is pre-classic dungeons so XP Multiplier is best way to determine bosses / rare mobs
|
||||
@@ -38,13 +42,13 @@ func (db *MySqlDb) GetBosses(mapId int) ([]creatures.Boss, error) {
|
||||
return bosses, nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetBossLoot(bossId int) ([]items.Item, error) {
|
||||
func (db *MySqlDb) GetBossLoot(bossId int) ([]DbItem, error) {
|
||||
if bossId == 0 {
|
||||
return nil, errors.New("bossId cannot be 0")
|
||||
}
|
||||
|
||||
// This will first find items that are not in the reference boss loot table
|
||||
items := []items.Item{}
|
||||
items := []DbItem{}
|
||||
fields := GetItemFields("")
|
||||
sql := `
|
||||
SELECT ` + fields + `
|
||||
@@ -77,7 +81,7 @@ func (db *MySqlDb) GetBossLoot(bossId int) ([]items.Item, error) {
|
||||
return items, nil
|
||||
}
|
||||
|
||||
refItems := []items.Item{}
|
||||
refItems := []DbItem{}
|
||||
|
||||
// For each reference we now need to get the items and add them to the items slice
|
||||
for _, ref := range references {
|
||||
|
||||
@@ -2,25 +2,100 @@ package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
)
|
||||
|
||||
func (db *MySqlDb) GetItem(entry int) (items.Item, error) {
|
||||
type DbItem struct {
|
||||
Entry int
|
||||
Name string
|
||||
DisplayId int `db:"displayid"`
|
||||
Quality *int
|
||||
ItemLevel *int `db:"ItemLevel"`
|
||||
Class *int
|
||||
Subclass *int
|
||||
Armor *int `db:"armor"`
|
||||
Material *int `db:"material"`
|
||||
InventoryType *int `db:"inventoryType"`
|
||||
AllowableClass *int `db:"allowableClass"`
|
||||
AllowableRace *int `db:"allowableRace"`
|
||||
RequiredSkill *int `db:"requiredSkill"`
|
||||
RequiredLevel *int `db:"requiredLevel"`
|
||||
Durability *int `db:"MaxDurability"`
|
||||
MinDmg1 *float64 `db:"dmg_min1"`
|
||||
MaxDmg1 *float64 `db:"dmg_max1"`
|
||||
MinDmg2 *float64 `db:"dmg_min2"`
|
||||
MaxDmg2 *float64 `db:"dmg_max2"`
|
||||
DmgType1 *int `db:"dmg_type1"`
|
||||
DmgType2 *int `db:"dmg_type2"`
|
||||
Delay *float64
|
||||
Sheath *int
|
||||
StatsCount *int `db:"statsCount"`
|
||||
StatType1 *int `db:"stat_type1"`
|
||||
StatValue1 *int `db:"stat_value1"`
|
||||
StatType2 *int `db:"stat_type2"`
|
||||
StatValue2 *int `db:"stat_value2"`
|
||||
StatType3 *int `db:"stat_type3"`
|
||||
StatValue3 *int `db:"stat_value3"`
|
||||
StatType4 *int `db:"stat_type4"`
|
||||
StatValue4 *int `db:"stat_value4"`
|
||||
StatType5 *int `db:"stat_type5"`
|
||||
StatValue5 *int `db:"stat_value5"`
|
||||
StatType6 *int `db:"stat_type6"`
|
||||
StatValue6 *int `db:"stat_value6"`
|
||||
StatType7 *int `db:"stat_type7"`
|
||||
StatValue7 *int `db:"stat_value7"`
|
||||
StatType8 *int `db:"stat_type8"`
|
||||
StatValue8 *int `db:"stat_value8"`
|
||||
StatType9 *int `db:"stat_type9"`
|
||||
StatValue9 *int `db:"stat_value9"`
|
||||
StatType10 *int `db:"stat_type10"`
|
||||
StatValue10 *int `db:"stat_value10"`
|
||||
SpellId1 *int `db:"spellid_1"`
|
||||
SpellId2 *int `db:"spellid_2"`
|
||||
SpellId3 *int `db:"spellid_3"`
|
||||
SpellTrigger1 *int `db:"spelltrigger_1"`
|
||||
SpellTrigger2 *int `db:"spelltrigger_2"`
|
||||
SpellTrigger3 *int `db:"spelltrigger_3"`
|
||||
SocketColor1 *int `db:"socketColor_1"`
|
||||
SocketContent1 *int `db:"socketContent_1"`
|
||||
SocketColor2 *int `db:"socketColor_2"`
|
||||
SocketContent2 *int `db:"socketContent_2"`
|
||||
SocketColor3 *int `db:"socketColor_3"`
|
||||
SocketContent3 *int `db:"socketContent_3"`
|
||||
SocketBonus *int `db:"socketBonus"`
|
||||
GemProperties *int `db:"GemProperties"`
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetItem(entry int) (DbItem, error) {
|
||||
if entry == 0 {
|
||||
return items.Item{}, fmt.Errorf("entry cannot be 0")
|
||||
return DbItem{}, fmt.Errorf("entry cannot be 0")
|
||||
}
|
||||
|
||||
item := items.Item{}
|
||||
item := DbItem{}
|
||||
sql := "SELECT " + GetItemFields("") + " FROM item_template WHERE entry = ?"
|
||||
err := db.Get(&item, sql, entry)
|
||||
if err != nil {
|
||||
return items.Item{}, err
|
||||
return DbItem{}, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetRarePlusItems(limit, offset int) ([]DbItem, error) {
|
||||
items := []DbItem{}
|
||||
sql := "SELECT " + GetItemFields("") + " FROM item_template WHERE Quality >= 3 and Quality <= 5 and (class = 2 or class = 4)"
|
||||
|
||||
if limit != 0 && offset != 0 {
|
||||
sql += fmt.Sprintf("LIMIT %v OFFSET %v", limit, offset)
|
||||
}
|
||||
|
||||
err := db.Select(&items, sql)
|
||||
if err != nil {
|
||||
return []DbItem{}, err
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func GetItemFields(prefix string) string {
|
||||
pre := ""
|
||||
if prefix != "" {
|
||||
@@ -49,130 +124,7 @@ func GetItemFields(prefix string) string {
|
||||
stat_type9, stat_value9,
|
||||
stat_type10, stat_value10,
|
||||
spellid_1, spellid_2, spellid_3,
|
||||
spelltrigger_1, spelltrigger_2, spelltrigger_3`
|
||||
}
|
||||
|
||||
func ItemToSql(item Item, reqLevel int, difficulty int) string {
|
||||
|
||||
entryBump := 20000000
|
||||
spellBump := 30000000
|
||||
if difficulty == 4 {
|
||||
entryBump = 21000000
|
||||
}
|
||||
if difficulty == 5 {
|
||||
entryBump = 22000000
|
||||
}
|
||||
|
||||
if *item.Quality == 4 {
|
||||
spellBump = 31000000
|
||||
}
|
||||
if *item.Quality == 5 {
|
||||
spellBump = 32000000
|
||||
}
|
||||
|
||||
spells := ""
|
||||
if len(item.Spells) > 0 {
|
||||
for i, spell := range item.Spells {
|
||||
spells.
|
||||
spells += spells.SpellToSql(spell, *item.Quality)
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", i), spellBump+spell.ID)
|
||||
}
|
||||
}
|
||||
|
||||
delete := fmt.Sprintf("DELETE FROM acore_world.item_template WHERE entry = %v;", entryBump+item.Entry)
|
||||
|
||||
clone := fmt.Sprintf(`
|
||||
INSERT INTO acore_world.item_template (
|
||||
entry, class, subclass, SoundOverrideSubclass, name, displayid, Quality, Flags, FlagsExtra, BuyCount,
|
||||
BuyPrice, SellPrice, InventoryType, AllowableClass, AllowableRace, ItemLevel, RequiredLevel,
|
||||
RequiredSkill, RequiredSkillRank, requiredspell, requiredhonorrank, RequiredCityRank,
|
||||
RequiredReputationFaction, RequiredReputationRank, maxcount, stackable, ContainerSlots, StatsCount,
|
||||
stat_type1, stat_value1, stat_type2, stat_value2, stat_type3, stat_value3, stat_type4, stat_value4,
|
||||
stat_type5, stat_value5, stat_type6, stat_value6, stat_type7, stat_value7, stat_type8, stat_value8,
|
||||
stat_type9, stat_value9, stat_type10, stat_value10, ScalingStatDistribution, ScalingStatValue,
|
||||
dmg_min1, dmg_max1, dmg_type1, dmg_min2, dmg_max2, dmg_type2, armor, holy_res, fire_res, nature_res,
|
||||
frost_res, shadow_res, arcane_res, delay, ammo_type, RangedModRange, spellid_1, spelltrigger_1,
|
||||
spellcharges_1, spellppmRate_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1, spellid_2,
|
||||
spelltrigger_2, spellcharges_2, spellppmRate_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2,
|
||||
spellid_3, spelltrigger_3, spellcharges_3, spellppmRate_3, spellcooldown_3, spellcategory_3,
|
||||
spellcategorycooldown_3, spellid_4, spelltrigger_4, spellcharges_4, spellppmRate_4, spellcooldown_4,
|
||||
spellcategory_4, spellcategorycooldown_4, spellid_5, spelltrigger_5, spellcharges_5, spellppmRate_5,
|
||||
spellcooldown_5, spellcategory_5, spellcategorycooldown_5, bonding, description, PageText, LanguageID,
|
||||
PageMaterial, startquest, lockid, Material, sheath, RandomProperty, RandomSuffix, block, itemset,
|
||||
MaxDurability, area, Map, BagFamily, TotemCategory, socketColor_1, socketContent_1, socketColor_2,
|
||||
socketContent_2, socketColor_3, socketContent_3, socketBonus, GemProperties, RequiredDisenchantSkill,
|
||||
ArmorDamageModifier, duration, ItemLimitCategory, HolidayId, ScriptName, DisenchantID, FoodType,
|
||||
minMoneyLoot, maxMoneyLoot, flagsCustom, VerifiedBuild
|
||||
)
|
||||
SELECT
|
||||
entry + %v, class, subclass, SoundOverrideSubclass, name, displayid, Quality, Flags, FlagsExtra, BuyCount,
|
||||
BuyPrice, SellPrice, InventoryType, AllowableClass, AllowableRace, ItemLevel, RequiredLevel,
|
||||
RequiredSkill, RequiredSkillRank, requiredspell, requiredhonorrank, RequiredCityRank,
|
||||
RequiredReputationFaction, RequiredReputationRank, maxcount, stackable, ContainerSlots, StatsCount,
|
||||
stat_type1, stat_value1, stat_type2, stat_value2, stat_type3, stat_value3, stat_type4, stat_value4,
|
||||
stat_type5, stat_value5, stat_type6, stat_value6, stat_type7, stat_value7, stat_type8, stat_value8,
|
||||
stat_type9, stat_value9, stat_type10, stat_value10, ScalingStatDistribution, ScalingStatValue,
|
||||
dmg_min1, dmg_max1, dmg_type1, dmg_min2, dmg_max2, dmg_type2, armor, holy_res, fire_res, nature_res,
|
||||
frost_res, shadow_res, arcane_res, delay, ammo_type, RangedModRange, spellid_1, spelltrigger_1,
|
||||
spellcharges_1, spellppmRate_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1, spellid_2,
|
||||
spelltrigger_2, spellcharges_2, spellppmRate_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2,
|
||||
spellid_3, spelltrigger_3, spellcharges_3, spellppmRate_3, spellcooldown_3, spellcategory_3,
|
||||
spellcategorycooldown_3, spellid_4, spelltrigger_4, spellcharges_4, spellppmRate_4, spellcooldown_4,
|
||||
spellcategory_4, spellcategorycooldown_4, spellid_5, spelltrigger_5, spellcharges_5, spellppmRate_5,
|
||||
spellcooldown_5, spellcategory_5, spellcategorycooldown_5, bonding, description, PageText, LanguageID,
|
||||
PageMaterial, startquest, lockid, Material, sheath, RandomProperty, RandomSuffix, block, itemset,
|
||||
MaxDurability, area, Map, BagFamily, TotemCategory, socketColor_1, socketContent_1, socketColor_2,
|
||||
socketContent_2, socketColor_3, socketContent_3, socketBonus, GemProperties, RequiredDisenchantSkill,
|
||||
ArmorDamageModifier, duration, ItemLimitCategory, HolidayId, ScriptName, DisenchantID, FoodType,
|
||||
minMoneyLoot, maxMoneyLoot, flagsCustom, VerifiedBuild
|
||||
FROM acore_world.item_template as src
|
||||
WHERE src.entry = %v ON DUPLICATE KEY UPDATE entry = src.entry + %v;
|
||||
`, entryBump, item.Entry, entryBump)
|
||||
|
||||
update := fmt.Sprintf(`
|
||||
UPDATE acore_world.item_template
|
||||
SET
|
||||
Quality = %v,
|
||||
ItemLevel = %v,
|
||||
RequiredLevel = %v,
|
||||
dmg_min1 = %v,
|
||||
dmg_max1 = %v,
|
||||
dmg_min2 = %v,
|
||||
dmg_max2 = %v,
|
||||
StatsCount = %v,
|
||||
stat_type1 = %v,
|
||||
stat_value1 = %v,
|
||||
stat_type2 = %v,
|
||||
stat_value2 = %v,
|
||||
stat_type3 = %v,
|
||||
stat_value3 = %v,
|
||||
stat_type4 = %v,
|
||||
stat_value4 = %v,
|
||||
stat_type5 = %v,
|
||||
stat_value5 = %v,
|
||||
stat_type6 = %v,
|
||||
stat_value6 = %v,
|
||||
stat_type7 = %v,
|
||||
stat_value7 = %v,
|
||||
stat_type8 = %v,
|
||||
stat_value8 = %v,
|
||||
stat_type9 = %v,
|
||||
stat_value9 = %v,
|
||||
stat_type10 = %v,
|
||||
stat_value10 = %v,
|
||||
spellid_1 = %v,
|
||||
spellid_2 = %v,
|
||||
spellid_3 = %v,
|
||||
RequiredDisenchantSkill = %v,
|
||||
DisenchantID = %v,
|
||||
SellPrice = FLOOR(100000 + (RAND() * 400001)),
|
||||
Armor = %v
|
||||
WHERE entry = %v;
|
||||
`, *item.Quality, *item.ItemLevel, reqLevel, *item.MinDmg1, *item.MaxDmg1, *item.MinDmg2, *item.MaxDmg2, *item.StatsCount,
|
||||
*item.StatType1, *item.StatValue1, *item.StatType2, *item.StatValue2, *item.StatType3, *item.StatValue3, *item.StatType4, *item.StatValue4,
|
||||
*item.StatType5, *item.StatValue5, *item.StatType6, *item.StatValue6, *item.StatType7, *item.StatValue7, *item.StatType8, *item.StatValue8,
|
||||
*item.StatType9, *item.StatValue9, *item.StatType10, *item.StatValue10, *item.SpellId1, *item.SpellId2, *item.SpellId3, 375,
|
||||
68, *item.Armor, entryBump+item.Entry)
|
||||
|
||||
return fmt.Sprintf("%s %s \n %s \n %s", spells, delete, clone, update)
|
||||
spelltrigger_1, spelltrigger_2, spelltrigger_3,
|
||||
socketColor_1, socketContent_1, socketColor_2, socketContent_2, socketColor_3, socketContent_3,
|
||||
socketBonus, GemProperties`
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
)
|
||||
|
||||
type Dungeon struct {
|
||||
@@ -104,10 +102,10 @@ func (db *MySqlDb) GetDungeons(expansionId int) ([]Dungeon, error) {
|
||||
}
|
||||
|
||||
// Gets a list of other rare+ items that drop in a specific instance.
|
||||
func (db *MySqlDb) GetAddlDungeonDrops(instanceId int) ([]items.Item, error) {
|
||||
func (db *MySqlDb) GetAddlDungeonDrops(instanceId int) ([]DbItem, error) {
|
||||
|
||||
fields := items.GetItemFields("it")
|
||||
var items []items.Item
|
||||
fields := GetItemFields("it")
|
||||
var items []DbItem
|
||||
sql := fmt.Sprintf(`
|
||||
SELECT `+fields+`
|
||||
from
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
@@ -41,6 +42,16 @@ func Connect(config *MySqlConfig) (*MySqlDb, error) {
|
||||
return MySql, nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) Close() {
|
||||
db.Close()
|
||||
func GetDb() (*MySqlDb, error) {
|
||||
if MySql == nil {
|
||||
return nil, errors.New("mysql not connected")
|
||||
}
|
||||
|
||||
return MySql, nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) Close() {
|
||||
if db.DB != nil {
|
||||
db.DB.Close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,47 @@ package mysql
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/spells"
|
||||
)
|
||||
|
||||
func (db *MySqlDb) GetSpell(id int) (spells.Spell, error) {
|
||||
type DbSpell struct {
|
||||
ID int `db:"ID"`
|
||||
Name string `db:"Name_Lang_enUS"`
|
||||
Description string `db:"Description_Lang_enUS"`
|
||||
AuraDescription string `db:"AuraDescription_Lang_enUS"`
|
||||
ProcChance int `db:"ProcChance"`
|
||||
SpellLevel int `db:"SpellLevel"`
|
||||
Effect1 int `db:"Effect_1"`
|
||||
Effect2 int `db:"Effect_2"`
|
||||
Effect3 int `db:"Effect_3"`
|
||||
EffectDieSides1 int `db:"EffectDieSides_1"`
|
||||
EffectDieSides2 int `db:"EffectDieSides_2"`
|
||||
EffectDieSides3 int `db:"EffectDieSides_3"`
|
||||
EffectRealPointsPerLevel1 int `db:"EffectRealPointsPerLevel_1"`
|
||||
EffectRealPointsPerLevel2 int `db:"EffectRealPointsPerLevel_2"`
|
||||
EffectRealPointsPerLevel3 int `db:"EffectRealPointsPerLevel_3"`
|
||||
EffectBasePoints1 int `db:"EffectBasePoints_1"`
|
||||
EffectBasePoints2 int `db:"EffectBasePoints_2"`
|
||||
EffectBasePoints3 int `db:"EffectBasePoints_3"`
|
||||
EffectAura1 int `db:"EffectAura_1"`
|
||||
EffectAura2 int `db:"EffectAura_2"`
|
||||
EffectAura3 int `db:"EffectAura_3"`
|
||||
EffectBonusMultiplier1 int `db:"EffectBonusMultiplier_1"`
|
||||
EffectBonusMultiplier2 int `db:"EffectBonusMultiplier_2"`
|
||||
EffectBonusMultiplier3 int `db:"EffectBonusMultiplier_3"`
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetSpell(id int) (DbSpell, error) {
|
||||
|
||||
if id == 0 {
|
||||
return spells.Spell{}, fmt.Errorf("id cannot be 0")
|
||||
return DbSpell{}, fmt.Errorf("id cannot be 0")
|
||||
}
|
||||
|
||||
spell := spells.Spell{}
|
||||
spell := DbSpell{}
|
||||
sql := "SELECT " + GetSpellFields() + " FROM `spell_dbc` WHERE ID = ? -- " + strconv.Itoa(id)
|
||||
|
||||
err := db.Get(&spell, sql, id)
|
||||
if err != nil {
|
||||
return spells.Spell{}, fmt.Errorf("failed to get spell: %v", err)
|
||||
return DbSpell{}, fmt.Errorf("failed to get spell: %v", err)
|
||||
}
|
||||
|
||||
return spell, nil
|
||||
@@ -52,96 +77,3 @@ func GetSpellFields() string {
|
||||
EffectBonusMultiplier_3
|
||||
`
|
||||
}
|
||||
|
||||
func SpellToSql(spell spells.Spell, quality int) string {
|
||||
|
||||
entryBump := 30000000
|
||||
if quality == 4 {
|
||||
entryBump = 31000000
|
||||
}
|
||||
if quality == 5 {
|
||||
entryBump = 32000000
|
||||
}
|
||||
|
||||
insert := fmt.Sprintf(`
|
||||
INSERT IGNORE INTO acore_world.spell_dbc (
|
||||
ID, Category, DispelType, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4,
|
||||
AttributesEx5, AttributesEx6, AttributesEx7, ShapeshiftMask, unk_320_2, ShapeshiftExclude, unk_320_3, Targets,
|
||||
TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, ExcludeCasterAuraState,
|
||||
ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex,
|
||||
RecoveryTime, CategoryRecoveryTime, InterruptFlags, AuraInterruptFlags, ChannelInterruptFlags, ProcTypeMask, ProcChance,
|
||||
ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, PowerType, ManaCost, ManaCostPerLevel, ManaPerSecond,
|
||||
ManaPerSecondPerLevel, RangeIndex, Speed, ModalNextSpell, CumulativeAura, Totem_1, Totem_2, Reagent_1, Reagent_2, Reagent_3,
|
||||
Reagent_4, Reagent_5, Reagent_6, Reagent_7, Reagent_8, ReagentCount_1, ReagentCount_2, ReagentCount_3, ReagentCount_4,
|
||||
ReagentCount_5, ReagentCount_6, ReagentCount_7, ReagentCount_8, EquippedItemClass, EquippedItemSubclass, EquippedItemInvTypes,
|
||||
Effect_1, Effect_2, Effect_3, EffectDieSides_1, EffectDieSides_2, EffectDieSides_3, EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3, EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3,
|
||||
EffectMechanic_1, EffectMechanic_2, EffectMechanic_3, ImplicitTargetA_1, ImplicitTargetA_2, ImplicitTargetA_3, ImplicitTargetB_1,
|
||||
ImplicitTargetB_2, ImplicitTargetB_3, EffectRadiusIndex_1, EffectRadiusIndex_2, EffectRadiusIndex_3, EffectAura_1,
|
||||
EffectAura_2, EffectAura_3, EffectAuraPeriod_1, EffectAuraPeriod_2, EffectAuraPeriod_3, EffectMultipleValue_1, EffectMultipleValue_2,
|
||||
EffectMultipleValue_3, EffectChainTargets_1, EffectChainTargets_2, EffectChainTargets_3, EffectItemType_1, EffectItemType_2,
|
||||
EffectItemType_3, EffectMiscValue_1, EffectMiscValue_2, EffectMiscValue_3, EffectMiscValueB_1, EffectMiscValueB_2, EffectMiscValueB_3,
|
||||
EffectTriggerSpell_1, EffectTriggerSpell_2, EffectTriggerSpell_3, EffectPointsPerCombo_1, EffectPointsPerCombo_2, EffectPointsPerCombo_3,
|
||||
EffectSpellClassMaskA_1, EffectSpellClassMaskA_2, EffectSpellClassMaskA_3, EffectSpellClassMaskB_1, EffectSpellClassMaskB_2,
|
||||
EffectSpellClassMaskB_3, EffectSpellClassMaskC_1, EffectSpellClassMaskC_2, EffectSpellClassMaskC_3, SpellVisualID_1, SpellVisualID_2,
|
||||
SpellIconID, ActiveIconID, SpellPriority, Name_Lang_enUS, Name_Lang_enGB, Name_Lang_koKR, Name_Lang_frFR, Name_Lang_deDE,
|
||||
Name_Lang_enCN, Name_Lang_zhCN, Name_Lang_enTW, Name_Lang_zhTW, Name_Lang_esES, Name_Lang_esMX, Name_Lang_ruRU, Name_Lang_ptPT,
|
||||
Name_Lang_ptBR, Name_Lang_itIT, Name_Lang_Unk, Name_Lang_Mask, NameSubtext_Lang_enUS, NameSubtext_Lang_enGB, NameSubtext_Lang_koKR,
|
||||
NameSubtext_Lang_frFR, NameSubtext_Lang_deDE, NameSubtext_Lang_enCN, NameSubtext_Lang_zhCN, NameSubtext_Lang_enTW, NameSubtext_Lang_zhTW,
|
||||
NameSubtext_Lang_esES, NameSubtext_Lang_esMX, NameSubtext_Lang_ruRU, NameSubtext_Lang_ptPT, NameSubtext_Lang_ptBR, NameSubtext_Lang_itIT,
|
||||
NameSubtext_Lang_Unk, NameSubtext_Lang_Mask, Description_Lang_enUS, Description_Lang_enGB, Description_Lang_koKR, Description_Lang_frFR,
|
||||
Description_Lang_deDE, Description_Lang_enCN, Description_Lang_zhCN, Description_Lang_enTW, Description_Lang_zhTW, Description_Lang_esES,
|
||||
Description_Lang_esMX, Description_Lang_ruRU, Description_Lang_ptPT, Description_Lang_ptBR, Description_Lang_itIT, Description_Lang_Unk,
|
||||
Description_Lang_Mask, AuraDescription_Lang_enUS, AuraDescription_Lang_enGB, AuraDescription_Lang_koKR, AuraDescription_Lang_frFR,
|
||||
AuraDescription_Lang_deDE, AuraDescription_Lang_enCN, AuraDescription_Lang_zhCN, AuraDescription_Lang_enTW, AuraDescription_Lang_zhTW,
|
||||
AuraDescription_Lang_esES, AuraDescription_Lang_esMX, AuraDescription_Lang_ruRU, AuraDescription_Lang_ptPT, AuraDescription_Lang_ptBR,
|
||||
AuraDescription_Lang_itIT, AuraDescription_Lang_Unk, AuraDescription_Lang_Mask, ManaCostPct, StartRecoveryCategory, StartRecoveryTime,
|
||||
MaxTargetLevel, SpellClassSet, SpellClassMask_1, SpellClassMask_2, SpellClassMask_3, MaxTargets, DefenseType, PreventionType, StanceBarOrder,
|
||||
EffectChainAmplitude_1, EffectChainAmplitude_2, EffectChainAmplitude_3, MinFactionID, MinReputation, RequiredAuraVision, RequiredTotemCategoryID_1,
|
||||
RequiredTotemCategoryID_2, RequiredAreasID, SchoolMask, RuneCostID, SpellMissileID, PowerDisplayID, EffectBonusMultiplier_1, EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3, SpellDescriptionVariableID, SpellDifficultyID
|
||||
) SELECT
|
||||
ID + %v, Category, DispelType, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4,
|
||||
AttributesEx5, AttributesEx6, AttributesEx7, ShapeshiftMask, unk_320_2, ShapeshiftExclude, unk_320_3, Targets,
|
||||
TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, ExcludeCasterAuraState,
|
||||
ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex,
|
||||
RecoveryTime, CategoryRecoveryTime, InterruptFlags, AuraInterruptFlags, ChannelInterruptFlags, ProcTypeMask, ProcChance,
|
||||
ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, PowerType, ManaCost, ManaCostPerLevel, ManaPerSecond,
|
||||
ManaPerSecondPerLevel, RangeIndex, Speed, ModalNextSpell, CumulativeAura, Totem_1, Totem_2, Reagent_1, Reagent_2, Reagent_3,
|
||||
Reagent_4, Reagent_5, Reagent_6, Reagent_7, Reagent_8, ReagentCount_1, ReagentCount_2, ReagentCount_3, ReagentCount_4,
|
||||
ReagentCount_5, ReagentCount_6, ReagentCount_7, ReagentCount_8, EquippedItemClass, EquippedItemSubclass, EquippedItemInvTypes,
|
||||
Effect_1, Effect_2, Effect_3, EffectDieSides_1, EffectDieSides_2, EffectDieSides_3, EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3, EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3,
|
||||
EffectMechanic_1, EffectMechanic_2, EffectMechanic_3, ImplicitTargetA_1, ImplicitTargetA_2, ImplicitTargetA_3, ImplicitTargetB_1,
|
||||
ImplicitTargetB_2, ImplicitTargetB_3, EffectRadiusIndex_1, EffectRadiusIndex_2, EffectRadiusIndex_3, EffectAura_1,
|
||||
EffectAura_2, EffectAura_3, EffectAuraPeriod_1, EffectAuraPeriod_2, EffectAuraPeriod_3, EffectMultipleValue_1, EffectMultipleValue_2,
|
||||
EffectMultipleValue_3, EffectChainTargets_1, EffectChainTargets_2, EffectChainTargets_3, EffectItemType_1, EffectItemType_2,
|
||||
EffectItemType_3, EffectMiscValue_1, EffectMiscValue_2, EffectMiscValue_3, EffectMiscValueB_1, EffectMiscValueB_2, EffectMiscValueB_3,
|
||||
EffectTriggerSpell_1, EffectTriggerSpell_2, EffectTriggerSpell_3, EffectPointsPerCombo_1, EffectPointsPerCombo_2, EffectPointsPerCombo_3,
|
||||
EffectSpellClassMaskA_1, EffectSpellClassMaskA_2, EffectSpellClassMaskA_3, EffectSpellClassMaskB_1, EffectSpellClassMaskB_2,
|
||||
EffectSpellClassMaskB_3, EffectSpellClassMaskC_1, EffectSpellClassMaskC_2, EffectSpellClassMaskC_3, SpellVisualID_1, SpellVisualID_2,
|
||||
SpellIconID, ActiveIconID, SpellPriority, Name_Lang_enUS, Name_Lang_enGB, Name_Lang_koKR, Name_Lang_frFR, Name_Lang_deDE,
|
||||
Name_Lang_enCN, Name_Lang_zhCN, Name_Lang_enTW, Name_Lang_zhTW, Name_Lang_esES, Name_Lang_esMX, Name_Lang_ruRU, Name_Lang_ptPT,
|
||||
Name_Lang_ptBR, Name_Lang_itIT, Name_Lang_Unk, Name_Lang_Mask, NameSubtext_Lang_enUS, NameSubtext_Lang_enGB, NameSubtext_Lang_koKR,
|
||||
NameSubtext_Lang_frFR, NameSubtext_Lang_deDE, NameSubtext_Lang_enCN, NameSubtext_Lang_zhCN, NameSubtext_Lang_enTW, NameSubtext_Lang_zhTW,
|
||||
NameSubtext_Lang_esES, NameSubtext_Lang_esMX, NameSubtext_Lang_ruRU, NameSubtext_Lang_ptPT, NameSubtext_Lang_ptBR, NameSubtext_Lang_itIT,
|
||||
NameSubtext_Lang_Unk, NameSubtext_Lang_Mask, Description_Lang_enUS, Description_Lang_enGB, Description_Lang_koKR, Description_Lang_frFR,
|
||||
Description_Lang_deDE, Description_Lang_enCN, Description_Lang_zhCN, Description_Lang_enTW, Description_Lang_zhTW, Description_Lang_esES,
|
||||
Description_Lang_esMX, Description_Lang_ruRU, Description_Lang_ptPT, Description_Lang_ptBR, Description_Lang_itIT, Description_Lang_Unk,
|
||||
Description_Lang_Mask, AuraDescription_Lang_enUS, AuraDescription_Lang_enGB, AuraDescription_Lang_koKR, AuraDescription_Lang_frFR,
|
||||
AuraDescription_Lang_deDE, AuraDescription_Lang_enCN, AuraDescription_Lang_zhCN, AuraDescription_Lang_enTW, AuraDescription_Lang_zhTW,
|
||||
AuraDescription_Lang_esES, AuraDescription_Lang_esMX, AuraDescription_Lang_ruRU, AuraDescription_Lang_ptPT, AuraDescription_Lang_ptBR,
|
||||
AuraDescription_Lang_itIT, AuraDescription_Lang_Unk, AuraDescription_Lang_Mask, ManaCostPct, StartRecoveryCategory, StartRecoveryTime,
|
||||
MaxTargetLevel, SpellClassSet, SpellClassMask_1, SpellClassMask_2, SpellClassMask_3, MaxTargets, DefenseType, PreventionType, StanceBarOrder,
|
||||
EffectChainAmplitude_1, EffectChainAmplitude_2, EffectChainAmplitude_3, MinFactionID, MinReputation, RequiredAuraVision, RequiredTotemCategoryID_1,
|
||||
RequiredTotemCategoryID_2, RequiredAreasID, SchoolMask, RuneCostID, SpellMissileID, PowerDisplayID, EffectBonusMultiplier_1, EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3, SpellDescriptionVariableID, SpellDifficultyID from acore_world.spell_dbc as src
|
||||
WHERE src.ID = %v ON DUPLICATE KEY UPDATE ID = src.ID + %v;`, entryBump, spell.ID, entryBump)
|
||||
|
||||
update := fmt.Sprintf(`
|
||||
UPDATE acore_world.spell_dbc
|
||||
SET EffectBasePoints_1 = %v, EffectBasePoints_2 = %v
|
||||
WHERE ID = %v;`, spell.EffectBasePoints1, spell.EffectBasePoints2, entryBump+spell.ID)
|
||||
|
||||
return fmt.Sprintf("\n %s \n %s \n", insert, update)
|
||||
}
|
||||
|
||||
86
internal/db/sqlite/items.go
Normal file
86
internal/db/sqlite/items.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
)
|
||||
|
||||
type HighLevelItem struct {
|
||||
Entry int `db:"entry"`
|
||||
Class *int `db:"class"`
|
||||
Name string `db:"name"`
|
||||
Quality int `db:"Quality"`
|
||||
ItemLevel int `db:"itemLevel"`
|
||||
Subclass *int `db:"subclass"`
|
||||
StatsList string `db:"stats_list"`
|
||||
}
|
||||
|
||||
func (db *SqlLite) GetItem(entry int) (HighLevelItem, error) {
|
||||
if entry == 0 {
|
||||
return HighLevelItem{}, fmt.Errorf("entry cannot be 0")
|
||||
}
|
||||
|
||||
item := HighLevelItem{}
|
||||
sql := "SELECT " + mysql.GetItemFields("") + " FROM item_template WHERE entry = ?"
|
||||
err := db.Get(&item, sql, entry)
|
||||
if err != nil {
|
||||
return HighLevelItem{}, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// This gets a random item that is close in stats type to the lower level items with some randomness
|
||||
func (db *SqlLite) GetRandItem(class, subclass int, statsList []int, end bool) (HighLevelItem, error) {
|
||||
rndItem := HighLevelItem{}
|
||||
var statsTxt string
|
||||
var err error
|
||||
var sql string
|
||||
|
||||
// if we have a stats_list try to match by that first, if not then just select a random item from the class and subclass
|
||||
if len(statsList) == 0 {
|
||||
sql = "SELECT * FROM items WHERE class = ? and subclass = ? ORDER BY RANDOM() LIMIT 1"
|
||||
err = db.Get(&rndItem, sql, class, subclass)
|
||||
} else {
|
||||
// convert the array of ints to a commas string for lookup
|
||||
statsTxt = intSliceToString(statsList)
|
||||
sql = "SELECT * FROM items WHERE class = ? and subclass = ? and stats_list like ? ORDER BY RANDOM() LIMIT 1"
|
||||
err = db.Get(&rndItem, sql, class, subclass, statsTxt+"%")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
// if we hit the last check and still no item match then return an error
|
||||
if end {
|
||||
msg := fmt.Sprintf("Failed to find a matching item class %v subclass %v statsTxt %v", class, subclass, statsTxt)
|
||||
return HighLevelItem{}, errors.New(msg)
|
||||
}
|
||||
|
||||
// if there was not a remove the last stat and try again
|
||||
if err.Error() == "sql: no rows in result set" {
|
||||
|
||||
if len(statsList) == 0 {
|
||||
return db.GetRandItem(class, subclass, statsList, true)
|
||||
} else {
|
||||
statsList = statsList[:len(statsList)-1]
|
||||
return db.GetRandItem(class, subclass, statsList, false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.Fatalf("Error getting random sql: %v error: %v", sql, err)
|
||||
return HighLevelItem{}, err
|
||||
}
|
||||
|
||||
return rndItem, nil
|
||||
}
|
||||
|
||||
func intSliceToString(slice []int) string {
|
||||
str := fmt.Sprint(slice)
|
||||
str = strings.Trim(str, "[]")
|
||||
return strings.ReplaceAll(str, " ", ",")
|
||||
}
|
||||
@@ -1,23 +1,33 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type SqlLite struct {
|
||||
client *sql.DB
|
||||
*sqlx.DB
|
||||
}
|
||||
|
||||
var SqlLiteDb *SqlLite
|
||||
|
||||
func Connect(path string) (*SqlLite, error) {
|
||||
client, err := sql.Open("sqlite3", path)
|
||||
client, err := sqlx.Open("sqlite3", path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SqlLite{client: client}, nil
|
||||
|
||||
SqlLiteDb = &SqlLite{client}
|
||||
return SqlLiteDb, nil
|
||||
}
|
||||
|
||||
func GetDb() (*SqlLite, error) {
|
||||
return SqlLiteDb, nil
|
||||
}
|
||||
|
||||
func (db *SqlLite) Close() {
|
||||
db.client.Close()
|
||||
if db.DB != nil {
|
||||
db.DB.Close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,8 +181,8 @@ func TestGetDPS(t *testing.T) {
|
||||
name: "Valid DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrInt(50),
|
||||
MaxDmg1: ptrInt(70),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Delay: ptrFloat64(3000),
|
||||
},
|
||||
},
|
||||
@@ -193,8 +193,8 @@ func TestGetDPS(t *testing.T) {
|
||||
name: "High damage DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrInt(100),
|
||||
MaxDmg1: ptrInt(150),
|
||||
MinDmg1: ptrFloat64(100),
|
||||
MaxDmg1: ptrFloat64(150),
|
||||
Delay: ptrFloat64(2000),
|
||||
},
|
||||
},
|
||||
@@ -205,8 +205,8 @@ func TestGetDPS(t *testing.T) {
|
||||
name: "Low damage DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrInt(10),
|
||||
MaxDmg1: ptrInt(15),
|
||||
MinDmg1: ptrFloat64(10),
|
||||
MaxDmg1: ptrFloat64(15),
|
||||
Delay: ptrFloat64(1500),
|
||||
},
|
||||
},
|
||||
@@ -217,7 +217,7 @@ func TestGetDPS(t *testing.T) {
|
||||
name: "Missing MinDmg1",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MaxDmg1: ptrInt(70),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Delay: ptrFloat64(3000),
|
||||
},
|
||||
},
|
||||
@@ -228,7 +228,7 @@ func TestGetDPS(t *testing.T) {
|
||||
name: "Missing MaxDmg1",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrInt(50),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
Delay: ptrFloat64(3000),
|
||||
},
|
||||
},
|
||||
@@ -239,8 +239,8 @@ func TestGetDPS(t *testing.T) {
|
||||
name: "Missing Delay",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrInt(50),
|
||||
MaxDmg1: ptrInt(70),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
},
|
||||
},
|
||||
wantDPS: 0,
|
||||
@@ -277,8 +277,8 @@ func TestScaleDPS(t *testing.T) {
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(60),
|
||||
Delay: ptrFloat64(3000),
|
||||
MinDmg1: ptrInt(50),
|
||||
MaxDmg1: ptrInt(70),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
@@ -294,8 +294,8 @@ func TestScaleDPS(t *testing.T) {
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(80),
|
||||
Delay: ptrFloat64(2000),
|
||||
MinDmg1: ptrInt(150),
|
||||
MaxDmg1: ptrInt(200),
|
||||
MinDmg1: ptrFloat64(150),
|
||||
MaxDmg1: ptrFloat64(200),
|
||||
Subclass: ptrInt(17), // Two-handed weapon
|
||||
Quality: ptrInt(4), // Epic
|
||||
},
|
||||
@@ -311,8 +311,8 @@ func TestScaleDPS(t *testing.T) {
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(20),
|
||||
Delay: ptrFloat64(1000),
|
||||
MinDmg1: ptrInt(30),
|
||||
MaxDmg1: ptrInt(50),
|
||||
MinDmg1: ptrFloat64(30),
|
||||
MaxDmg1: ptrFloat64(50),
|
||||
Subclass: ptrInt(2), // Ranged weapon
|
||||
Quality: ptrInt(2), // Uncommon
|
||||
},
|
||||
@@ -327,8 +327,8 @@ func TestScaleDPS(t *testing.T) {
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Delay: ptrFloat64(3000),
|
||||
MinDmg1: ptrInt(50),
|
||||
MaxDmg1: ptrInt(70),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
@@ -343,8 +343,8 @@ func TestScaleDPS(t *testing.T) {
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(60),
|
||||
MinDmg1: ptrInt(50),
|
||||
MaxDmg1: ptrInt(70),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
@@ -360,10 +360,10 @@ func TestScaleDPS(t *testing.T) {
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(60),
|
||||
Delay: ptrFloat64(3000),
|
||||
MinDmg1: ptrInt(50),
|
||||
MaxDmg1: ptrInt(70),
|
||||
MinDmg2: ptrInt(25),
|
||||
MaxDmg2: ptrInt(35),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
MinDmg2: ptrFloat64(25),
|
||||
MaxDmg2: ptrFloat64(35),
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
|
||||
@@ -33,6 +33,13 @@ type ItemStat struct {
|
||||
AdjValue float64
|
||||
}
|
||||
|
||||
// Create a new item from the database item
|
||||
func ItemFromDbItem(dbItem mysql.DbItem) Item {
|
||||
return Item{
|
||||
DbItem: dbItem,
|
||||
}
|
||||
}
|
||||
|
||||
// Get the primary stat for an item (strength, agility, intellect, spirit, stamina)
|
||||
func (item Item) GetPrimaryStat() (int, int, error) {
|
||||
var primaryStat int64
|
||||
@@ -75,6 +82,31 @@ func (item Item) GetPrimaryStat() (int, int, error) {
|
||||
func (item Item) GetStatList() ([]int, error) {
|
||||
|
||||
statList := []int{}
|
||||
|
||||
// Also need to get spells that on the item that convert to stats
|
||||
spells, err := item.GetSpells()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get spells for item: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, spell := range spells {
|
||||
convStats, err := spell.ConvertToStats()
|
||||
if err != nil {
|
||||
log.Printf("Failed to convert spell to stats: %v for spell %v", err, spell.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(convStats) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, convStat := range convStats {
|
||||
statList = append(statList, convStat.StatType)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for i := 1; i < 11; i++ {
|
||||
val, err := item.GetField(fmt.Sprintf("StatValue%v", i))
|
||||
|
||||
@@ -190,8 +222,8 @@ func (item *Item) ScaleDPS(level int) (float64, error) {
|
||||
if item.MinDmg2 != nil && item.MaxDmg2 != nil {
|
||||
ratioMin := float64(*item.MinDmg2) / float64(*item.MinDmg1)
|
||||
ratioMax := float64(*item.MaxDmg2) / float64(*item.MaxDmg1)
|
||||
minimum2 := int(ratioMin * float64(minimum))
|
||||
maximum2 := int(ratioMax * float64(maximum))
|
||||
minimum2 := ratioMin * float64(minimum)
|
||||
maximum2 := ratioMax * float64(maximum)
|
||||
|
||||
item.MinDmg2 = &minimum2
|
||||
item.MaxDmg2 = &maximum2
|
||||
@@ -199,14 +231,13 @@ func (item *Item) ScaleDPS(level int) (float64, error) {
|
||||
// In order to balance the original scale of the secondary damage from primary
|
||||
minimum = minimum - float64(minimum2)*0.75
|
||||
maximum = maximum - float64(maximum2)*0.75
|
||||
|
||||
}
|
||||
|
||||
// item.MinDmg1 = &minimum
|
||||
var min int = int(minimum)
|
||||
var max int = int(maximum)
|
||||
item.MinDmg1 = &min
|
||||
item.MaxDmg1 = &max
|
||||
// var min int = int(minimum)
|
||||
// var max int = int(maximum)
|
||||
item.MinDmg1 = &minimum
|
||||
item.MaxDmg1 = &maximum
|
||||
|
||||
return dps, nil
|
||||
}
|
||||
@@ -225,7 +256,7 @@ func (item Item) GetStatPercents(spellStats []spells.ConvItemStat) map[int]*Item
|
||||
continue
|
||||
}
|
||||
|
||||
adjValue := float64(statValue) / config.StatModifiers[int(statType)]
|
||||
adjValue := float64(statValue) * config.StatModifiers[int(statType)]
|
||||
statBudget += adjValue
|
||||
statMap[int(statType)] = &ItemStat{
|
||||
Value: int(statValue),
|
||||
@@ -337,6 +368,42 @@ func (item *Item) GetNonStatSpells() ([]spells.Spell, error) {
|
||||
return nonStatSpells, nil
|
||||
}
|
||||
|
||||
// Applies status of one item to another overwriting the current stats
|
||||
func (item *Item) ApplyStats(otherItem Item) (success bool, err error) {
|
||||
|
||||
for i := 1; i < 11; i++ {
|
||||
statType, err := otherItem.GetField(fmt.Sprintf("StatType%v", i))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
statValue, err := otherItem.GetField(fmt.Sprintf("StatValue%v", i))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
item.UpdateField(fmt.Sprintf("StatType%v", i), statType)
|
||||
item.UpdateField(fmt.Sprintf("StatValue%v", i), statValue)
|
||||
}
|
||||
|
||||
if otherItem.SocketColor1 != nil {
|
||||
item.SocketColor1 = otherItem.SocketColor1
|
||||
item.SocketContent1 = otherItem.SocketContent1
|
||||
}
|
||||
|
||||
if otherItem.SocketColor2 != nil {
|
||||
item.SocketColor2 = otherItem.SocketColor2
|
||||
item.SocketContent2 = otherItem.SocketContent2
|
||||
}
|
||||
|
||||
if otherItem.SocketColor3 != nil {
|
||||
item.SocketColor3 = otherItem.SocketColor3
|
||||
item.SocketContent3 = otherItem.SocketContent3
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Stat Formula scaler
|
||||
// Ceiling of ((ItemLevel * QualityModifier * ItemTypeModifier)^1.7095 * %ofStats) ^ (1/1.7095)) / StatModifier
|
||||
// i.e) Green Strength Helmet (((100 * 1.1 * 1.0)^1.705) * 1)^(1/1.7095) / 1.0 = 110 Strength on item
|
||||
@@ -440,7 +507,7 @@ func (item *Item) ScaleItem(itemLevel int, itemQuality int) (bool, error) {
|
||||
item.Spells = []spells.Spell{}
|
||||
// Spells that can not be scaled into stats must get new spells scaled and created
|
||||
for _, spell := range otherSpells {
|
||||
log.Printf(" --^^^^^^--------SPELL --- Spell %v (%v) Effect %v AuraEffect %v Spell Desc: %v basePoints %v", spell.Name, spell.ID, spell.Effect1, spell.EffectAura1, spell.Description, spell.EffectBasePoints1)
|
||||
// log.Printf(" --^^^^^^--------SPELL --- Spell %v (%v) Effect %v AuraEffect %v Spell Desc: %v basePoints %v", spell.Name, spell.ID, spell.Effect1, spell.EffectAura1, spell.Description, spell.EffectBasePoints1)
|
||||
newId, err := spell.ScaleSpell(fromItemLevel, itemLevel, *item.Quality)
|
||||
if err != nil {
|
||||
log.Printf("Failed to scale spell: %v, Spell %v", err, spell.ID)
|
||||
@@ -455,7 +522,7 @@ func (item *Item) ScaleItem(itemLevel int, itemQuality int) (bool, error) {
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", spell.ItemSpellSlot), newId)
|
||||
item.Spells = append(item.Spells, spell)
|
||||
|
||||
log.Printf(" --SCALED---SPELL --- Spell %v (%v) Effect %v AuraEffect %v Spell Desc: %v basePoints %v", spell.Name, spell.ID, spell.Effect1, spell.EffectAura1, spell.Description, spell.EffectBasePoints1)
|
||||
// log.Printf(" --SCALED---SPELL --- Spell %v (%v) Effect %v AuraEffect %v Spell Desc: %v basePoints %v", spell.Name, spell.ID, spell.Effect1, spell.EffectAura1, spell.Description, spell.EffectBasePoints1)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
@@ -601,7 +668,7 @@ func (item *Item) addStats(stats map[int]*ItemStat) {
|
||||
|
||||
// Scale formula ((ItemLevel * QualityModifier * ItemTypeModifier)^1.7095 * %ofStats) ^ (1/1.7095)) / StatModifier
|
||||
func scaleStat(itemLevel int, itemType int, itemQuality int, percOfStat float64, statModifier float64) int {
|
||||
scaledUp := math.Pow((float64(itemLevel)*config.QualityModifiers[itemQuality]*config.InvTypeModifiers[itemType]), 1.7095) * percOfStat
|
||||
scaledUp := (math.Pow((float64(itemLevel)*config.QualityModifiers[itemQuality]*config.InvTypeModifiers[itemType]), 1.7095) * percOfStat)
|
||||
|
||||
// leaving modifier off for now but not changing signature in case I need to add it back
|
||||
_ = statModifier
|
||||
@@ -719,6 +786,14 @@ func ItemToSql(item Item, reqLevel int, difficulty int) string {
|
||||
spellid_1 = %v,
|
||||
spellid_2 = %v,
|
||||
spellid_3 = %v,
|
||||
socketColor_1 = %v,
|
||||
socketContent_1 = %v,
|
||||
socketColor_2 = %v,
|
||||
socketContent_2 = %v,
|
||||
socketColor_3 = %v,
|
||||
socketContent_3 = %v,
|
||||
socketBonus = %v,
|
||||
GemProperties = %v,
|
||||
RequiredDisenchantSkill = %v,
|
||||
DisenchantID = %v,
|
||||
SellPrice = FLOOR(100000 + (RAND() * 400001)),
|
||||
@@ -727,8 +802,9 @@ func ItemToSql(item Item, reqLevel int, difficulty int) string {
|
||||
`, *item.Quality, *item.ItemLevel, reqLevel, *item.MinDmg1, *item.MaxDmg1, *item.MinDmg2, *item.MaxDmg2, *item.StatsCount,
|
||||
*item.StatType1, *item.StatValue1, *item.StatType2, *item.StatValue2, *item.StatType3, *item.StatValue3, *item.StatType4, *item.StatValue4,
|
||||
*item.StatType5, *item.StatValue5, *item.StatType6, *item.StatValue6, *item.StatType7, *item.StatValue7, *item.StatType8, *item.StatValue8,
|
||||
*item.StatType9, *item.StatValue9, *item.StatType10, *item.StatValue10, *item.SpellId1, *item.SpellId2, *item.SpellId3, 375,
|
||||
68, *item.Armor, entryBump+item.Entry)
|
||||
*item.StatType9, *item.StatValue9, *item.StatType10, *item.StatValue10, *item.SpellId1, *item.SpellId2, *item.SpellId3, *item.SocketColor1, *item.SocketContent1,
|
||||
*item.SocketColor2, *item.SocketContent2, *item.SocketColor3, *item.SocketContent3, *item.SocketBonus, *item.GemProperties,
|
||||
375, 68, *item.Armor, entryBump+item.Entry)
|
||||
|
||||
return fmt.Sprintf("%s %s \n %s \n %s", spellList, delete, clone, update)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/config"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
@@ -27,6 +28,7 @@ var SpellAuraEffects = [...]int{
|
||||
13, // Modifies Spell Damage Done
|
||||
15, // Modifies Damage Shield
|
||||
22, // Modifies Resistance
|
||||
29, // Modifies Strength
|
||||
34, // Modifies HEalth
|
||||
85, // Modifies Mana Regen
|
||||
99, // Modifies Attack Power
|
||||
@@ -39,6 +41,7 @@ var SpellAuraEffects = [...]int{
|
||||
var AuraEffectsStatMap = map[int]int{
|
||||
8: 46,
|
||||
13: 45,
|
||||
29: 4,
|
||||
85: 43,
|
||||
99: 38,
|
||||
124: 38,
|
||||
@@ -93,34 +96,10 @@ type SpellEffect struct {
|
||||
CalculatedMax int
|
||||
}
|
||||
|
||||
// DB Mapping from spell_dbc
|
||||
type Spell struct {
|
||||
ID int `db:"ID"`
|
||||
Name string `db:"Name_Lang_enUS"`
|
||||
Description string `db:"Description_Lang_enUS"`
|
||||
AuraDescription string `db:"AuraDescription_Lang_enUS"`
|
||||
ProcChance int `db:"ProcChance"`
|
||||
SpellLevel int `db:"SpellLevel"`
|
||||
Effect1 int `db:"Effect_1"`
|
||||
Effect2 int `db:"Effect_2"`
|
||||
Effect3 int `db:"Effect_3"`
|
||||
EffectDieSides1 int `db:"EffectDieSides_1"`
|
||||
EffectDieSides2 int `db:"EffectDieSides_2"`
|
||||
EffectDieSides3 int `db:"EffectDieSides_3"`
|
||||
EffectRealPointsPerLevel1 int `db:"EffectRealPointsPerLevel_1"`
|
||||
EffectRealPointsPerLevel2 int `db:"EffectRealPointsPerLevel_2"`
|
||||
EffectRealPointsPerLevel3 int `db:"EffectRealPointsPerLevel_3"`
|
||||
EffectBasePoints1 int `db:"EffectBasePoints_1"`
|
||||
EffectBasePoints2 int `db:"EffectBasePoints_2"`
|
||||
EffectBasePoints3 int `db:"EffectBasePoints_3"`
|
||||
EffectAura1 int `db:"EffectAura_1"`
|
||||
EffectAura2 int `db:"EffectAura_2"`
|
||||
EffectAura3 int `db:"EffectAura_3"`
|
||||
EffectBonusMultiplier1 int `db:"EffectBonusMultiplier_1"`
|
||||
EffectBonusMultiplier2 int `db:"EffectBonusMultiplier_2"`
|
||||
EffectBonusMultiplier3 int `db:"EffectBonusMultiplier_3"`
|
||||
ItemSpellSlot int
|
||||
Scaled bool
|
||||
mysql.DbSpell
|
||||
Scaled bool
|
||||
ItemSpellSlot int
|
||||
}
|
||||
|
||||
func calcMaxValue(base int, sides int) int {
|
||||
@@ -225,14 +204,13 @@ func (s Spell) HasAuraEffect() bool {
|
||||
}
|
||||
|
||||
func AuraEffectCanBeConv(effect int) bool {
|
||||
statMods := [...]int{8, 13, 22, 34, 85, 99, 124, 135, 189}
|
||||
return funk.Contains(statMods, effect)
|
||||
return funk.Contains(SpellAuraEffects, effect)
|
||||
}
|
||||
|
||||
// Lookup details about the effect and return the stat type -1 indicates not found
|
||||
func convertAuraEffect(effect int) int {
|
||||
if !funk.Contains(AuraEffectsStatMap, effect) {
|
||||
log.Printf("effect %v not found in SpellEffectStatMap skipping", effect)
|
||||
// log.Printf("effect %v not found in SpellEffectStatMap skipping", effect)
|
||||
return -1
|
||||
}
|
||||
|
||||
@@ -251,8 +229,8 @@ func (s Spell) ConvertToStats() ([]ConvItemStat, error) {
|
||||
|
||||
if s.ID == 9397 {
|
||||
log.Printf("Spell: %v AuraEffect1: %v AuraEffect2: %v AuraEffect3: %v", s.Name, s.EffectAura1, s.EffectAura2, s.EffectAura3)
|
||||
|
||||
}
|
||||
|
||||
var seen []int
|
||||
for _, e := range effects {
|
||||
if !AuraEffectCanBeConv(e.Effect) {
|
||||
@@ -282,14 +260,14 @@ func (s Spell) ConvertToStats() ([]ConvItemStat, error) {
|
||||
|
||||
// Handle special stat case where 189 is catch all for crit, dodge, parry, hit, haste, expertise
|
||||
if s.Effect1 != 0 && s.Effect1 == 6 && (s.EffectAura1 == 189 || s.EffectAura1 == 123) {
|
||||
log.Printf("Special case for spell aura effect: %v", s.Description)
|
||||
// log.Printf("Special case for spell aura effect: %v", s.Description)
|
||||
statId := parseStatDesc(s.Description)
|
||||
if statId == 0 {
|
||||
log.Printf("Could not determine stat for spell aura effect description: %v", s.Name)
|
||||
}
|
||||
// if statId == 0 {
|
||||
// // log.Printf("Could not determine stat for spell aura effect description: %v", s.Name)
|
||||
// }
|
||||
|
||||
calced := calcMaxValue(s.EffectBasePoints1, s.EffectDieSides1)
|
||||
log.Printf("StatId: %v Calced: %v", statId, calced)
|
||||
// log.Printf("StatId: %v Calced: %v", statId, calced)
|
||||
stats = append(stats, ConvItemStat{
|
||||
StatType: statId,
|
||||
StatValue: calced,
|
||||
@@ -297,6 +275,12 @@ func (s Spell) ConvertToStats() ([]ConvItemStat, error) {
|
||||
})
|
||||
}
|
||||
|
||||
// if len(stats) == 0 {
|
||||
// // log.Printf("Failed to Convert Spell to Stats: %v AuraEffect1: %v AuraEffect2: %v AuraEffect3: %v", s.Name, s.EffectAura1, s.EffectAura2, s.EffectAura3)
|
||||
// } else {
|
||||
// // log.Printf("Converted Spell to Stats: %v AuraEffect1: %v AuraEffect2: %v AuraEffect3: %v", s.Name, s.EffectAura1, s.EffectAura2, s.EffectAura3)
|
||||
// }
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
@@ -447,3 +431,96 @@ func (s *Spell) ScaleSpell(fromItemLevel int, itemLevel int, itemQuality int) (i
|
||||
s.Scaled = true
|
||||
return idBump + s.ID, nil
|
||||
}
|
||||
|
||||
func SpellToSql(spell Spell, quality int) string {
|
||||
|
||||
entryBump := 30000000
|
||||
if quality == 4 {
|
||||
entryBump = 31000000
|
||||
}
|
||||
if quality == 5 {
|
||||
entryBump = 32000000
|
||||
}
|
||||
|
||||
insert := fmt.Sprintf(`
|
||||
INSERT IGNORE INTO acore_world.spell_dbc (
|
||||
ID, Category, DispelType, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4,
|
||||
AttributesEx5, AttributesEx6, AttributesEx7, ShapeshiftMask, unk_320_2, ShapeshiftExclude, unk_320_3, Targets,
|
||||
TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, ExcludeCasterAuraState,
|
||||
ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex,
|
||||
RecoveryTime, CategoryRecoveryTime, InterruptFlags, AuraInterruptFlags, ChannelInterruptFlags, ProcTypeMask, ProcChance,
|
||||
ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, PowerType, ManaCost, ManaCostPerLevel, ManaPerSecond,
|
||||
ManaPerSecondPerLevel, RangeIndex, Speed, ModalNextSpell, CumulativeAura, Totem_1, Totem_2, Reagent_1, Reagent_2, Reagent_3,
|
||||
Reagent_4, Reagent_5, Reagent_6, Reagent_7, Reagent_8, ReagentCount_1, ReagentCount_2, ReagentCount_3, ReagentCount_4,
|
||||
ReagentCount_5, ReagentCount_6, ReagentCount_7, ReagentCount_8, EquippedItemClass, EquippedItemSubclass, EquippedItemInvTypes,
|
||||
Effect_1, Effect_2, Effect_3, EffectDieSides_1, EffectDieSides_2, EffectDieSides_3, EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3, EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3,
|
||||
EffectMechanic_1, EffectMechanic_2, EffectMechanic_3, ImplicitTargetA_1, ImplicitTargetA_2, ImplicitTargetA_3, ImplicitTargetB_1,
|
||||
ImplicitTargetB_2, ImplicitTargetB_3, EffectRadiusIndex_1, EffectRadiusIndex_2, EffectRadiusIndex_3, EffectAura_1,
|
||||
EffectAura_2, EffectAura_3, EffectAuraPeriod_1, EffectAuraPeriod_2, EffectAuraPeriod_3, EffectMultipleValue_1, EffectMultipleValue_2,
|
||||
EffectMultipleValue_3, EffectChainTargets_1, EffectChainTargets_2, EffectChainTargets_3, EffectItemType_1, EffectItemType_2,
|
||||
EffectItemType_3, EffectMiscValue_1, EffectMiscValue_2, EffectMiscValue_3, EffectMiscValueB_1, EffectMiscValueB_2, EffectMiscValueB_3,
|
||||
EffectTriggerSpell_1, EffectTriggerSpell_2, EffectTriggerSpell_3, EffectPointsPerCombo_1, EffectPointsPerCombo_2, EffectPointsPerCombo_3,
|
||||
EffectSpellClassMaskA_1, EffectSpellClassMaskA_2, EffectSpellClassMaskA_3, EffectSpellClassMaskB_1, EffectSpellClassMaskB_2,
|
||||
EffectSpellClassMaskB_3, EffectSpellClassMaskC_1, EffectSpellClassMaskC_2, EffectSpellClassMaskC_3, SpellVisualID_1, SpellVisualID_2,
|
||||
SpellIconID, ActiveIconID, SpellPriority, Name_Lang_enUS, Name_Lang_enGB, Name_Lang_koKR, Name_Lang_frFR, Name_Lang_deDE,
|
||||
Name_Lang_enCN, Name_Lang_zhCN, Name_Lang_enTW, Name_Lang_zhTW, Name_Lang_esES, Name_Lang_esMX, Name_Lang_ruRU, Name_Lang_ptPT,
|
||||
Name_Lang_ptBR, Name_Lang_itIT, Name_Lang_Unk, Name_Lang_Mask, NameSubtext_Lang_enUS, NameSubtext_Lang_enGB, NameSubtext_Lang_koKR,
|
||||
NameSubtext_Lang_frFR, NameSubtext_Lang_deDE, NameSubtext_Lang_enCN, NameSubtext_Lang_zhCN, NameSubtext_Lang_enTW, NameSubtext_Lang_zhTW,
|
||||
NameSubtext_Lang_esES, NameSubtext_Lang_esMX, NameSubtext_Lang_ruRU, NameSubtext_Lang_ptPT, NameSubtext_Lang_ptBR, NameSubtext_Lang_itIT,
|
||||
NameSubtext_Lang_Unk, NameSubtext_Lang_Mask, Description_Lang_enUS, Description_Lang_enGB, Description_Lang_koKR, Description_Lang_frFR,
|
||||
Description_Lang_deDE, Description_Lang_enCN, Description_Lang_zhCN, Description_Lang_enTW, Description_Lang_zhTW, Description_Lang_esES,
|
||||
Description_Lang_esMX, Description_Lang_ruRU, Description_Lang_ptPT, Description_Lang_ptBR, Description_Lang_itIT, Description_Lang_Unk,
|
||||
Description_Lang_Mask, AuraDescription_Lang_enUS, AuraDescription_Lang_enGB, AuraDescription_Lang_koKR, AuraDescription_Lang_frFR,
|
||||
AuraDescription_Lang_deDE, AuraDescription_Lang_enCN, AuraDescription_Lang_zhCN, AuraDescription_Lang_enTW, AuraDescription_Lang_zhTW,
|
||||
AuraDescription_Lang_esES, AuraDescription_Lang_esMX, AuraDescription_Lang_ruRU, AuraDescription_Lang_ptPT, AuraDescription_Lang_ptBR,
|
||||
AuraDescription_Lang_itIT, AuraDescription_Lang_Unk, AuraDescription_Lang_Mask, ManaCostPct, StartRecoveryCategory, StartRecoveryTime,
|
||||
MaxTargetLevel, SpellClassSet, SpellClassMask_1, SpellClassMask_2, SpellClassMask_3, MaxTargets, DefenseType, PreventionType, StanceBarOrder,
|
||||
EffectChainAmplitude_1, EffectChainAmplitude_2, EffectChainAmplitude_3, MinFactionID, MinReputation, RequiredAuraVision, RequiredTotemCategoryID_1,
|
||||
RequiredTotemCategoryID_2, RequiredAreasID, SchoolMask, RuneCostID, SpellMissileID, PowerDisplayID, EffectBonusMultiplier_1, EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3, SpellDescriptionVariableID, SpellDifficultyID
|
||||
) SELECT
|
||||
ID + %v, Category, DispelType, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4,
|
||||
AttributesEx5, AttributesEx6, AttributesEx7, ShapeshiftMask, unk_320_2, ShapeshiftExclude, unk_320_3, Targets,
|
||||
TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, ExcludeCasterAuraState,
|
||||
ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex,
|
||||
RecoveryTime, CategoryRecoveryTime, InterruptFlags, AuraInterruptFlags, ChannelInterruptFlags, ProcTypeMask, ProcChance,
|
||||
ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, PowerType, ManaCost, ManaCostPerLevel, ManaPerSecond,
|
||||
ManaPerSecondPerLevel, RangeIndex, Speed, ModalNextSpell, CumulativeAura, Totem_1, Totem_2, Reagent_1, Reagent_2, Reagent_3,
|
||||
Reagent_4, Reagent_5, Reagent_6, Reagent_7, Reagent_8, ReagentCount_1, ReagentCount_2, ReagentCount_3, ReagentCount_4,
|
||||
ReagentCount_5, ReagentCount_6, ReagentCount_7, ReagentCount_8, EquippedItemClass, EquippedItemSubclass, EquippedItemInvTypes,
|
||||
Effect_1, Effect_2, Effect_3, EffectDieSides_1, EffectDieSides_2, EffectDieSides_3, EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3, EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3,
|
||||
EffectMechanic_1, EffectMechanic_2, EffectMechanic_3, ImplicitTargetA_1, ImplicitTargetA_2, ImplicitTargetA_3, ImplicitTargetB_1,
|
||||
ImplicitTargetB_2, ImplicitTargetB_3, EffectRadiusIndex_1, EffectRadiusIndex_2, EffectRadiusIndex_3, EffectAura_1,
|
||||
EffectAura_2, EffectAura_3, EffectAuraPeriod_1, EffectAuraPeriod_2, EffectAuraPeriod_3, EffectMultipleValue_1, EffectMultipleValue_2,
|
||||
EffectMultipleValue_3, EffectChainTargets_1, EffectChainTargets_2, EffectChainTargets_3, EffectItemType_1, EffectItemType_2,
|
||||
EffectItemType_3, EffectMiscValue_1, EffectMiscValue_2, EffectMiscValue_3, EffectMiscValueB_1, EffectMiscValueB_2, EffectMiscValueB_3,
|
||||
EffectTriggerSpell_1, EffectTriggerSpell_2, EffectTriggerSpell_3, EffectPointsPerCombo_1, EffectPointsPerCombo_2, EffectPointsPerCombo_3,
|
||||
EffectSpellClassMaskA_1, EffectSpellClassMaskA_2, EffectSpellClassMaskA_3, EffectSpellClassMaskB_1, EffectSpellClassMaskB_2,
|
||||
EffectSpellClassMaskB_3, EffectSpellClassMaskC_1, EffectSpellClassMaskC_2, EffectSpellClassMaskC_3, SpellVisualID_1, SpellVisualID_2,
|
||||
SpellIconID, ActiveIconID, SpellPriority, Name_Lang_enUS, Name_Lang_enGB, Name_Lang_koKR, Name_Lang_frFR, Name_Lang_deDE,
|
||||
Name_Lang_enCN, Name_Lang_zhCN, Name_Lang_enTW, Name_Lang_zhTW, Name_Lang_esES, Name_Lang_esMX, Name_Lang_ruRU, Name_Lang_ptPT,
|
||||
Name_Lang_ptBR, Name_Lang_itIT, Name_Lang_Unk, Name_Lang_Mask, NameSubtext_Lang_enUS, NameSubtext_Lang_enGB, NameSubtext_Lang_koKR,
|
||||
NameSubtext_Lang_frFR, NameSubtext_Lang_deDE, NameSubtext_Lang_enCN, NameSubtext_Lang_zhCN, NameSubtext_Lang_enTW, NameSubtext_Lang_zhTW,
|
||||
NameSubtext_Lang_esES, NameSubtext_Lang_esMX, NameSubtext_Lang_ruRU, NameSubtext_Lang_ptPT, NameSubtext_Lang_ptBR, NameSubtext_Lang_itIT,
|
||||
NameSubtext_Lang_Unk, NameSubtext_Lang_Mask, Description_Lang_enUS, Description_Lang_enGB, Description_Lang_koKR, Description_Lang_frFR,
|
||||
Description_Lang_deDE, Description_Lang_enCN, Description_Lang_zhCN, Description_Lang_enTW, Description_Lang_zhTW, Description_Lang_esES,
|
||||
Description_Lang_esMX, Description_Lang_ruRU, Description_Lang_ptPT, Description_Lang_ptBR, Description_Lang_itIT, Description_Lang_Unk,
|
||||
Description_Lang_Mask, AuraDescription_Lang_enUS, AuraDescription_Lang_enGB, AuraDescription_Lang_koKR, AuraDescription_Lang_frFR,
|
||||
AuraDescription_Lang_deDE, AuraDescription_Lang_enCN, AuraDescription_Lang_zhCN, AuraDescription_Lang_enTW, AuraDescription_Lang_zhTW,
|
||||
AuraDescription_Lang_esES, AuraDescription_Lang_esMX, AuraDescription_Lang_ruRU, AuraDescription_Lang_ptPT, AuraDescription_Lang_ptBR,
|
||||
AuraDescription_Lang_itIT, AuraDescription_Lang_Unk, AuraDescription_Lang_Mask, ManaCostPct, StartRecoveryCategory, StartRecoveryTime,
|
||||
MaxTargetLevel, SpellClassSet, SpellClassMask_1, SpellClassMask_2, SpellClassMask_3, MaxTargets, DefenseType, PreventionType, StanceBarOrder,
|
||||
EffectChainAmplitude_1, EffectChainAmplitude_2, EffectChainAmplitude_3, MinFactionID, MinReputation, RequiredAuraVision, RequiredTotemCategoryID_1,
|
||||
RequiredTotemCategoryID_2, RequiredAreasID, SchoolMask, RuneCostID, SpellMissileID, PowerDisplayID, EffectBonusMultiplier_1, EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3, SpellDescriptionVariableID, SpellDifficultyID from acore_world.spell_dbc as src
|
||||
WHERE src.ID = %v ON DUPLICATE KEY UPDATE ID = src.ID + %v;`, entryBump, spell.ID, entryBump)
|
||||
|
||||
update := fmt.Sprintf(`
|
||||
UPDATE acore_world.spell_dbc
|
||||
SET EffectBasePoints_1 = %v, EffectBasePoints_2 = %v
|
||||
WHERE ID = %v;`, spell.EffectBasePoints1, spell.EffectBasePoints2, entryBump+spell.ID)
|
||||
|
||||
return fmt.Sprintf("\n %s \n %s \n", insert, update)
|
||||
}
|
||||
|
||||
60
internal/spells/spells_test.go
Normal file
60
internal/spells/spells_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package spells
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
)
|
||||
|
||||
func TestCanBeConverted(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
spell Spell
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "Spell with non-aura effect",
|
||||
spell: Spell{
|
||||
DbSpell: mysql.DbSpell{
|
||||
Effect1: 1,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Spell with aura effect that can be converted",
|
||||
spell: Spell{
|
||||
DbSpell: mysql.DbSpell{
|
||||
EffectAura1: 8,
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Spell with mixed effects",
|
||||
spell: Spell{
|
||||
DbSpell: mysql.DbSpell{
|
||||
Effect1: 1,
|
||||
EffectAura1: 8,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Spell with no effects",
|
||||
spell: Spell{
|
||||
DbSpell: mysql.DbSpell{},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.spell.CanBeConverted()
|
||||
if result != tt.expected {
|
||||
t.Errorf("expected %v, got %v", tt.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
95
main.go
95
main.go
@@ -6,6 +6,10 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/sqlite"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
@@ -17,23 +21,98 @@ func main() {
|
||||
// database.models.Connect()
|
||||
|
||||
debug := flag.Bool("debug", false, "Enable verbose logging inside generator")
|
||||
// itemLevel := flag.Int("ilvl", 305, "Specify the item level to start scaling from, expansion and difficulty modifiers scale up.")
|
||||
// difficulty := flag.Int("difficulty", 3, "set the difficulty of the dungeon, defaults to 3 (mythic) 4 (legendary) 5 (ascendant)")
|
||||
itemLevel := flag.Int("ilvl", 305, "Specify the item level to start scaling from, expansion and difficulty modifiers scale up.")
|
||||
difficulty := flag.Int("difficulty", 3, "set the difficulty of the dungeon, defaults to 3 (mythic) 4 (legendary) 5 (ascendant)")
|
||||
// levelUp := flag.Bool("levelUp", false, "Boss items require higher +1 level to equip, defaults to false")
|
||||
// baselevel := flag.Int("baselevel", 80, "set the base level for items to be used, defaults to 80 this is required for levelUp flag")
|
||||
|
||||
baselevel := flag.Int("baselevel", 80, "set the base level for items to be used, defaults to 80 this is required for levelUp flag")
|
||||
flag.Parse()
|
||||
|
||||
if difficulty == nil || *difficulty < 3 || *difficulty > 5 {
|
||||
log.Fatal("difficulty must be between 3-5")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if itemLevel == nil || *itemLevel < 280 {
|
||||
log.Fatal("item level must be greater than 280")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if baselevel == nil || *baselevel < 0 {
|
||||
log.Fatal("base level must be greater than 80")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *debug {
|
||||
log.SetOutput(os.Stdout)
|
||||
} else {
|
||||
log.SetOutput(io.Discard)
|
||||
}
|
||||
|
||||
// if difficulty == nil || *difficulty < 3 || *difficulty > 5 {
|
||||
// log.Fatal("difficulty must be between 3-5")
|
||||
// os.Exit(1)
|
||||
// }
|
||||
// Connect to Mysql
|
||||
mysqlDb, err := mysql.Connect(&mysql.MySqlConfig{
|
||||
Host: os.Getenv("DB_HOST"),
|
||||
User: os.Getenv("DB_USER"),
|
||||
Password: os.Getenv("DB_PASSWORD"),
|
||||
Database: os.Getenv("DB_NAME"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Connect to SqlList for EndGame Mapping
|
||||
sqliteDb, err := sqlite.Connect("./data/items.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
rareItems, err := mysqlDb.GetRarePlusItems(0, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for itr, dbItem := range rareItems {
|
||||
item := items.ItemFromDbItem(dbItem)
|
||||
|
||||
statsList, err := item.GetStatList()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Item: %v Entry: %v StatsList: %v\n", item.Name, item.Entry, statsList)
|
||||
rndItem, err := sqliteDb.GetRandItem(*item.Class, *item.Subclass, statsList, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if rndItem == (sqlite.HighLevelItem{}) {
|
||||
log.Fatalf("Failed to get random item for %v Entry: %v\n", item.Name, item.Entry)
|
||||
}
|
||||
|
||||
log.Printf("Random Item: %v Entry: %v\n", rndItem.Name, rndItem.Entry)
|
||||
|
||||
highLevelItem, err := mysqlDb.GetItem(rndItem.Entry)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Print all the status for the item that was copied
|
||||
log.Printf("Item Name: %v Stat1: %v Stat2: %v Stat3: %v Stat4: %v Stat5: %v Stat6: %v Stat7: %v Stat8: %v \n",
|
||||
item.Entry, *item.StatValue1, *item.StatValue2, *item.StatValue3, *item.StatValue4, *item.StatValue5, *item.StatValue6, *item.StatValue7, *item.StatValue8)
|
||||
|
||||
item.ApplyStats(items.ItemFromDbItem(highLevelItem))
|
||||
|
||||
item.ScaleItem(*itemLevel, 4)
|
||||
log.Printf("Item Name: %v Stat1: %v Stat2: %v Stat3: %v Stat4: %v Stat5: %v Stat6: %v Stat7: %v Stat8: %v \n",
|
||||
item.Name, *item.StatValue1, *item.StatValue2, *item.StatValue3, *item.StatValue4, *item.StatValue5, *item.StatValue6, *item.StatValue7, *item.StatValue8)
|
||||
|
||||
if itr > 100 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// // main loop
|
||||
// dungeons, err := models.DB.GetDungeons(-1)
|
||||
|
||||
Binary file not shown.
@@ -1,103 +0,0 @@
|
||||
// package main
|
||||
|
||||
// import (
|
||||
// "database/sql"
|
||||
// "fmt"
|
||||
// "log"
|
||||
// "slices"
|
||||
// "strconv"
|
||||
// "strings"
|
||||
|
||||
// // "github.com/araxiaonline/endgame-item-generator/internal/models"
|
||||
// "github.com/araxiaonline/endgame-item-generator/internal/utils"
|
||||
// "github.com/joho/godotenv"
|
||||
// _ "github.com/mattn/go-sqlite3"
|
||||
// )
|
||||
|
||||
// type EndGameItem struct {
|
||||
// Entry int `db:"entry"`
|
||||
// Class int `db:"class"`
|
||||
// Subclass int `db:"subclass"`
|
||||
// StatsList string `db:"stats_list"`
|
||||
// }
|
||||
|
||||
// func createItemsTable(db *sql.DB) {
|
||||
// createItems := `CREATE TABLE IF NOT EXISTS items (
|
||||
// entry int unsigned NOT NULL DEFAULT '0',
|
||||
// class tinyint unsigned NOT NULL DEFAULT '0',
|
||||
// name varchar(250) NOT NULL DEFAULT '',
|
||||
// Quality int unsigned NOT NULL DEFAULT '0',
|
||||
// itemLevel int unsigned NOT NULL DEFAULT '0',
|
||||
// subclass tinyint unsigned NOT NULL DEFAULT '0',
|
||||
// stats_list varchar(250) NOT NULL DEFAULT '',
|
||||
// PRIMARY KEY (entry)
|
||||
// )`
|
||||
|
||||
// _, err := db.Exec(createItems)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func ConvertIntSliceToString(slice []int) string {
|
||||
// sliceStr := make([]string, len(slice))
|
||||
// for i, v := range slice {
|
||||
// sliceStr[i] = strconv.Itoa(v)
|
||||
// }
|
||||
|
||||
// return strings.Join(sliceStr, ",")
|
||||
// }
|
||||
|
||||
// func main() {
|
||||
|
||||
// liteDb, err := sql.Open("sqlite3", "./items.db")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// godotenv.Load("../../.env")
|
||||
// models.Connect()
|
||||
// sqlDb := models.DB.Client()
|
||||
|
||||
// defer liteDb.Close()
|
||||
// defer sqlDb.Close()
|
||||
|
||||
// // create the items table if it doesnt exist
|
||||
// createItemsTable(liteDb)
|
||||
|
||||
// // create the endgames items lookup table locally for items 200 and above
|
||||
// var items []models.Item
|
||||
// sql := `
|
||||
// SELECT ` + utils.GetItemFields("") + `
|
||||
// from acore_world.item_template
|
||||
// where ItemLevel >= 200 and Quality >= 3 and ItemLevel < 290
|
||||
// AND name NOT LIKE 'NPC Equip%' and name NOT LIKE 'OLD%'
|
||||
// AND name NOT LIKE '%(test)%' AND name NOT LIKE '%Deprecated%'
|
||||
// AND name NOT LIKE '%Monster - %'
|
||||
// AND ((class = 2 and subclass IN(0,1,2,3,4,5,6,7,8,10,11,12,13,15,16,17,18,19)) or ((class = 4 AND subclass IN (1,2,3,4,6))))
|
||||
// `
|
||||
// err = sqlDb.Select(&items, sql)
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to get items: %v", err)
|
||||
// }
|
||||
|
||||
// for _, item := range items {
|
||||
// var statsList []int
|
||||
// for i := 1; i <= 10; i++ {
|
||||
// val, _ := item.GetField(fmt.Sprintf("StatValue%v", i))
|
||||
// statId, _ := item.GetField(fmt.Sprintf("StatType%v", i))
|
||||
// if val != 0 {
|
||||
// statsList = append(statsList, statId)
|
||||
// }
|
||||
// }
|
||||
// slices.Sort(statsList)
|
||||
// statsListStr := ConvertIntSliceToString(statsList)
|
||||
// log.Printf("StatList %s for Item %v", statsListStr, item.Name)
|
||||
// _, err = liteDb.Exec("INSERT OR IGNORE INTO items (entry, class, name, Quality, itemLevel, subclass, stats_list) VALUES (?, ?, ?, ?, ?,?,?)", item.Entry, *item.Class, item.Name, *item.Quality, *item.ItemLevel, *item.Subclass, statsListStr)
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to insert item %v: %v", item.Entry, err)
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// log.Printf("Items: %v", len(items))
|
||||
// }
|
||||
Reference in New Issue
Block a user