Repository: genshinsim/gcsim
Pull request #175 (2022-01-20 06:35:16)

Bugfixes: Ayaka/Mona ICD, Heart of Depth, Burst CDs and various Burst bugs
From commit comments:
- Fix Ayaka NA/Dash and Mona Dash having no ICD
- Fix Heart of Depth artifact set not having active character check
- Change burst CDs to start at energy drain; Fixes several burst bugs. 
   - Fixes following burst bugs:
   - Gorou burst CD was incorrect
   - Kaeya C6 energy refund didn't work
   - Kokomi burst drained way too late
   - Added Shenhe and Yun Jin energy drain frames


Patch:
diff --git a/internal/artifacts/heartofdepth/heartofdepth.go b/internal/artifacts/heartofdepth/heartofdepth.go
index 162220896..9cdbdc6f2 100644
--- a/internal/artifacts/heartofdepth/heartofdepth.go
+++ b/internal/artifacts/heartofdepth/heartofdepth.go
@@ -30,6 +30,9 @@ func New(c core.Character, s *core.Core, count int, params map[string]int) {
 		m[core.DmgP] = 0.3
 
 		s.Events.Subscribe(core.PostSkill, func(args ...interface{}) bool {
+			if s.ActiveChar != c.CharIndex() {
+				return false
+			}
 			s.Status.AddStatus(key, 900) //activate for 15 seoncds
 			//add stat mod here
 			c.AddPreDamageMod(core.PreDamageMod{
diff --git a/internal/characters/albedo/albedo.go b/internal/characters/albedo/albedo.go
index 08f48de93..d8ff16eab 100644
--- a/internal/characters/albedo/albedo.go
+++ b/internal/characters/albedo/albedo.go
@@ -301,7 +301,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		})
 	}
 
-	c.SetCD(core.ActionSkill, 720)
+	c.SetCDWithDelay(core.ActionSkill, 720, 80)
 	c.ConsumeEnergy(80)
 	return f, a
 }
diff --git a/internal/characters/aloy/abil.go b/internal/characters/aloy/abil.go
index 3bd5c3c96..038722378 100644
--- a/internal/characters/aloy/abil.go
+++ b/internal/characters/aloy/abil.go
@@ -230,8 +230,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 	c.Core.Combat.QueueAttack(ai, core.NewDefCircHit(3, false, core.TargettableEnemy), f, f)
 
-	c.SetCD(core.ActionBurst, 12*60)
-	// TODO: Not sure when energy drain happens
+	c.SetCDWithDelay(core.ActionBurst, 12*60, 8)
 	c.ConsumeEnergy(8)
 
 	return f, a
diff --git a/internal/characters/amber/abil.go b/internal/characters/amber/abil.go
index 7f7352dff..93cc73038 100644
--- a/internal/characters/amber/abil.go
+++ b/internal/characters/amber/abil.go
@@ -190,6 +190,6 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	c.ConsumeEnergy(64)
-	c.SetCD(core.ActionBurst, 720)
+	c.SetCDWithDelay(core.ActionBurst, 720, 64)
 	return f, a
 }
diff --git a/internal/characters/ayaka/abil.go b/internal/characters/ayaka/abil.go
index 67adbd346..9df1b6afd 100644
--- a/internal/characters/ayaka/abil.go
+++ b/internal/characters/ayaka/abil.go
@@ -14,7 +14,7 @@ func (c *char) Attack(p map[string]int) (int, int) {
 		Abil:       fmt.Sprintf("Normal %v", c.NormalCounter),
 		ActorIndex: c.Index,
 		AttackTag:  core.AttackTagNormal,
-		ICDTag:     core.ICDTagNone,
+		ICDTag:     core.ICDTagNormalAttack,
 		ICDGroup:   core.ICDGroupDefault,
 		Element:    core.Physical,
 		Durability: 25,
@@ -62,7 +62,7 @@ func (c *char) Dash(p map[string]int) (int, int) {
 		Abil:       "Dash",
 		ActorIndex: c.Index,
 		AttackTag:  core.AttackTagNone,
-		ICDTag:     core.ICDTagNone,
+		ICDTag:     core.ICDTagDash,
 		ICDGroup:   core.ICDGroupDefault,
 		Element:    core.Cryo,
 		Durability: 25,
@@ -160,7 +160,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		c.Core.Combat.QueueAttack(ai, core.NewDefCircHit(5, false, core.TargettableEnemy), f, f+i*15)
 	}
 
-	c.SetCD(core.ActionBurst, 20*60)
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 13)
 	c.ConsumeEnergy(13)
 
 	return f, a
diff --git a/internal/characters/beidou/abil.go b/internal/characters/beidou/abil.go
index d56a2ff36..02ba405bc 100644
--- a/internal/characters/beidou/abil.go
+++ b/internal/characters/beidou/abil.go
@@ -129,7 +129,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	c.ConsumeEnergy(11)
-	c.SetCD(core.ActionBurst, 1200)
+	c.SetCDWithDelay(core.ActionBurst, 1200, 11)
 	return f, a
 }
 
diff --git a/internal/characters/bennett/bennett.go b/internal/characters/bennett/bennett.go
index dba1e78e2..5dc786c6c 100644
--- a/internal/characters/bennett/bennett.go
+++ b/internal/characters/bennett/bennett.go
@@ -257,7 +257,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	c.ConsumeEnergy(42)
-	c.SetCD(core.ActionBurst, 900)
+	c.SetCDWithDelay(core.ActionBurst, 900, 42)
 	return f, a //todo fix field cast time
 }
 
diff --git a/internal/characters/chongyun/abil.go b/internal/characters/chongyun/abil.go
index 1d4fe2d32..ec79337cc 100644
--- a/internal/characters/chongyun/abil.go
+++ b/internal/characters/chongyun/abil.go
@@ -150,7 +150,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		c.Core.Combat.QueueAttack(ai, core.NewDefCircHit(5, false, core.TargettableEnemy), 76, 76)
 	}
 
-	c.SetCD(core.ActionBurst, 720)
+	c.SetCDWithDelay(core.ActionBurst, 720, 10)
 	c.ConsumeEnergy(10)
 	return f, a
 }
diff --git a/internal/characters/diluc/abil.go b/internal/characters/diluc/abil.go
index 1b3557231..91126bfe6 100644
--- a/internal/characters/diluc/abil.go
+++ b/internal/characters/diluc/abil.go
@@ -155,6 +155,6 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}, "diluc-burst", 100)
 
 	c.ConsumeEnergy(24)
-	c.SetCD(core.ActionBurst, 720)
+	c.SetCDWithDelay(core.ActionBurst, 720, 24)
 	return f, a
 }
diff --git a/internal/characters/diona/abil.go b/internal/characters/diona/abil.go
index 510d2d509..977802448 100644
--- a/internal/characters/diona/abil.go
+++ b/internal/characters/diona/abil.go
@@ -187,7 +187,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		}, "c6-em-share", f)
 	}
 
-	c.SetCD(core.ActionBurst, 1200+f)
+	c.SetCDWithDelay(core.ActionBurst, 1200, 49)
 	c.ConsumeEnergy(49)
 	return f, a
 }
diff --git a/internal/characters/eula/abil.go b/internal/characters/eula/abil.go
index 2853babe7..9a12658fd 100644
--- a/internal/characters/eula/abil.go
+++ b/internal/characters/eula/abil.go
@@ -218,7 +218,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		}
 	}, "Eula-Burst-Lightfall", 7*60+f) //after 8 seconds
 
-	c.SetCD(core.ActionBurst, 20*60+f)
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 107)
 	//energy does not deplete until after animation
 	c.ConsumeEnergy(107)
 
diff --git a/internal/characters/fischl/fischl.go b/internal/characters/fischl/fischl.go
index e644a319b..7100055a3 100644
--- a/internal/characters/fischl/fischl.go
+++ b/internal/characters/fischl/fischl.go
@@ -246,6 +246,6 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	c.ConsumeEnergy(11)
-	c.SetCD(core.ActionBurst, 15*60)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 11)
 	return f, a
 }
diff --git a/internal/characters/ganyu/abil.go b/internal/characters/ganyu/abil.go
index 29fbfb9b1..256ed42d4 100644
--- a/internal/characters/ganyu/abil.go
+++ b/internal/characters/ganyu/abil.go
@@ -236,7 +236,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	//add cooldown to sim
-	c.SetCD(core.ActionBurst, 15*60)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 8)
 	//use up energy
 	c.ConsumeEnergy(8)
 
diff --git a/internal/characters/gorou/abil.go b/internal/characters/gorou/abil.go
index f1f7a18f8..fe18b30c4 100644
--- a/internal/characters/gorou/abil.go
+++ b/internal/characters/gorou/abil.go
@@ -255,7 +255,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 
 	c.c2Extension = 0
 
-	c.SetCD(core.ActionBurst, 18*60) //20s cd
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 8)
 	c.ConsumeEnergy(8)
 	return f, a
 }
diff --git a/internal/characters/hutao/abil.go b/internal/characters/hutao/abil.go
index acba75094..78644c96b 100644
--- a/internal/characters/hutao/abil.go
+++ b/internal/characters/hutao/abil.go
@@ -225,6 +225,6 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	c.Core.Combat.QueueAttack(ai, core.NewDefCircHit(5, false, core.TargettableEnemy), f-5, f-5)
 
 	c.ConsumeEnergy(73)
-	c.SetCD(core.ActionBurst, 900)
+	c.SetCDWithDelay(core.ActionBurst, 900, 73)
 	return f, a
 }
diff --git a/internal/characters/kaeya/kaeya.go b/internal/characters/kaeya/kaeya.go
index 5d975ac53..304c24a29 100644
--- a/internal/characters/kaeya/kaeya.go
+++ b/internal/characters/kaeya/kaeya.go
@@ -176,14 +176,12 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		}
 	}
 
+	c.ConsumeEnergy(55)
 	if c.Base.Cons == 6 {
-		c.Energy = 15
-	} else {
-		c.ConsumeEnergy(55)
+		c.AddTask(func() { c.AddEnergy(15) }, "kaeya-c6", 56)
 	}
 
-	// c.CD[def.BurstCD] = c.Sim.F + 900
-	c.SetCD(core.ActionBurst, 900)
+	c.SetCDWithDelay(core.ActionBurst, 900, 55)
 	return f, a
 }
 
diff --git a/internal/characters/kazuha/abil.go b/internal/characters/kazuha/abil.go
index d0dd11e04..3726611e6 100644
--- a/internal/characters/kazuha/abil.go
+++ b/internal/characters/kazuha/abil.go
@@ -235,7 +235,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		c.c6Active = c.Core.F + f + 300
 	}
 
-	c.SetCD(core.ActionBurst, 15*60)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 7)
 	c.ConsumeEnergy(7)
 	return f, a
 }
diff --git a/internal/characters/keqing/abil.go b/internal/characters/keqing/abil.go
index 65202a0fe..916e48697 100644
--- a/internal/characters/keqing/abil.go
+++ b/internal/characters/keqing/abil.go
@@ -227,7 +227,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 
 	c.ConsumeEnergy(60)
 	// c.CD[def.BurstCD] = c.Core.F + 720 //12s
-	c.SetCD(core.ActionBurst, 720)
+	c.SetCDWithDelay(core.ActionBurst, 720, 60)
 
 	return f, a
 }
diff --git a/internal/characters/klee/abil.go b/internal/characters/klee/abil.go
index 734378a1d..db12176dc 100644
--- a/internal/characters/klee/abil.go
+++ b/internal/characters/klee/abil.go
@@ -270,7 +270,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 
 	c.c1(132)
 
-	c.SetCD(core.ActionBurst, 15*60)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 15)
 	c.ConsumeEnergy(15)
 	return f, a
 }
diff --git a/internal/characters/kokomi/abil.go b/internal/characters/kokomi/abil.go
index c29cd978d..ebf07f40e 100644
--- a/internal/characters/kokomi/abil.go
+++ b/internal/characters/kokomi/abil.go
@@ -235,11 +235,8 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	// Cannot be prefed particles
-	c.AddTask(func() {
-		c.ConsumeEnergy(57)
-	}, "kokomi-q-energy-drain", f)
-
-	c.SetCD(core.ActionBurst, 18*60)
+	c.ConsumeEnergy(57)
+	c.SetCDWithDelay(core.ActionBurst, 18*60, 57)
 	return f, a
 }
 
diff --git a/internal/characters/lisa/abil.go b/internal/characters/lisa/abil.go
index d130f5314..faafcb26a 100644
--- a/internal/characters/lisa/abil.go
+++ b/internal/characters/lisa/abil.go
@@ -229,7 +229,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 
 	c.ConsumeEnergy(64)
 	// c.CD[def.BurstCD] = c.Core.F + 1200
-	c.SetCD(core.ActionBurst, 1200)
+	c.SetCDWithDelay(core.ActionBurst, 1200, 64)
 	return f, a
 }
 
diff --git a/internal/characters/mona/abil.go b/internal/characters/mona/abil.go
index 7cf9e39bd..dd095e202 100644
--- a/internal/characters/mona/abil.go
+++ b/internal/characters/mona/abil.go
@@ -58,7 +58,7 @@ func (c *char) Dash(p map[string]int) (int, int) {
 		Abil:       "Dash",
 		ActorIndex: c.Index,
 		AttackTag:  core.AttackTagNone,
-		ICDTag:     core.ICDTagNone,
+		ICDTag:     core.ICDTagDash,
 		ICDGroup:   core.ICDGroupDefault,
 		Element:    core.Hydro,
 		Durability: 25,
@@ -158,7 +158,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 	c.Core.Combat.QueueAttack(aiBreak, core.NewDefCircHit(4, false, core.TargettableEnemy), -1, 102+480)
 
-	c.SetCD(core.ActionBurst, 15*60)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 13)
 	c.ConsumeEnergy(13)
 	return f, a
 }
diff --git a/internal/characters/ningguang/abil.go b/internal/characters/ningguang/abil.go
index 077e8fe7a..b3198994c 100644
--- a/internal/characters/ningguang/abil.go
+++ b/internal/characters/ningguang/abil.go
@@ -168,6 +168,6 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	c.ConsumeEnergy(8)
-	c.SetCD(core.ActionBurst, 720)
+	c.SetCDWithDelay(core.ActionBurst, 720, 8)
 	return f, a
 }
diff --git a/internal/characters/noelle/abil.go b/internal/characters/noelle/abil.go
index 95159a6b4..cb2c2db16 100644
--- a/internal/characters/noelle/abil.go
+++ b/internal/characters/noelle/abil.go
@@ -245,7 +245,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	// TODO: Not sure of the exact frames
 	c.Core.Combat.QueueAttack(ai, core.NewDefCircHit(4.5, false, core.TargettableEnemy), f-10, f-10)
 
-	c.SetCD(core.ActionBurst, 900)
+	c.SetCDWithDelay(core.ActionBurst, 900, 8)
 	c.ConsumeEnergy(8)
 	return f, a
 }
diff --git a/internal/characters/qiqi/abil.go b/internal/characters/qiqi/abil.go
index 5e8293500..89198c22a 100644
--- a/internal/characters/qiqi/abil.go
+++ b/internal/characters/qiqi/abil.go
@@ -201,7 +201,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	c.Core.Combat.QueueAttack(ai, core.NewDefCircHit(5, false, core.TargettableEnemy), f, f)
-	c.SetCD(core.ActionBurst, 20*60)
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 10)
 	c.ConsumeEnergy(10)
 
 	return f, a
diff --git a/internal/characters/raiden/abil.go b/internal/characters/raiden/abil.go
index 90be27bfa..2ca9bfd3b 100644
--- a/internal/characters/raiden/abil.go
+++ b/internal/characters/raiden/abil.go
@@ -305,7 +305,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 	c.Core.Combat.QueueAttack(ai, core.NewDefCircHit(2, false, core.TargettableEnemy), f, f)
 
-	c.SetCD(core.ActionBurst, 18*60) //20s cd
+	c.SetCDWithDelay(core.ActionBurst, 18*60, 12)
 	c.ConsumeEnergy(12)
 	return f, a
 }
diff --git a/internal/characters/rosaria/abil.go b/internal/characters/rosaria/abil.go
index c7e28c04f..7507d0a9f 100644
--- a/internal/characters/rosaria/abil.go
+++ b/internal/characters/rosaria/abil.go
@@ -199,7 +199,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		})
 	}
 
-	c.SetCD(core.ActionBurst, 15*60)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 12)
 	c.ConsumeEnergy(12)
 
 	return f, a
diff --git a/internal/characters/sara/abil.go b/internal/characters/sara/abil.go
index 04ad8ced7..c6a595245 100644
--- a/internal/characters/sara/abil.go
+++ b/internal/characters/sara/abil.go
@@ -258,7 +258,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		}
 	}, "sara-q-snapshot", f)
 
-	c.SetCD(core.ActionBurst, 20*60)
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 54)
 	c.ConsumeEnergy(54)
 
 	return f, a
diff --git a/internal/characters/shenhe/abil.go b/internal/characters/shenhe/abil.go
index 7f0816138..2f03ee286 100644
--- a/internal/characters/shenhe/abil.go
+++ b/internal/characters/shenhe/abil.go
@@ -185,8 +185,8 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		}
 	}, "shenhe-snapshot", f+2)
 
-	c.SetCD(core.ActionBurst, 20*60)
-	c.ConsumeEnergy(0)
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 11)
+	c.ConsumeEnergy(11)
 
 	return f, a
 }
diff --git a/internal/characters/shenhe/cd.go b/internal/characters/shenhe/cd.go
index 67bf03d67..8247afa78 100644
--- a/internal/characters/shenhe/cd.go
+++ b/internal/characters/shenhe/cd.go
@@ -34,6 +34,14 @@ func (c *char) SetCD(a core.ActionType, dur int) {
 	)
 }
 
+func (c *char) SetCDWithDelay(a core.ActionType, dur int, delay int) {
+	if delay == 0 {
+		c.SetCD(a, dur)
+		return
+	}
+	c.AddTask(func() { c.SetCD(a, dur) }, "set-cd", delay)
+}
+
 func (c *char) Cooldown(a core.ActionType) int {
 	//remaining cooldown is src + first item in queue - current frame
 	if c.availableCDCharge[a] > 0 {
diff --git a/internal/characters/sucrose/abil.go b/internal/characters/sucrose/abil.go
index 7f89d1e39..c9173467b 100644
--- a/internal/characters/sucrose/abil.go
+++ b/internal/characters/sucrose/abil.go
@@ -153,7 +153,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	//
 	c.AddTask(c.absorbCheck(c.Core.F, 0, int(duration/18)), "absorb-check", f)
 
-	c.SetCD(core.ActionBurst, 1200)
+	c.SetCDWithDelay(core.ActionBurst, 1200, 26)
 	c.ConsumeEnergy(26)
 	return f, a
 }
diff --git a/internal/characters/tartaglia/abil.go b/internal/characters/tartaglia/abil.go
index 6d50149cc..3c27d9f1d 100644
--- a/internal/characters/tartaglia/abil.go
+++ b/internal/characters/tartaglia/abil.go
@@ -274,10 +274,11 @@ func (c *char) Burst(p map[string]int) (int, int) {
 
 	if c.Core.Status.Duration("tartagliamelee") == 0 {
 		c.ConsumeEnergy(8)
+		c.SetCDWithDelay(core.ActionBurst, 900, 8)
 	} else {
 		c.ConsumeEnergy(75)
+		c.SetCDWithDelay(core.ActionBurst, 900, 75)
 	}
 
-	c.SetCD(core.ActionBurst, 900)
 	return f, a
 }
diff --git a/internal/characters/travelergeo/abil.go b/internal/characters/travelergeo/abil.go
index 2ee2b79b8..53290af10 100644
--- a/internal/characters/travelergeo/abil.go
+++ b/internal/characters/travelergeo/abil.go
@@ -140,6 +140,6 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}, "geomc-wall", f)
 
 	c.ConsumeEnergy(43)
-	c.SetCD(core.ActionBurst, 900)
+	c.SetCDWithDelay(core.ActionBurst, 900, 43)
 	return f, a
 }
diff --git a/internal/characters/venti/abil.go b/internal/characters/venti/abil.go
index 8cbaa8479..b7ee94087 100644
--- a/internal/characters/venti/abil.go
+++ b/internal/characters/venti/abil.go
@@ -136,7 +136,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		c.a4Restore()
 	}, "venti-a4-restore", 480+f)
 
-	c.SetCD(core.ActionBurst, 15*60)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 90)
 	c.ConsumeEnergy(90)
 	return f, a
 }
diff --git a/internal/characters/xiangling/xiangling.go b/internal/characters/xiangling/xiangling.go
index b0cc70e43..367ea1964 100644
--- a/internal/characters/xiangling/xiangling.go
+++ b/internal/characters/xiangling/xiangling.go
@@ -266,7 +266,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	//add cooldown to sim
-	c.SetCD(core.ActionBurst, 20*60)
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 29)
 	//use up energy
 	c.ConsumeEnergy(29)
 
diff --git a/internal/characters/xiao/abil.go b/internal/characters/xiao/abil.go
index bb97b4fff..ecf5ea036 100644
--- a/internal/characters/xiao/abil.go
+++ b/internal/characters/xiao/abil.go
@@ -253,7 +253,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}
 
 	// Checked gameplay - burst starts ticking down from activation. CD is 16.6 seconds after animation is done
-	c.SetCD(core.ActionBurst, 18*60)
+	c.SetCDWithDelay(core.ActionBurst, 18*60, 39)
 	c.ConsumeEnergy(39)
 
 	return f, a
diff --git a/internal/characters/xingqiu/xingqiu.go b/internal/characters/xingqiu/xingqiu.go
index 712015d42..f8550cff5 100644
--- a/internal/characters/xingqiu/xingqiu.go
+++ b/internal/characters/xingqiu/xingqiu.go
@@ -240,7 +240,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	c.numSwords = 2
 
 	// c.CD[combat.BurstCD] = c.S.F + 20*60
-	c.SetCD(core.ActionBurst, 20*60)
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 7)
 	c.ConsumeEnergy(7)
 	return f, a
 }
diff --git a/internal/characters/yanfei/abil.go b/internal/characters/yanfei/abil.go
index f72eb4516..409a32351 100644
--- a/internal/characters/yanfei/abil.go
+++ b/internal/characters/yanfei/abil.go
@@ -190,7 +190,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 
 	c.c4()
 
-	c.SetCD(core.ActionBurst, 20*60)
+	c.SetCDWithDelay(core.ActionBurst, 20*60, 8)
 	c.ConsumeEnergy(8)
 
 	return f, a
diff --git a/internal/characters/yoimiya/abil.go b/internal/characters/yoimiya/abil.go
index 38ec69308..4583235cd 100644
--- a/internal/characters/yoimiya/abil.go
+++ b/internal/characters/yoimiya/abil.go
@@ -135,7 +135,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 	}, "start-blaze", f)
 
 	//add cooldown to sim
-	c.SetCD(core.ActionBurst, 15*60)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 5)
 	//use up energy
 	c.ConsumeEnergy(5)
 
diff --git a/internal/characters/yunjin/abil.go b/internal/characters/yunjin/abil.go
index 02bdd6b94..61183c757 100644
--- a/internal/characters/yunjin/abil.go
+++ b/internal/characters/yunjin/abil.go
@@ -183,9 +183,8 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		}
 	}
 
-	// TODO: Revisit once known burst energy consumption timing
-	c.ConsumeEnergy(0)
-	c.SetCD(core.ActionBurst, 15*60)
+	c.ConsumeEnergy(8)
+	c.SetCDWithDelay(core.ActionBurst, 15*60, 8)
 
 	return f, a
 }
diff --git a/internal/characters/zhongli/abil.go b/internal/characters/zhongli/abil.go
index 704642317..e3428de1d 100644
--- a/internal/characters/zhongli/abil.go
+++ b/internal/characters/zhongli/abil.go
@@ -129,7 +129,7 @@ func (c *char) Burst(p map[string]int) (int, int) {
 		c.addJadeShield()
 	}
 
-	c.SetCD(core.ActionBurst, 720)
+	c.SetCDWithDelay(core.ActionBurst, 720, 6)
 	c.ConsumeEnergy(6)
 	return f, a
 }
diff --git a/pkg/character/actions.go b/pkg/character/actions.go
index 75d0815b4..3eca40e86 100644
--- a/pkg/character/actions.go
+++ b/pkg/character/actions.go
@@ -104,6 +104,16 @@ func (c *Tmpl) SetCD(a core.ActionType, dur int) {
 	c.Core.Log.Debugw("cooldown triggered", "frame", c.Core.F, "event", core.LogCharacterEvent, "char", c.Index, "type", a.String(), "expiry", c.Core.F+dur)
 }
 
+// Thin wrapper around SetCD to allow for setting CD after some delay frames
+// Useful for bursts that consume energy and start CD at some point into their animation
+func (c *Tmpl) SetCDWithDelay(a core.ActionType, dur int, delay int) {
+	if delay == 0 {
+		c.SetCD(a, dur)
+		return
+	}
+	c.AddTask(func() { c.SetCD(a, dur) }, "set-cd", delay)
+}
+
 func (c *Tmpl) Cooldown(a core.ActionType) int {
 	cd := c.ActionCD[a] - c.Core.F
 	if cd < 0 {
diff --git a/pkg/core/icd.go b/pkg/core/icd.go
index f855f4283..0ba542fc1 100644
--- a/pkg/core/icd.go
+++ b/pkg/core/icd.go
@@ -33,6 +33,7 @@ const (
 	ICDTagExtraAttack
 	ICDTagElementalArt
 	ICDTagElementalBurst
+	ICDTagDash
 	ICDTagLisaElectro
 	ICDTagYanfeiFire
 	ICDTagVentiBurstAnemo


Test patch:
diff --git a/internal/characters/shenhe/shenhe_test.go b/internal/characters/shenhe/shenhe_test.go
index 495c95390..c209d993e 100644
--- a/internal/characters/shenhe/shenhe_test.go
+++ b/internal/characters/shenhe/shenhe_test.go
@@ -196,14 +196,9 @@ func TestBurstCDBasic(t *testing.T) {
 
 	sh := x.(*char)
 
-	var f int
-
-	f, _ = x.Burst(p)
-	for i := 0; i < f; i++ {
-		c.Tick()
-	}
-	//expecting skill to come up in f+10*60
-	for c.F < 1200-1 {
+	_, _ = x.Burst(p)
+	// Burst should be ready at 1200+11 frames after usage
+	for i := 0; i < 1200+11-1; i++ {
 		c.Tick()
 	}
 	//stack shouldn't be ready yet