Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Clorinde eNA AtkSpd Not Applying #2327

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d0756cb
Update Dehya C2 Skill Mechanics
Aftermathrar Jan 14, 2024
a9456dc
Update Dehya E proc delay
Aftermathrar Jan 14, 2024
3126658
Update Dehya skill.go
Aftermathrar Jan 14, 2024
9b90e5a
Merge branch 'main' of https://github.com/Aftermathrar/gcsim
Aftermathrar Jan 16, 2024
189d294
Update Dehya C2 Field Mechanics
Aftermathrar Jan 16, 2024
584f80b
Update Dehya Field After Burst
Aftermathrar Jan 16, 2024
be41358
Update Dehya C2 Recast Mechanics
Aftermathrar Jan 18, 2024
82b92c0
Merge remote-tracking branch 'upstream/main'
Aftermathrar Jan 20, 2024
efe07d2
Update Dehya Burst Mechanics
Aftermathrar Jan 20, 2024
d0a1105
Merge branch 'master' into dehya
k0l11 Jan 30, 2024
1f92ddb
fix dehya n1 to n4 and reposition lv.4 multipliers
k0l11 Jan 30, 2024
f2a9ffe
fix dehya n1 to n4 hitlag and small frame adjustments
k0l11 Jan 30, 2024
071ef26
Merge branch 'master' into dehya
k0l11 Feb 2, 2024
d78f830
Merge branch 'master' into dehya
k0l11 Feb 3, 2024
c33e2c6
Merge branch 'master' into dehya
k0l11 Feb 3, 2024
10af7b8
Merge branch 'master' into dehya
k0l11 Feb 3, 2024
76eb2e2
more dehya fixes
k0l11 Feb 3, 2024
eb11d47
fix dehya a1 missing trigger icd
k0l11 Feb 3, 2024
c06ca08
refactor dehya c1
k0l11 Feb 3, 2024
6ac972d
refactor dehya c2
k0l11 Feb 3, 2024
84484b4
refactor dehya c4
k0l11 Feb 3, 2024
5b5b320
refactor dehya c6
k0l11 Feb 3, 2024
483388e
fix dehya burst
k0l11 Feb 3, 2024
f380652
fix dehya q kick frames
k0l11 Feb 3, 2024
0c37152
fix dehya q not being hitlag extendable
k0l11 Feb 4, 2024
8fa9550
fix dehya e
k0l11 Feb 4, 2024
9d5b606
Initial mavuika implementation
Charlie-Zheng Jan 1, 2025
60de875
Fix Clorinde eNA AtkSpd Not Applying
Aftermathrar Jan 27, 2025
ff95553
Merge branch 'main' of https://github.com/Aftermathrar/gcsim
Aftermathrar Jan 27, 2025
284347c
Initial Charge Attack Logic
Aftermathrar Jan 30, 2025
fa64a51
Merge branch 'main' into mav-dev
Aftermathrar Jan 30, 2025
5178015
Mavuika Charge Attack Logic
Aftermathrar Jan 30, 2025
71e7b79
Merge branch 'mav-dev' of https://github.com/Aftermathrar/gcsim into …
Aftermathrar Jan 30, 2025
dc5c325
Update charge.go
Aftermathrar Jan 30, 2025
1bfad24
Merge pull request #1 from Aftermathrar/mav-dev
Aftermathrar Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions internal/characters/clorinde/attack.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var (

var (
skillAttackFrames [][]int
skillAttackHitmarks = []int{10, 10, 11}
skillAttackHitmarks = []int{8, 8, 9}
)

const (
Expand Down Expand Up @@ -160,8 +160,8 @@ func (c *char) skillAttack(_ map[string]int) (action.Info, error) {
Frames: func(next action.Action) int {
return frames.AtkSpdAdjust(skillAttackFrames[n][next], atkspd)
},
AnimationLength: skillAttackFrames[c.normalSCounter][action.InvalidAction],
CanQueueAfter: skillAttackFrames[c.normalSCounter][action.ActionBurst],
AnimationLength: frames.AtkSpdAdjust(skillAttackFrames[n][action.InvalidAction], atkspd),
CanQueueAfter: frames.AtkSpdAdjust(skillAttackFrames[n][action.ActionBurst], atkspd),
State: action.NormalAttackState,
}, nil
}
Expand Down
60 changes: 60 additions & 0 deletions internal/characters/mavuika/asc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package mavuika
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mavuika?


import (
"github.com/genshinsim/gcsim/pkg/core/attributes"
"github.com/genshinsim/gcsim/pkg/core/combat"
"github.com/genshinsim/gcsim/pkg/core/event"
"github.com/genshinsim/gcsim/pkg/core/player/character"
"github.com/genshinsim/gcsim/pkg/modifier"
)

const (
a1Key = "mavuika-a1"
)

func (c *char) a1() {
if c.Base.Ascension < 1 {
return
}
m := make([]float64, attributes.EndStatType)
m[attributes.ATKP] = 0.3
c.Core.Events.Subscribe(event.OnNightsoulBurst, func(args ...interface{}) bool {
c.AddStatMod(character.StatMod{
Base: modifier.NewBaseWithHitlag(a1Key, 10*60),
Amount: func() ([]float64, bool) {
return m, true
},
})
return false
}, a1Key)
}

func (c *char) a4Init() {
if c.Base.Ascension < 4 {
return
}
c.a4buff = make([]float64, attributes.EndStatType)
}

func (c *char) a4() {
if c.Base.Ascension < 4 {
return
}
started := c.Core.F
for _, char := range c.Core.Player.Chars() {
this := char
this.AddAttackMod(character.AttackMod{
Base: modifier.NewBase("mavuika-a4", 20*60),
Amount: func(_ *combat.AttackEvent, _ combat.Target) ([]float64, bool) {
// char must be active
if c.Core.Player.Active() != this.Index {
return nil, false
}
dmg := c.burstStacks*0.002 + c.c4BonusVal()
dmg *= 1.0 - float64(c.Core.F-started)*c.c4DecayRate()
c.a4buff[attributes.DmgP] = dmg
return c.a4buff, true
},
})
}
}
137 changes: 137 additions & 0 deletions internal/characters/mavuika/attack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package mavuika

import (
"fmt"

"github.com/genshinsim/gcsim/internal/frames"
"github.com/genshinsim/gcsim/pkg/core/action"
"github.com/genshinsim/gcsim/pkg/core/attacks"
"github.com/genshinsim/gcsim/pkg/core/attributes"
"github.com/genshinsim/gcsim/pkg/core/combat"
"github.com/genshinsim/gcsim/pkg/core/geometry"
)

var (
attackFrames [][]int
attackHitmarks = [][]int{{21}, {11, 23}, {10, 18, 26}, {28}}
attackPoiseDMG = []float64{93.33, 92.72, 115.14, 143.17}
attackHitlagHaltFrame = []float64{0.09, 0.10, 0.08, .12}
attackHitboxes = []float64{2.2, 2.3, 1.8, 3}
attackOffsets = []float64{0.5, -1.3, 0.5, -0.8}

bikeAttackFrames [][]int
bikeAttackHitmarks = []int{21, 22, 27, 14, 41}
bikeAttackPoiseDMG = []float64{76.6, 79.1, 93.6, 93.2, 121.7}
bikeAttackHitlagHaltFrame = []float64{0.09, 0.08, 0.04, 0.03, 0.0}
bikeAttackHitboxes = [][]float64{{3.7}, {4}, {3.7}, {5.5, 4.5}, {4.7}}
bikeAttackOffsets = []float64{0.5, -1.3, 0.5, -0.8, 1}
)

const normalHitNum = 4
const bikeHitNum = 5

func init() {
attackFrames = make([][]int, normalHitNum)

attackFrames[0] = frames.InitNormalCancelSlice(attackHitmarks[0][0], 35) // N1 -> N2
attackFrames[1] = frames.InitNormalCancelSlice(attackHitmarks[1][1], 44) // N2 -> N3
attackFrames[2] = frames.InitNormalCancelSlice(attackHitmarks[2][2], 54) // N3 -> N4
attackFrames[3] = frames.InitNormalCancelSlice(attackHitmarks[3][0], 42) // N4 -> N1

bikeAttackFrames = make([][]int, bikeHitNum)

bikeAttackFrames[0] = frames.InitNormalCancelSlice(bikeAttackHitmarks[0], 26) // N1 -> N2
bikeAttackFrames[1] = frames.InitNormalCancelSlice(bikeAttackHitmarks[1], 35) // N2 -> N3
bikeAttackFrames[2] = frames.InitNormalCancelSlice(bikeAttackHitmarks[2], 34) // N3 -> N4
bikeAttackFrames[3] = frames.InitNormalCancelSlice(bikeAttackHitmarks[3], 22) // N4 -> N5
bikeAttackFrames[4] = frames.InitNormalCancelSlice(bikeAttackHitmarks[4], 63) // N5 -> N1
}

func (c *char) Attack(p map[string]int) (action.Info, error) {
if c.armamentState == bike && c.nightsoulState.HasBlessing() {
return c.bikeAttack(), nil
}
ai := combat.AttackInfo{
ActorIndex: c.Index,
Abil: fmt.Sprintf("Normal %v", c.NormalCounter),
AttackTag: attacks.AttackTagNormal,
ICDTag: attacks.ICDTagNormalAttack,
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeBlunt,
PoiseDMG: attackPoiseDMG[c.NormalCounter],
Element: attributes.Physical,
Durability: 25,
Mult: attack[c.NormalCounter][c.TalentLvlAttack()],
HitlagFactor: 0.01,
HitlagHaltFrames: attackHitlagHaltFrame[c.NormalCounter] * 60,
}
ap := combat.NewCircleHitOnTarget(
c.Core.Combat.Player(),
geometry.Point{Y: attackOffsets[c.NormalCounter]},
attackHitboxes[c.NormalCounter],
)

for _, delay := range attackHitmarks[c.NormalCounter] {
c.Core.QueueAttack(ai, ap, delay, delay)
}

defer c.AdvanceNormalIndex()

return action.Info{
Frames: frames.NewAttackFunc(c.Character, attackFrames),
AnimationLength: attackFrames[c.NormalCounter][action.InvalidAction],
CanQueueAfter: attackHitmarks[c.NormalCounter][len(attackHitmarks[c.NormalCounter])-1],
State: action.NormalAttackState,
}, nil
}

func (c *char) bikeAttack() action.Info {
delay := bikeAttackHitmarks[c.NormalCounter]
ai := combat.AttackInfo{
ActorIndex: c.Index,
Abil: fmt.Sprintf("Flamestrider Normal %v", c.NormalCounter),
AttackTag: attacks.AttackTagNormal,
AdditionalTags: []attacks.AdditionalTag{attacks.AdditionalTagNightsoul},
ICDTag: attacks.ICDTagMavuikaFlamestrider,
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeBlunt,
PoiseDMG: bikeAttackPoiseDMG[c.NormalCounter],
Element: attributes.Pyro,
Durability: 25,
Mult: skillAttack[c.NormalCounter][c.TalentLvlAttack()],
HitlagFactor: 0.01,
HitlagHaltFrames: bikeAttackHitlagHaltFrame[c.NormalCounter] * 60,
IgnoreInfusion: true,
}

ap := combat.NewCircleHitOnTarget(
c.Core.Combat.Player(),
geometry.Point{Y: bikeAttackOffsets[c.NormalCounter]},
bikeAttackHitboxes[c.NormalCounter][0],
)

if c.NormalCounter == 3 {
ap = combat.NewBoxHitOnTarget(
c.Core.Combat.Player(),
geometry.Point{Y: bikeAttackOffsets[c.NormalCounter]},
bikeAttackHitboxes[c.NormalCounter][0],
bikeAttackHitboxes[c.NormalCounter][1],
)
}
c.QueueCharTask(func() {
ai.FlatDmg = c.burstBuffNA() + c.c2BikeNA()
c.Core.QueueAttack(ai, ap, 0, 0)
c.reduceNightsoulPoints(1)
}, delay)

defer c.AdvanceNormalIndex()

return action.Info{
Frames: frames.NewAttackFunc(c.Character, bikeAttackFrames),
AnimationLength: bikeAttackFrames[c.NormalCounter][action.InvalidAction],
CanQueueAfter: bikeAttackHitmarks[c.NormalCounter],
State: action.NormalAttackState,
}
}

// TODO: charged attack
137 changes: 137 additions & 0 deletions internal/characters/mavuika/burst.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package mavuika

import (
"github.com/genshinsim/gcsim/internal/frames"
"github.com/genshinsim/gcsim/pkg/core/action"
"github.com/genshinsim/gcsim/pkg/core/attacks"
"github.com/genshinsim/gcsim/pkg/core/attributes"
"github.com/genshinsim/gcsim/pkg/core/combat"
"github.com/genshinsim/gcsim/pkg/core/event"
"github.com/genshinsim/gcsim/pkg/core/geometry"
"github.com/genshinsim/gcsim/pkg/enemy"
)

const (
burstKey = "mavuika-burst"
energyNAICDKey = "mavuika-fighting-spirit-na-icd"
burstDuration = 7.0 * 60
burstHitmark = 106
)

var (
burstFrames []int
)

func (c *char) nightsoulConsumptionMul() float64 {
if c.StatusIsActive(burstKey) {
return 0.0
}
return 1.0
}

func init() {
burstFrames = frames.InitAbilSlice(116) // Q -> Swap
}

func (c *char) Burst(p map[string]int) (action.Info, error) {
c.burstStacks = c.fightingSpirit
c.fightingSpirit = 0
c.enterBike()
c.QueueCharTask(func() {
c.enterNightsoulOrRegenerate(10)
}, 87)
c.QueueCharTask(func() {
c.AddStatus(burstKey, burstDuration, true)
}, burstHitmark-1)
c.QueueCharTask(func() {
c.a4()

ai := combat.AttackInfo{
ActorIndex: c.Index,
Abil: "Sunfell Slice",
AttackTag: attacks.AttackTagElementalBurst,
ICDTag: attacks.ICDTagNone,
AdditionalTags: []attacks.AdditionalTag{attacks.AdditionalTagNightsoul},
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeBlunt,
PoiseDMG: 150,
Element: attributes.Pyro,
Durability: 25,
Mult: burst[c.TalentLvlBurst()],
FlatDmg: c.burstBuffSunfell() + c.c2BikeQ(),
}
ap := combat.NewCircleHitOnTarget(
c.Core.Combat.Player(),
geometry.Point{Y: 1.0},
6,
)
c.Core.QueueAttack(ai, ap, 0, 0)
}, burstHitmark)

c.SetCDWithDelay(action.ActionBurst, 18*60, 0)

return action.Info{
Frames: frames.NewAbilFunc(burstFrames),
AnimationLength: burstFrames[action.InvalidAction],
CanQueueAfter: burstFrames[action.ActionSwap], // earliest cancel
State: action.BurstState,
}, nil
}

func (c *char) burstBuffCA() float64 {
if !c.StatusIsActive(burstKey) {
return 0.0
}
return c.burstStacks * burstCABonus[c.TalentLvlBurst()] * c.TotalAtk()
}

func (c *char) burstBuffNA() float64 {
if !c.StatusIsActive(burstKey) {
return 0.0
}
return c.burstStacks * burstNABonus[c.TalentLvlBurst()] * c.TotalAtk()
}

func (c *char) burstBuffSunfell() float64 {
if !c.StatusIsActive(burstKey) {
return 0.0
}
return c.burstStacks * burstQBonus[c.TalentLvlBurst()] * c.TotalAtk()
}

func (c *char) gainFightingSpirit(val float64) {
c.fightingSpirit += val * c.c1FightingSpiritEff()
if c.fightingSpirit > 200 {
c.fightingSpirit = 200
}
c.c1OnFightingSpirit()
}

func (c *char) burstInit() {
c.fightingSpirit = 200
c.Core.Events.Subscribe(event.OnNightsoulConsume, func(args ...interface{}) bool {
amount := args[1].(float64)
if amount < 0.0000001 {
return false
}
c.gainFightingSpirit(amount)
return false
}, "mavuika-fighting-spirit-ns")

c.Core.Events.Subscribe(event.OnEnemyDamage, func(args ...interface{}) bool {
ae := args[1].(*combat.AttackEvent)
_, ok := args[0].(*enemy.Enemy)
if !ok {
return false
}
if ae.Info.AttackTag != attacks.AttackTagNormal {
return false
}
if c.StatusIsActive(energyNAICDKey) {
return false
}
c.AddStatus(energyNAICDKey, 0.1*60, true)
c.gainFightingSpirit(1.5)
return false
}, "mavuika-fighting-spirit-na")
}
Loading