Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/wowsims/sod
Browse files Browse the repository at this point in the history
  • Loading branch information
kayla-glick committed Nov 18, 2024
2 parents a41d6d2 + afbeafc commit 7d9c64f
Show file tree
Hide file tree
Showing 50 changed files with 368 additions and 292 deletions.
Binary file modified assets/database/db.bin
Binary file not shown.
28 changes: 14 additions & 14 deletions assets/database/db.json

Large diffs are not rendered by default.

Binary file modified assets/database/leftover_db.bin
Binary file not shown.
4 changes: 2 additions & 2 deletions assets/database/leftover_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -1482,8 +1482,8 @@
{"effectId":63,"spellId":13538,"name":"Enchant Chest - Lesser Absorption","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1},
{"effectId":66,"spellId":7457,"name":"Enchant Bracer - Minor Stamina","type":6,"stats":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1},
{"effectId":66,"spellId":7863,"name":"Enchant Boots - Minor Stamina","type":10,"stats":[0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1},
{"effectId":241,"spellId":7745,"name":"Enchant 2H Weapon - Minor Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1},
{"effectId":241,"spellId":13503,"name":"Enchant Weapon - Lesser Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1},
{"effectId":241,"spellId":7745,"name":"Enchant 2H Weapon - Minor Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1},
{"effectId":242,"spellId":7748,"name":"Enchant Chest - Lesser Health","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0],"quality":1},
{"effectId":243,"spellId":7766,"name":"Enchant Bracer - Minor Spirit","type":6,"stats":[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
{"effectId":246,"spellId":7776,"name":"Enchant Chest - Lesser Mana","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
Expand Down Expand Up @@ -1585,8 +1585,8 @@
{"effectId":1893,"spellId":20028,"name":"Enchant Chest - Major Mana","type":5,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
{"effectId":1894,"spellId":20029,"name":"Enchant Weapon - Icy Chill","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
{"effectId":1896,"spellId":20030,"name":"Enchant 2H Weapon - Superior Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
{"effectId":1897,"spellId":20031,"name":"Enchant Weapon - Superior Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
{"effectId":1897,"spellId":13695,"name":"Enchant 2H Weapon - Impact","type":13,"enchantType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":1},
{"effectId":1897,"spellId":20031,"name":"Enchant Weapon - Superior Striking","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
{"effectId":1898,"spellId":20032,"name":"Enchant Weapon - Lifestealing","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":3},
{"effectId":1899,"spellId":20033,"name":"Enchant Weapon - Unholy Weapon","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
{"effectId":1900,"spellId":20034,"name":"Enchant Weapon - Crusader","type":13,"stats":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"quality":2},
Expand Down
6 changes: 4 additions & 2 deletions proto/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,15 @@ enum Stat {
// between the UI and backend.
//
// It's also OK to include things here which aren't in the PseudoStats struct.
// NextIndex: 31
// NextIndex: 32
enum PseudoStat {
PseudoStatMainHandDps = 0;
PseudoStatOffHandDps = 1;
PseudoStatRangedDps = 2;
PseudoStatBlockValueMultiplier = 3;
PseudoStatDodge = 4;
PseudoStatParry = 5;
BonusPhysicalDamage = 31;

// Melee Weapon Skill
PseudoStatUnarmedSkill = 6;
Expand Down Expand Up @@ -933,7 +934,7 @@ message SimDatabase {
}

// Contains only the Item info needed by the sim.
// NextIndex: 20
// NextIndex: 21
message SimItem {
int32 id = 1;
int32 requires_level = 16;
Expand All @@ -951,6 +952,7 @@ message SimItem {
double weapon_damage_min = 11;
double weapon_damage_max = 12;
double weapon_speed = 13;
double bonus_physical_damage = 20;

string set_name = 14;
int32 set_id = 18;
Expand Down
3 changes: 2 additions & 1 deletion proto/ui.proto
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ message UIFaction {
// Contains all information about an Item needed by the UI.
// Generally this will include everything needed by the sim, plus some
// additional data for displaying / filtering.
// NextIndex: 31
// NextIndex: 32
message UIItem {
int32 id = 1;
string name = 2;
Expand All @@ -65,6 +65,7 @@ message UIItem {
double weapon_damage_max = 14;
double weapon_speed = 15;
repeated double weapon_skills = 28;
double bonus_physical_damage = 31;

int32 ilvl = 16;
int32 phase = 17;
Expand Down
2 changes: 0 additions & 2 deletions sim/common/sod/crafted/phase_2.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ func init() {
core.NewItemEffect(215166, func(agent core.Agent) {
character := agent.GetCharacter()

character.PseudoStats.BonusDamage += 3

actionId := core.ActionID{SpellID: 437349}

buffAura := character.GetOrRegisterAura(core.Aura{
Expand Down
2 changes: 1 addition & 1 deletion sim/common/sod/item_effects/phase_3.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func init() {
aura.SetStacks(sim, aura.MaxStacks)
},
OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) {
character.PseudoStats.BonusDamage += float64(newStacks - oldStacks)
character.PseudoStats.BonusPhysicalDamage += float64(newStacks - oldStacks)
},
OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
if result.Landed() && spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) {
Expand Down
10 changes: 0 additions & 10 deletions sim/common/sod/item_effects/phase_4.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const (
BroodmothersBrooch = 228163
TreantsBane = 228486
FistOfTheFireswornMolten = 229374
StuddedTimbermawBrawlers = 227809
)

func init() {
Expand Down Expand Up @@ -83,8 +82,6 @@ func init() {
core.NewItemEffect(WoodcarvedMoonstalker, func(agent core.Agent) {
character := agent.GetCharacter()

character.PseudoStats.BonusDamage += 4

// Woodcarved Moonstalker isn't unique, but presumably the on-use has a shared CD
if character.HasAura("Woodcarved Moonstalker") {
return
Expand Down Expand Up @@ -184,12 +181,5 @@ func init() {
}
})

// https://www.wowhead.com/classic/item=227809/studded-timbermaw-brawlers
// Equip: +3 Weapon Damage.
core.NewItemEffect(StuddedTimbermawBrawlers, func(agent core.Agent) {
character := agent.GetCharacter()
character.PseudoStats.BonusDamage += 3
})

core.AddEffectsToTest = true
}
6 changes: 3 additions & 3 deletions sim/common/vanilla/item_effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -2904,7 +2904,7 @@ func init() {
aura.SetStacks(sim, aura.MaxStacks)
},
OnStacksChange: func(aura *core.Aura, sim *core.Simulation, oldStacks, newStacks int32) {
character.PseudoStats.BonusDamage += 2 * float64(newStacks-oldStacks)
character.PseudoStats.BonusPhysicalDamage += 2 * float64(newStacks-oldStacks)
},
OnSpellHitDealt: func(aura *core.Aura, sim *core.Simulation, spell *core.Spell, result *core.SpellResult) {
if result.Landed() && spell.ProcMask.Matches(core.ProcMaskMeleeOrRanged) {
Expand Down Expand Up @@ -3049,11 +3049,11 @@ func EnrageAura446327(character *core.Character) *core.Aura {
Label: "Enrage (446327)",
Duration: time.Second * 15,
OnGain: func(aura *core.Aura, sim *core.Simulation) {
character.PseudoStats.BonusDamage += 20
character.PseudoStats.BonusPhysicalDamage += 20
character.MultiplyAttackSpeed(sim, 1.05)
},
OnExpire: func(aura *core.Aura, sim *core.Simulation) {
character.PseudoStats.BonusDamage -= 20
character.PseudoStats.BonusPhysicalDamage -= 20
character.MultiplyAttackSpeed(sim, 1/1.05)
},
})
Expand Down
9 changes: 8 additions & 1 deletion sim/core/character.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ func NewCharacter(party *Party, partyIndex int, player *proto.Player) Character
character.PseudoStats.BowsSkill += ps[proto.PseudoStat_PseudoStatBowsSkill]
character.PseudoStats.CrossbowsSkill += ps[proto.PseudoStat_PseudoStatCrossbowsSkill]
character.PseudoStats.GunsSkill += ps[proto.PseudoStat_PseudoStatGunsSkill]

character.PseudoStats.BonusPhysicalDamage += ps[proto.PseudoStat_BonusPhysicalDamage]
character.PseudoStats.TimewornBonus += int32(ps[proto.PseudoStat_TimewornBonus])
}
}

Expand Down Expand Up @@ -267,7 +268,10 @@ func (character *Character) applyEquipment() {
if item.Timeworn {
character.PseudoStats.TimewornBonus += 1
}

character.PseudoStats.BonusPhysicalDamage += item.BonusPhysicalDamage
}

}

func (character *Character) addUniversalStatDependencies() {
Expand Down Expand Up @@ -636,6 +640,9 @@ func (character *Character) GetPseudoStatsProto() []float64 {
proto.PseudoStat_PseudoStatMeleeSpeedMultiplier: float64(character.PseudoStats.MeleeSpeedMultiplier),
proto.PseudoStat_PseudoStatRangedSpeedMultiplier: float64(character.PseudoStats.RangedSpeedMultiplier),
proto.PseudoStat_PseudoStatBlockValuePerStrength: float64(character.PseudoStats.BlockValuePerStrength),

proto.PseudoStat_TimewornBonus: float64(character.PseudoStats.TimewornBonus),
proto.PseudoStat_BonusPhysicalDamage: float64(character.PseudoStats.BonusPhysicalDamage),
}
}

Expand Down
19 changes: 10 additions & 9 deletions sim/core/consumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,8 @@ func applyDefensiveBuffConsumes(character *Character, consumes *proto.Consumes)
switch consumes.ArmorElixir {
case proto.ArmorElixir_ElixirOfTheIronside:
character.AddStats(stats.Stats{
stats.BonusArmor: 350,
stats.Defense: 5,
stats.BonusArmor: 350,
stats.Defense: 5,
stats.NatureResistance: 15,
})
case proto.ArmorElixir_ElixirOfSuperiorDefense:
Expand Down Expand Up @@ -525,8 +525,8 @@ func applyPhysicalBuffConsumes(character *Character, consumes *proto.Consumes) {
switch consumes.AgilityElixir {
case proto.AgilityElixir_ElixirOfTheHoneyBadger:
character.AddStats(stats.Stats{
stats.Agility: 30,
stats.MeleeCrit: 2 * CritRatingPerCritChance,
stats.Agility: 30,
stats.MeleeCrit: 2 * CritRatingPerCritChance,
stats.NatureResistance: 15,
})
case proto.AgilityElixir_ElixirOfTheMongoose:
Expand Down Expand Up @@ -592,7 +592,7 @@ func applySpellBuffConsumes(character *Character, consumes *proto.Consumes) {
})
case proto.SpellPowerBuff_ElixirOfTheMageLord:
character.AddStats(stats.Stats{
stats.SpellDamage: 40,
stats.SpellDamage: 40,
stats.NatureResistance: 15,
})
}
Expand Down Expand Up @@ -777,7 +777,7 @@ func applyMiscConsumes(character *Character, miscConsumes *proto.MiscConsumes) {
}

if miscConsumes.BoglingRoot {
character.PseudoStats.BonusDamage += 1
character.PseudoStats.BonusPhysicalDamage += 1
}

if miscConsumes.ElixirOfCoalescedRegret {
Expand Down Expand Up @@ -908,7 +908,7 @@ func applyEnchantingConsumes(character *Character, consumes *proto.Consumes) {
stats.SpellPower: 40,
})
}
}
}
}

///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1044,6 +1044,7 @@ func (character *Character) newBasicExplosiveSpellConfig(sharedTimer *Timer, act
func (character *Character) newSapperSpell(sharedTimer *Timer) *Spell {
return character.GetOrRegisterSpell(character.newBasicExplosiveSpellConfig(sharedTimer, SapperActionID, SpellSchoolFire, 450, 750, Cooldown{Timer: character.NewTimer(), Duration: time.Minute * 5}, 375, 625))
}

// Needs testing for Silithid interaction if in raid
func (character *Character) newFumigatorSpell(sharedTimer *Timer) *Spell {
return character.GetOrRegisterSpell(character.newBasicExplosiveSpellConfig(sharedTimer, FumigatorActionID, SpellSchoolFire, 650, 950, Cooldown{Timer: character.NewTimer(), Duration: time.Minute * 5}, 475, 725))
Expand Down Expand Up @@ -1296,7 +1297,7 @@ func makeArmorConsumableMCD(itemId int32, character *Character, cdTimer *Timer)
cdDuration := time.Minute * 2
lesserStoneshieldAura := character.NewTemporaryStatsAura("Lesser Stoneshield Potion", actionID, stats.Stats{stats.BonusArmor: 1000}, time.Second*90)
greaterStoneshieldAura := character.NewTemporaryStatsAura("Greater Stoneshield Potion", actionID, stats.Stats{stats.BonusArmor: 2000}, time.Second*120)

return MajorCooldown{
Type: CooldownTypeSurvival,
Spell: character.GetOrRegisterSpell(SpellConfig{
Expand All @@ -1316,7 +1317,7 @@ func makeArmorConsumableMCD(itemId int32, character *Character, cdTimer *Timer)
case 4623:
lesserStoneshieldAura.Activate(sim)
case 13455:

greaterStoneshieldAura.Activate(sim)
}
},
Expand Down
48 changes: 25 additions & 23 deletions sim/core/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ type Item struct {
WeaponDamageMax float64
SwingSpeed float64

Name string
Stats stats.Stats // Stats applied to wearer
Quality proto.ItemQuality
SetName string // Empty string if not part of a set.
SetID int32 // 0 if not part of a set.
WeaponSkills stats.WeaponSkills
Name string
Stats stats.Stats // Stats applied to wearer
BonusPhysicalDamage float64
Quality proto.ItemQuality
SetName string // Empty string if not part of a set.
SetID int32 // 0 if not part of a set.
WeaponSkills stats.WeaponSkills

Timeworn bool

Expand All @@ -78,23 +79,24 @@ type Item struct {

func ItemFromProto(pData *proto.SimItem) Item {
return Item{
ID: pData.Id,
RequiresLevel: pData.RequiresLevel,
ClassAllowlist: pData.ClassAllowlist,
Name: pData.Name,
Type: pData.Type,
ArmorType: pData.ArmorType,
WeaponType: pData.WeaponType,
HandType: pData.HandType,
RangedWeaponType: pData.RangedWeaponType,
WeaponDamageMin: pData.WeaponDamageMin,
WeaponDamageMax: pData.WeaponDamageMax,
SwingSpeed: pData.WeaponSpeed,
Stats: stats.FromFloatArray(pData.Stats),
SetName: pData.SetName,
SetID: pData.SetId,
WeaponSkills: stats.WeaponSkillsFloatArray(pData.WeaponSkills),
Timeworn: pData.Timeworn,
ID: pData.Id,
RequiresLevel: pData.RequiresLevel,
ClassAllowlist: pData.ClassAllowlist,
Name: pData.Name,
Type: pData.Type,
ArmorType: pData.ArmorType,
WeaponType: pData.WeaponType,
HandType: pData.HandType,
RangedWeaponType: pData.RangedWeaponType,
WeaponDamageMin: pData.WeaponDamageMin,
WeaponDamageMax: pData.WeaponDamageMax,
SwingSpeed: pData.WeaponSpeed,
Stats: stats.FromFloatArray(pData.Stats),
BonusPhysicalDamage: pData.BonusPhysicalDamage,
SetName: pData.SetName,
SetID: pData.SetId,
WeaponSkills: stats.WeaponSkillsFloatArray(pData.WeaponSkills),
Timeworn: pData.Timeworn,
}
}

Expand Down
35 changes: 18 additions & 17 deletions sim/core/database_load.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,24 @@ func init() {

for i, item := range db.Items {
simDB.Items[i] = &proto.SimItem{
Id: item.Id,
RequiresLevel: item.RequiresLevel,
ClassAllowlist: item.ClassAllowlist,
Name: item.Name,
Type: item.Type,
ArmorType: item.ArmorType,
WeaponType: item.WeaponType,
HandType: item.HandType,
RangedWeaponType: item.RangedWeaponType,
Stats: item.Stats,
WeaponDamageMin: item.WeaponDamageMin,
WeaponDamageMax: item.WeaponDamageMax,
WeaponSpeed: item.WeaponSpeed,
SetName: item.SetName,
SetId: item.SetId,
WeaponSkills: item.WeaponSkills,
Timeworn: item.Timeworn,
Id: item.Id,
RequiresLevel: item.RequiresLevel,
ClassAllowlist: item.ClassAllowlist,
Name: item.Name,
Type: item.Type,
ArmorType: item.ArmorType,
WeaponType: item.WeaponType,
HandType: item.HandType,
RangedWeaponType: item.RangedWeaponType,
Stats: item.Stats,
BonusPhysicalDamage: item.BonusPhysicalDamage,
WeaponDamageMin: item.WeaponDamageMin,
WeaponDamageMax: item.WeaponDamageMax,
WeaponSpeed: item.WeaponSpeed,
SetName: item.SetName,
SetId: item.SetId,
WeaponSkills: item.WeaponSkills,
Timeworn: item.Timeworn,
}
}

Expand Down
4 changes: 2 additions & 2 deletions sim/core/debuffs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1177,10 +1177,10 @@ func CurseOfWeaknessAura(target *Unit, points int32, playerLevel int32) *Aura {
ActionID: ActionID{SpellID: spellID},
Duration: time.Minute * 2,
OnGain: func(aura *Aura, sim *Simulation) {
aura.Unit.PseudoStats.BonusDamage += modDmgReduction
aura.Unit.PseudoStats.BonusPhysicalDamage += modDmgReduction
},
OnExpire: func(aura *Aura, sim *Simulation) {
aura.Unit.PseudoStats.BonusDamage -= modDmgReduction
aura.Unit.PseudoStats.BonusPhysicalDamage -= modDmgReduction
},
})
return aura
Expand Down
4 changes: 2 additions & 2 deletions sim/core/spell_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (spell *Spell) GetBonusDamage() float64 {
// PseudoStats.BonusDamage is physical "spell power", just return that here.
// TODO: Do "MobTypeSpellPower" effects for physical exist? E.g. something like "Do x extra weapon damage against y type"?
// If yes then it needs to be handled here and for the multi school case below.
return spell.Unit.PseudoStats.BonusDamage
return spell.Unit.PseudoStats.BonusPhysicalDamage
case stats.SchoolIndexArcane:
schoolBonusDamage = spell.Unit.GetStat(stats.ArcanePower)
case stats.SchoolIndexFire:
Expand All @@ -163,7 +163,7 @@ func (spell *Spell) GetBonusDamage() float64 {
// non-physical schools and would need to be considered against physical here and obviously not applied
// if physical is chosen.
if baseSchoolIndex == stats.SchoolIndexPhysical {
power = spell.Unit.PseudoStats.BonusDamage
power = spell.Unit.PseudoStats.BonusPhysicalDamage
} else {
// School and stat indices are ordered the same way.
power = spell.Unit.GetStat(stats.ArcanePower + stats.Stat(baseSchoolIndex) - 2)
Expand Down
Loading

0 comments on commit 7d9c64f

Please sign in to comment.