@@ -15,6 +15,12 @@ import (
1515var (
1616 highPlungeFrames []int
1717 fieryHighPlungeFrames []int
18+
19+ xianyunLowPlungeFrames []int
20+ xianyunHighPlungeFrames []int
21+
22+ xianyunFieryLowPlungeFrames []int
23+ xianyunFieryHighPlungeFrames []int
1824)
1925
2026// TODO: low_plunge
@@ -23,6 +29,16 @@ const highPlungeHitmark = 37
2329const fieryHighPlungeHitmark = 41
2430const collisionHitmark = highPlungeHitmark - 6
2531
32+ const xianyunLowPlungeHitmark = 37
33+ const xianyunHighPlungeHitmark = 38
34+
35+ const xianyunLowPlungeNonNSWalk = 72
36+ const xianyunHighPlungeNonNSWalk = 72
37+
38+ const xianyunFieryLowPlungeHitmark = 40
39+ const xianyunFieryHighPlungeHitmark = 40
40+
41+ const lowPlungeRadius = 3.0
2642const highPlungeRadius = 5.0
2743
2844const (
@@ -50,6 +66,46 @@ func init() {
5066 fieryHighPlungeFrames [action .ActionDash ] = 40
5167 fieryHighPlungeFrames [action .ActionJump ] = 79
5268 fieryHighPlungeFrames [action .ActionSwap ] = 45
69+
70+ // xianyun low_plunge -> x
71+ xianyunLowPlungeFrames = frames .InitAbilSlice (75 ) // Plunge -> Walk
72+ xianyunLowPlungeFrames [action .ActionAttack ] = 40
73+ xianyunLowPlungeFrames [action .ActionCharge ] = 39
74+ xianyunLowPlungeFrames [action .ActionSkill ] = 39
75+ xianyunLowPlungeFrames [action .ActionBurst ] = 39
76+ xianyunLowPlungeFrames [action .ActionDash ] = xianyunLowPlungeHitmark
77+ xianyunLowPlungeFrames [action .ActionJump ] = 50
78+ xianyunLowPlungeFrames [action .ActionSwap ] = 38
79+
80+ // xianyun high_plunge -> x
81+ xianyunHighPlungeFrames = frames .InitAbilSlice (77 ) // Plunge -> Walk
82+ xianyunHighPlungeFrames [action .ActionAttack ] = 39
83+ xianyunHighPlungeFrames [action .ActionCharge ] = 40
84+ xianyunHighPlungeFrames [action .ActionSkill ] = 39
85+ xianyunHighPlungeFrames [action .ActionBurst ] = 39
86+ xianyunHighPlungeFrames [action .ActionDash ] = xianyunHighPlungeHitmark
87+ xianyunHighPlungeFrames [action .ActionJump ] = 49
88+ xianyunHighPlungeFrames [action .ActionSwap ] = 39
89+
90+ // xianyun nightsoul low_plunge -> x
91+ xianyunFieryLowPlungeFrames = frames .InitAbilSlice (91 ) // Plunge -> Walk
92+ xianyunFieryLowPlungeFrames [action .ActionAttack ] = 46
93+ xianyunFieryLowPlungeFrames [action .ActionCharge ] = 45
94+ xianyunFieryLowPlungeFrames [action .ActionSkill ] = 45
95+ xianyunFieryLowPlungeFrames [action .ActionBurst ] = 46
96+ xianyunFieryLowPlungeFrames [action .ActionDash ] = xianyunFieryLowPlungeHitmark
97+ xianyunFieryLowPlungeFrames [action .ActionJump ] = 76
98+ xianyunFieryLowPlungeFrames [action .ActionSwap ] = 46
99+
100+ // xianyun nightsoul high_plunge -> x
101+ xianyunFieryHighPlungeFrames = frames .InitAbilSlice (91 ) // Plunge -> Walk
102+ xianyunFieryHighPlungeFrames [action .ActionAttack ] = 47
103+ xianyunFieryHighPlungeFrames [action .ActionCharge ] = 47
104+ xianyunFieryHighPlungeFrames [action .ActionSkill ] = 47
105+ xianyunFieryHighPlungeFrames [action .ActionBurst ] = 47
106+ xianyunFieryHighPlungeFrames [action .ActionDash ] = xianyunFieryHighPlungeHitmark
107+ xianyunFieryHighPlungeFrames [action .ActionJump ] = 77
108+ xianyunFieryHighPlungeFrames [action .ActionSwap ] = 46
53109}
54110
55111// High Plunge attack damage queue generator
@@ -58,12 +114,30 @@ func init() {
58114func (c * char ) HighPlungeAttack (p map [string ]int ) (action.Info , error ) {
59115 defer c .Core .Player .SetAirborne (player .Grounded )
60116 if c .Core .Player .CurrentState () == action .ChargeAttackState {
117+ return c .highPlungeCA (p ), nil
118+ }
119+ switch c .Core .Player .Airborne () {
120+ case player .AirborneXianyun :
61121 return c .highPlungeXY (p ), nil
122+ default :
123+ return action.Info {}, errors .New ("high_plunge can only be used after charge or while airborne" )
62124 }
63- return action.Info {}, errors .New ("high_plunge can only be used after charge" )
64125}
65126
66- func (c * char ) highPlungeXY (p map [string ]int ) action.Info {
127+ // Low Plunge attack damage queue generator
128+ // Use the "collision" optional argument if you want to do a falling hit on the way down
129+ // Default = 0
130+ func (c * char ) LowPlungeAttack (p map [string ]int ) (action.Info , error ) {
131+ defer c .Core .Player .SetAirborne (player .Grounded )
132+ switch c .Core .Player .Airborne () {
133+ case player .AirborneXianyun :
134+ return c .lowPlungeXY (p ), nil
135+ default :
136+ return action.Info {}, errors .New ("low_plunge can only be used while airborne" )
137+ }
138+ }
139+
140+ func (c * char ) highPlungeCA (p map [string ]int ) action.Info {
67141 collision , ok := p ["collision" ]
68142 if ! ok {
69143 collision = 0 // Whether or not collision hit
@@ -124,6 +198,138 @@ func (c *char) highPlungeXY(p map[string]int) action.Info {
124198 }
125199}
126200
201+ func (c * char ) highPlungeXY (p map [string ]int ) action.Info {
202+ collision , ok := p ["collision" ]
203+ if ! ok {
204+ collision = 0 // Whether or not collision hit
205+ }
206+
207+ if collision > 0 {
208+ c .plungeCollision (collisionHitmark )
209+ }
210+
211+ ai := combat.AttackInfo {
212+ ActorIndex : c .Index ,
213+ Abil : "High Plunge" ,
214+ AdditionalTags : []attacks.AdditionalTag {attacks .AdditionalTagNightsoul },
215+ AttackTag : attacks .AttackTagPlunge ,
216+ ICDTag : attacks .ICDTagNone ,
217+ ICDGroup : attacks .ICDGroupDefault ,
218+ StrikeType : attacks .StrikeTypeDefault ,
219+ Element : attributes .Electro ,
220+ Durability : 25 ,
221+ Mult : highPlunge [c .TalentLvlAttack ()],
222+ FlatDmg : c .c4FlatBonus (),
223+ HitlagFactor : 0.1 ,
224+ }
225+
226+ hitmark := xianyunHighPlungeHitmark
227+ c .exitNS = false
228+ plungeFrames := c .newAbilFuncXYPlunge (xianyunHighPlungeFrames , xianyunHighPlungeNonNSWalk )
229+ if c .nightsoulState .HasBlessing () {
230+ ai .Abil = "Fiery Passion High Plunge"
231+ ai .Mult = fieryHighPlunge [c .TalentLvlAttack ()]
232+ hitmark = xianyunFieryHighPlungeHitmark
233+ c .exitNS = true
234+ plungeFrames = frames .NewAbilFunc (xianyunFieryHighPlungeFrames )
235+
236+ c .QueueCharTask (c .nightsoulState .ClearPoints , 2 )
237+ } else {
238+ c .QueueCharTask (c .generatePlungeNightsoul , hitmark )
239+ }
240+ ai .Mult += c .a1PlungeBuff ()
241+ c .getApexDrive ()
242+
243+ c .Core .QueueAttack (
244+ ai ,
245+ combat .NewCircleHitOnTarget (c .Core .Combat .Player (), geometry.Point {Y : 1 }, highPlungeRadius ),
246+ hitmark ,
247+ hitmark ,
248+ c .a1Cancel ,
249+ c .c2CB (),
250+ c .c4CB ,
251+ )
252+
253+ return action.Info {
254+ Frames : plungeFrames ,
255+ AnimationLength : plungeFrames (action .InvalidAction ),
256+ CanQueueAfter : plungeFrames (action .ActionDash ),
257+ State : action .PlungeAttackState ,
258+ OnRemoved : c .clearNightsoulCB ,
259+ }
260+ }
261+
262+ func (c * char ) lowPlungeXY (p map [string ]int ) action.Info {
263+ collision , ok := p ["collision" ]
264+ if ! ok {
265+ collision = 0 // Whether or not collision hit
266+ }
267+
268+ if collision > 0 {
269+ c .plungeCollision (collisionHitmark )
270+ }
271+
272+ ai := combat.AttackInfo {
273+ ActorIndex : c .Index ,
274+ Abil : "Low Plunge" ,
275+ AdditionalTags : []attacks.AdditionalTag {attacks .AdditionalTagNightsoul },
276+ AttackTag : attacks .AttackTagPlunge ,
277+ ICDTag : attacks .ICDTagNone ,
278+ ICDGroup : attacks .ICDGroupDefault ,
279+ StrikeType : attacks .StrikeTypeDefault ,
280+ Element : attributes .Electro ,
281+ Durability : 25 ,
282+ Mult : lowPlunge [c .TalentLvlAttack ()],
283+ FlatDmg : c .c4FlatBonus (),
284+ HitlagFactor : 0.1 ,
285+ }
286+
287+ hitmark := xianyunLowPlungeHitmark
288+ c .exitNS = false
289+ plungeFrames := c .newAbilFuncXYPlunge (xianyunLowPlungeFrames , xianyunLowPlungeNonNSWalk )
290+ if c .nightsoulState .HasBlessing () {
291+ ai .Abil = "Fiery Passion Low Plunge"
292+ ai .Mult = fieryLowPlunge [c .TalentLvlAttack ()]
293+ hitmark = xianyunFieryLowPlungeHitmark
294+ c .exitNS = true
295+ plungeFrames = frames .NewAbilFunc (xianyunFieryLowPlungeFrames )
296+
297+ c .QueueCharTask (c .nightsoulState .ClearPoints , 2 )
298+ } else {
299+ c .QueueCharTask (c .generatePlungeNightsoul , hitmark )
300+ }
301+ ai .Mult += c .a1PlungeBuff ()
302+ c .getApexDrive ()
303+
304+ c .Core .QueueAttack (
305+ ai ,
306+ combat .NewCircleHitOnTarget (c .Core .Combat .Player (), geometry.Point {Y : 1 }, lowPlungeRadius ),
307+ hitmark ,
308+ hitmark ,
309+ c .a1Cancel ,
310+ c .c2CB (),
311+ c .c4CB ,
312+ )
313+
314+ return action.Info {
315+ Frames : plungeFrames ,
316+ AnimationLength : plungeFrames (action .InvalidAction ),
317+ CanQueueAfter : plungeFrames (action .ActionDash ),
318+ State : action .PlungeAttackState ,
319+ OnRemoved : c .clearNightsoulCB ,
320+ }
321+ }
322+
323+ func (c * char ) newAbilFuncXYPlunge (slice []int , nonNSWalk int ) func (action.Action ) int {
324+ // This is different because the walk frames after plunge change based on if in nightsoul or not
325+ return func (next action.Action ) int {
326+ if ! c .nightsoulState .HasBlessing () && next == action .ActionWalk {
327+ return nonNSWalk
328+ }
329+ return slice [next ]
330+ }
331+ }
332+
127333// Plunge normal falling attack damage queue generator
128334// Standard - Always part of high/low plunge attacks
129335func (c * char ) plungeCollision (delay int ) {
0 commit comments