mirror of
https://github.com/araxiaonline/wow-item-generator.git
synced 2026-06-13 03:02:22 -04:00
Added Maps and updated logging methods
This commit is contained in:
48
main.go
48
main.go
@@ -1,8 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/models"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
@@ -15,9 +18,18 @@ func main() {
|
||||
godotenv.Load()
|
||||
models.Connect()
|
||||
|
||||
debug := flag.Bool("debug", false, "Enable verbose logging inside generator")
|
||||
flag.Parse()
|
||||
|
||||
if *debug {
|
||||
log.SetOutput(os.Stdout)
|
||||
} else {
|
||||
log.SetOutput(io.Discard)
|
||||
}
|
||||
|
||||
bosses, err := models.DB.GetBosses(229)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatal("failed to get bosses")
|
||||
}
|
||||
|
||||
for _, boss := range bosses {
|
||||
@@ -30,30 +42,7 @@ func main() {
|
||||
|
||||
for _, item := range items {
|
||||
|
||||
fmt.Printf("\nItem %v Entry: %v ItemLevel %v \n", item.Name, item.Entry, *item.ItemLevel)
|
||||
// item.GetStatPercents()
|
||||
|
||||
// if *item.SpellId1 != 0 {
|
||||
// spell, err := models.DB.GetSpell(*item.SpellId1)
|
||||
// if err != nil {
|
||||
// log.Printf("failed to get the spell: %v error: %v", *item.SpellId1, err)
|
||||
// }
|
||||
|
||||
// log.Printf("Spell %v Spell Effects 1: %v 2: %v, 3: %v \n", spell.Name, spell.Effect1, spell.Effect2, spell.Effect3)
|
||||
// log.Printf("Spell Aura 1: %v 2: %v, 3: %v \n", spell.EffectAura1, spell.EffectAura2, spell.EffectAura3)
|
||||
|
||||
// convStats, err := spell.ConvertToStats()
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to convert spell to stats: %v", err)
|
||||
// }
|
||||
|
||||
// scaleItemStats := item.GetStatPercents(convStats)
|
||||
// for statId, stat := range scaleItemStats {
|
||||
// log.Printf("StatId: %v Type: %s Value: %v Percent: %v", statId, stat.Type, stat.Value, stat.Percent)
|
||||
// }
|
||||
// log.Printf("Scaled Spell Stats: %v\n", convStats)
|
||||
|
||||
// }
|
||||
log.Printf("\nItem %v Entry: %v ItemLevel %v \n", item.Name, item.Entry, *item.ItemLevel)
|
||||
|
||||
_, error := item.ScaleItem(320, 3)
|
||||
fmt.Print(ItemToSql(item, 80, 3))
|
||||
@@ -65,18 +54,9 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// fmt.Println(stat, value)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// iLevel := 219
|
||||
// qual := 3
|
||||
// delay := 2.60
|
||||
// sub := 0
|
||||
// myItem := models.Item{Name: "Hypnotic Blade", ItemLevel: &iLevel, Quality: &qual, Delay: &delay, Subclass: &sub}
|
||||
// dps, err := myItem.ScaleDPS()
|
||||
|
||||
// log.Printf("Item %s DPS: %.1f", myItem.Name, dps)
|
||||
defer models.DB.Close()
|
||||
}
|
||||
|
||||
179
models/items.go
179
models/items.go
@@ -71,6 +71,14 @@ type Item struct {
|
||||
Spells []Spell
|
||||
}
|
||||
|
||||
// Use for storing item stats for all stats that will be scaled.
|
||||
type ItemStat struct {
|
||||
Value int
|
||||
Percent float64
|
||||
Type string
|
||||
AdjValue float64
|
||||
}
|
||||
|
||||
var InvTypeModifiers = map[int]float64{
|
||||
1: 0.813, // Head
|
||||
2: 1.0, // Neck
|
||||
@@ -163,13 +171,6 @@ var StatModifiers = map[int]float64{
|
||||
48: 0.65, // ITEM_MOD_BLOCK_VALUE
|
||||
}
|
||||
|
||||
type ItemStat struct {
|
||||
Value int
|
||||
Percent float64
|
||||
Type string
|
||||
AdjValue float64
|
||||
}
|
||||
|
||||
func (item Item) GetPrimaryStat() (int, int, error) {
|
||||
var primaryStat int64
|
||||
var primaryVal int64
|
||||
@@ -488,7 +489,7 @@ func (item *Item) ScaleItem(itemLevel int, itemQuality int) (bool, error) {
|
||||
log.Printf("DPS: %.1f scaled up from previous dps %v", dps, predps)
|
||||
}
|
||||
|
||||
item.CleanSpells()
|
||||
item.cleanSpells()
|
||||
|
||||
// Item is scaled now we have to determine if there are additional spell effects that need scaled.
|
||||
// this will be as simple as possible as the effects will just be a percentage of the item stats.
|
||||
@@ -515,87 +516,6 @@ func (item *Item) ScaleItem(itemLevel int, itemQuality int) (bool, error) {
|
||||
|
||||
}
|
||||
|
||||
func (item *Item) emptyStats() {
|
||||
*item.StatType1 = 0
|
||||
*item.StatValue1 = 0
|
||||
*item.StatType2 = 0
|
||||
*item.StatValue2 = 0
|
||||
*item.StatType3 = 0
|
||||
*item.StatValue3 = 0
|
||||
*item.StatType4 = 0
|
||||
*item.StatValue4 = 0
|
||||
*item.StatType5 = 0
|
||||
*item.StatValue5 = 0
|
||||
*item.StatType6 = 0
|
||||
*item.StatValue6 = 0
|
||||
*item.StatType7 = 0
|
||||
*item.StatValue7 = 0
|
||||
*item.StatType8 = 0
|
||||
*item.StatValue8 = 0
|
||||
*item.StatType9 = 0
|
||||
*item.StatValue9 = 0
|
||||
*item.StatType10 = 0
|
||||
*item.StatValue10 = 0
|
||||
}
|
||||
|
||||
func (item *Item) addStats(stats map[int]*ItemStat) {
|
||||
item.emptyStats()
|
||||
i := 1
|
||||
|
||||
// itemValue := reflect.ValueOf(item).Elem() // Get value of underlying struct
|
||||
|
||||
for statId, stat := range stats {
|
||||
if i > 10 {
|
||||
break
|
||||
}
|
||||
|
||||
statTypeField := fmt.Sprintf("StatType%d", i)
|
||||
statValueField := fmt.Sprintf("StatValue%d", i)
|
||||
|
||||
// Update the item with new stats from scaling
|
||||
item.UpdateField(statTypeField, statId)
|
||||
item.UpdateField(statValueField, stat.Value)
|
||||
|
||||
// Get the stats for logging purposes
|
||||
// tmpType, _ := item.GetField(statTypeField)
|
||||
// tmpStat, _ := item.GetField(statValueField)
|
||||
// log.Printf("Updated %s to %v, %s to %v", statTypeField, tmpType, statValueField, tmpStat)
|
||||
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Cleans up spells from the item that have been converted to stats and leaves only the ones that are not
|
||||
func (item *Item) CleanSpells() {
|
||||
spells, err := item.GetSpells()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get spells for item: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(spells) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 1; i < 4; i++ {
|
||||
for _, spell := range spells {
|
||||
currentId, err := item.GetField(fmt.Sprintf("SpellId%v", i))
|
||||
if err != nil {
|
||||
log.Printf("ERROR: Failed to get spell id %v err: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if currentId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if currentId == spell.ID {
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", i), 0)
|
||||
log.Printf("Removed spell %v from spellSlot: %v", spell.Name, fmt.Sprintf("SpellId%v", i))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (item *Item) GetField(fieldName string) (int, error) {
|
||||
itemValue := reflect.ValueOf(item).Elem()
|
||||
field := itemValue.FieldByName(fieldName)
|
||||
@@ -633,6 +553,87 @@ func (item *Item) UpdateField(fieldName string, value int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (item *Item) emptyStats() {
|
||||
*item.StatType1 = 0
|
||||
*item.StatValue1 = 0
|
||||
*item.StatType2 = 0
|
||||
*item.StatValue2 = 0
|
||||
*item.StatType3 = 0
|
||||
*item.StatValue3 = 0
|
||||
*item.StatType4 = 0
|
||||
*item.StatValue4 = 0
|
||||
*item.StatType5 = 0
|
||||
*item.StatValue5 = 0
|
||||
*item.StatType6 = 0
|
||||
*item.StatValue6 = 0
|
||||
*item.StatType7 = 0
|
||||
*item.StatValue7 = 0
|
||||
*item.StatType8 = 0
|
||||
*item.StatValue8 = 0
|
||||
*item.StatType9 = 0
|
||||
*item.StatValue9 = 0
|
||||
*item.StatType10 = 0
|
||||
*item.StatValue10 = 0
|
||||
}
|
||||
|
||||
// Cleans up spells from the item that have been converted to stats and leaves only the ones that are not
|
||||
func (item *Item) cleanSpells() {
|
||||
spells, err := item.GetSpells()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get spells for item: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(spells) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 1; i < 4; i++ {
|
||||
for _, spell := range spells {
|
||||
currentId, err := item.GetField(fmt.Sprintf("SpellId%v", i))
|
||||
if err != nil {
|
||||
log.Printf("ERROR: Failed to get spell id %v err: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if currentId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if currentId == spell.ID {
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", i), 0)
|
||||
log.Printf("Removed spell %v from spellSlot: %v", spell.Name, fmt.Sprintf("SpellId%v", i))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (item *Item) addStats(stats map[int]*ItemStat) {
|
||||
item.emptyStats()
|
||||
i := 1
|
||||
|
||||
// itemValue := reflect.ValueOf(item).Elem() // Get value of underlying struct
|
||||
|
||||
for statId, stat := range stats {
|
||||
if i > 10 {
|
||||
break
|
||||
}
|
||||
|
||||
statTypeField := fmt.Sprintf("StatType%d", i)
|
||||
statValueField := fmt.Sprintf("StatValue%d", i)
|
||||
|
||||
// Update the item with new stats from scaling
|
||||
item.UpdateField(statTypeField, statId)
|
||||
item.UpdateField(statValueField, stat.Value)
|
||||
|
||||
// Get the stats for logging purposes
|
||||
// tmpType, _ := item.GetField(statTypeField)
|
||||
// tmpStat, _ := item.GetField(statValueField)
|
||||
// log.Printf("Updated %s to %v, %s to %v", statTypeField, tmpType, statValueField, tmpStat)
|
||||
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// 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)*QualityModifiers[itemQuality]*InvTypeModifiers[itemType]), 1.7095) * percOfStat
|
||||
|
||||
94
models/maps.go
Normal file
94
models/maps.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package models
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Dungeon struct {
|
||||
Id int `db:"Id"`
|
||||
Name string `db:"Name"`
|
||||
Level int
|
||||
ExpansionId int `db:"ExpansionId"`
|
||||
}
|
||||
|
||||
var dungeons = map[int]int{
|
||||
// Classic WoW dungeons
|
||||
389: 18, // Ragefire Chasm
|
||||
43: 25, // Wailing Caverns
|
||||
36: 23, // The Deadmines
|
||||
33: 30, // Shadowfang Keep
|
||||
34: 30, // The Stockade
|
||||
48: 32, // Blackfathom Deeps
|
||||
90: 38, // Gnomeregan
|
||||
47: 40, // Razorfen Kraul
|
||||
189: 45, // Scarlet Monastery (Graveyard)
|
||||
289: 60, // Scholomance
|
||||
329: 60, // Stratholme
|
||||
229: 60, // Blackrock Spire (Lower)
|
||||
230: 60, // Blackrock Spire (Upper)
|
||||
429: 60, // Dire Maul
|
||||
209: 54, // Zul'Farrak
|
||||
349: 55, // Maraudon
|
||||
269: 57, // Temple of Atal'Hakkar
|
||||
// The Burning Crusade dungeons
|
||||
540: 62, // Hellfire Citadel: Hellfire Ramparts
|
||||
542: 63, // Hellfire Citadel: The Blood Furnace
|
||||
547: 64, // Coilfang Reservoir: The Slave Pens
|
||||
546: 65, // Coilfang Reservoir: The Underbog
|
||||
557: 66, // Auchindoun: Mana-Tombs
|
||||
558: 67, // Auchindoun: Auchenai Crypts
|
||||
560: 68, // Caverns of Time: Old Hillsbrad Foothills
|
||||
556: 69, // Auchindoun: Sethekk Halls
|
||||
545: 70, // Coilfang Reservoir: The Steamvault
|
||||
555: 70, // Auchindoun: Shadow Labyrinth
|
||||
543: 70, // Hellfire Citadel: The Shattered Halls
|
||||
553: 70, // Tempest Keep: The Botanica
|
||||
554: 70, // Tempest Keep: The Mechanar
|
||||
552: 70, // Tempest Keep: The Arcatraz
|
||||
585: 70, // Magisters' Terrace
|
||||
// Wrath of the Lich King dungeons
|
||||
70: 72, // Utgarde Keep
|
||||
129: 74, // Azjol-Nerub
|
||||
619: 75, // Ahn'kahet: The Old Kingdom
|
||||
576: 73, // The Nexus
|
||||
600: 76, // Drak'Tharon Keep
|
||||
608: 77, // The Violet Hold
|
||||
604: 78, // Gundrak
|
||||
599: 79, // Halls of Stone
|
||||
602: 80, // Halls of Lightning
|
||||
578: 79, // The Oculus
|
||||
575: 80, // Utgarde Pinnacle
|
||||
595: 80, // The Culling of Stratholme
|
||||
650: 80, // Trial of the Champion
|
||||
632: 80, // The Forge of Souls
|
||||
658: 80, // Pit of Saron
|
||||
668: 80, // Halls of Reflection
|
||||
}
|
||||
|
||||
func (db Database) GetDungeons(expansionId int) ([]Dungeon, error) {
|
||||
dungeons := []Dungeon{}
|
||||
|
||||
sql := `
|
||||
SELECT ID as Id, MapName_Lang_enUS as Name, ExpansionID as ExpansionId
|
||||
FROM map_dbc
|
||||
WHERE InstanceType = 1 AND Name NOT LIKE '%unused%';
|
||||
`
|
||||
var err error
|
||||
if expansionId != -1 {
|
||||
sql = sql + "AND ExpansionID = ?"
|
||||
err = db.client.Select(&dungeons, sql, expansionId)
|
||||
} else {
|
||||
err = db.client.Select(&dungeons, sql)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get dungeons %v", err)
|
||||
}
|
||||
|
||||
return dungeons, nil
|
||||
}
|
||||
|
||||
func addLevels(dungeons []Dungeon) {
|
||||
for _, dungeon := range dungeons {
|
||||
|
||||
dungeon.Level = 60
|
||||
}
|
||||
}
|
||||
@@ -388,13 +388,14 @@ func parseStatDesc(desc string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Scales a spell effect
|
||||
// Scales a spell effect, means creating a new spell with the same effect but scaled to a new item level, then passing
|
||||
// back the new spellId, In order to be predictable I will use 30000000 for rare, 31000000 for epic, 32000000 for legendary
|
||||
// An example of this might on hit do $s1 nature damage over $d seconds. We would just scale the $s1 value
|
||||
// based on the formula below. This assumes that Blizzard has already balanced the spell bonus against the
|
||||
// stats on the item level and quality. This is a big assumption as the stats are not penalized
|
||||
// from having the extra damage. This could really create some unique sought after weapons that exploit this.
|
||||
// modified ratio ((s1 / existing iLevel) * newIlevel) * (0.20 Rare or 0.30 Epic or 0.4 for Legendary).
|
||||
func (s *Spell) ScaleSpell(itemLevel int, itemQuality int) error {
|
||||
func (s *Spell) ScaleSpell(itemLevel int, itemQuality int) (int, error) {
|
||||
|
||||
qualModifier := map[int]float64{
|
||||
3: 0.20,
|
||||
@@ -402,15 +403,26 @@ func (s *Spell) ScaleSpell(itemLevel int, itemQuality int) error {
|
||||
5: 0.40,
|
||||
}
|
||||
|
||||
idBump := 30000000
|
||||
if itemQuality == 4 {
|
||||
idBump = 31000000
|
||||
}
|
||||
if itemQuality == 5 {
|
||||
idBump = 32000000
|
||||
}
|
||||
|
||||
// direct damage types
|
||||
dd := [...]int{2, 9, 10}
|
||||
|
||||
didScale := false
|
||||
// Causes direct damage
|
||||
if s.Effect1 != 0 && funk.Contains(dd, s.Effect1) {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(s.SpellLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
if s.Effect2 != 0 && funk.Contains(dd, s.Effect1) {
|
||||
s.EffectBasePoints2 = int(float64(s.EffectBasePoints2) / float64(s.SpellLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Restores a Power / Mana
|
||||
@@ -418,26 +430,34 @@ func (s *Spell) ScaleSpell(itemLevel int, itemQuality int) error {
|
||||
// skip anyhing else that is not mana as they are flat values
|
||||
if strings.Contains(s.Description, "Mana") {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(s.SpellLevel) * float64(itemLevel) * qualModifier[itemQuality] * 0.75)
|
||||
didScale = true
|
||||
}
|
||||
}
|
||||
|
||||
// Scales a stat buff
|
||||
if s.Effect1 != 0 && s.Effect1 == 35 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(s.SpellLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
if s.Effect1 != 0 && s.Effect2 == 35 {
|
||||
s.EffectBasePoints2 = int(float64(s.EffectBasePoints2) / float64(s.SpellLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Handle special aura effects
|
||||
if s.EffectAura1 != 0 && s.EffectAura1 == 3 && s.Effect1 == 6 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(s.SpellLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Damage Shield Increase Scale due to HP curve
|
||||
if s.EffectAura1 != 0 && s.EffectAura1 == 15 && s.Effect1 == 6 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(s.SpellLevel) * float64(itemLevel) * qualModifier[itemQuality] * 1.50)
|
||||
didScale = true
|
||||
}
|
||||
|
||||
return nil
|
||||
if !didScale {
|
||||
return 0, fmt.Errorf("did not qualify to be scaled in ScaleSpell %v (%v)", s.Name, s.ID)
|
||||
}
|
||||
return idBump + s.ID, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user