diff --git a/internal/characters/sethos/aimed.go b/internal/characters/sethos/aimed.go
new file mode 100644
index 0000000000..f403db41c6
--- /dev/null
+++ b/internal/characters/sethos/aimed.go
@@ -0,0 +1,191 @@
+package sethos
+
+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"
+ "github.com/genshinsim/gcsim/pkg/core/glog"
+)
+
+var aimedFrames [][]int
+
+var aimedHitmarks = []int{16, 74, 368}
+var startCharge = aimedHitmarks[0]
+
+const shadowPierceShotAil = "Shadowpiercing Shot"
+
+func init() {
+ // outside of E status
+ aimedFrames = make([][]int, 3)
+
+ // Aimed Shot
+ aimedFrames[0] = frames.InitAbilSlice(26)
+ aimedFrames[0][action.ActionDash] = aimedHitmarks[0]
+ aimedFrames[0][action.ActionJump] = aimedHitmarks[0]
+
+ // Fully-Charged Aimed Shot
+ aimedFrames[1] = frames.InitAbilSlice(83)
+ aimedFrames[1][action.ActionDash] = aimedHitmarks[1]
+ aimedFrames[1][action.ActionJump] = aimedHitmarks[1]
+
+ // Shadowpiercing Shot
+ aimedFrames[2] = frames.InitAbilSlice(379)
+ aimedFrames[2][action.ActionDash] = aimedHitmarks[2]
+ aimedFrames[2][action.ActionJump] = aimedHitmarks[2]
+}
+
+func (c *char) Aimed(p map[string]int) (action.Info, error) {
+ if c.StatusIsActive(burstBuffKey) {
+ return action.Info{}, fmt.Errorf("%v: Cannot aim while in burst", c.Base.Key)
+ }
+
+ hold, ok := p["hold"]
+ if !ok {
+ // is this a good default? it's gonna take 6s to do without energy
+ hold = attacks.AimParamLv2
+ }
+ switch hold {
+ case attacks.AimParamPhys:
+ case attacks.AimParamLv1:
+ case attacks.AimParamLv2:
+ return c.ShadowPierce(p)
+ default:
+ return action.Info{}, fmt.Errorf("invalid hold param supplied, got %v", hold)
+ }
+
+ skip, energy := c.a1Calc()
+ if skip > aimedHitmarks[hold]-startCharge {
+ skip = aimedHitmarks[hold] - startCharge
+ }
+
+ travel, ok := p["travel"]
+ if !ok {
+ travel = 10
+ }
+ weakspot := p["weakspot"]
+
+ c.QueueCharTask(func() {
+ ai := combat.AttackInfo{
+ ActorIndex: c.Index,
+ Abil: "Fully-Charged Aimed Shot",
+ AttackTag: attacks.AttackTagExtra,
+ ICDTag: attacks.ICDTagNone,
+ ICDGroup: attacks.ICDGroupDefault,
+ StrikeType: attacks.StrikeTypePierce,
+ Element: attributes.Electro,
+ Durability: 25,
+ Mult: fullaim[c.TalentLvlAttack()],
+ HitWeakPoint: weakspot == 1,
+ HitlagHaltFrames: 0.12 * 60,
+ HitlagFactor: 0.01,
+ HitlagOnHeadshotOnly: true,
+ IsDeployable: true,
+ }
+ if hold < attacks.AimParamLv1 {
+ ai.Abil = "Aimed Shot"
+ ai.Element = attributes.Physical
+ ai.Mult = aim[c.TalentLvlAttack()]
+ }
+
+ c.Core.QueueAttack(
+ ai,
+ combat.NewBoxHit(
+ c.Core.Combat.Player(),
+ c.Core.Combat.PrimaryTarget(),
+ geometry.Point{Y: -0.5},
+ 0.1,
+ 1,
+ ),
+ 0,
+ travel,
+ )
+ c.a1Consume(energy, hold)
+ }, aimedHitmarks[hold]-skip)
+
+ return action.Info{
+ Frames: func(next action.Action) int { return aimedFrames[hold][next] - skip },
+ AnimationLength: aimedFrames[hold][action.InvalidAction] - skip,
+ CanQueueAfter: aimedHitmarks[hold] - skip,
+ State: action.AimState,
+ }, nil
+}
+
+func (c *char) ShadowPierce(p map[string]int) (action.Info, error) {
+ travel, ok := p["travel"]
+ if !ok {
+ travel = 10
+ }
+ weakspot := p["weakspot"]
+
+ skip, energy := c.a1Calc()
+ if skip > aimedHitmarks[2]-startCharge {
+ skip = aimedHitmarks[2] - startCharge
+ }
+ hitHaltFrames := 0.0
+ if weakspot == 1 {
+ hitHaltFrames = 0.12 * 60
+ }
+
+ c.QueueCharTask(func() {
+ em := c.Stat(attributes.EM)
+ ai := combat.AttackInfo{
+ ActorIndex: c.Index,
+ Abil: shadowPierceShotAil,
+ AttackTag: attacks.AttackTagExtra,
+ ICDTag: attacks.ICDTagNone,
+ ICDGroup: attacks.ICDGroupDefault,
+ StrikeType: attacks.StrikeTypeDefault,
+ Element: attributes.Electro,
+ Durability: 50,
+ Mult: shadowpierceAtk[c.TalentLvlAttack()],
+ HitWeakPoint: weakspot == 1,
+ HitlagHaltFrames: hitHaltFrames,
+ HitlagFactor: 0.01,
+ HitlagOnHeadshotOnly: true,
+ IsDeployable: true,
+ FlatDmg: shadowpierceEM[c.TalentLvlAttack()] * em,
+ }
+
+ if c.StatusIsActive(a4Key) {
+ ai.FlatDmg += 7 * em
+ c.Core.Log.NewEvent("Sethos A4 proc dmg add", glog.LogPreDamageMod, c.Index).
+ Write("em", em).
+ Write("ratio", 7.0).
+ Write("addition", 7*em)
+ }
+
+ deltaPos := c.Core.Combat.Player().Pos().Sub(c.Core.Combat.PrimaryTarget().Pos())
+ dist := deltaPos.Magnitude()
+
+ // simulate piercing. Extends 15 units from player
+ ap := combat.NewBoxHit(
+ c.Core.Combat.Player(),
+ c.Core.Combat.PrimaryTarget(),
+ geometry.Point{Y: -dist},
+ 0.1,
+ 15,
+ )
+ c.a1Consume(energy, attacks.AimParamLv2)
+ c.Core.QueueAttack(
+ ai,
+ ap,
+ 0,
+ travel,
+ c.makeA4cb(),
+ c.makeC4cb(),
+ c.makeC6cb(energy),
+ )
+ }, aimedHitmarks[2]-skip)
+
+ return action.Info{
+ Frames: func(next action.Action) int { return aimedFrames[2][next] - skip },
+ AnimationLength: aimedFrames[2][action.InvalidAction] - skip,
+ CanQueueAfter: aimedHitmarks[2] - skip,
+ State: action.AimState,
+ }, nil
+}
diff --git a/internal/characters/sethos/asc.go b/internal/characters/sethos/asc.go
new file mode 100644
index 0000000000..626714e4e9
--- /dev/null
+++ b/internal/characters/sethos/asc.go
@@ -0,0 +1,81 @@
+package sethos
+
+import (
+ "github.com/genshinsim/gcsim/pkg/core/attacks"
+ "github.com/genshinsim/gcsim/pkg/core/combat"
+ "github.com/genshinsim/gcsim/pkg/core/targets"
+)
+
+const a1Key = "sethos-a1"
+
+// returns the amount of time to save, and the amount of energy considered
+func (c *char) a1Calc() (int, float64) {
+ if c.Base.Ascension < 1 {
+ return 0, 0
+ }
+ energy := min(c.Energy, 20)
+ // floor or round the skip?
+ return int(0.285 * energy * 60), energy
+}
+
+func (c *char) a1Consume(energy float64, holdLevel int) {
+ switch holdLevel {
+ default:
+ return
+ case attacks.AimParamLv1:
+ c.AddEnergy(a1Key, -energy*0.5)
+ case attacks.AimParamLv2:
+ c.AddEnergy(a1Key, -energy)
+ }
+ c.c2AddStack(c2ConsumingKey)
+}
+
+const a4Key = "sethos-a4"
+const a4IcdKey = "sethos-a4-icd"
+const a4Icd = 15 * 60
+
+func (c *char) a4() {
+ if c.Base.Ascension < 4 {
+ return
+ }
+ // buff stays active until a4 is proc'd
+ c.AddStatus(a4Key, -1, true)
+ c.a4Count = 0
+}
+
+func (c *char) makeA4cb() combat.AttackCBFunc {
+ if c.Base.Ascension < 4 {
+ return nil
+ }
+
+ done := false
+ return func(a combat.AttackCB) {
+ if a.Target.Type() != targets.TargettableEnemy {
+ return
+ }
+ if done {
+ return
+ }
+ if !c.StatusIsActive(a4Key) {
+ return
+ }
+ done = true
+ if c.a4Count == 0 {
+ // overwrite the expiry of the a4 buff to be 5s after
+ c.AddStatus(a4Key, 5*60, true)
+ c.startA4Icd()
+ }
+ c.a4Count += 1
+ if c.a4Count >= 4 {
+ c.DeleteStatus(a4Key)
+ }
+ }
+}
+
+func (c *char) startA4Icd() {
+ if c.StatusIsActive(a4IcdKey) {
+ return
+ }
+ c.AddStatus(a4IcdKey, a4Icd, true)
+ c.QueueCharTask(c.a4, a4Icd)
+}
diff --git a/internal/characters/sethos/attack.go b/internal/characters/sethos/attack.go
new file mode 100644
index 0000000000..c10803071a
--- /dev/null
+++ b/internal/characters/sethos/attack.go
@@ -0,0 +1,103 @@
+package sethos
+
+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"
+)
+
+const normalHitNum = 3
+
+var (
+ attackFrames [][]int
+ attackHitmarks = [][]int{{10}, {12, 12 + 3}, {39}}
+)
+
+func init() {
+ attackFrames = make([][]int, normalHitNum)
+
+ attackFrames[0] = frames.InitNormalCancelSlice(attackHitmarks[0][0], 19) // N1 -> Walk
+ attackFrames[0][action.ActionAttack] = 17
+ attackFrames[0][action.ActionAim] = 15
+
+ attackFrames[1] = frames.InitNormalCancelSlice(attackHitmarks[1][1], 52-17) // N2 -> Walk
+ attackFrames[1][action.ActionAttack] = 32
+ attackFrames[1][action.ActionAim] = 45 - 17
+
+ attackFrames[2] = frames.InitNormalCancelSlice(attackHitmarks[2][0], 118-32-17) // N3 -> Walk
+ attackFrames[2][action.ActionAttack] = 63
+}
+
+func (c *char) Attack(p map[string]int) (action.Info, error) {
+ travel, ok := p["travel"]
+ if !ok {
+ travel = 10
+ }
+
+ ai := combat.AttackInfo{
+ ActorIndex: c.Index,
+ Abil: fmt.Sprintf("Normal %v", c.NormalCounter),
+ AttackTag: attacks.AttackTagNormal,
+ ICDTag: attacks.ICDTagNone,
+ ICDGroup: attacks.ICDGroupDefault,
+ StrikeType: attacks.StrikeTypePierce,
+ Element: attributes.Physical,
+ Durability: 25,
+ }
+
+ ap := combat.NewBoxHit(
+ c.Core.Combat.Player(),
+ c.Core.Combat.PrimaryTarget(),
+ geometry.Point{Y: -0.5},
+ 0.1,
+ 1,
+ )
+
+ for i, mult := range attack[c.NormalCounter] {
+ c.QueueCharTask(func() {
+ var c4cb combat.AttackCBFunc
+ if c.StatusIsActive(burstBuffKey) {
+ ai.Abil = fmt.Sprintf("Dusk Bolt %v", c.NormalCounter)
+ ai.AttackTag = attacks.AttackTagExtra
+ ai.ICDTag = attacks.ICDTagElementalBurst
+ ai.Element = attributes.Electro
+ ai.FlatDmg += burstEM[c.TalentLvlBurst()] * c.Stat(attributes.EM)
+
+ deltaPos := c.Core.Combat.Player().Pos().Sub(c.Core.Combat.PrimaryTarget().Pos())
+ dist := deltaPos.Magnitude()
+
+ // simulate piercing. Extends 15 units from player
+ ap = combat.NewBoxHit(
+ c.Core.Combat.Player(),
+ c.Core.Combat.PrimaryTarget(),
+ geometry.Point{Y: -dist},
+ 0.1,
+ 15,
+ )
+ c4cb = c.makeC4cb()
+ }
+ ai.Mult = mult[c.TalentLvlAttack()]
+ c.Core.QueueAttack(
+ ai,
+ ap,
+ 0,
+ travel,
+ c4cb,
+ )
+ }, attackHitmarks[c.NormalCounter][i])
+ }
+
+ 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
+}
diff --git a/internal/characters/sethos/burst.go b/internal/characters/sethos/burst.go
new file mode 100644
index 0000000000..10a0a3a110
--- /dev/null
+++ b/internal/characters/sethos/burst.go
@@ -0,0 +1,29 @@
+package sethos
+
+import (
+ "github.com/genshinsim/gcsim/internal/frames"
+ "github.com/genshinsim/gcsim/pkg/core/action"
+)
+
+var burstFrames []int
+
+const burstBuffKey = "sethos-burst"
+
+func init() {
+ burstFrames = frames.InitAbilSlice(50)
+}
+
+func (c *char) Burst(p map[string]int) (action.Info, error) {
+ c.AddStatus(burstBuffKey, 8*60, true)
+ c.c2AddStack(c2BurstKey)
+
+ c.SetCD(action.ActionBurst, 15*60)
+ c.ConsumeEnergy(7)
+
+ return action.Info{
+ Frames: frames.NewAbilFunc(burstFrames),
+ AnimationLength: burstFrames[action.InvalidAction],
+ CanQueueAfter: burstFrames[action.ActionDash], // earliest cancel
+ State: action.BurstState,
+ }, nil
+}
diff --git a/internal/characters/sethos/config.yml b/internal/characters/sethos/config.yml
new file mode 100644
index 0000000000..506608ba2d
--- /dev/null
+++ b/internal/characters/sethos/config.yml
@@ -0,0 +1,35 @@
+package_name: sethos
+genshin_id: 10000097
+key: sethos
+action_param_keys:
+ attack:
+ - param: "travel"
+ aim:
+ - param: "hold"
+ - param: "travel"
+ - param: "weakspot"
+skill_data_mapping:
+ attack: # Normal Attack: Royal Reed Bowmanship
+ attack_1:
+ - 0 # 1-Hit DMG|{param0:F1P}
+ attack_2:
+ - 1 # 2-Hit DMG|{param1:F1P}+{param2:F1P}
+ - 2 # 2-Hit DMG|{param1:F1P}+{param2:F1P}
+ attack_3:
+ - 3 # 3-Hit DMG|{param3:F1P}
+ aim:
+ - 4 # Aimed Shot|{param4:F1P}
+ fullaim:
+ - 5 # Aimed Shot Charge Level 1|{param5:F1P}
+ shadowpierceAtk:
+ - 6 # Shadowpiercing Shot DMG|{param6:P} ATK+{param7:P} Elemental Mastery
+ shadowpierceEM:
+ - 7 # Shadowpiercing Shot DMG|{param6:P} ATK+{param7:P} Elemental Mastery
+ skill: # Ancient Rite: Thunderous Roar of Sand
+ skill:
+ - 0 # Skill DMG|{param0:F1P}
+ skillEnergyRegen:
+ - 1 # Energy Regeneration|{param1:I}
+ burst: # Secret Rite: Twilight Shadowpiercer
+ burstEM:
+ - 0 # Dusk Bolt DMG Increase|{param0:F1P} Elemental Mastery
diff --git a/internal/characters/sethos/cons.go b/internal/characters/sethos/cons.go
new file mode 100644
index 0000000000..c53b3d1516
--- /dev/null
+++ b/internal/characters/sethos/cons.go
@@ -0,0 +1,145 @@
+package sethos
+
+import (
+ "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/player/character"
+ "github.com/genshinsim/gcsim/pkg/core/targets"
+ "github.com/genshinsim/gcsim/pkg/modifier"
+)
+
+const (
+ c2Key = "sethos-c2"
+ c2ConsumingKey = "sethos-c2-consuming"
+ c2RegainingKey = "sethos-c2-regaining"
+ c2BurstKey = "sethos-c2-burst"
+
+ c2Dur = 10 * 60
+)
+
+const c4Key = "sethos-c4"
+const c4Dur = 10 * 60
+
+const c6Key = "sethos-c6"
+const c6IcdKey = "sethos-c6-icd"
+const c6IcdDur = 15 * 60
+
+func (c *char) c1() {
+ if c.Base.Cons < 1 {
+ return
+ }
+ m := make([]float64, attributes.EndStatType)
+ m[attributes.CR] = 0.15
+ c.AddAttackMod(character.AttackMod{
+ Base: modifier.NewBase("sethos-c1", -1),
+ Amount: func(atk *combat.AttackEvent, t combat.Target) ([]float64, bool) {
+ if atk.Info.AttackTag != attacks.AttackTagExtra {
+ return nil, false
+ }
+ if atk.Info.Abil != shadowPierceShotAil {
+ return nil, false
+ }
+ return m, true
+ },
+ })
+}
+
+func (c *char) c2() {
+ if c.Base.Cons < 2 {
+ return
+ }
+ mElectro := make([]float64, attributes.EndStatType)
+ c.AddStatMod(character.StatMod{
+ Base: modifier.NewBase(c2Key, -1),
+ Amount: func() ([]float64, bool) {
+ stackCount := c.c2Stacks()
+ if stackCount == 0 {
+ return nil, false
+ }
+ mElectro[attributes.ElectroP] = 0.15 * float64(stackCount)
+ return mElectro, true
+ },
+ })
+}
+
+func (c *char) c2AddStack(name string) {
+ if c.Base.Cons < 2 {
+ return
+ }
+ c.AddStatus(name, c2Dur, true)
+}
+
+func (c *char) c2Stacks() int {
+ stacks := 0
+ if c.StatusIsActive(c2ConsumingKey) {
+ stacks++
+ }
+ if c.StatusIsActive(c2RegainingKey) {
+ stacks++
+ }
+ if c.StatusIsActive(c2BurstKey) {
+ stacks++
+ }
+ return min(stacks, 2)
+}
+
+func (c *char) c4() {
+ if c.Base.Cons < 4 {
+ return
+ }
+ c.c4Buff = make([]float64, attributes.EndStatType)
+ c.c4Buff[attributes.EM] = 80
+}
+
+func (c *char) makeC4cb() combat.AttackCBFunc {
+ if c.Base.Cons < 4 {
+ return nil
+ }
+ count := 0
+ return func(a combat.AttackCB) {
+ if a.Target.Type() != targets.TargettableEnemy {
+ return
+ }
+ if count >= 2 {
+ return
+ }
+ count += 1
+ if count == 2 {
+ for _, char := range c.Core.Player.Chars() {
+ char.AddStatMod(character.StatMod{
+ Base: modifier.NewBaseWithHitlag(c4Key, c4Dur),
+ AffectedStat: attributes.EM,
+ Amount: func() ([]float64, bool) {
+ return c.c4Buff, true
+ },
+ })
+ }
+ }
+ }
+}
+
+func (c *char) makeC6cb(energy float64) combat.AttackCBFunc {
+ if c.Base.Cons < 6 {
+ return nil
+ }
+ if c.Base.Ascension < 1 {
+ return nil
+ }
+
+ done := false
+ return func(a combat.AttackCB) {
+ if a.Target.Type() != targets.TargettableEnemy {
+ return
+ }
+ if done {
+ return
+ }
+ if c.StatusIsActive(c6IcdKey) {
+ return
+ }
+ done = true
+ c.AddStatus(c6IcdKey, c6IcdDur, true)
+ c.AddEnergy(c6Key, energy)
+ }
+}
diff --git a/internal/characters/sethos/data_gen.textproto b/internal/characters/sethos/data_gen.textproto
new file mode 100644
index 0000000000..38f3db3446
--- /dev/null
+++ b/internal/characters/sethos/data_gen.textproto
@@ -0,0 +1,151 @@
+id: 10000097
+key: "sethos"
+rarity: QUALITY_PURPLE
+body: BODY_BOY
+region: ASSOC_TYPE_SUMERU
+element: Electric
+weapon_class: WEAPON_BOW
+icon_name: "UI_AvatarIcon_Sethos"
+stats: {
+ base_hp: 820.6119
+ base_atk: 19.05456
+ base_def: 46.9245
+ hp_curve: GROW_CURVE_HP_S4
+ atk_curve: GROW_CURVE_ATTACK_S4
+ def_cruve: GROW_CURVE_HP_S4
+ promo_data: {
+ max_level: 20
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_HP
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_DEFENSE
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_ELEMENT_MASTERY
+ }
+ }
+ promo_data: {
+ max_level: 40
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_HP
+ value: 613.0391
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_DEFENSE
+ value: 35.055
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 14.235066
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_ELEMENT_MASTERY
+ }
+ }
+ promo_data: {
+ max_level: 50
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_HP
+ value: 1048.6195
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_DEFENSE
+ value: 59.9625
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 24.349455
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_ELEMENT_MASTERY
+ value: 24
+ }
+ }
+ promo_data: {
+ max_level: 60
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_HP
+ value: 1629.3934
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_DEFENSE
+ value: 93.1725
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 37.835308
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_ELEMENT_MASTERY
+ value: 48
+ }
+ }
+ promo_data: {
+ max_level: 70
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_HP
+ value: 2064.9739
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_DEFENSE
+ value: 118.08
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 47.949696
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_ELEMENT_MASTERY
+ value: 48
+ }
+ }
+ promo_data: {
+ max_level: 80
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_HP
+ value: 2500.5542
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_DEFENSE
+ value: 142.9875
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 58.064083
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_ELEMENT_MASTERY
+ value: 72
+ }
+ }
+ promo_data: {
+ max_level: 90
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_HP
+ value: 2936.1348
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_DEFENSE
+ value: 167.895
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 68.178474
+ }
+ add_props: {
+ prop_type: FIGHT_PROP_ELEMENT_MASTERY
+ value: 96
+ }
+ }
+}
+skill_details: {
+ skill: 10972
+ burst: 10975
+ attack: 10971
+ burst_energy_cost: 60
+}
+name_text_hash_map: 1431322346
diff --git a/internal/characters/sethos/sethos.go b/internal/characters/sethos/sethos.go
new file mode 100644
index 0000000000..c0c357b304
--- /dev/null
+++ b/internal/characters/sethos/sethos.go
@@ -0,0 +1,58 @@
+package sethos
+
+import (
+ tmpl "github.com/genshinsim/gcsim/internal/template/character"
+ "github.com/genshinsim/gcsim/pkg/core"
+ "github.com/genshinsim/gcsim/pkg/core/info"
+ "github.com/genshinsim/gcsim/pkg/core/keys"
+ "github.com/genshinsim/gcsim/pkg/core/player/character"
+ "github.com/genshinsim/gcsim/pkg/model"
+)
+
+func init() {
+ core.RegisterCharFunc(keys.Sethos, NewChar)
+}
+
+type char struct {
+ *tmpl.Character
+ lastSkillFrame int
+ a4Count int
+ c4Buff []float64
+}
+
+func NewChar(s *core.Core, w *character.CharWrapper, _ info.CharacterProfile) error {
+ c := char{}
+
+ c.Character = tmpl.NewWithWrapper(s, w)
+
+ c.EnergyMax = 60
+ c.NormalHitNum = normalHitNum
+ c.BurstCon = 5
+ c.NormalCon = 3
+
+ c.lastSkillFrame = -1
+
+ w.Character = &c
+
+ return nil
+}
+
+func (c *char) Init() error {
+ c.skillRefundHook()
+ c.a4()
+ c.c1()
+ c.c2()
+ c.c4()
+ return nil
+}
+
+func (c *char) AnimationStartDelay(k model.AnimationDelayKey) int {
+ switch k {
+ case model.AnimationXingqiuN0StartDelay:
+ return 5
+ case model.AnimationYelanN0StartDelay:
+ return 4
+ default:
+ return c.Character.AnimationStartDelay(k)
+ }
+}
diff --git a/internal/characters/sethos/sethos_gen.go b/internal/characters/sethos/sethos_gen.go
new file mode 100644
index 0000000000..7648407f47
--- /dev/null
+++ b/internal/characters/sethos/sethos_gen.go
@@ -0,0 +1,258 @@
+// Code generated by "pipeline"; DO NOT EDIT.
+package sethos
+
+import (
+ _ "embed"
+
+ "fmt"
+ "github.com/genshinsim/gcsim/pkg/core/action"
+ "github.com/genshinsim/gcsim/pkg/core/keys"
+ "github.com/genshinsim/gcsim/pkg/gcs/validation"
+ "github.com/genshinsim/gcsim/pkg/model"
+ "google.golang.org/protobuf/encoding/prototext"
+ "slices"
+)
+
+//go:embed data_gen.textproto
+var pbData []byte
+var base *model.AvatarData
+var paramKeysValidation = map[action.Action][]string{
+ 3: {"travel"},
+ 7: {"rr_cancel", "hold", "travel", "weakspot"},
+}
+
+func init() {
+ base = &model.AvatarData{}
+ err := prototext.Unmarshal(pbData, base)
+ if err != nil {
+ panic(err)
+ }
+ validation.RegisterCharParamValidationFunc(keys.Sethos, ValidateParamKeys)
+}
+
+func ValidateParamKeys(a action.Action, keys []string) error {
+ valid, ok := paramKeysValidation[a]
+ if !ok {
+ return nil
+ }
+ for _, v := range keys {
+ if !slices.Contains(valid, v) {
+ return fmt.Errorf("key %v is invalid for action %v", v, a.String())
+ }
+ }
+ return nil
+}
+
+func (x *char) Data() *model.AvatarData {
+ return base
+}
+
+var (
+ attack = [][][]float64{
+ {attack_1},
+ attack_2,
+ {attack_3},
+ }
+)
+
+var (
+ // attack: aim = [4]
+ aim = []float64{
+ 0.4386,
+ 0.4743,
+ 0.51,
+ 0.561,
+ 0.5967,
+ 0.6375,
+ 0.6936,
+ 0.7497,
+ 0.8058,
+ 0.867,
+ 0.9282,
+ 0.9894,
+ 1.0506,
+ 1.1118,
+ 1.173,
+ }
+ // attack: attack_1 = [0]
+ attack_1 = []float64{
+ 0.526139,
+ 0.568965,
+ 0.61179,
+ 0.672969,
+ 0.715794,
+ 0.764737,
+ 0.832034,
+ 0.899331,
+ 0.966628,
+ 1.040043,
+ 1.113458,
+ 1.186873,
+ 1.260287,
+ 1.333702,
+ 1.407117,
+ }
+ // attack: attack_2 = [1 2]
+ attack_2 = [][]float64{
+ {
+ 0.237962,
+ 0.257331,
+ 0.2767,
+ 0.30437,
+ 0.323739,
+ 0.345875,
+ 0.376312,
+ 0.406749,
+ 0.437186,
+ 0.47039,
+ 0.503594,
+ 0.536798,
+ 0.570002,
+ 0.603206,
+ 0.63641,
+ },
+ {
+ 0.266084,
+ 0.287742,
+ 0.3094,
+ 0.34034,
+ 0.361998,
+ 0.38675,
+ 0.420784,
+ 0.454818,
+ 0.488852,
+ 0.52598,
+ 0.563108,
+ 0.600236,
+ 0.637364,
+ 0.674492,
+ 0.71162,
+ },
+ }
+ // attack: attack_3 = [3]
+ attack_3 = []float64{
+ 0.739867,
+ 0.800088,
+ 0.86031,
+ 0.946341,
+ 1.006563,
+ 1.075387,
+ 1.170022,
+ 1.264656,
+ 1.35929,
+ 1.462527,
+ 1.565764,
+ 1.669001,
+ 1.772239,
+ 1.875476,
+ 1.978713,
+ }
+ // attack: fullaim = [5]
+ fullaim = []float64{
+ 1.24,
+ 1.333,
+ 1.426,
+ 1.55,
+ 1.643,
+ 1.736,
+ 1.86,
+ 1.984,
+ 2.108,
+ 2.232,
+ 2.356,
+ 2.48,
+ 2.635,
+ 2.79,
+ 2.945,
+ }
+ // attack: shadowpierceAtk = [6]
+ shadowpierceAtk = []float64{
+ 1.4,
+ 1.505,
+ 1.61,
+ 1.75,
+ 1.855,
+ 1.96,
+ 2.1,
+ 2.24,
+ 2.38,
+ 2.52,
+ 2.66,
+ 2.8,
+ 2.975,
+ 3.15,
+ 3.325,
+ }
+ // attack: shadowpierceEM = [7]
+ shadowpierceEM = []float64{
+ 1.3456,
+ 1.44652,
+ 1.54744,
+ 1.682,
+ 1.78292,
+ 1.88384,
+ 2.0184,
+ 2.15296,
+ 2.28752,
+ 2.42208,
+ 2.55664,
+ 2.6912,
+ 2.8594,
+ 3.0276,
+ 3.1958,
+ }
+ // skill: skill = [0]
+ skill = []float64{
+ 1.156,
+ 1.2427,
+ 1.3294,
+ 1.445,
+ 1.5317,
+ 1.6184,
+ 1.734,
+ 1.8496,
+ 1.9652,
+ 2.0808,
+ 2.1964,
+ 2.312,
+ 2.4565,
+ 2.601,
+ 2.7455,
+ }
+ // skill: skillEnergyRegen = [1]
+ skillEnergyRegen = []float64{
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ 12,
+ }
+ // burst: burstEM = [0]
+ burstEM = []float64{
+ 1.9616,
+ 2.10872,
+ 2.25584,
+ 2.452,
+ 2.59912,
+ 2.74624,
+ 2.9424,
+ 3.13856,
+ 3.33472,
+ 3.53088,
+ 3.72704,
+ 3.9232,
+ 4.1684,
+ 4.4136,
+ 4.6588,
+ }
+)
diff --git a/internal/characters/sethos/skill.go b/internal/characters/sethos/skill.go
new file mode 100644
index 0000000000..353357dc13
--- /dev/null
+++ b/internal/characters/sethos/skill.go
@@ -0,0 +1,97 @@
+package sethos
+
+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/targets"
+)
+
+var skillFrames []int
+
+const skillParticleICDKey = "sethos-particle-icd"
+
+func init() {
+ skillFrames = frames.InitAbilSlice(38) // E -> Charge
+ skillFrames[action.ActionAttack] = 28
+ skillFrames[action.ActionSkill] = 32
+ skillFrames[action.ActionBurst] = 28
+ skillFrames[action.ActionDash] = 27
+ skillFrames[action.ActionJump] = 27
+ skillFrames[action.ActionWalk] = 25
+ skillFrames[action.ActionSwap] = 30
+}
+
+func (c *char) skillRefundHook() {
+ refundCB := func(args ...interface{}) bool {
+ // TODO: Check if Sethos E filters by enemy
+ // a := args[0].(combat.Target)
+ // if a.Type() != targets.TargettableEnemy {
+ // return false
+ // }
+ ae := args[1].(*combat.AttackEvent)
+ if ae.Info.ActorIndex != c.Index {
+ return false
+ }
+ if ae.Info.AttackTag != attacks.AttackTagElementalArt {
+ return false
+ }
+ // to avoid procing twice in aoe
+ if c.lastSkillFrame == ae.SourceFrame {
+ return false
+ }
+ c.lastSkillFrame = ae.SourceFrame
+ c.AddEnergy("sethos-skill", skillEnergyRegen[c.TalentLvlSkill()])
+ c.c2AddStack(c2RegainingKey)
+
+ return false
+ }
+
+ c.Core.Events.Subscribe(event.OnOverload, refundCB, "sethos-e-refund")
+ c.Core.Events.Subscribe(event.OnElectroCharged, refundCB, "sethos-e-refund")
+ c.Core.Events.Subscribe(event.OnSuperconduct, refundCB, "sethos-e-refund")
+ c.Core.Events.Subscribe(event.OnSwirlElectro, refundCB, "sethos-e-refund")
+ c.Core.Events.Subscribe(event.OnHyperbloom, refundCB, "sethos-e-refund")
+ c.Core.Events.Subscribe(event.OnQuicken, refundCB, "sethos-e-refund")
+ c.Core.Events.Subscribe(event.OnAggravate, refundCB, "sethos-e-refund")
+}
+
+func (c *char) Skill(p map[string]int) (action.Info, error) {
+ ai := combat.AttackInfo{
+ ActorIndex: c.Index,
+ Abil: "Ancient Rite: Thunderous Roar of Sand",
+ AttackTag: attacks.AttackTagElementalArt,
+ ICDTag: attacks.ICDTagNone,
+ ICDGroup: attacks.ICDGroupDefault,
+ StrikeType: attacks.StrikeTypeDefault,
+ Element: attributes.Electro,
+ Durability: 25,
+ Mult: skill[c.TalentLvlSkill()],
+ }
+
+ ap := combat.NewCircleHitOnTarget(c.Core.Combat.Player(), nil, 4.5)
+ c.Core.QueueAttack(ai, ap, 0, 13, c.particleCB)
+
+ c.SetCDWithDelay(action.ActionSkill, 8*60, 10)
+
+ return action.Info{
+ Frames: frames.NewAbilFunc(skillFrames),
+ AnimationLength: skillFrames[action.InvalidAction],
+ CanQueueAfter: skillFrames[action.ActionSwap], // earliest cancel
+ State: action.SkillState,
+ }, nil
+}
+
+func (c *char) particleCB(a combat.AttackCB) {
+ if a.Target.Type() != targets.TargettableEnemy {
+ return
+ }
+ if c.StatusIsActive(skillParticleICDKey) {
+ return
+ }
+ c.AddStatus(skillParticleICDKey, 0.5*60, true)
+ c.Core.QueueParticle(c.Base.Key.String(), 2, attributes.Electro, c.ParticleDelay)
+}
diff --git a/pkg/core/keys/keys_char_gen.go b/pkg/core/keys/keys_char_gen.go
index 26d39c3dc5..7e52b4342b 100644
--- a/pkg/core/keys/keys_char_gen.go
+++ b/pkg/core/keys/keys_char_gen.go
@@ -70,6 +70,7 @@ const (
Rosaria
Sara
Sayu
+ Sethos
Shenhe
Sucrose
Tartaglia
@@ -346,6 +347,10 @@ func init() {
charPrettyName[Sayu] = "Sayu"
CharKeyToEle[Sayu] = attributes.Anemo
+ charNames[Sethos] = "sethos"
+ charPrettyName[Sethos] = "Sethos"
+ CharKeyToEle[Sethos] = attributes.Electro
+
charNames[Shenhe] = "shenhe"
charPrettyName[Shenhe] = "Shenhe"
CharKeyToEle[Shenhe] = attributes.Cryo
diff --git a/pkg/model/enemy_gen.go b/pkg/model/enemy_gen.go
index 752c06f7aa..19266dc692 100644
--- a/pkg/model/enemy_gen.go
+++ b/pkg/model/enemy_gen.go
@@ -3020,6 +3020,36 @@ var EnemyMap = map[int]*MonsterData{
},
},
},
+ 22120201: {
+ Id: 22120201,
+ Key: "tenebrousmimiflora",
+ NameTextHashMap: 2988972984,
+ BaseStats: &MonsterStatsData{
+ BaseHp: 46.1856,
+ HpCurve: MonsterCurveType_GROW_CURVE_HP_2,
+ Resist: &MonsterResistData{
+ FireResist: 0.1,
+ GrassResist: 0.1,
+ WaterResist: 0.1,
+ ElectricResist: 0.1,
+ WindResist: 0.1,
+ IceResist: 0.1,
+ RockResist: 0.1,
+ PhysicalResist: 0.1,
+ },
+ FreezeResist: 0,
+ HpDrop: []*MonsterHPDrop{
+ {
+ DropId: 22010010,
+ HpPercent: 0.6,
+ },
+ {
+ DropId: 22010010,
+ HpPercent: 0,
+ },
+ },
+ },
+ },
21030101: {
Id: 21030101,
Key: "hydrosamachurl",
@@ -4383,6 +4413,44 @@ var EnemyMap = map[int]*MonsterData{
},
},
},
+ 24090201: {
+ Id: 24090201,
+ Key: "secretsourceautomatonconfigurationdevice",
+ NameTextHashMap: 2834509656,
+ BaseStats: &MonsterStatsData{
+ BaseHp: 353.184,
+ HpCurve: MonsterCurveType_GROW_CURVE_HP_2,
+ Resist: &MonsterResistData{
+ FireResist: 0.1,
+ GrassResist: 0.1,
+ WaterResist: 0.1,
+ ElectricResist: 0.1,
+ WindResist: 0.1,
+ IceResist: 0.1,
+ RockResist: 0.1,
+ PhysicalResist: 0.1,
+ },
+ FreezeResist: 1,
+ HpDrop: []*MonsterHPDrop{
+ {
+ DropId: 22010030,
+ HpPercent: 0.75,
+ },
+ {
+ DropId: 22010030,
+ HpPercent: 0.5,
+ },
+ {
+ DropId: 22010030,
+ HpPercent: 0.25,
+ },
+ {
+ DropId: 22010030,
+ HpPercent: 0,
+ },
+ },
+ },
+ },
24810101: {
Id: 24810101,
Key: "basicdefensivepyrotower",
diff --git a/pkg/shortcut/characters.go b/pkg/shortcut/characters.go
index 5f6f0d0373..6f7ea0d847 100644
--- a/pkg/shortcut/characters.go
+++ b/pkg/shortcut/characters.go
@@ -169,4 +169,5 @@ var CharNameToKey = map[string]keys.Char{
"clorinde": keys.Clorinde,
"emilie": keys.Emilie,
"mualani": keys.Mualani,
+ "sethos": keys.Sethos,
}
diff --git a/pkg/shortcut/enemies_gen.go b/pkg/shortcut/enemies_gen.go
index 5e475af8e3..b841934603 100644
--- a/pkg/shortcut/enemies_gen.go
+++ b/pkg/shortcut/enemies_gen.go
@@ -96,6 +96,7 @@ var MonsterNameToID = map[string]int{
"shatterstonebreacherprimus": 22110201,
"largeovergrownbreacherprimus": 22110301,
"overgrownbreacherprimus": 22110402,
+ "tenebrousmimiflora": 22120201,
"hydrosamachurl": 21030101,
"dendrosamachurl": 21030201,
"anemosamachurl": 21030301,
@@ -137,6 +138,7 @@ var MonsterNameToID = map[string]int{
"icewindsuite": 24070101,
"experimentalfieldgenerator": 24080101,
"secretsourceautomatonhunterseeker": 24090101,
+ "secretsourceautomatonconfigurationdevice": 24090201,
"basicdefensivepyrotower": 24810101,
"advanceddefensivepyrotower": 24810201,
"basicdefensiveelectrotower": 24810301,
diff --git a/pkg/simulation/imports_char_gen.go b/pkg/simulation/imports_char_gen.go
index 4f341d2256..d78bce1906 100644
--- a/pkg/simulation/imports_char_gen.go
+++ b/pkg/simulation/imports_char_gen.go
@@ -65,6 +65,7 @@ import (
_ "github.com/genshinsim/gcsim/internal/characters/rosaria"
_ "github.com/genshinsim/gcsim/internal/characters/sara"
_ "github.com/genshinsim/gcsim/internal/characters/sayu"
+ _ "github.com/genshinsim/gcsim/internal/characters/sethos"
_ "github.com/genshinsim/gcsim/internal/characters/shenhe"
_ "github.com/genshinsim/gcsim/internal/characters/sucrose"
_ "github.com/genshinsim/gcsim/internal/characters/tartaglia"
diff --git a/ui/packages/components/src/Editor/mode-gcsim.js b/ui/packages/components/src/Editor/mode-gcsim.js
index ca13be0c5f..918b13cdf2 100644
--- a/ui/packages/components/src/Editor/mode-gcsim.js
+++ b/ui/packages/components/src/Editor/mode-gcsim.js
@@ -79,7 +79,7 @@ ace.define(
'let|while|if|else|fn|switch|case|default|break|continue|fallthrough|return|for|' +
'options|add|char|stats|weapon|set|lvl|refine|cons|talent|count|active|target|particle_threshold|particle_drop_count|resist|energy|hurt';
var gcsimAvatars =
- 'traveleranemo|travelergeo|travelerelectro|travelerdendro|travelerhydro|travelerpyro|travelercryo|aether-anemo|lumine-anemo|aether-geo|lumine-geo|aether-electro|lumine-electro|aether-dendro|lumine-dendro|aether-hydro|lumine-hydro|aether-pyro|lumine-pyro|aether-cryo|lumine-cryo|aetheranemo|lumineanemo|aethergeo|luminegeo|aetherelectro|lumineelectro|aetherdendro|luminedendro|aetherhydro|luminehydro|aetherpyro|luminepyro|aethercryo|luminecryo|albedo|aloy|amber|barbara|barb|beidou|bennett|charlotte|chongyun|chong|cyno|diluc|diona|eula|fischl|fish|amy|ganyu|hutao|tao|ht|jean|kaedeharakazuha|kazuha|kaz|kaeya|kamisatoayaka|ayaka|kamisatoayato|ayato|keqing|keq|klee|kujousara|kujosara|sara|lisa|mona|ningguang|ning|noelle|qiqi|raidenshogun|raiden|herexcellencythealmightynarukamiogoshogodofthunder|razor|rosaria|rosa|sangonomiyakokomi|kokomi|koko|sayu|sucrose|tartaglia|childe|thoma|venti|xiangling|xl|xianyun|cloudretainer|liuyun|xiao|xingqiu|xq|xinyan|yanfei|yoimiya|yoi|yunjin|zhongli|zhong|zl|gorou|aratakiitto|itto|aratakitheoneandoniitto|shenhe|yae|yaemiko|yelan|kukishinobu|kuki|shikanoinheizou|heizou|tighnari|collei|dori|candace|nilou|kusanali|lesserlordkusanali|nahida|layla|faruzan|faru|wanderer|scaramouche|scara|kunikuzushi|kuni|kabukimono|alhaitham|haitham|baizhu|dehya|yaoyao|mika|kaveh|kirara|lyney|lynette|neuvillette|neuv|chiefjusticeoffontaine|freminet|furina|furinadefontaine|navia|demoiselle|wriothesley|wrio|chevreuse|chev|gaming|chiori|arlecchino|arle|mualani';
+ 'traveleranemo|travelergeo|travelerelectro|travelerdendro|travelerhydro|travelerpyro|travelercryo|aether-anemo|lumine-anemo|aether-geo|lumine-geo|aether-electro|lumine-electro|aether-dendro|lumine-dendro|aether-hydro|lumine-hydro|aether-pyro|lumine-pyro|aether-cryo|lumine-cryo|aetheranemo|lumineanemo|aethergeo|luminegeo|aetherelectro|lumineelectro|aetherdendro|luminedendro|aetherhydro|luminehydro|aetherpyro|luminepyro|aethercryo|luminecryo|albedo|aloy|amber|barbara|barb|beidou|bennett|charlotte|chongyun|chong|cyno|diluc|diona|eula|fischl|fish|amy|ganyu|hutao|tao|ht|jean|kaedeharakazuha|kazuha|kaz|kaeya|kamisatoayaka|ayaka|kamisatoayato|ayato|keqing|keq|klee|kujousara|kujosara|sara|lisa|mona|ningguang|ning|noelle|qiqi|raidenshogun|raiden|herexcellencythealmightynarukamiogoshogodofthunder|razor|rosaria|rosa|sangonomiyakokomi|kokomi|koko|sayu|sucrose|tartaglia|childe|thoma|venti|xiangling|xl|xianyun|cloudretainer|liuyun|xiao|xingqiu|xq|xinyan|yanfei|yoimiya|yoi|yunjin|zhongli|zhong|zl|gorou|aratakiitto|itto|aratakitheoneandoniitto|shenhe|yae|yaemiko|yelan|kukishinobu|kuki|shikanoinheizou|heizou|tighnari|collei|dori|candace|nilou|kusanali|lesserlordkusanali|nahida|layla|faruzan|faru|wanderer|scaramouche|scara|kunikuzushi|kuni|kabukimono|alhaitham|haitham|baizhu|dehya|yaoyao|mika|kaveh|kirara|lyney|lynette|neuvillette|neuv|chiefjusticeoffontaine|freminet|furina|furinadefontaine|navia|demoiselle|wriothesley|wrio|chevreuse|chev|gaming|chiori|arlecchino|arle|mualani|sethos';
var gcsimAbilities =
'attack|charge|aim|skill|burst|low_plunge|high_plunge|dash|jump|walk|swap';
var gcsimStats = 'hp(?:%)?|atk(?:%)?|def(?:%)?|er|em|cr|cd|heal|phys%';
diff --git a/ui/packages/db/src/Data/char_data.generated.json b/ui/packages/db/src/Data/char_data.generated.json
index b172bd636f..7795dbcef8 100644
--- a/ui/packages/db/src/Data/char_data.generated.json
+++ b/ui/packages/db/src/Data/char_data.generated.json
@@ -1251,6 +1251,23 @@
},
"name_text_hash_map ": "2388785242"
},
+ "sethos": {
+ "id": 10000097,
+ "key": "sethos",
+ "rarity": "QUALITY_PURPLE",
+ "body": "BODY_BOY",
+ "region": "ASSOC_TYPE_SUMERU",
+ "element": "Electric",
+ "weapon_class": "WEAPON_BOW",
+ "icon_name": "UI_AvatarIcon_Sethos",
+ "skill_details": {
+ "skill": 10972,
+ "burst": 10975,
+ "attack": 10971,
+ "burst_energy_cost": 60
+ },
+ "name_text_hash_map ": "1431322346"
+ },
"shenhe": {
"id": 10000063,
"key": "shenhe",
diff --git a/ui/packages/docs/docs/reference/characters/sethos.md b/ui/packages/docs/docs/reference/characters/sethos.md
new file mode 100644
index 0000000000..25b985bf4f
--- /dev/null
+++ b/ui/packages/docs/docs/reference/characters/sethos.md
@@ -0,0 +1,44 @@
+---
+title: Sethos
+---
+
+import HitlagTable from "@site/src/components/Hitlag/HitlagTable";
+import FieldsTable from "@site/src/components/Fields/FieldsTable";
+import ParamsTable from "@site/src/components/Params/ParamsTable";
+import FramesTable from "@site/src/components/Frames/FramesTable";
+import IssuesTable from "@site/src/components/Issues/IssuesTable";
+import AoETable from "@site/src/components/AoE/AoETable";
+import NamesList from "@site/src/components/Names/NamesList";
+import ActionsTable from "@site/src/components/Actions/ActionsTable";
+
+## Frames
+
+
+
+## Hitlag Data
+
+
+
+## AoE Data
+
+
+
+## Known issues
+
+
+
+## Names
+
+
+
+## Legal Actions
+
+
+
+## Params
+
+
+
+## Fields
+
+
diff --git a/ui/packages/docs/src/components/Actions/character_data.json b/ui/packages/docs/src/components/Actions/character_data.json
index 06de48834b..3335011f52 100644
--- a/ui/packages/docs/src/components/Actions/character_data.json
+++ b/ui/packages/docs/src/components/Actions/character_data.json
@@ -2303,6 +2303,40 @@
"legal": true
}
],
+ "sethos": [
+ {
+ "ability": "attack",
+ "legal": true
+ },
+ {
+ "ability": "aim",
+ "legal": true
+ },
+ {
+ "ability": "skill",
+ "legal": true
+ },
+ {
+ "ability": "burst",
+ "legal": true
+ },
+ {
+ "ability": "dash",
+ "legal": true
+ },
+ {
+ "ability": "jump",
+ "legal": true
+ },
+ {
+ "ability": "walk",
+ "notes": "Only aim followed by walk has proper frames."
+ },
+ {
+ "ability": "swap",
+ "legal": true
+ }
+ ],
"shenhe": [
{
"ability": "attack",
diff --git a/ui/packages/docs/src/components/AoE/character_data.json b/ui/packages/docs/src/components/AoE/character_data.json
index cad4573122..7bb6480271 100644
--- a/ui/packages/docs/src/components/AoE/character_data.json
+++ b/ui/packages/docs/src/components/AoE/character_data.json
@@ -7389,6 +7389,132 @@
}
]
},
+ "sethos": {
+ "normal": [
+ {
+ "ability": "N1",
+ "shape": "Box",
+ "center": "PrimaryTarget",
+ "offsetY": -0.5,
+ "boxX": 0.1,
+ "boxY": 1
+ },
+ {
+ "ability": "N2-1",
+ "shape": "Box",
+ "center": "PrimaryTarget",
+ "offsetY": -0.5,
+ "boxX": 0.1,
+ "boxY": 1
+ },
+ {
+ "ability": "N2-2",
+ "shape": "Box",
+ "center": "PrimaryTarget",
+ "offsetY": -0.5,
+ "boxX": 0.1,
+ "boxY": 1
+ },
+ {
+ "ability": "N3",
+ "shape": "Box",
+ "center": "PrimaryTarget",
+ "offsetY": -0.5,
+ "boxX": 0.1,
+ "boxY": 1
+ },
+ {
+ "ability": "Q-N1",
+ "shape": "Box",
+ "center": "Player",
+ "boxX": 0.1,
+ "boxY": 15,
+ "notes": "This is an approximation because we do not actually know the real AoE. This attack is a line going from the Player to the direction of the Primary Target."
+ },
+ {
+ "ability": "Q-N2-1",
+ "shape": "Box",
+ "center": "Player",
+ "boxX": 0.1,
+ "boxY": 15,
+ "notes": "This is an approximation because we do not actually know the real AoE. This attack is a line going from the Player to the direction of the Primary Target."
+ },
+ {
+ "ability": "Q-N2-2",
+ "shape": "Box",
+ "center": "Player",
+ "boxX": 0.1,
+ "boxY": 15,
+ "notes": "This is an approximation because we do not actually know the real AoE. This attack is a line going from the Player to the direction of the Primary Target."
+ },
+ {
+ "ability": "Q-N3",
+ "shape": "Box",
+ "center": "Player",
+ "boxX": 0.1,
+ "boxY": 15,
+ "notes": "This is an approximation because we do not actually know the real AoE. This attack is a line going from the Player to the direction of the Primary Target."
+ }
+ ],
+ "aim": [
+ {
+ "ability": "Aim",
+ "shape": "Box",
+ "center": "PrimaryTarget",
+ "offsetY": -0.5,
+ "boxX": 0.1,
+ "boxY": 1
+ },
+ {
+ "ability": "Aim-Head",
+ "shape": "Box",
+ "center": "PrimaryTarget",
+ "offsetY": -0.5,
+ "boxX": 0.1,
+ "boxY": 1
+ },
+ {
+ "ability": "FullAim",
+ "shape": "Box",
+ "center": "PrimaryTarget",
+ "offsetY": -0.5,
+ "boxX": 0.1,
+ "boxY": 1
+ },
+ {
+ "ability": "FullAim-Head",
+ "shape": "Box",
+ "center": "PrimaryTarget",
+ "offsetY": -0.5,
+ "boxX": 0.1,
+ "boxY": 1
+ },
+ {
+ "ability": "ShadowpiercingShot",
+ "shape": "Box",
+ "center": "Player",
+ "boxX": 0.1,
+ "boxY": 15,
+ "notes": "This is an approximation because we do not actually know the real AoE. This attack is a line going from the Player to the direction of the Primary Target."
+ },
+ {
+ "ability": "ShadowpiercingShot-Head",
+ "shape": "Box",
+ "center": "Player",
+ "boxX": 0.1,
+ "boxY": 15,
+ "notes": "This is an approximation because we do not actually know the real AoE. This attack is a line going from the Player to the direction of the Primary Target."
+ }
+ ],
+ "skill": [
+ {
+ "ability": "E",
+ "shape": "Circle",
+ "center": "Player",
+ "radius": 4.5
+ }
+ ]
+ },
"shenhe": {
"normal": [
{
diff --git a/ui/packages/docs/src/components/Fields/character_data.json b/ui/packages/docs/src/components/Fields/character_data.json
index ff58a6aeba..94cd4dffdb 100644
--- a/ui/packages/docs/src/components/Fields/character_data.json
+++ b/ui/packages/docs/src/components/Fields/character_data.json
@@ -163,14 +163,6 @@
"desc": "Number of Prop Surplus stacks."
}
],
- "mualani": [
- {
- "fields": [
- ".mualani.momentum"
- ],
- "desc": "Number of Wave Momentum stacks."
- }
- ],
"navia": [
{
"fields": [
diff --git a/ui/packages/docs/src/components/Frames/character_data.json b/ui/packages/docs/src/components/Frames/character_data.json
index 5399f17669..569c386b2c 100644
--- a/ui/packages/docs/src/components/Frames/character_data.json
+++ b/ui/packages/docs/src/components/Frames/character_data.json
@@ -1125,6 +1125,14 @@
"count": "https://docs.google.com/spreadsheets/d/1vLH6ZiAhb7G-f5ecYy-sPLoCdouA5krMixtgh9ITX2Q/edit?usp=sharing"
}
],
+ "sethos": [
+ {
+ "vid_credit": "wh1t3snak",
+ "count_credit": "wh1t3snak",
+ "vid": "https://youtu.be/MYXatbTDbBo",
+ "count": "https://docs.google.com/spreadsheets/d/1Fxk8KZtVJjY2P9BX5IIy4oNHIcPqCTi6zqrdAn335dY/edit?usp=sharing"
+ }
+ ],
"shenhe": [
{
"vid_credit": "Kolibri#7675 (special thanks to Xreejan#1180)",
diff --git a/ui/packages/docs/src/components/Hitlag/character_data.json b/ui/packages/docs/src/components/Hitlag/character_data.json
index 1ee6979e23..840f02f00c 100644
--- a/ui/packages/docs/src/components/Hitlag/character_data.json
+++ b/ui/packages/docs/src/components/Hitlag/character_data.json
@@ -2845,6 +2845,31 @@
}
]
},
+ "sethos": {
+ "aim": [
+ {
+ "ability": "Aim-Head",
+ "hitHaltTime": 0.12,
+ "hitHaltTimeScale": 0.01,
+ "canBeDefenseHalt": false,
+ "deployable": true
+ },
+ {
+ "ability": "FullAim-Head",
+ "hitHaltTime": 0.12,
+ "hitHaltTimeScale": 0.01,
+ "canBeDefenseHalt": false,
+ "deployable": true
+ },
+ {
+ "ability": "ShadowpiercingShot-Head",
+ "hitHaltTime": 0.12,
+ "hitHaltTimeScale": 0.01,
+ "canBeDefenseHalt": false,
+ "deployable": true
+ }
+ ]
+ },
"shenhe": {
"normal": [
{
diff --git a/ui/packages/docs/src/components/Names/character_data.json b/ui/packages/docs/src/components/Names/character_data.json
index b65e2ef72d..0b3c65db84 100644
--- a/ui/packages/docs/src/components/Names/character_data.json
+++ b/ui/packages/docs/src/components/Names/character_data.json
@@ -117,6 +117,7 @@
"koko"
],
"sayu": [],
+ "sethos": [],
"shenhe": [],
"heizou": [
"shikanoinheizou"
diff --git a/ui/packages/docs/src/components/Params/character_data.json b/ui/packages/docs/src/components/Params/character_data.json
index 1bf3ab85eb..bac80c28b7 100644
--- a/ui/packages/docs/src/components/Params/character_data.json
+++ b/ui/packages/docs/src/components/Params/character_data.json
@@ -961,6 +961,28 @@
"desc": "0 for Tap (default), value between 1 and 600 for Hold. The number determines the E duration in frames."
}
],
+ "sethos": [
+ {
+ "ability": "attack",
+ "param": "travel",
+ "desc": "Projectile travel time. Default 10 frames."
+ },
+ {
+ "ability": "aim",
+ "param": "hold",
+ "desc": "0 for Physical Aimed Shot, 1 for Fully-Charged Aimed Shot (default), 2 for Shadowpiercing Shot."
+ },
+ {
+ "ability": "aim",
+ "param": "travel",
+ "desc": "Projectile travel time. Default 10 frames."
+ },
+ {
+ "ability": "aim",
+ "param": "weakspot",
+ "desc": "Hit weakspot with aimed shot. Default 0 (false), 1 for true."
+ }
+ ],
"shenhe": [
{
"ability": "skill",
diff --git a/ui/packages/localization/src/locales/names.generated.json b/ui/packages/localization/src/locales/names.generated.json
index f3805480ca..a75b4cd502 100644
--- a/ui/packages/localization/src/locales/names.generated.json
+++ b/ui/packages/localization/src/locales/names.generated.json
@@ -74,6 +74,7 @@
"rosaria": "罗莎莉亚",
"sara": "九条裟罗",
"sayu": "早柚",
+ "sethos": "赛索斯",
"shenhe": "申鹤",
"sucrose": "砂糖",
"tartaglia": "达达利亚",
@@ -578,6 +579,7 @@
"rulerofthechizhangmountainsyiji": "赤璋巡岳府君·移即",
"samachurlboss": "(test)丘丘萨满BOSS",
"sangonomiyacohort": "珊瑚宫众",
+ "secretsourceautomatonconfigurationdevice": "秘源机兵·构型械",
"secretsourceautomatonhunterseeker": "秘源机兵·寻捕械",
"setekhwenut": "风蚀沙虫",
"shadowyhuskdefender": "黯色空壳·近卫",
@@ -605,6 +607,7 @@
"swiftstepstormscout": "疾迅勇士·荡风斥候",
"taintedwatersplittingphantasm": "浊水粉碎幻灵",
"taintedwaterspoutingphantasm": "浊水喷吐幻灵",
+ "tenebrousmimiflora": "深邃拟覆叶",
"tepetlisaurus": "嵴锋龙",
"tepetlisaurustribechief": "嵴锋龙部族首领",
"tepetlisauruswarriorrockbreakerblade": "嵴锋龙武士·破岩锐刃",
@@ -734,6 +737,7 @@
"rosaria": "Rosaria",
"sara": "Kujou Sara",
"sayu": "Sayu",
+ "sethos": "Sethos",
"shenhe": "Shenhe",
"sucrose": "Sucrose",
"tartaglia": "Tartaglia",
@@ -1238,6 +1242,7 @@
"rulerofthechizhangmountainsyiji": "Ruler of the Chizhang Mountains: Yiji",
"samachurlboss": "Samachurl Boss",
"sangonomiyacohort": "Sangonomiya Cohort",
+ "secretsourceautomatonconfigurationdevice": "Secret Source Automaton: Configuration Device",
"secretsourceautomatonhunterseeker": "Secret Source Automaton: Hunter-Seeker",
"setekhwenut": "Setekh Wenut",
"shadowyhuskdefender": "Shadowy Husk: Defender",
@@ -1265,6 +1270,7 @@
"swiftstepstormscout": "Swiftstep Storm Scout",
"taintedwatersplittingphantasm": "Tainted Water-Splitting Phantasm",
"taintedwaterspoutingphantasm": "Tainted Water-Spouting Phantasm",
+ "tenebrousmimiflora": "Tenebrous Mimiflora",
"tepetlisaurus": "Tepetlisaurus",
"tepetlisaurustribechief": "Tepetlisaurus Tribe Chief",
"tepetlisauruswarriorrockbreakerblade": "Tepetlisaurus Warrior: Rockbreaker Blade",
@@ -1394,6 +1400,7 @@
"rosaria": "Rosaria",
"sara": "Kujou Sara",
"sayu": "Sayu",
+ "sethos": "Sethos",
"shenhe": "Shenhe",
"sucrose": "Saccharose",
"tartaglia": "Tartaglia",
@@ -1898,6 +1905,7 @@
"rulerofthechizhangmountainsyiji": "Streifenherrscher der Berge von Chizhang – Yiji",
"samachurlboss": "Samachurl-Boss",
"sangonomiyacohort": "Sangonomiya-Kohorte",
+ "secretsourceautomatonconfigurationdevice": "Geheimquellen-Automaton – Konfigurationsgerät",
"secretsourceautomatonhunterseeker": "Geheimquellen-Automaton – Jäger-Sucher",
"setekhwenut": "Setekh Wenut",
"shadowyhuskdefender": "Hülle der Finsternis – Garde",
@@ -1925,6 +1933,7 @@
"swiftstepstormscout": "Recke des schnellen Schritts – Sturmspäher",
"taintedwatersplittingphantasm": "Wasser spaltender Okeanospuk",
"taintedwaterspoutingphantasm": "Wasser speiender Okeanospuk",
+ "tenebrousmimiflora": "Abgrundimitator",
"tepetlisaurus": "Tepetlisaurier",
"tepetlisaurustribechief": "Häuptling des Tepetlisaurierstamms",
"tepetlisauruswarriorrockbreakerblade": "Tepetlisaurierkrieger – Felsbrecherklinge",
@@ -2054,6 +2063,7 @@
"rosaria": "ロサリア",
"sara": "九条裟羅",
"sayu": "早柚",
+ "sethos": "セトス",
"shenhe": "申鶴",
"sucrose": "スクロース",
"tartaglia": "タルタリヤ",
@@ -2557,6 +2567,7 @@
"rulerofthechizhangmountainstianyu": "赤璋巡岳府君·天虞",
"rulerofthechizhangmountainsyiji": "赤璋巡岳府君·移即",
"sangonomiyacohort": "珊瑚宮衆",
+ "secretsourceautomatonconfigurationdevice": "秘源機兵・機巧デバイス",
"secretsourceautomatonhunterseeker": "秘源機兵·ハンターシーカー",
"setekhwenut": "風蝕ウェネト",
"shadowyhuskdefender": "シャドウハスク·守衛",
@@ -2584,6 +2595,7 @@
"swiftstepstormscout": "迅疾の勇士·ストームスカウト",
"taintedwatersplittingphantasm": "濁水粉砕の幻霊",
"taintedwaterspoutingphantasm": "濁水噴出の幻霊",
+ "tenebrousmimiflora": "深遠なるミミックフローラ",
"tepetlisaurus": "テペトル竜",
"tepetlisaurustribechief": "テペトル竜の部族の長",
"tepetlisauruswarriorrockbreakerblade": "テペトル竜戦士·砕岩のブレード",
@@ -2713,6 +2725,7 @@
"rosaria": "로자리아",
"sara": "쿠죠 사라",
"sayu": "사유",
+ "sethos": "세토스",
"shenhe": "신학",
"sucrose": "설탕",
"tartaglia": "타르탈리아",
@@ -3217,6 +3230,7 @@
"rulerofthechizhangmountainsyiji": "적장순악부군·이즉",
"samachurlboss": "츄츄 샤먼BOSS",
"sangonomiyacohort": "산호궁 사람들",
+ "secretsourceautomatonconfigurationdevice": "비밀근원 기계·구축기",
"secretsourceautomatonhunterseeker": "비밀근원 기계·포획기",
"setekhwenut": "바람 침식 모래 벌레",
"shadowyhuskdefender": "암흑의 빈 갑주·근위",
@@ -3244,6 +3258,7 @@
"swiftstepstormscout": "날쌘 용사·바람 척후병",
"taintedwatersplittingphantasm": "탁한 물의 분쇄 환령",
"taintedwaterspoutingphantasm": "탁한 물의 분사 환령",
+ "tenebrousmimiflora": "그윽한 의태 잎뭉치",
"tepetlisaurus": "산룡",
"tepetlisaurustribechief": "산룡 부족 족장",
"tepetlisauruswarriorrockbreakerblade": "산룡 무사·바위 파쇄검",
@@ -3373,6 +3388,7 @@
"rosaria": "Розария",
"sara": "Сара",
"sayu": "Саю",
+ "sethos": "Сетос",
"shenhe": "Шэнь Хэ",
"sucrose": "Сахароза",
"tartaglia": "Тарталья",
@@ -3877,6 +3893,7 @@
"rulerofthechizhangmountainsyiji": "Владыка гор Чичжан: Ицзи",
"samachurlboss": "Босс шамачурлов",
"sangonomiyacohort": "Сторонник Сангономии",
+ "secretsourceautomatonconfigurationdevice": "Автоматон таинственного источника: Конфигуратор",
"secretsourceautomatonhunterseeker": "Автоматон таинственного источника: Охотник-ищейка",
"setekhwenut": "Унут Сетеха",
"shadowyhuskdefender": "Чёрный доспех: Гвардеец",
@@ -3904,6 +3921,7 @@
"swiftstepstormscout": "Стремительный воин: Разведчик ветра",
"taintedwatersplittingphantasm": "Дробящий воду фантазм",
"taintedwaterspoutingphantasm": "Извергающий воду фантазм",
+ "tenebrousmimiflora": "Сумрачная мимифлора",
"tepetlisaurus": "Тепетлизавр",
"tepetlisaurustribechief": "Вождь племени тепетлизавров",
"tepetlisauruswarriorrockbreakerblade": "Тепетлизавр-воин: Камнедробитель",
@@ -4033,6 +4051,7 @@
"rosaria": "Rosaria",
"sara": "Kujou Sara",
"sayu": "Sayu",
+ "sethos": "Sethos",
"shenhe": "Shenhe",
"sucrose": "Sacarosa",
"tartaglia": "Tartaglia",
@@ -4537,6 +4556,7 @@
"rulerofthechizhangmountainsyiji": "Patrullamontañas de Chizhang - Yiji",
"samachurlboss": "Samachurl jefe",
"sangonomiyacohort": "Secuaz de Sangonomiya",
+ "secretsourceautomatonconfigurationdevice": "Autómata Fuentenigma - Máquina configuracional",
"secretsourceautomatonhunterseeker": "Autómata Fuentenigma - Rastreador",
"setekhwenut": "Gusano de Sutej",
"shadowyhuskdefender": "Soldado del Vacío - Defensor",
@@ -4564,6 +4584,7 @@
"swiftstepstormscout": "Guerrero Raudo - Exploracéfiros",
"taintedwatersplittingphantasm": "Ánima Aplastalodo",
"taintedwaterspoutingphantasm": "Ánima Escupelodo",
+ "tenebrousmimiflora": "Licopodio Abismático",
"tepetlisaurus": "Tepetlisaurio",
"tepetlisaurustribechief": "Jefe de la tribu de los Tepetlisaurios",
"tepetlisauruswarriorrockbreakerblade": "Soldado Tepetlisaurio - Destrozarrocas",
diff --git a/ui/packages/ui/src/Data/char_data.generated.json b/ui/packages/ui/src/Data/char_data.generated.json
index b172bd636f..7795dbcef8 100644
--- a/ui/packages/ui/src/Data/char_data.generated.json
+++ b/ui/packages/ui/src/Data/char_data.generated.json
@@ -1251,6 +1251,23 @@
},
"name_text_hash_map ": "2388785242"
},
+ "sethos": {
+ "id": 10000097,
+ "key": "sethos",
+ "rarity": "QUALITY_PURPLE",
+ "body": "BODY_BOY",
+ "region": "ASSOC_TYPE_SUMERU",
+ "element": "Electric",
+ "weapon_class": "WEAPON_BOW",
+ "icon_name": "UI_AvatarIcon_Sethos",
+ "skill_details": {
+ "skill": 10972,
+ "burst": 10975,
+ "attack": 10971,
+ "burst_energy_cost": 60
+ },
+ "name_text_hash_map ": "1431322346"
+ },
"shenhe": {
"id": 10000063,
"key": "shenhe",
diff --git a/ui/packages/ui/src/Data/weapon_data.generated.json b/ui/packages/ui/src/Data/weapon_data.generated.json
index 830850e627..337c94a864 100644
--- a/ui/packages/ui/src/Data/weapon_data.generated.json
+++ b/ui/packages/ui/src/Data/weapon_data.generated.json
@@ -1561,4 +1561,4 @@
"name_text_hash_map ": "143051931"
}
}
-}
\ No newline at end of file
+}
diff --git a/ui/packages/ui/src/util/mode-gcsim.js b/ui/packages/ui/src/util/mode-gcsim.js
index c05ff28f0e..0cf4efe39c 100644
--- a/ui/packages/ui/src/util/mode-gcsim.js
+++ b/ui/packages/ui/src/util/mode-gcsim.js
@@ -79,7 +79,7 @@ ace.define(
'let|while|if|else|fn|switch|case|default|break|continue|fallthrough|return|for|' +
'options|add|char|stats|weapon|set|lvl|refine|cons|talent|count|active|target|particle_threshold|particle_drop_count|resist|energy|hurt';
var gcsimAvatars =
- 'traveleranemo|travelergeo|travelerelectro|travelerdendro|travelerhydro|travelerpyro|travelercryo|aether-anemo|lumine-anemo|aether-geo|lumine-geo|aether-electro|lumine-electro|aether-dendro|lumine-dendro|aether-hydro|lumine-hydro|aether-pyro|lumine-pyro|aether-cryo|lumine-cryo|aetheranemo|lumineanemo|aethergeo|luminegeo|aetherelectro|lumineelectro|aetherdendro|luminedendro|aetherhydro|luminehydro|aetherpyro|luminepyro|aethercryo|luminecryo|albedo|aloy|amber|barbara|barb|beidou|bennett|charlotte|chongyun|chong|cyno|diluc|diona|eula|fischl|fish|amy|ganyu|hutao|tao|ht|jean|kaedeharakazuha|kazuha|kaz|kaeya|kamisatoayaka|ayaka|kamisatoayato|ayato|keqing|keq|klee|kujousara|kujosara|sara|lisa|mona|ningguang|ning|noelle|qiqi|raidenshogun|raiden|herexcellencythealmightynarukamiogoshogodofthunder|razor|rosaria|rosa|sangonomiyakokomi|kokomi|koko|sayu|sucrose|tartaglia|childe|thoma|venti|xiangling|xl|xianyun|cloudretainer|liuyun|xiao|xingqiu|xq|xinyan|yanfei|yoimiya|yoi|yunjin|zhongli|zhong|zl|gorou|aratakiitto|itto|aratakitheoneandoniitto|shenhe|yae|yaemiko|yelan|kukishinobu|kuki|shikanoinheizou|heizou|tighnari|collei|dori|candace|nilou|kusanali|lesserlordkusanali|nahida|layla|faruzan|faru|wanderer|scaramouche|scara|kunikuzushi|kuni|kabukimono|alhaitham|haitham|baizhu|dehya|yaoyao|mika|kaveh|kirara|lyney|lynette|neuvillette|neuv|chiefjusticeoffontaine|freminet|furina|furinadefontaine|navia|demoiselle|wriothesley|wrio|chevreuse|chev|gaming|chiori|arlecchino|arle|clorinde|emilie|mualani';
+ 'traveleranemo|travelergeo|travelerelectro|travelerdendro|travelerhydro|travelerpyro|travelercryo|aether-anemo|lumine-anemo|aether-geo|lumine-geo|aether-electro|lumine-electro|aether-dendro|lumine-dendro|aether-hydro|lumine-hydro|aether-pyro|lumine-pyro|aether-cryo|lumine-cryo|aetheranemo|lumineanemo|aethergeo|luminegeo|aetherelectro|lumineelectro|aetherdendro|luminedendro|aetherhydro|luminehydro|aetherpyro|luminepyro|aethercryo|luminecryo|albedo|aloy|amber|barbara|barb|beidou|bennett|charlotte|chongyun|chong|cyno|diluc|diona|eula|fischl|fish|amy|ganyu|hutao|tao|ht|jean|kaedeharakazuha|kazuha|kaz|kaeya|kamisatoayaka|ayaka|kamisatoayato|ayato|keqing|keq|klee|kujousara|kujosara|sara|lisa|mona|ningguang|ning|noelle|qiqi|raidenshogun|raiden|herexcellencythealmightynarukamiogoshogodofthunder|razor|rosaria|rosa|sangonomiyakokomi|kokomi|koko|sayu|sucrose|tartaglia|childe|thoma|venti|xiangling|xl|xianyun|cloudretainer|liuyun|xiao|xingqiu|xq|xinyan|yanfei|yoimiya|yoi|yunjin|zhongli|zhong|zl|gorou|aratakiitto|itto|aratakitheoneandoniitto|shenhe|yae|yaemiko|yelan|kukishinobu|kuki|shikanoinheizou|heizou|tighnari|collei|dori|candace|nilou|kusanali|lesserlordkusanali|nahida|layla|faruzan|faru|wanderer|scaramouche|scara|kunikuzushi|kuni|kabukimono|alhaitham|haitham|baizhu|dehya|yaoyao|mika|kaveh|kirara|lyney|lynette|neuvillette|neuv|chiefjusticeoffontaine|freminet|furina|furinadefontaine|navia|demoiselle|wriothesley|wrio|chevreuse|chev|gaming|chiori|arlecchino|arle|clorinde|emilie|mualani|sethos';
var gcsimAbilities =
'attack|charge|aim|skill|burst|low_plunge|high_plunge|dash|jump|walk|swap';
var gcsimStats = 'hp(?:%)?|atk(?:%)?|def(?:%)?|er|em|cr|cd|heal|phys%';