Skip to content

Commit d1d1fa1

Browse files
just1ce5Charlie-Zhengimring
authored
Add Pyro MC and Skirk's Story buffs (#2329)
* add pyro mc implementation. * add pyro mc implementation. * added frames and removed bugs. * fix lint and add MVs. * Updated Configs. Ran pipeline * bug fixes pt. 1 + implement Traveler's Skirk story buffs. * made story buffs as 2 separate options. * bug fixes pt. 2 * removed ec and hydro swirl ignore. * Various fixes * Added frames sheet * Added lumine pyro plunge * Fix golangci-plus * rewrote enter/exit nightsoul for pyromc --------- Co-authored-by: Charlie Zheng <charlie.x.3000@gmail.com> Co-authored-by: imring <35897995+imring@users.noreply.github.com>
1 parent 938c0a6 commit d1d1fa1

File tree

36 files changed

+2245
-33
lines changed

36 files changed

+2245
-33
lines changed

internal/characters/traveler/common/anemo/traveleranemo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
3535
c.SkillCon = 5
3636
c.NormalHitNum = normalHitNum
3737

38-
common.TravelerBaseAtkIncrease(w, p)
38+
common.TravelerStoryBuffs(w, p)
3939
return &c, nil
4040
}
4141

internal/characters/traveler/common/baseatk.go

Lines changed: 0 additions & 28 deletions
This file was deleted.

internal/characters/traveler/common/dendro/travelerdendro.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
3333
c.SkillCon = 3
3434
c.NormalHitNum = normalHitNum
3535

36-
common.TravelerBaseAtkIncrease(w, p)
36+
common.TravelerStoryBuffs(w, p)
3737
return &c, nil
3838
}
3939

internal/characters/traveler/common/electro/travelerelectro.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
3434
c.SkillCon = 5
3535
c.NormalHitNum = normalHitNum
3636

37-
common.TravelerBaseAtkIncrease(w, p)
37+
common.TravelerStoryBuffs(w, p)
3838
return &c, nil
3939
}
4040

internal/characters/traveler/common/geo/travelergeo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
3232
c.NormalHitNum = normalHitNum
3333
c.skillCD = 6 * 60
3434

35-
common.TravelerBaseAtkIncrease(w, p)
35+
common.TravelerStoryBuffs(w, p)
3636
return &c, nil
3737
}
3838

internal/characters/traveler/common/hydro/travelerhydro.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
2929
c.HasArkhe = true
3030
c.NormalHitNum = normalHitNum
3131

32-
common.TravelerBaseAtkIncrease(w, p)
32+
common.TravelerStoryBuffs(w, p)
3333
return &c, nil
3434
}
3535

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package pyro
2+
3+
import "github.com/genshinsim/gcsim/pkg/core/event"
4+
5+
const a4OnReactICD = "travelerpyro-a4-icd"
6+
7+
func (c *Traveler) a4Init() {
8+
if c.Base.Ascension < 4 {
9+
return
10+
}
11+
fReactionHook := func(args ...interface{}) bool {
12+
// if PMC is in NS Blessing, then the active character should
13+
// be inside a Blazing Threshold or Scorching Threshold since it
14+
// always follows active character
15+
if !c.nightsoulState.HasBlessing() {
16+
return false
17+
}
18+
if c.StatusIsActive(a4OnReactICD) {
19+
return false
20+
}
21+
22+
c.AddStatus(a4OnReactICD, 12, true)
23+
c.AddEnergy("travelerpyro-a4-energy", 5)
24+
return false
25+
}
26+
27+
fNSHook := func(args ...interface{}) bool {
28+
c.AddEnergy("travelerpyro-a4-energy", 4)
29+
return false
30+
}
31+
32+
c.Core.Events.Subscribe(event.OnBurning, fReactionHook, "travelerpyro-a4-onburning")
33+
c.Core.Events.Subscribe(event.OnVaporize, fReactionHook, "travelerpyro-a4-onvaporize")
34+
c.Core.Events.Subscribe(event.OnMelt, fReactionHook, "travelerpyro-a4-onmelt")
35+
c.Core.Events.Subscribe(event.OnOverload, fReactionHook, "travelerpyro-a4-onoverload")
36+
c.Core.Events.Subscribe(event.OnBurgeon, fReactionHook, "travelerpyro-a4-onburgeon")
37+
c.Core.Events.Subscribe(event.OnSwirlPyro, fReactionHook, "travelerpyro-a4-onswirlpyro")
38+
c.Core.Events.Subscribe(event.OnCrystallizePyro, fReactionHook, "travelerpyro-a4-oncrystallizepyro")
39+
c.Core.Events.Subscribe(event.OnNightsoulBurst, fNSHook, "travelerpyro-a4-onnsburst")
40+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package pyro
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/genshinsim/gcsim/internal/frames"
7+
"github.com/genshinsim/gcsim/pkg/core/action"
8+
"github.com/genshinsim/gcsim/pkg/core/attacks"
9+
"github.com/genshinsim/gcsim/pkg/core/attributes"
10+
"github.com/genshinsim/gcsim/pkg/core/combat"
11+
"github.com/genshinsim/gcsim/pkg/core/geometry"
12+
)
13+
14+
var (
15+
attackFrames [][][]int
16+
attackHitmarks = [][]int{{13, 13, 16, 30, 25}, {16, 10, 19, 23, 14}}
17+
attackHitlagHaltFrame = [][]float64{{0.03, 0.03, 0.06, 0.09, 0.12}, {0.03, 0.03, 0.06, 0.06, 0.10}}
18+
attackHitboxes = [][][]float64{{{1.4, 2.2}, {1.7}, {1.5, 2.2}, {1.7}, {1.75}}, {{1.6}, {1.4, 2.2}, {1.5}, {1.5}, {1.6}}}
19+
attackOffsets = [][]float64{{0, 0.6, 0.4, 0.6, 0.6}, {1, 0, 0.7, 0.7, 1}}
20+
attackFanAngles = [][]float64{{360, 180, 360, 360, 240}, {360, 360, 360, 360, 360}}
21+
)
22+
23+
const normalHitNum = 5
24+
25+
func init() {
26+
attackFrames = make([][][]int, 2)
27+
28+
// Male
29+
attackFrames[0] = make([][]int, normalHitNum)
30+
31+
attackFrames[0][0] = frames.InitNormalCancelSlice(attackHitmarks[0][0], 28) // N1 -> CA
32+
attackFrames[0][0][action.ActionAttack] = 17 // N1 -> N2
33+
34+
attackFrames[0][1] = frames.InitNormalCancelSlice(attackHitmarks[0][1], 28) // N2 -> CA
35+
attackFrames[0][1][action.ActionAttack] = 26 // N2 -> N3
36+
37+
attackFrames[0][2] = frames.InitNormalCancelSlice(attackHitmarks[0][2], 36) // N3 -> CA
38+
attackFrames[0][2][action.ActionAttack] = 32 // N3 -> N4
39+
40+
attackFrames[0][3] = frames.InitNormalCancelSlice(attackHitmarks[0][3], 45) // N4 -> CA
41+
attackFrames[0][3][action.ActionAttack] = 39 // N4 -> N5
42+
43+
attackFrames[0][4] = frames.InitNormalCancelSlice(attackHitmarks[0][4], 69) // N5 -> N1
44+
attackFrames[0][4][action.ActionCharge] = 500 // N5 -> CA, TODO: this action is illegal; need better way to handle it
45+
46+
// Female
47+
attackFrames[1] = make([][]int, normalHitNum)
48+
49+
attackFrames[1][0] = frames.InitNormalCancelSlice(attackHitmarks[1][0], 32) // N1 -> CA
50+
attackFrames[1][0][action.ActionAttack] = 24 // N1 -> N2
51+
52+
attackFrames[1][1] = frames.InitNormalCancelSlice(attackHitmarks[1][1], 23) // N2 -> CA
53+
attackFrames[1][1][action.ActionAttack] = 21 // N2 -> N3
54+
55+
attackFrames[1][2] = frames.InitNormalCancelSlice(attackHitmarks[1][2], 39) // N3 -> CA
56+
attackFrames[1][2][action.ActionAttack] = 27 // N3 -> N4
57+
58+
attackFrames[1][3] = frames.InitNormalCancelSlice(attackHitmarks[1][3], 45) // N4 -> CA
59+
attackFrames[1][3][action.ActionAttack] = 38 // N4 -> N5
60+
61+
attackFrames[1][4] = frames.InitNormalCancelSlice(attackHitmarks[1][4], 64) // N5 -> N1
62+
attackFrames[1][4][action.ActionCharge] = 500 // N5 -> CA, TODO: this action is illegal; need better way to handle it
63+
}
64+
65+
func (c *Traveler) Attack(p map[string]int) (action.Info, error) {
66+
ai := combat.AttackInfo{
67+
ActorIndex: c.Index,
68+
Abil: fmt.Sprintf("Normal %v", c.NormalCounter),
69+
AttackTag: attacks.AttackTagNormal,
70+
ICDTag: attacks.ICDTagNormalAttack,
71+
ICDGroup: attacks.ICDGroupDefault,
72+
StrikeType: attacks.StrikeTypeSlash,
73+
Element: attributes.Physical,
74+
Durability: 25,
75+
Mult: attack[c.NormalCounter][c.TalentLvlAttack()],
76+
HitlagFactor: 0.01,
77+
HitlagHaltFrames: attackHitlagHaltFrame[c.gender][c.NormalCounter] * 60,
78+
CanBeDefenseHalted: true,
79+
}
80+
if c.Base.Cons >= 6 && c.nightsoulState.HasBlessing() {
81+
ai.Element = attributes.Pyro
82+
ai.IgnoreInfusion = true
83+
ai.AdditionalTags = []attacks.AdditionalTag{attacks.AdditionalTagNightsoul}
84+
}
85+
ap := combat.NewCircleHitOnTargetFanAngle(
86+
c.Core.Combat.Player(),
87+
geometry.Point{Y: attackOffsets[c.gender][c.NormalCounter]},
88+
attackHitboxes[c.gender][c.NormalCounter][0],
89+
attackFanAngles[c.gender][c.NormalCounter],
90+
)
91+
if (c.gender == 0 && (c.NormalCounter == 0 || c.NormalCounter == 2)) ||
92+
(c.gender == 1 && c.NormalCounter == 1) {
93+
ap = combat.NewBoxHitOnTarget(
94+
c.Core.Combat.Player(),
95+
geometry.Point{Y: attackOffsets[c.gender][c.NormalCounter]},
96+
attackHitboxes[c.gender][c.NormalCounter][0],
97+
attackHitboxes[c.gender][c.NormalCounter][1],
98+
)
99+
}
100+
c.Core.QueueAttack(
101+
ai,
102+
ap,
103+
attackHitmarks[c.gender][c.NormalCounter],
104+
attackHitmarks[c.gender][c.NormalCounter],
105+
)
106+
107+
defer c.AdvanceNormalIndex()
108+
109+
return action.Info{
110+
Frames: frames.NewAttackFunc(c.Character, attackFrames[c.gender]),
111+
AnimationLength: attackFrames[c.gender][c.NormalCounter][action.InvalidAction],
112+
CanQueueAfter: attackHitmarks[c.gender][c.NormalCounter],
113+
State: action.NormalAttackState,
114+
}, nil
115+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package pyro
2+
3+
import (
4+
"github.com/genshinsim/gcsim/internal/frames"
5+
"github.com/genshinsim/gcsim/pkg/core/action"
6+
"github.com/genshinsim/gcsim/pkg/core/attacks"
7+
"github.com/genshinsim/gcsim/pkg/core/attributes"
8+
"github.com/genshinsim/gcsim/pkg/core/combat"
9+
)
10+
11+
var burstFrames [][]int
12+
13+
const (
14+
burstHitmark = 40
15+
)
16+
17+
var (
18+
nightsoulGainDelays = []int{42, 52, 59, 59}
19+
)
20+
21+
func init() {
22+
burstFrames = make([][]int, 2)
23+
24+
// Male
25+
burstFrames[0] = frames.InitAbilSlice(49) // Q -> N1
26+
burstFrames[0][action.ActionSkill] = 48 // Q -> E, Eh
27+
burstFrames[0][action.ActionSwap] = 47
28+
29+
// Female
30+
burstFrames[1] = frames.InitAbilSlice(49) // Q -> N1
31+
burstFrames[1][action.ActionSkill] = 48 // Q -> E, Eh
32+
burstFrames[1][action.ActionSwap] = 47
33+
}
34+
35+
func (c *Traveler) Burst(p map[string]int) (action.Info, error) {
36+
c.SetCD(action.ActionBurst, 18*60)
37+
c.ConsumeEnergy(19)
38+
39+
c.c4AddMod()
40+
41+
ai := combat.AttackInfo{
42+
ActorIndex: c.Index,
43+
Abil: "Plains Scorcher",
44+
AttackTag: attacks.AttackTagElementalBurst,
45+
AdditionalTags: []attacks.AdditionalTag{attacks.AdditionalTagNightsoul},
46+
ICDTag: attacks.ICDTagNone,
47+
ICDGroup: attacks.ICDGroupDefault,
48+
StrikeType: attacks.StrikeTypeDefault,
49+
Element: attributes.Pyro,
50+
Durability: 25,
51+
Mult: burst[c.TalentLvlBurst()],
52+
}
53+
54+
c.Core.QueueAttack(
55+
ai,
56+
combat.NewCircleHitOnTarget(c.Core.Combat.PrimaryTarget(), nil, 4.5),
57+
burstHitmark,
58+
burstHitmark,
59+
)
60+
61+
c.QueueCharTask(c.nightsoulGainFunc(0), nightsoulGainDelays[0])
62+
63+
return action.Info{
64+
Frames: frames.NewAbilFunc(burstFrames[c.gender]),
65+
AnimationLength: burstFrames[c.gender][action.InvalidAction],
66+
CanQueueAfter: burstFrames[c.gender][action.ActionSwap], // earliest cancel
67+
State: action.BurstState,
68+
}, nil
69+
}
70+
71+
func (c *Traveler) nightsoulGainFunc(count int) func() {
72+
return func() {
73+
c.nightsoulState.GeneratePoints(7)
74+
if count < 3 {
75+
c.QueueCharTask(c.nightsoulGainFunc(count+1), nightsoulGainDelays[count+1])
76+
}
77+
}
78+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package pyro
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/genshinsim/gcsim/internal/frames"
7+
"github.com/genshinsim/gcsim/pkg/core/action"
8+
"github.com/genshinsim/gcsim/pkg/core/attacks"
9+
"github.com/genshinsim/gcsim/pkg/core/attributes"
10+
"github.com/genshinsim/gcsim/pkg/core/combat"
11+
)
12+
13+
var chargeFrames [][]int
14+
var chargeHitmarks = [][]int{{9, 20}, {14, 25}}
15+
16+
func init() {
17+
chargeFrames = make([][]int, 2)
18+
// Male
19+
chargeFrames[0] = frames.InitAbilSlice(55) // CA -> N1
20+
chargeFrames[0][action.ActionSkill] = 37 // CA -> E
21+
chargeFrames[0][action.ActionBurst] = 36 // CA -> Q
22+
chargeFrames[0][action.ActionDash] = chargeHitmarks[0][len(chargeHitmarks[0])-1] // CA -> D
23+
chargeFrames[0][action.ActionJump] = chargeHitmarks[0][len(chargeHitmarks[0])-1] // CA -> J
24+
chargeFrames[0][action.ActionSwap] = 44 // CA -> Swap
25+
26+
// Female
27+
chargeFrames[1] = frames.InitAbilSlice(58) // CA -> N1
28+
chargeFrames[1][action.ActionSkill] = 34 // CA -> E
29+
chargeFrames[1][action.ActionBurst] = 35 // CA -> Q
30+
chargeFrames[1][action.ActionDash] = chargeHitmarks[1][len(chargeHitmarks[1])-1] // CA -> D
31+
chargeFrames[1][action.ActionJump] = chargeHitmarks[1][len(chargeHitmarks[1])-1] // CA -> J
32+
chargeFrames[1][action.ActionSwap] = chargeHitmarks[1][len(chargeHitmarks[1])-1] // CA -> Swap
33+
}
34+
35+
func (c *Traveler) ChargeAttack(p map[string]int) (action.Info, error) {
36+
ai := combat.AttackInfo{
37+
ActorIndex: c.Index,
38+
AttackTag: attacks.AttackTagExtra,
39+
ICDTag: attacks.ICDTagNormalAttack,
40+
ICDGroup: attacks.ICDGroupDefault,
41+
StrikeType: attacks.StrikeTypeSlash,
42+
Element: attributes.Physical,
43+
Durability: 25,
44+
}
45+
if c.Base.Cons >= 6 && c.nightsoulState.HasBlessing() {
46+
ai.Element = attributes.Pyro
47+
ai.IgnoreInfusion = true
48+
ai.AdditionalTags = []attacks.AdditionalTag{attacks.AdditionalTagNightsoul}
49+
}
50+
51+
for i, mult := range charge[c.gender] {
52+
ai.Mult = mult[c.TalentLvlAttack()]
53+
ai.Abil = fmt.Sprintf("Charge %v", i)
54+
c.Core.QueueAttack(
55+
ai,
56+
combat.NewCircleHitOnTarget(c.Core.Combat.Player(), nil, 2.2),
57+
chargeHitmarks[c.gender][i],
58+
chargeHitmarks[c.gender][i],
59+
)
60+
}
61+
62+
return action.Info{
63+
Frames: frames.NewAbilFunc(chargeFrames[c.gender]),
64+
AnimationLength: chargeFrames[c.gender][action.InvalidAction],
65+
CanQueueAfter: chargeHitmarks[c.gender][len(chargeHitmarks[c.gender])-1],
66+
State: action.ChargeAttackState,
67+
}, nil
68+
}

0 commit comments

Comments
 (0)