Major changes and refactor of all code to break things out more and add in more testing

This commit is contained in:
2024-08-21 02:08:46 -04:00
parent dc35137e19
commit c2281e0c19
21 changed files with 974 additions and 331 deletions

4
go.mod
View File

@@ -2,13 +2,13 @@ module github.com/araxiaonline/endgame-item-generator
go 1.22.4
replace github.com/araxiaonline/endgame-item-generator/models => ../models
require github.com/go-sql-driver/mysql v1.8.1
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/jmoiron/sqlx v1.4.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/thoas/go-funk v0.9.3 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
)

3
go.sum
View File

@@ -8,11 +8,14 @@ github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -1,10 +1,10 @@
package models
package creatures
import (
"errors"
"fmt"
"github.com/araxiaonline/endgame-item-generator/utils"
"github.com/araxiaonline/endgame-item-generator/import/utils"
_ "github.com/go-sql-driver/mysql"
_ "github.com/jmoiron/sqlx"
)

450
internal/items/item_test.go Normal file
View File

@@ -0,0 +1,450 @@
package items
import (
"io"
"log"
"math"
"reflect"
"testing"
"golang.org/x/exp/rand"
)
func TestGetPrimaryStat(t *testing.T) {
originalLog := log.Writer()
log.SetOutput(io.Discard)
defer log.SetOutput(originalLog)
tests := []struct {
name string
item Item
wantStat int
wantValue int
expectError bool
}{
{
name: "No primary stat found",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(1), StatValue1: ptrInt(10),
StatType2: ptrInt(2), StatValue2: ptrInt(20),
StatType3: ptrInt(12), StatValue3: ptrInt(15),
},
wantStat: 0,
wantValue: 0,
expectError: false,
},
{
name: "Primary stat found with higher value",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(3), StatValue1: ptrInt(10), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
},
wantStat: 4, // Strength
wantValue: 20,
expectError: false,
},
{
name: "Primary stat found with lower value",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(3), StatValue1: ptrInt(30), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
},
wantStat: 3, // Agility
wantValue: 30,
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotStat, gotValue, err := tt.item.GetPrimaryStat()
if (err != nil) != tt.expectError {
t.Errorf("GetPrimaryStat() error = %v, expectError %v", err, tt.expectError)
return
}
if gotStat != tt.wantStat {
t.Errorf("GetPrimaryStat() gotStat = %v, want %v", gotStat, tt.wantStat)
}
if gotValue != tt.wantValue {
t.Errorf("GetPrimaryStat() gotValue = %v, want %v", gotValue, tt.wantValue)
}
})
}
}
func TestGetStatList(t *testing.T) {
originalLog := log.Writer()
log.SetOutput(io.Discard)
defer log.SetOutput(originalLog)
tests := []struct {
name string
item Item
want []int
expectError bool
}{
{
name: "No stats available",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(0), StatValue1: ptrInt(0),
StatType2: ptrInt(0), StatValue2: ptrInt(0),
},
want: []int{},
expectError: false,
},
{
name: "Multiple stats available",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(3), StatValue1: ptrInt(10), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
},
want: []int{3, 4, 5},
expectError: false,
},
{
name: "Stats are ordered correctly",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(7), StatValue1: ptrInt(10), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(31), StatValue3: ptrInt(15), // Intellect
},
want: []int{4, 7, 31},
expectError: false,
},
{
name: "Some stats are zero",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(3), StatValue1: ptrInt(0), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(5), StatValue3: ptrInt(0), // Intellect
},
want: []int{4},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.item.GetStatList()
if (err != nil) != tt.expectError {
t.Errorf("GetStatList() error = %v, expectError %v", err, tt.expectError)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetStatList() got = %v, want %v", got, tt.want)
}
})
}
}
func TestGetDPS(t *testing.T) {
tests := []struct {
name string
item Item
wantDPS float64
expectError bool
}{
{
name: "Valid DPS calculation",
item: Item{
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
Delay: ptrFloat64(3000),
},
wantDPS: 20.00,
expectError: false,
},
{
name: "High damage DPS calculation",
item: Item{
MinDmg1: ptrInt(100),
MaxDmg1: ptrInt(150),
Delay: ptrFloat64(2000),
},
wantDPS: 62.50,
expectError: false,
},
{
name: "Low damage DPS calculation",
item: Item{
MinDmg1: ptrInt(10),
MaxDmg1: ptrInt(15),
Delay: ptrFloat64(1500),
},
wantDPS: 8.33,
expectError: false,
},
{
name: "Missing MinDmg1",
item: Item{
MaxDmg1: ptrInt(70),
Delay: ptrFloat64(3000),
},
wantDPS: 0,
expectError: true,
},
{
name: "Missing MaxDmg1",
item: Item{
MinDmg1: ptrInt(50),
Delay: ptrFloat64(3000),
},
wantDPS: 0,
expectError: true,
},
{
name: "Missing Delay",
item: Item{
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
},
wantDPS: 0,
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotDPS, err := tt.item.GetDPS()
if (err != nil) != tt.expectError {
t.Errorf("GetDPS() error = %v, expectError %v", err, tt.expectError)
return
}
if !tt.expectError && !almostEqual(gotDPS, tt.wantDPS, 0.01) {
t.Errorf("GetDPS() = %v, want %v", gotDPS, tt.wantDPS)
}
})
}
}
func TestScaleDPS(t *testing.T) {
tests := []struct {
name string
item Item
level int
wantDPSMin float64
wantDPSMax float64
expectError bool
}{
{
name: "Valid Scale DPS calculation",
item: Item{
ItemLevel: ptrInt(60),
Delay: ptrFloat64(3000),
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
level: 70,
wantDPSMin: 53.0, // Expected DPS range due to randomness
wantDPSMax: 107.0,
expectError: false,
},
{
name: "High level Scale DPS calculation",
item: Item{
ItemLevel: ptrInt(80),
Delay: ptrFloat64(2000),
MinDmg1: ptrInt(150),
MaxDmg1: ptrInt(200),
Subclass: ptrInt(17), // Two-handed weapon
Quality: ptrInt(4), // Epic
},
level: 100,
wantDPSMin: 120.0, // Expected DPS range due to randomness
wantDPSMax: 240.0,
expectError: false,
},
{
name: "Low level Scale DPS calculation",
item: Item{
ItemLevel: ptrInt(20),
Delay: ptrFloat64(1000),
MinDmg1: ptrInt(30),
MaxDmg1: ptrInt(50),
Subclass: ptrInt(2), // Ranged weapon
Quality: ptrInt(2), // Uncommon
},
level: 25,
wantDPSMin: 21.0, // Expected DPS range due to randomness
wantDPSMax: 42.0,
expectError: false,
},
{
name: "Missing ItemLevel",
item: Item{
Delay: ptrFloat64(3000),
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
level: 70,
wantDPSMin: 0,
wantDPSMax: 0,
expectError: true,
},
{
name: "Missing Delay",
item: Item{
ItemLevel: ptrInt(60),
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
level: 70,
wantDPSMin: 0,
wantDPSMax: 0,
expectError: true,
},
{
name: "Secondary damage scaling",
item: Item{
ItemLevel: ptrInt(60),
Delay: ptrFloat64(3000),
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
MinDmg2: ptrInt(25),
MaxDmg2: ptrInt(35),
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
level: 70,
wantDPSMin: 53.0, // Expected DPS range due to randomness
wantDPSMax: 107.0,
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Seed the random number generator for consistent test results
rand.Seed(1)
gotDPS, err := tt.item.ScaleDPS(tt.level)
if (err != nil) != tt.expectError {
t.Errorf("ScaleDPS() error = %v, expectError %v", err, tt.expectError)
return
}
if !tt.expectError && (gotDPS < tt.wantDPSMin || gotDPS > tt.wantDPSMax) {
t.Errorf("ScaleDPS() = %v, want between %v and %v", gotDPS, tt.wantDPSMin, tt.wantDPSMax)
}
})
}
}
func TestGetDpsModifier(t *testing.T) {
tests := []struct {
name string
item Item
wantModifier float64
expectError bool
}{
{
name: "Valid one-handed weapon modifier",
item: Item{
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
wantModifier: 0.64 * 1.38,
expectError: false,
},
{
name: "Valid two-handed weapon modifier",
item: Item{
Subclass: ptrInt(17), // Two-handed weapon
Quality: ptrInt(4), // Epic
},
wantModifier: 0.80 * 1.5,
expectError: false,
},
{
name: "Valid ranged weapon modifier",
item: Item{
Subclass: ptrInt(2), // Ranged weapon
Quality: ptrInt(2), // Uncommon
},
wantModifier: 0.70 * 1.25,
expectError: false,
},
{
name: "Valid wand modifier",
item: Item{
Subclass: ptrInt(19), // Wand
Quality: ptrInt(4), // Epic
},
wantModifier: 0.70 * 1.5,
expectError: false,
},
{
name: "Invalid subclass",
item: Item{
Subclass: ptrInt(99), // Invalid subclass
Quality: ptrInt(3), // Rare
},
wantModifier: 0,
expectError: true,
},
{
name: "Missing subclass",
item: Item{
Quality: ptrInt(3), // Rare
},
wantModifier: 0,
expectError: true,
},
{
name: "Missing quality",
item: Item{
Subclass: ptrInt(4), // One-handed weapon
},
wantModifier: 0,
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotModifier, err := tt.item.GetDpsModifier()
if (err != nil) != tt.expectError {
t.Errorf("GetDpsModifier() error = %v, expectError %v", err, tt.expectError)
return
}
if !tt.expectError && !almostEqual(gotModifier, tt.wantModifier, 0.01) {
t.Errorf("GetDpsModifier() = %v, want %v", gotModifier, tt.wantModifier)
}
})
}
}
// Helper function to return a pointer to an int
func ptrInt(i int) *int {
return &i
}
func ptrFloat64(f float64) *float64 {
return &f
}
func almostEqual(a, b, tolerance float64) bool {
return math.Abs(a-b) <= tolerance
}

View File

@@ -1,4 +1,4 @@
package models
package items
import (
"errors"
@@ -7,8 +7,7 @@ import (
"math"
"math/rand/v2"
"reflect"
"github.com/araxiaonline/endgame-item-generator/utils"
"slices"
)
/**
@@ -171,28 +170,71 @@ var StatModifiers = map[int]float64{
48: 0.65, // ITEM_MOD_BLOCK_VALUE
}
// Get the primary stat for an item (strength, agility, intellect, spirit, stamina)
func (item Item) GetPrimaryStat() (int, int, error) {
var primaryStat int64
var primaryVal int64
values := reflect.ValueOf(item)
for i := 1; i < 11; i++ {
statType := values.FieldByName(fmt.Sprintf("StatType%v", i)).Elem().Int()
// first check if the stat type is not in the primary stats str, agi, intellect, spirit, stamina
statType, err := item.GetField(fmt.Sprintf("StatType%v", i))
if err != nil {
log.Printf("Failed to get stat type %v for item: %v", i, item.Name)
continue
}
if statType < 3 || statType > 7 {
continue
}
statValue := values.FieldByName(fmt.Sprintf("StatValue%v", i)).Elem().Int()
if statValue > primaryVal {
primaryVal = statValue
primaryStat = statType
val, err := item.GetField(fmt.Sprintf("StatValue%v", i))
if err != nil {
log.Printf("Failed to get stat value %v for item: %v", i, item.Name)
continue
}
if val == 0 {
continue
}
if int64(val) > primaryVal {
primaryVal = int64(val)
primaryStat = int64(statType)
}
}
return int(primaryStat), int(primaryVal), nil
}
/**
* Get the statIds for anitem as a slice of integers
* @return []int
*/
func (item Item) GetStatList() ([]int, error) {
statList := []int{}
for i := 1; i < 11; i++ {
val, err := item.GetField(fmt.Sprintf("StatValue%v", i))
if err != nil {
log.Printf("Failed to get stat value %v for item: %v", i, item.Name)
continue
}
if val == 0 {
continue
}
statId, err := item.GetField(fmt.Sprintf("StatType%v", i))
if err != nil {
log.Printf("Failed to get stat type %v for item: %s", i, item.Name)
continue
}
statList = append(statList, statId)
slices.Sort(statList)
}
return statList, nil
}
func (i Item) GetDpsModifier() (float64, error) {
if i.Subclass == nil {
return 0, fmt.Errorf("subclass on the item is not set")

View File

@@ -0,0 +1,160 @@
package items
import (
"fmt"
)
func GetItemFields(prefix string) string {
pre := ""
if prefix != "" {
pre = prefix + "."
}
return `
` + pre + `entry, ` + pre + `name, ` + pre + `displayid,
quality, ItemLevel, class, subclass, inventoryType,
allowableClass, allowableRace,
armor,material,
requiredSkill, requiredLevel,
dmg_min1, dmg_max1,
dmg_min2,dmg_max2,
dmg_type1, dmg_type2,
delay, sheath, MaxDurability,
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,
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.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)
}

View File

@@ -1,4 +1,4 @@
package models
package maps
import (
"fmt"

43
internal/pkg/db/mysql.go Normal file
View File

@@ -0,0 +1,43 @@
package db
import (
"os"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
type MySql struct {
client *sqlx.DB
}
type MySqlConfig struct {
Host string
User string
Password string
Database string
}
func ConnectMySql(config *MySqlConfig) (*MySql, error) {
if config == nil {
config = &MySqlConfig{
Host: os.Getenv("DB_HOST"),
User: os.Getenv("DB_USER"),
Password: os.Getenv("DB_PASSWORD"),
Database: os.Getenv("DB_NAME"),
}
}
connString := config.User + ":" + config.Password + "@tcp(" + config.Host + ")/" + config.Database
client, err := sqlx.Open("mysql", connString)
if err != nil {
return nil, err
}
return &MySql{client: client}, nil
}
func (db *MySql) Close() {
db.client.Close()
}

23
internal/pkg/db/sqlite.go Normal file
View File

@@ -0,0 +1,23 @@
package db
import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
)
type SqlLite struct {
client *sql.DB
}
func ConnectSqlLite(path string) (*SqlLite, error) {
client, err := sql.Open("sqlite3", path)
if err != nil {
return nil, err
}
return &SqlLite{client: client}, nil
}
func (db *SqlLite) Close() {
db.client.Close()
}

View File

@@ -1,4 +1,4 @@
package models
package spells
import (
"fmt"
@@ -7,7 +7,6 @@ import (
"strconv"
"strings"
"github.com/araxiaonline/endgame-item-generator/utils"
"github.com/thoas/go-funk"
)
@@ -130,7 +129,7 @@ func (db Database) GetSpell(id int) (Spell, error) {
}
spell := Spell{}
sql := "SELECT " + utils.GetSpellFields() + " FROM `spell_dbc` WHERE ID = ? -- " + strconv.Itoa(id)
sql := "SELECT " + GetSpellFields() + " FROM `spell_dbc` WHERE ID = ? -- " + strconv.Itoa(id)
err := db.client.Get(&spell, sql, id)
if err != nil {

View File

@@ -1,137 +1,39 @@
package main
package spells
import (
"fmt"
"github.com/araxiaonline/endgame-item-generator/models"
)
// convert an item to a create sql statement
func ItemToSql(item models.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 += 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)
func GetSpellFields() string {
return `
ID,
Name_Lang_enUS,
Description_Lang_enUS,
AuraDescription_Lang_enUS,
ProcChance,
SpellLevel,
Effect_1,
Effect_2,
Effect_3,
EffectDieSides_1,
EffectDieSides_2,
EffectDieSides_3,
EffectRealPointsPerLevel_1,
EffectRealPointsPerLevel_2,
EffectRealPointsPerLevel_3,
EffectBasePoints_1,
EffectBasePoints_2,
EffectBasePoints_3,
EffectAura_1,
EffectAura_2,
EffectAura_3,
EffectBonusMultiplier_1,
EffectBonusMultiplier_2,
EffectBonusMultiplier_3
`
}
func SpellToSql(spell models.Spell, quality int) string {
func SpellToSql(spell Spell, quality int) string {
entryBump := 30000000
if quality == 4 {

View File

@@ -0,0 +1 @@
package utils

194
main.go
View File

@@ -2,12 +2,10 @@ package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"github.com/araxiaonline/endgame-item-generator/models"
_ "github.com/go-sql-driver/mysql"
"github.com/joho/godotenv"
)
@@ -16,13 +14,13 @@ func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
godotenv.Load()
models.Connect()
// 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)")
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")
// 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")
flag.Parse()
@@ -32,119 +30,119 @@ func main() {
log.SetOutput(io.Discard)
}
if difficulty == nil || *difficulty < 3 || *difficulty > 5 {
log.Fatal("difficulty must be between 3-5")
os.Exit(1)
}
// if difficulty == nil || *difficulty < 3 || *difficulty > 5 {
// log.Fatal("difficulty must be between 3-5")
// os.Exit(1)
// }
// main loop
dungeons, err := models.DB.GetDungeons(-1)
if err != nil {
log.Panicf("failed to get dungeons for expansion %v error: %v", 0, err)
}
// // main loop
// dungeons, err := models.DB.GetDungeons(-1)
// if err != nil {
// log.Panicf("failed to get dungeons for expansion %v error: %v", 0, err)
// }
for _, dungeon := range dungeons {
// for _, dungeon := range dungeons {
log.Printf("+++++Dungeon: %s ID: %v level %v \n", dungeon.Name, dungeon.Id, dungeon.Level)
// log.Printf("+++++Dungeon: %s ID: %v level %v \n", dungeon.Name, dungeon.Id, dungeon.Level)
bosses, err := models.DB.GetBosses(dungeon.Id)
if err != nil {
log.Fatal("failed to get bosses")
}
// bosses, err := models.DB.GetBosses(dungeon.Id)
// if err != nil {
// log.Fatal("failed to get bosses")
// }
// Determine the scale value of the item based on expansion and dungeon level
scaleValue := *itemLevel
endGameDung := false
if dungeon.Level == 60 {
scaleValue += 10
endGameDung = true
}
// // Determine the scale value of the item based on expansion and dungeon level
// scaleValue := *itemLevel
// endGameDung := false
// if dungeon.Level == 60 {
// scaleValue += 10
// endGameDung = true
// }
if dungeon.ExpansionId == 1 && dungeon.Level <= 70 {
scaleValue += 3
}
// if dungeon.ExpansionId == 1 && dungeon.Level <= 70 {
// scaleValue += 3
// }
if dungeon.ExpansionId == 1 && dungeon.Level == 70 {
scaleValue += 12
endGameDung = true
}
// if dungeon.ExpansionId == 1 && dungeon.Level == 70 {
// scaleValue += 12
// endGameDung = true
// }
if dungeon.ExpansionId == 2 && dungeon.Level <= 80 {
scaleValue += 4
}
// if dungeon.ExpansionId == 2 && dungeon.Level <= 80 {
// scaleValue += 4
// }
if dungeon.ExpansionId == 2 && dungeon.Level == 80 {
scaleValue += 15
endGameDung = true
}
// if dungeon.ExpansionId == 2 && dungeon.Level == 80 {
// scaleValue += 15
// endGameDung = true
// }
// Apply difficuly modifiers for gear scale
// mythic: Bosses-Epic Gear (Purple) drops and Rare (Blue) for random drops (BOE)
// legendary: Bosses-Epic Gear (Purple) drops and Epic (Purple) for random drops (BOE)
// ascendant: Bosses-Legendary Gear (Yellow) drops and Epic (Purple) for random drops (BOE)
var bossQuality int
var boeQuality int
// // Apply difficuly modifiers for gear scale
// // mythic: Bosses-Epic Gear (Purple) drops and Rare (Blue) for random drops (BOE)
// // legendary: Bosses-Epic Gear (Purple) drops and Epic (Purple) for random drops (BOE)
// // ascendant: Bosses-Legendary Gear (Yellow) drops and Epic (Purple) for random drops (BOE)
// var bossQuality int
// var boeQuality int
if *difficulty == 4 {
bossQuality = 4
boeQuality = 4
} else if *difficulty == 5 {
bossQuality = 5
boeQuality = 4
} else {
bossQuality = 4
boeQuality = 3
}
// if *difficulty == 4 {
// bossQuality = 4
// boeQuality = 4
// } else if *difficulty == 5 {
// bossQuality = 5
// boeQuality = 4
// } else {
// bossQuality = 4
// boeQuality = 3
// }
for _, boss := range bosses {
// for _, boss := range bosses {
items, err := models.DB.GetBossLoot(boss.Entry)
log.Printf("++++++++++ Boss: %s Entry: %v has %v items\n", boss.Name, boss.Entry, len(items))
if err != nil {
log.Fatal(err)
continue
}
// items, err := models.DB.GetBossLoot(boss.Entry)
// log.Printf("++++++++++ Boss: %s Entry: %v has %v items\n", boss.Name, boss.Entry, len(items))
// if err != nil {
// log.Fatal(err)
// continue
// }
for _, item := range items {
// for _, item := range items {
_, error := item.ScaleItem(scaleValue, bossQuality)
if error != nil {
log.Printf("Failed to scale item: %v", error)
continue
}
// _, error := item.ScaleItem(scaleValue, bossQuality)
// if error != nil {
// log.Printf("Failed to scale item: %v", error)
// continue
// }
fmt.Printf("\n-- Item %v Entry: %v ItemLevel %v \n", item.Name, item.Entry, *item.ItemLevel)
if *levelUp && endGameDung {
fmt.Print(ItemToSql(item, *baselevel+1, *difficulty))
} else {
fmt.Print(ItemToSql(item, *baselevel, *difficulty))
}
}
// fmt.Printf("\n-- Item %v Entry: %v ItemLevel %v \n", item.Name, item.Entry, *item.ItemLevel)
// if *levelUp && endGameDung {
// fmt.Print(ItemToSql(item, *baselevel+1, *difficulty))
// } else {
// fmt.Print(ItemToSql(item, *baselevel, *difficulty))
// }
// }
}
// }
items2, err := models.DB.GetAddlDungeonDrops(dungeon.Id)
if err != nil {
log.Printf("failed to get additional loot for dungeon %v - err: %v", dungeon.Id, err)
}
// items2, err := models.DB.GetAddlDungeonDrops(dungeon.Id)
// if err != nil {
// log.Printf("failed to get additional loot for dungeon %v - err: %v", dungeon.Id, err)
// }
for _, item := range items2 {
// for _, item := range items2 {
// reduce item level of dungeon random drops since they are not boss fights
adjScaleValue := scaleValue - 4
// // reduce item level of dungeon random drops since they are not boss fights
// adjScaleValue := scaleValue - 4
_, error := item.ScaleItem(adjScaleValue, boeQuality)
if error != nil {
log.Printf("Failed to scale item: %v", error)
continue
}
// _, error := item.ScaleItem(adjScaleValue, boeQuality)
// if error != nil {
// log.Printf("Failed to scale item: %v", error)
// continue
// }
fmt.Printf("\n-- Item %v Entry: %v ItemLevel %v \n", item.Name, item.Entry, *item.ItemLevel)
fmt.Print(ItemToSql(item, *baselevel, *difficulty))
// fmt.Printf("\n-- Item %v Entry: %v ItemLevel %v \n", item.Name, item.Entry, *item.ItemLevel)
// fmt.Print(ItemToSql(item, *baselevel, *difficulty))
}
log.Printf("++++++++++ AdditionalLoot Count: %v\n", len(items2))
}
// }
// log.Printf("++++++++++ Additional Count: %v\n", len(items2))
// }
defer models.DB.Close()
// defer models.DB.Close()
}

View File

@@ -1,27 +0,0 @@
package models
import (
"os"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
type Database struct {
client *sqlx.DB
}
var DB Database
func Connect() {
var connString string = os.Getenv("DB_USER") + ":" + os.Getenv("DB_PASSWORD") + "@tcp(" + os.Getenv("DB_HOST") + ")/" + os.Getenv("DB_NAME")
var err error
DB.client, err = sqlx.Open("mysql", connString)
if err != nil {
panic(err.Error())
}
}
func (db Database) Close() {
db.client.Close()
}

BIN
scripts/localdb/items.db Normal file

Binary file not shown.

View File

@@ -0,0 +1,103 @@
// 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))
// }

7
spells-list.txt Normal file
View File

@@ -0,0 +1,7 @@
19451 - Frenzy - fast attack / damage (major)
25516 - Aura of Command - regen, attack speed, dmg (minor)
14538 - Aural Shock (reduce casting speed by 35%) (major)
Grievous Bite
67719 Frost Fever = deals frost damage and reduces attack speed
Aura of Anger - Shadow damage over time

View File

@@ -1,61 +0,0 @@
package utils
func GetItemFields(prefix string) string {
pre := ""
if prefix != "" {
pre = prefix + "."
}
return `
` + pre + `entry, ` + pre + `name, ` + pre + `displayid,
quality, ItemLevel, class, subclass, inventoryType,
allowableClass, allowableRace,
armor,material,
requiredSkill, requiredLevel,
dmg_min1, dmg_max1,
dmg_min2,dmg_max2,
dmg_type1, dmg_type2,
delay, sheath, MaxDurability,
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,
spellid_1, spellid_2, spellid_3,
spelltrigger_1, spelltrigger_2, spelltrigger_3`
}
func GetSpellFields() string {
return `
ID,
Name_Lang_enUS,
Description_Lang_enUS,
AuraDescription_Lang_enUS,
ProcChance,
SpellLevel,
Effect_1,
Effect_2,
Effect_3,
EffectDieSides_1,
EffectDieSides_2,
EffectDieSides_3,
EffectRealPointsPerLevel_1,
EffectRealPointsPerLevel_2,
EffectRealPointsPerLevel_3,
EffectBasePoints_1,
EffectBasePoints_2,
EffectBasePoints_3,
EffectAura_1,
EffectAura_2,
EffectAura_3,
EffectBonusMultiplier_1,
EffectBonusMultiplier_2,
EffectBonusMultiplier_3
`
}