Added changes to reduce scaling of molten core

This commit is contained in:
2025-09-07 22:54:57 -04:00
parent 8b5effaed7
commit 74b2f9d37c
5 changed files with 701 additions and 762 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,29 @@
package config package config
// modifiers to stats based on inventory type
var InvTypeModifiers = map[int]float64{ var InvTypeModifiers = map[int]float64{
0: 0.6, // Trinket 0: 0.6, // Trinket
1: 0.813, // Head 1: 0.813, // Head
2: 1.0, // Neck 2: 1.0, // Neck
3: 0.75, // Shoulder 3: 0.75, // Shoulder
5: 1.0, // Chest 5: 0.95, // Chest
6: 0.562, // Waist 6: 0.562, // Waist
7: 0.875, // Legs 7: 0.875, // Legs
8: 0.688, // Feet 8: 0.688, // Feet
9: 0.437, // Wrists 9: 0.437, // Wrists
10: 0.625, // Hands 10: 0.625, // Hands
11: 1.0, // Finger 11: 1.0, // Finger
13: 0.62, // One-Hand (not to confuse with Off-Hand = 22) 13: 0.70, // One-Hand (not to confuse with Off-Hand = 22)
14: 0.66, // Shield (class = armor, not weapon even if in weapon slot) 14: 0.66, // Shield (class = armor, not weapon even if in weapon slot)
15: 0.32, // Ranged (Bows) (see also Ranged right = 26) 15: 0.32, // Ranged (Bows) (see also Ranged right = 26)
16: 0.66, // Back 16: 0.70, // Back
17: 1.0, // Two-Hand 17: 1.3, // Two-Hand
18: 1.0, // Bag (assuming same as Chest for simplicity) 18: 1.0, // Bag (assuming same as Chest for simplicity)
19: 1.0, // Tabard (assuming same as Chest for simplicity) 19: 1.0, // Tabard (assuming same as Chest for simplicity)
20: 1.0, // Robe (see also Chest = 5) 20: 1.0, // Robe (see also Chest = 5)
21: 0.80, // Main hand 21: 0.85, // Main hand
22: 0.60, // Off Hand weapons (see also One-Hand = 13) 22: 0.65, // Off Hand weapons (see also One-Hand = 13)
23: 0.56, // Held in Off-Hand (class = armor, not weapon even if in weapon slot) 23: 0.60, // Held in Off-Hand (class = armor, not weapon even if in weapon slot)
24: 1.0, // Ammo (assuming same as Chest for simplicity) 24: 1.0, // Ammo (assuming same as Chest for simplicity)
25: 0.38, // Thrown 25: 0.38, // Thrown
26: 0.38, // Ranged right (Wands, Guns) (see also Ranged = 15) 26: 0.38, // Ranged right (Wands, Guns) (see also Ranged = 15)
@@ -48,13 +49,14 @@ var MaterialModifiers = map[int]float64{
// Modifies stats flat for difficulty of dungeon / raid itself. // Modifies stats flat for difficulty of dungeon / raid itself.
var GearTierModifiers = map[int]float64{ var GearTierModifiers = map[int]float64{
1: 1.05, 1: 1.25,
2: 1.10, 2: 1.50,
3: 1.15, 3: 1.75,
4: 1.20, 4: 2.00,
5: 1.25, 5: 2.25,
} }
// how much a stat weighs against the stat point pool based on iLevel
var StatModifiers = map[int]float64{ var StatModifiers = map[int]float64{
0: 1.0, // ITEM_MOD_MANA 0: 1.0, // ITEM_MOD_MANA
1: 1.0, // ITEM_MOD_HEALTH 1: 1.0, // ITEM_MOD_HEALTH
@@ -82,23 +84,23 @@ var StatModifiers = map[int]float64{
28: 1.0, // ITEM_MOD_HASTE_MELEE_RATING 28: 1.0, // ITEM_MOD_HASTE_MELEE_RATING
29: 1.0, // ITEM_MOD_HASTE_RANGED_RATING 29: 1.0, // ITEM_MOD_HASTE_RANGED_RATING
30: 1.0, // ITEM_MOD_HASTE_SPELL_RATING 30: 1.0, // ITEM_MOD_HASTE_SPELL_RATING
31: 2.5, // ITEM_MOD_HIT_RATING 31: 1.3, // ITEM_MOD_HIT_RATING
32: 1.0, // ITEM_MOD_CRIT_RATING 32: 1.0, // ITEM_MOD_CRIT_RATING
33: 1.0, // ITEM_MOD_HIT_TAKEN_RATING 33: 1.0, // ITEM_MOD_HIT_TAKEN_RATING
34: 1.0, // ITEM_MOD_CRIT_TAKEN_RATING 34: 1.0, // ITEM_MOD_CRIT_TAKEN_RATING
35: 1.0, // ITEM_MOD_RESILIENCE_RATING 35: 1.0, // ITEM_MOD_RESILIENCE_RATING
36: 1.0, // ITEM_MOD_HASTE_RATING 36: 1.0, // ITEM_MOD_HASTE_RATING
37: 1.0, // ITEM_MOD_EXPERTISE_RATING 37: 1.5, // ITEM_MOD_EXPERTISE_RATING
38: 0.65, // ITEM_MOD_ATTACK_POWER 38: 0.65, // ITEM_MOD_ATTACK_POWER
39: 0.65, // ITEM_MOD_RANGED_ATTACK_POWER 39: 0.70, // ITEM_MOD_RANGED_ATTACK_POWER
40: 0.65, // ITEM_MOD_FERAL_ATTACK_POWER (not used as of 3.3) 40: 0.95, // ITEM_MOD_FERAL_ATTACK_POWER (not used as of 3.3)
41: 0.65, // ITEM_MOD_SPELL_HEALING_DONE 41: 0.95, // ITEM_MOD_SPELL_HEALING_DONE
42: 0.65, // ITEM_MOD_SPELL_DAMAGE_DONE 42: 0.95, // ITEM_MOD_SPELL_DAMAGE_DONE
43: 2.5, // ITEM_MOD_MANA_REGENERATION 43: 2.0, // ITEM_MOD_MANA_REGENERATION
44: 1.0, // ITEM_MOD_ARMOR_PENETRATION_RATING 44: 1.3, // ITEM_MOD_ARMOR_PENETRATION_RATING
45: 0.65, // ITEM_MOD_SPELL_POWER 45: 0.95, // ITEM_MOD_SPELL_POWER
46: 1.0, // ITEM_MOD_HEALTH_REGEN 46: 1.0, // ITEM_MOD_HEALTH_REGEN
47: 1.8, // ITEM_MOD_SPELL_PENETRATION 47: 1.2, // ITEM_MOD_SPELL_PENETRATION
48: 1.5, // ITEM_MOD_BLOCK_VALUE 48: 1.5, // ITEM_MOD_BLOCK_VALUE
} }
@@ -149,6 +151,7 @@ var StatModifierNames = map[int]string{
48: "BLOCK_VALUE", 48: "BLOCK_VALUE",
} }
// how much a bonus to apply
var ScalingFactor = map[int]float64{ var ScalingFactor = map[int]float64{
0: 1.1, // ITEM_MOD_MANA 0: 1.1, // ITEM_MOD_MANA
1: 1.2, // ITEM_MOD_HEALTH 1: 1.2, // ITEM_MOD_HEALTH
@@ -157,7 +160,7 @@ var ScalingFactor = map[int]float64{
5: 1.35, // ITEM_MOD_INTELLECT 5: 1.35, // ITEM_MOD_INTELLECT
6: 1.35, // ITEM_MOD_SPIRIT 6: 1.35, // ITEM_MOD_SPIRIT
7: 1.40, // ITEM_MOD_STAMINA 7: 1.40, // ITEM_MOD_STAMINA
12: 1.1, // ITEM_MOD_DEFENSE_SKILL_RATING 12: 1.25, // ITEM_MOD_DEFENSE_SKILL_RATING
13: 1.0, // ITEM_MOD_DODGE_RATING 13: 1.0, // ITEM_MOD_DODGE_RATING
14: 0.85, // ITEM_MOD_PARRY_RATING 14: 0.85, // ITEM_MOD_PARRY_RATING
15: 1.15, // ITEM_MOD_BLOCK_RATING 15: 1.15, // ITEM_MOD_BLOCK_RATING
@@ -191,7 +194,7 @@ var ScalingFactor = map[int]float64{
43: 1.0, // ITEM_MOD_MANA_REGENERATION 43: 1.0, // ITEM_MOD_MANA_REGENERATION
44: 1.1, // ITEM_MOD_ARMOR_PENETRATION_RATING 44: 1.1, // ITEM_MOD_ARMOR_PENETRATION_RATING
45: 1.0, // ITEM_MOD_SPELL_POWER 45: 1.0, // ITEM_MOD_SPELL_POWER
46: 1.3, // ITEM_MOD_HEALTH_REGEN 46: 1.0, // ITEM_MOD_HEALTH_REGEN
47: 1.0, // ITEM_MOD_SPELL_PENETRATION 47: 1.0, // ITEM_MOD_SPELL_PENETRATION
48: 1.2, // ITEM_MOD_BLOCK_VALUE 48: 1.2, // ITEM_MOD_BLOCK_VALUE
} }

View File

@@ -260,27 +260,44 @@ func (db *MySqlDb) GetRaidPhase1Items(class, subclass, limit, offset int) ([]DbI
items := []DbItem{} items := []DbItem{}
sql := `SELECT DISTINCT ` + GetItemFields("it") + ` sql := `SELECT DISTINCT ` + GetItemFields("it") + `
FROM acore_world.creature c FROM acore_world.creature c
JOIN acore_world.creature_template ct ON c.id1 = ct.entry JOIN acore_world.creature_template ct ON c.id1 = ct.entry
JOIN acore_world.map_dbc m ON c.map = m.ID JOIN acore_world.map_dbc m ON c.map = m.ID
LEFT JOIN acore_world.creature_loot_template clt ON ct.lootid = clt.Entry JOIN acore_world.creature_loot_template clt ON ct.lootid = clt.Entry
LEFT JOIN acore_world.reference_loot_template rlt ON clt.Reference = rlt.Entry JOIN acore_world.item_template it ON clt.Item = it.entry
LEFT JOIN acore_world.item_template it ON rlt.Item = it.entry
WHERE WHERE
m.ID IN (533,615,616) m.ID IN (533,615,616)
AND ct.rank = 3 AND ct.rank = 3
AND it.class = ? -- Weapons and armor AND it.class = ?
AND it.subclass = ? AND it.subclass = ?
AND it.bonding IN (1, 2) -- Binds when picked up/equipped AND it.bonding IN (1, 2) -- Binds when picked up/equipped
AND it.Quality >= 3 -- Epic and above AND it.Quality >= 4 -- Epic and above
UNION ALL
-- Get loot from reference_loot_template (reference items)
SELECT DISTINCT ` + GetItemFields("it") + `
FROM acore_world.creature c
JOIN acore_world.creature_template ct ON c.id1 = ct.entry
JOIN acore_world.map_dbc m ON c.map = m.ID
JOIN acore_world.creature_loot_template clt ON ct.lootid = clt.Entry
JOIN acore_world.reference_loot_template rlt ON clt.Reference = rlt.Entry
JOIN acore_world.item_template it ON rlt.Item = it.entry
WHERE
m.ID IN (533,615,616)
AND ct.rank = 3
AND it.class = ?
AND it.subclass = ?
AND it.bonding IN (1, 2) -- Binds when picked up/equipped
AND it.Quality >= 4 -- Epic and above
` `
if limit != 0 && offset != 0 { if limit != 0 && offset != 0 {
sql += fmt.Sprintf("LIMIT %v OFFSET %v", limit, offset) sql += fmt.Sprintf("LIMIT %v OFFSET %v", limit, offset)
} }
err := db.Select(&items, sql, class, subclass) err := db.Select(&items, sql, class, subclass, class, subclass)
if err != nil { if err != nil {
return []DbItem{}, err return []DbItem{}, err
} }

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"log" "log"
"math" "math"
"math/rand/v2" "math/rand"
"reflect" "reflect"
"slices" "slices"
"strings" "strings"
@@ -16,6 +16,17 @@ import (
"github.com/araxiaonline/endgame-item-generator/internal/spells" "github.com/araxiaonline/endgame-item-generator/internal/spells"
) )
// Class User Type constants for GetClassUserType()
const (
CLASS_USER_TYPE_MELEE_STRENGTH_ATTACKER = 1 // Melee Strength Attacker
CLASS_USER_TYPE_MELEE_AGILITY_ATTACKER = 2 // Melee Agility Attacker
CLASS_USER_TYPE_RANGED_ATTACKER = 3 // Ranged Attacker
CLASS_USER_TYPE_MAGE = 4 // Mage
CLASS_USER_TYPE_HEALER = 5 // Healer
CLASS_USER_TYPE_TANK = 6 // Tank
CLASS_USER_TYPE_GENERIC = 7 // Generic (Could not determine)
)
/** /**
* For details about values of item int values use link below * For details about values of item int values use link below
* @link https://www.azerothcore.org/wiki/item_template * @link https://www.azerothcore.org/wiki/item_template
@@ -770,6 +781,15 @@ func (item *Item) ScaleItem(itemLevel int, itemQuality int) (bool, error) {
log.Printf("\n\n\n -------------------- COUNT OF other spells %v \n\n", len(otherSpells)) log.Printf("\n\n\n -------------------- COUNT OF other spells %v \n\n", len(otherSpells))
// Define spellBump based on item quality for spell ID generation
spellBump := 30000000
if *item.Quality == 4 {
spellBump = 31000000
}
if *item.Quality == 5 {
spellBump = 32000000
}
item.Spells = []spells.Spell{} item.Spells = []spells.Spell{}
// Spells that can not be scaled into stats must get new spells scaled and created // Spells that can not be scaled into stats must get new spells scaled and created
for _, spell := range otherSpells { for _, spell := range otherSpells {
@@ -795,7 +815,7 @@ func (item *Item) ScaleItem(itemLevel int, itemQuality int) (bool, error) {
} }
// ForceScaleSpell modifies the spell in place, so we use the original spell ID // ForceScaleSpell modifies the spell in place, so we use the original spell ID
item.UpdateField(fmt.Sprintf("SpellId%v", spell.ItemSpellSlot), spell.ID) item.UpdateField(fmt.Sprintf("SpellId%v", spell.ItemSpellSlot), spellBump+spell.ID)
item.Spells = append(item.Spells, spell) item.Spells = append(item.Spells, spell)
// do one last check on all setting StatsCount based on how many stats have been set // do one last check on all setting StatsCount based on how many stats have been set
@@ -1047,21 +1067,21 @@ func (item *Item) GetClassUserType() int {
// Tanking weapons will have defensive stats on them // Tanking weapons will have defensive stats on them
if statTypePtr == STAT.ParryRating || statTypePtr == STAT.DefenseSkillRating || statTypePtr == STAT.BlockRating || statTypePtr == STAT.BlockValue { if statTypePtr == STAT.ParryRating || statTypePtr == STAT.DefenseSkillRating || statTypePtr == STAT.BlockRating || statTypePtr == STAT.BlockValue {
return 6 return CLASS_USER_TYPE_TANK
} }
// Check for a healer stats like MP5 and Spell Healing Done // Check for a healer stats like MP5 and Spell Healing Done
if statTypePtr == STAT.ManaRegeneration || statTypePtr == STAT.SpellHealingDone { if statTypePtr == STAT.ManaRegeneration || statTypePtr == STAT.SpellHealingDone {
return 5 return CLASS_USER_TYPE_HEALER
} }
// Check for a Mage stat if they have spell penetration we know it is a mage // Check for a Mage stat if they have spell penetration we know it is a mage
if statTypePtr == STAT.SpellPenetration { if statTypePtr == STAT.SpellPenetration {
return 4 return CLASS_USER_TYPE_MAGE
} }
if statTypePtr == STAT.RangedAttackPower || statTypePtr == STAT.CritRangedRating || statTypePtr == STAT.HitRangedRating { if statTypePtr == STAT.RangedAttackPower || statTypePtr == STAT.CritRangedRating || statTypePtr == STAT.HitRangedRating {
return 3 return CLASS_USER_TYPE_RANGED_ATTACKER
} }
} }
@@ -1069,12 +1089,19 @@ func (item *Item) GetClassUserType() int {
if *item.Class == 4 { if *item.Class == 4 {
// if the item is cloth its a mage and did not have healer stats just treat as a mage item // if the item is cloth its a mage and did not have healer stats just treat as a mage item
if *item.Subclass == 1 && *item.InventoryType != 16 { if *item.Subclass == 1 && *item.InventoryType != 16 {
return 4 return CLASS_USER_TYPE_MAGE
} }
// If it is plate and not a tank then it is a strength melee attack // If it is plate and not a tank then it is a strength melee attack
if *item.Subclass == 4 { if *item.Subclass == 4 {
return 1 for i := 1; i <= 7; i++ {
statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.SpellPower || statTypePtr == STAT.CritSpellRating ||
statTypePtr == STAT.HitSpellRating || (statTypePtr == STAT.Intellect && statTypePtr == STAT.Spirit) {
return CLASS_USER_TYPE_MAGE
}
}
} }
// If it is mail/leather armor then it is limited to Mage, Agility Fighter // If it is mail/leather armor then it is limited to Mage, Agility Fighter
@@ -1084,12 +1111,12 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.SpellPower || statTypePtr == STAT.CritSpellRating || if statTypePtr == STAT.SpellPower || statTypePtr == STAT.CritSpellRating ||
statTypePtr == STAT.HitSpellRating || statTypePtr == STAT.Intellect || statTypePtr == STAT.Spirit { statTypePtr == STAT.HitSpellRating {
return 4 return CLASS_USER_TYPE_MAGE
} }
} }
return 2 return CLASS_USER_TYPE_MELEE_AGILITY_ATTACKER
} }
} }
@@ -1097,11 +1124,11 @@ func (item *Item) GetClassUserType() int {
if *item.Class == 2 { if *item.Class == 2 {
// If it is a fist weapon or ranged throwing weapons its agility class type // If it is a fist weapon or ranged throwing weapons its agility class type
if *item.Subclass == 13 || *item.Subclass == 16 { if *item.Subclass == 13 || *item.Subclass == 16 {
return 2 return CLASS_USER_TYPE_MELEE_AGILITY_ATTACKER
} }
if *item.Subclass == 19 { if *item.Subclass == 19 {
return 4 return CLASS_USER_TYPE_MAGE
} }
// if it is a polearm or spear 17 or 6 and strength then its strength class type // if it is a polearm or spear 17 or 6 and strength then its strength class type
@@ -1110,12 +1137,12 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.Strength { if statTypePtr == STAT.Strength {
return 1 return CLASS_USER_TYPE_MELEE_STRENGTH_ATTACKER
} }
// or attack power // or attack power
if statTypePtr == STAT.AttackPower { if statTypePtr == STAT.AttackPower {
return 1 return CLASS_USER_TYPE_MELEE_STRENGTH_ATTACKER
} }
} }
@@ -1124,12 +1151,12 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.Agility { if statTypePtr == STAT.Agility {
return 2 return CLASS_USER_TYPE_MELEE_AGILITY_ATTACKER
} }
} }
// last assume it is a healer // last assume it is a healer
return 5 return CLASS_USER_TYPE_HEALER
} }
if *item.Subclass == 2 || *item.Subclass == 3 || *item.Subclass == 18 { if *item.Subclass == 2 || *item.Subclass == 3 || *item.Subclass == 18 {
@@ -1137,11 +1164,11 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.Strength { if statTypePtr == STAT.Strength {
return 1 return CLASS_USER_TYPE_MELEE_STRENGTH_ATTACKER
} }
} }
return 3 return CLASS_USER_TYPE_RANGED_ATTACKER
} }
} }
@@ -1151,7 +1178,7 @@ func (item *Item) GetClassUserType() int {
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
// fmt.Printf("itemName: %s StatType%d: %v \n", item.Name, i, statTypePtr) // fmt.Printf("itemName: %s StatType%d: %v \n", item.Name, i, statTypePtr)
if statTypePtr == STAT.Spirit { if statTypePtr == STAT.Spirit {
return 5 return CLASS_USER_TYPE_HEALER
} }
} }
@@ -1159,7 +1186,7 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.Intellect { if statTypePtr == STAT.Intellect {
return 4 return CLASS_USER_TYPE_MAGE
} }
} }
@@ -1167,7 +1194,7 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.Strength { if statTypePtr == STAT.Strength {
return 1 return CLASS_USER_TYPE_MELEE_STRENGTH_ATTACKER
} }
} }
@@ -1175,7 +1202,7 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.Agility { if statTypePtr == STAT.Agility {
return 2 return CLASS_USER_TYPE_MELEE_AGILITY_ATTACKER
} }
} }
@@ -1184,7 +1211,7 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.AttackPower || statTypePtr == STAT.HasteMeleeRating || statTypePtr == STAT.CritMeleeRating { if statTypePtr == STAT.AttackPower || statTypePtr == STAT.HasteMeleeRating || statTypePtr == STAT.CritMeleeRating {
return 2 return CLASS_USER_TYPE_MELEE_AGILITY_ATTACKER
} }
} }
@@ -1193,7 +1220,7 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.SpellPower || statTypePtr == STAT.CritSpellRating || statTypePtr == STAT.HitSpellRating { if statTypePtr == STAT.SpellPower || statTypePtr == STAT.CritSpellRating || statTypePtr == STAT.HitSpellRating {
return 4 return CLASS_USER_TYPE_MAGE
} }
} }
@@ -1202,24 +1229,90 @@ func (item *Item) GetClassUserType() int {
statTypeField := fmt.Sprintf("StatType%d", i) statTypeField := fmt.Sprintf("StatType%d", i)
statTypePtr, _ := item.GetField(statTypeField) statTypePtr, _ := item.GetField(statTypeField)
if statTypePtr == STAT.RangedAttackPower || statTypePtr == STAT.HasteRangedRating || statTypePtr == STAT.CritRangedRating { if statTypePtr == STAT.RangedAttackPower || statTypePtr == STAT.HasteRangedRating || statTypePtr == STAT.CritRangedRating {
return 3 return CLASS_USER_TYPE_RANGED_ATTACKER
} }
} }
// if we have made it here then the only thing left to do is base it purely on armor material type // if we have made it here then the only thing left to do is base it purely on armor material type
if *item.Class == 4 && *item.Subclass == 1 { if *item.Class == 4 && *item.Subclass == 1 {
return 4 return CLASS_USER_TYPE_MAGE
} }
if *item.Class == 4 && *item.Subclass == 4 { if *item.Class == 4 && *item.Subclass == 4 {
return 1 return CLASS_USER_TYPE_MELEE_STRENGTH_ATTACKER
} }
if *item.Class == 4 && (*item.Subclass == 2 || *item.Subclass == 3) { if *item.Class == 4 && (*item.Subclass == 2 || *item.Subclass == 3) {
return 2 return CLASS_USER_TYPE_MELEE_AGILITY_ATTACKER
} }
return 7 return CLASS_USER_TYPE_GENERIC
}
// AddElementalDamage adds elemental damage to weapons based on weapon type and scales it to item level
// damageType: 1=Holy, 2=Fire, 3=Nature, 4=Frost, 5=Shadow, 6=Arcane
func (item *Item) AddElementalDamage(damageType int) {
// Only apply to weapons (class 2)
if item.Class == nil || *item.Class != 2 {
return
}
// Initialize elemental damage fields if they don't exist
if item.MinDmg2 == nil {
minDmg := 0.0
maxDmg := 0.0
item.MinDmg2 = &minDmg
item.MaxDmg2 = &maxDmg
item.DmgType2 = &damageType
}
// Get base damage values based on weapon type
var baseMinDamage, baseMaxDamage float64
if item.InventoryType != nil && (*item.InventoryType == 13 || *item.InventoryType == 21 || *item.InventoryType == 22) {
// One-handed weapons (main hand, off hand, one-hand)
baseMinDamage = float64(10 + rand.Intn(11)) // 10-20 base
baseMaxDamage = float64(20 + rand.Intn(11)) // 20-30 base
} else {
// Two-handed weapons
baseMinDamage = float64(25 + rand.Intn(16)) // 25-40 base
baseMaxDamage = float64(40 + rand.Intn(21)) // 40-60 base
}
// Scale damage based on item level and quality
itemLevel := float64(60) // Default base level
if item.ItemLevel != nil {
itemLevel = float64(*item.ItemLevel)
}
quality := 2 // Default uncommon
if item.Quality != nil {
quality = *item.Quality
}
// Scale factor based on item level (scales from level 60 baseline)
levelScale := itemLevel / 60.0
if levelScale < 1.0 {
levelScale = 1.0 // Don't scale down below base
}
// Quality multiplier
qualityMultiplier := 1.0
switch quality {
case 3: // Rare
qualityMultiplier = 1.3
case 4: // Epic
qualityMultiplier = 1.6
case 5: // Legendary
qualityMultiplier = 2.0
}
// Apply scaling
scaledMinDamage := baseMinDamage * levelScale * qualityMultiplier
scaledMaxDamage := baseMaxDamage * levelScale * qualityMultiplier
item.MinDmg2 = &scaledMinDamage
item.MaxDmg2 = &scaledMaxDamage
item.DmgType2 = &damageType
} }
func (item *Item) ApplyTierModifiers(optionalTier ...int) { func (item *Item) ApplyTierModifiers(optionalTier ...int) {
@@ -1241,6 +1334,7 @@ func (item *Item) ApplyTierModifiers(optionalTier ...int) {
if tier > 0 && tier <= 5 { if tier > 0 && tier <= 5 {
if mod, ok := config.GearTierModifiers[tier]; ok { if mod, ok := config.GearTierModifiers[tier]; ok {
tierModifier = mod tierModifier = mod
fmt.Printf("DEBUG: Applying tier %d modifier %.2f to item %s\n", tier, tierModifier, item.Name)
} }
} }
@@ -1259,6 +1353,8 @@ func (item *Item) ApplyTierModifiers(optionalTier ...int) {
continue continue
} }
fmt.Printf("DEBUG: Processing stat %d: type=%d, value=%d\n", i, statTypePtr, statValuePtr)
// Get the stat modifier (inverse of the cost modifier) // Get the stat modifier (inverse of the cost modifier)
statModifier, ok := config.StatModifiers[statTypePtr] statModifier, ok := config.StatModifiers[statTypePtr]
if !ok { if !ok {
@@ -1274,6 +1370,9 @@ func (item *Item) ApplyTierModifiers(optionalTier ...int) {
// Apply tier modifier and stat modifier // Apply tier modifier and stat modifier
newValue := int(float64(statValuePtr) * tierModifier * inverseModifier * catchUpBonus) newValue := int(float64(statValuePtr) * tierModifier * inverseModifier * catchUpBonus)
fmt.Printf("DEBUG: Stat %d changed from %d to %d (tier=%.2f, inverse=%.2f, catchup=%.2f)\n",
i, statValuePtr, newValue, tierModifier, inverseModifier, catchUpBonus)
// Update the item's stat value // Update the item's stat value
item.UpdateField(statValueField, newValue) item.UpdateField(statValueField, newValue)
@@ -1306,7 +1405,7 @@ func (item *Item) ApplyTierModifiers(optionalTier ...int) {
// } // }
} }
func ItemToSql(item Item, reqLevel int, difficulty int) string { func ItemToSql(item Item, reqLevel int, difficulty int, skipSpellGen bool) string {
fmt.Printf("-- Required level: %v\n", reqLevel) fmt.Printf("-- Required level: %v\n", reqLevel)
@@ -1332,7 +1431,7 @@ func ItemToSql(item Item, reqLevel int, difficulty int) string {
name = getRandomWord(difficulty) + " " + name name = getRandomWord(difficulty) + " " + name
spellList := "" spellList := ""
if len(item.Spells) > 0 { if len(item.Spells) > 0 && !skipSpellGen {
for i, spell := range item.Spells { for i, spell := range item.Spells {
spellList += spells.SpellToSql(spell, *item.Quality) spellList += spells.SpellToSql(spell, *item.Quality)
@@ -1401,6 +1500,7 @@ func ItemToSql(item Item, reqLevel int, difficulty int) string {
dmg_max1 = %v, dmg_max1 = %v,
dmg_min2 = %v, dmg_min2 = %v,
dmg_max2 = %v, dmg_max2 = %v,
dmg_type2 = %v,
StatsCount = %v, StatsCount = %v,
stat_type1 = %v, stat_type1 = %v,
stat_value1 = %v, stat_value1 = %v,
@@ -1441,7 +1541,7 @@ func ItemToSql(item Item, reqLevel int, difficulty int) string {
SellPrice = FLOOR(100000 + (RAND() * 400001)), SellPrice = FLOOR(100000 + (RAND() * 400001)),
Armor = %v Armor = %v
WHERE entry = %v; WHERE entry = %v;
`, *item.Quality, strings.ReplaceAll(name, "'", "''"), *item.ItemLevel, reqLevel, *item.MinDmg1, *item.MaxDmg1, *item.MinDmg2, *item.MaxDmg2, *item.StatsCount, `, *item.Quality, strings.ReplaceAll(name, "'", "''"), *item.ItemLevel, reqLevel, *item.MinDmg1, *item.MaxDmg1, *item.MinDmg2, *item.MaxDmg2, *item.DmgType2, *item.StatsCount,
*item.StatType1, *item.StatValue1, *item.StatType2, *item.StatValue2, *item.StatType3, *item.StatValue3, *item.StatType4, *item.StatValue4, *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.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, *item.SpellTrigger1, *item.SpellTrigger2, *item.StatType9, *item.StatValue9, *item.StatType10, *item.StatValue10, *item.SpellId1, *item.SpellId2, *item.SpellId3, *item.SpellTrigger1, *item.SpellTrigger2,
@@ -1457,17 +1557,17 @@ func getRandomWord(difficulty int) string {
legendary := []string{"Legendary", "Fabled", "Exalted", "Magnificent", "Pristine", "Supreme", "Glorious"} legendary := []string{"Legendary", "Fabled", "Exalted", "Magnificent", "Pristine", "Supreme", "Glorious"}
ascendant := []string{"Ascendant", "Godlike", "Celestial", "Transcendant", "Divine", "Omnipotent", "Demonforged", "Immortal", "Omniscient", "Ethereal"} ascendant := []string{"Ascendant", "Godlike", "Celestial", "Transcendant", "Divine", "Omnipotent", "Demonforged", "Immortal", "Omniscient", "Ethereal"}
r := rand.New(rand.NewPCG(uint64(time.Now().UnixNano()), 2)) r := rand.New(rand.NewSource(time.Now().UnixNano()))
switch difficulty { switch difficulty {
case 3: // Mythic case 3: // Mythic
randomIndex := r.IntN(len(mythic)) randomIndex := r.Intn(len(mythic))
return mythic[randomIndex] return mythic[randomIndex]
case 4: // Legendary case 4: // Legendary
randomIndex := r.IntN(len(legendary)) randomIndex := r.Intn(len(legendary))
return legendary[randomIndex] return legendary[randomIndex]
case 5: // Ascendant case 5: // Ascendant
randomIndex := r.IntN(len(ascendant)) randomIndex := r.Intn(len(ascendant))
return ascendant[randomIndex] return ascendant[randomIndex]
default: default:
return "" return ""

26
main.go
View File

@@ -151,7 +151,7 @@ func main() {
// if the item is not from a dungeon and we made it here, then just scale to mythic which can be used for weekly loot chests or new recipes. // if the item is not from a dungeon and we made it here, then just scale to mythic which can be used for weekly loot chests or new recipes.
if lookupItem.Entry == 0 { if lookupItem.Entry == 0 {
Scale(highLevelItem, &item, *itemLevel, *item.Quality) Scale(highLevelItem, &item, *itemLevel, *item.Quality)
fmt.Print(items.ItemToSql(item, *baselevel, *difficulty)) fmt.Print(items.ItemToSql(item, *baselevel, *difficulty, false))
continue continue
} }
@@ -160,32 +160,32 @@ func main() {
if lookupItem.DungeonLevel < 60 && lookupItem.Expansion == 0 { if lookupItem.DungeonLevel < 60 && lookupItem.Expansion == 0 {
Scale(highLevelItem, &item, *itemLevel+5, *item.Quality) Scale(highLevelItem, &item, *itemLevel+5, *item.Quality)
fmt.Print(items.ItemToSql(item, *baselevel, *difficulty)) fmt.Print(items.ItemToSql(item, *baselevel, *difficulty, false))
} }
if lookupItem.DungeonLevel == 60 && lookupItem.Expansion == 0 { if lookupItem.DungeonLevel == 60 && lookupItem.Expansion == 0 {
Scale(highLevelItem, &item, *itemLevel+10, *item.Quality) Scale(highLevelItem, &item, *itemLevel+10, *item.Quality)
fmt.Print(items.ItemToSql(item, *baselevel, *difficulty)) fmt.Print(items.ItemToSql(item, *baselevel, *difficulty, false))
} }
if lookupItem.DungeonLevel < 70 && lookupItem.Expansion == 1 { if lookupItem.DungeonLevel < 70 && lookupItem.Expansion == 1 {
Scale(highLevelItem, &item, *itemLevel+7, *item.Quality) Scale(highLevelItem, &item, *itemLevel+7, *item.Quality)
fmt.Print(items.ItemToSql(item, *baselevel, *difficulty)) fmt.Print(items.ItemToSql(item, *baselevel, *difficulty, false))
} }
if lookupItem.DungeonLevel == 70 && lookupItem.Expansion == 1 { if lookupItem.DungeonLevel == 70 && lookupItem.Expansion == 1 {
Scale(highLevelItem, &item, *itemLevel+10, *item.Quality) Scale(highLevelItem, &item, *itemLevel+10, *item.Quality)
fmt.Print(items.ItemToSql(item, *baselevel, *difficulty)) fmt.Print(items.ItemToSql(item, *baselevel, *difficulty, false))
} }
if lookupItem.DungeonLevel < 80 && lookupItem.Expansion == 2 { if lookupItem.DungeonLevel < 80 && lookupItem.Expansion == 2 {
Scale(highLevelItem, &item, *itemLevel+7, *item.Quality) Scale(highLevelItem, &item, *itemLevel+7, *item.Quality)
fmt.Print(items.ItemToSql(item, *baselevel, *difficulty)) fmt.Print(items.ItemToSql(item, *baselevel, *difficulty, false))
} }
if lookupItem.DungeonLevel == 80 && lookupItem.Expansion == 2 { if lookupItem.DungeonLevel == 80 && lookupItem.Expansion == 2 {
Scale(highLevelItem, &item, *itemLevel+10, *item.Quality) Scale(highLevelItem, &item, *itemLevel+10, *item.Quality)
fmt.Print(items.ItemToSql(item, *baselevel+2, *difficulty)) fmt.Print(items.ItemToSql(item, *baselevel+2, *difficulty, false))
} }
} else { } else {
@@ -212,32 +212,32 @@ func main() {
// if the item is from a boss fight // if the item is from a boss fight
if lookupItem.DungeonLevel < 60 && lookupItem.Expansion == 0 { if lookupItem.DungeonLevel < 60 && lookupItem.Expansion == 0 {
Scale(highLevelItem, &item, *itemLevel+9+finalBonus, quality) Scale(highLevelItem, &item, *itemLevel+9+finalBonus, quality)
fmt.Print(items.ItemToSql(item, reqLevel-1, *difficulty)) fmt.Print(items.ItemToSql(item, reqLevel-1, *difficulty, false))
} }
if lookupItem.DungeonLevel == 60 && lookupItem.Expansion == 0 { if lookupItem.DungeonLevel == 60 && lookupItem.Expansion == 0 {
Scale(highLevelItem, &item, *itemLevel+23+finalBonus, quality) Scale(highLevelItem, &item, *itemLevel+23+finalBonus, quality)
fmt.Print(items.ItemToSql(item, reqLevel, *difficulty)) fmt.Print(items.ItemToSql(item, reqLevel, *difficulty, false))
} }
if lookupItem.DungeonLevel < 70 && lookupItem.Expansion == 1 { if lookupItem.DungeonLevel < 70 && lookupItem.Expansion == 1 {
Scale(highLevelItem, &item, *itemLevel+10+finalBonus, quality) Scale(highLevelItem, &item, *itemLevel+10+finalBonus, quality)
fmt.Print(items.ItemToSql(item, reqLevel-1, *difficulty)) fmt.Print(items.ItemToSql(item, reqLevel-1, *difficulty, false))
} }
if lookupItem.DungeonLevel == 70 && lookupItem.Expansion == 1 { if lookupItem.DungeonLevel == 70 && lookupItem.Expansion == 1 {
Scale(highLevelItem, &item, *itemLevel+23+finalBonus, quality) Scale(highLevelItem, &item, *itemLevel+23+finalBonus, quality)
fmt.Print(items.ItemToSql(item, reqLevel, *difficulty)) fmt.Print(items.ItemToSql(item, reqLevel, *difficulty, false))
} }
if lookupItem.DungeonLevel < 80 && lookupItem.Expansion == 2 { if lookupItem.DungeonLevel < 80 && lookupItem.Expansion == 2 {
Scale(highLevelItem, &item, *itemLevel+12+finalBonus, quality) Scale(highLevelItem, &item, *itemLevel+12+finalBonus, quality)
fmt.Print(items.ItemToSql(item, reqLevel-1, *difficulty)) fmt.Print(items.ItemToSql(item, reqLevel-1, *difficulty, false))
} }
if lookupItem.DungeonLevel == 80 && lookupItem.Expansion == 2 { if lookupItem.DungeonLevel == 80 && lookupItem.Expansion == 2 {
Scale(highLevelItem, &item, *itemLevel+25+finalBonus, quality) Scale(highLevelItem, &item, *itemLevel+25+finalBonus, quality)
fmt.Print(items.ItemToSql(item, reqLevel, *difficulty)) fmt.Print(items.ItemToSql(item, reqLevel, *difficulty, false))
} }
} }