diff --git a/internal/characters/fischl/asc.go b/internal/characters/fischl/asc.go index a934f4750..bab57f4b3 100644 --- a/internal/characters/fischl/asc.go +++ b/internal/characters/fischl/asc.go @@ -6,10 +6,16 @@ import ( "github.com/genshinsim/gcsim/pkg/core/combat" "github.com/genshinsim/gcsim/pkg/core/event" "github.com/genshinsim/gcsim/pkg/core/info" + "github.com/genshinsim/gcsim/pkg/core/player/character" "github.com/genshinsim/gcsim/pkg/enemy" + "github.com/genshinsim/gcsim/pkg/modifier" ) -const a4IcdKey = "fischl-a4-icd" +const ( + a4IcdKey = "fischl-a4-icd" + hexAtkpKey = "fischl-hexerei-atkp" + hexEMKey = "fischl-hexerei-em" +) // A1 is not implemented: // TODO: When Fischl hits Oz with a fully-charged Aimed Shot, Oz brings down Thundering Retribution, dealing AoE Electro DMG equal to 152.7% of the arrow's DMG. @@ -74,3 +80,95 @@ func (c *char) a4() { c.Core.Events.Subscribe(event.OnQuicken, a4cbNoGadget, "fischl-a4") c.Core.Events.Subscribe(event.OnAggravate, a4cbNoGadget, "fischl-a4") } + +func (c *char) hexInit() { + if !c.IsHexerei { + return + } + + if c.Core.Player.GetHexereiCount() < 2 { + return + } + + mAtkp := make([]float64, attributes.EndStatType) + mAtkp[attributes.ATKP] = 0.225 + mEM := make([]float64, attributes.EndStatType) + mEM[attributes.EM] = 90 + + for _, other := range c.Core.Player.Chars() { + if other.Index() == c.Index() { + continue + } + + other.AddStatMod(character.StatMod{ + Base: modifier.NewBase(hexAtkpKey, -1), + AffectedStat: attributes.ATKP, + Amount: func() []float64 { + if c.Core.Player.Active() != other.Index() { + return nil + } + if !c.StatModIsActive(hexAtkpKey) { + return nil + } + mAtkp[attributes.ATKP] = 0.225 * (1 + c.c6HexBonus()) + return mAtkp + }, + }) + + other.AddStatMod(character.StatMod{ + Base: modifier.NewBase(hexEMKey, -1), + AffectedStat: attributes.EM, + Amount: func() []float64 { + if c.Core.Player.Active() != other.Index() { + return nil + } + if !c.StatModIsActive(hexEMKey) { + return nil + } + mEM[attributes.EM] = 90 * (1 + c.c6HexBonus()) + return mEM + }, + }) + } + + atkpHook := func(args ...any) { + if _, ok := args[0].(*enemy.Enemy); !ok { + return + } + // do nothing if oz not on field + if !c.StatusIsActive(ozActiveKey) { + return + } + + c.AddStatMod(character.StatMod{ + Base: modifier.NewBaseWithHitlag(hexAtkpKey, 10*60), + AffectedStat: attributes.ATKP, + Amount: func() []float64 { + mAtkp[attributes.ATKP] = 0.225 * (1 + c.c6HexBonus()) + return mAtkp + }, + }) + } + emHook := func(args ...any) { + if _, ok := args[0].(*enemy.Enemy); !ok { + return + } + // do nothing if oz not on field + if !c.StatusIsActive(ozActiveKey) { + return + } + + c.AddStatMod(character.StatMod{ + Base: modifier.NewBaseWithHitlag(hexEMKey, 10*60), + AffectedStat: attributes.EM, + Amount: func() []float64 { + mEM[attributes.EM] = 90 * (1 + c.c6HexBonus()) + return mEM + }, + }) + } + + c.Core.Events.Subscribe(event.OnOverload, atkpHook, "fischl-hex-ol") + c.Core.Events.Subscribe(event.OnElectroCharged, emHook, "fischl-hex-ec") + c.Core.Events.Subscribe(event.OnLunarCharged, emHook, "fischl-hex-lc") +} diff --git a/internal/characters/fischl/cons.go b/internal/characters/fischl/cons.go index 3f0a61db7..7277375a0 100644 --- a/internal/characters/fischl/cons.go +++ b/internal/characters/fischl/cons.go @@ -7,6 +7,8 @@ import ( "github.com/genshinsim/gcsim/pkg/core/info" ) +const c6HexereiKey = "fischl-c6-hexerei" + func (c *char) c6Wave() { ai := info.AttackInfo{ ActorIndex: c.Index(), @@ -33,4 +35,18 @@ func (c *char) c6Wave() { ), c.ozTravel, ) + + c.AddStatus(c6HexereiKey, 10*60, true) +} + +func (c *char) c6HexBonus() float64 { + if c.Base.Cons < 6 { + return 0 + } + + if !c.StatusIsActive(c6HexereiKey) { + return 0 + } + + return 1 } diff --git a/internal/characters/fischl/fischl.go b/internal/characters/fischl/fischl.go index 3dd87239d..ae55fabf1 100644 --- a/internal/characters/fischl/fischl.go +++ b/internal/characters/fischl/fischl.go @@ -46,6 +46,13 @@ func NewChar(s *core.Core, w *character.CharWrapper, p info.CharacterProfile) er c.ozTravel = travel } + hex, ok := p.Params["hexerei"] + if !ok { + // default hexerei is enabled + hex = 1 + } + c.IsHexerei = (hex != 0) + w.Character = &c return nil @@ -53,7 +60,7 @@ func NewChar(s *core.Core, w *character.CharWrapper, p info.CharacterProfile) er func (c *char) Init() error { c.a4() - + c.hexInit() if c.Base.Cons >= 6 { w, err := minazuki.New( minazuki.WithMandatory(keys.Fischl, "fischl c6", ozActiveKey, "", 60, c.c6Wave, c.Core), diff --git a/pkg/core/player/character/character.go b/pkg/core/player/character/character.go index b227a92c0..5fc2bb681 100644 --- a/pkg/core/player/character/character.go +++ b/pkg/core/player/character/character.go @@ -99,6 +99,7 @@ type CharWrapper struct { SkillCon int BurstCon int HasArkhe bool + IsHexerei bool Moonsign int Equip struct { diff --git a/pkg/core/player/player.go b/pkg/core/player/player.go index bc5b9e3b4..7c806c2cd 100644 --- a/pkg/core/player/player.go +++ b/pkg/core/player/player.go @@ -406,3 +406,14 @@ func (h *Handler) GetMoonsignLevel() int { } return count } + +func (h *Handler) GetHexereiCount() int { + count := 0 + for _, char := range h.chars { + if char.IsHexerei { + count++ + } + } + + return count +}