Skip to content

Commit

Permalink
citlali from ange1o5
Browse files Browse the repository at this point in the history
  • Loading branch information
kengzzzz committed Nov 29, 2024
1 parent d0ce684 commit 6c8d76b
Show file tree
Hide file tree
Showing 16 changed files with 665 additions and 0 deletions.
76 changes: 76 additions & 0 deletions internal/characters/citlali/asc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package citlali

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

const (
nightSoulGenerationIcd = "a1-ns-icd-key"
)

func (c *char) a1() {
if c.Base.Ascension < 1 {
return
}
c.Core.Events.Subscribe(event.OnMelt, c.a1Hook, "citlali-a1-onmelt-res-shred")
c.Core.Events.Subscribe(event.OnFrozen, c.a1Hook, "citlali-a1-onfrozen-res-shred")
}
func (c *char) a1Hook(args ...interface{}) bool {
t, ok := args[0].(*enemy.Enemy)
if !ok {
return false
}
if !c.nightsoulState.HasBlessing() {
return false
}
if !c.StatusIsActive(nightSoulGenerationIcd) {
c.AddStatus(nightSoulGenerationIcd, 8*60, false)
c.nightsoulState.GeneratePoints(16)
c.ActivateItzpapa(c.itzpapaSrc)
if c.Base.Cons >= 1 {
c.numStellarBlades += 3
}
}
amt := -0.2
if c.Base.Cons >= 2 {
amt = -0.4
}
t.AddResistMod(combat.ResistMod{
Base: modifier.NewBaseWithHitlag("citlali-a1-hydro-res-shred", 12*60),
Ele: attributes.Hydro,
Value: amt,
})
t.AddResistMod(combat.ResistMod{
Base: modifier.NewBaseWithHitlag("citlali-a1-pyro-res-shred", 12*60),
Ele: attributes.Pyro,
Value: amt,
})
return false
}
func (c *char) a4() {
if c.Base.Ascension < 4 {
return
}
c.Core.Events.Subscribe(event.OnNightsoulBurst, func(args ...interface{}) bool {
c.nightsoulState.GeneratePoints(4)
c.ActivateItzpapa(c.itzpapaSrc)
return false
}, "citlali-a4-ns-gain")
}
func (c *char) a4Dmg(abil string) float64 {
if c.Base.Ascension < 4 {
return 0
}
em := c.NonExtraStat(attributes.EM)
if abil == iceStormAbil {
return 24 * em
}
if abil == frostFallAbil {
return 0.9 * em
}
return 0
}
69 changes: 69 additions & 0 deletions internal/characters/citlali/burst.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package citlali

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"
)

const (
iceStormHitmark = 118
spiritVesselSkullHitmark = 223
iceStormAbil = "Ice Storm DMG"
)

var (
burstFrames []int
)

func init() {
burstFrames = frames.InitAbilSlice(133) // Q -> Swap
}
func (c *char) Burst(p map[string]int) (action.Info, error) {
aiIceStorm := combat.AttackInfo{
ActorIndex: c.Index,
Abil: iceStormAbil,
AttackTag: attacks.AttackTagElementalBurst,
AdditionalTags: []attacks.AdditionalTag{attacks.AdditionalTagNightsoul},
ICDTag: attacks.ICDTagNone,
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeDefault,
Element: attributes.Cryo,
Durability: 50,
Mult: 9.677,
FlatDmg: c.a4Dmg(iceStormAbil),
}
aiSpiritVesselSkull := combat.AttackInfo{
ActorIndex: c.Index,
Abil: "Spiritvessel Skull DMG",
AttackTag: attacks.AttackTagElementalBurst,
AdditionalTags: []attacks.AdditionalTag{attacks.AdditionalTagNightsoul},
ICDTag: attacks.ICDTagElementalBurst, // TODO: check this
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeDefault,
Element: attributes.Cryo,
Durability: 25,
Mult: 2.419,
}
c.ConsumeEnergy(5)
c.SetCD(action.ActionBurst, 15*60)
c.nightsoulState.GeneratePoints(24)
c.ActivateItzpapa(c.itzpapaSrc)
c.Core.QueueAttack(aiIceStorm, combat.NewCircleHitOnTarget(c.Core.Combat.PrimaryTarget(), nil, 6.5), iceStormHitmark, iceStormHitmark)
enemies := c.Core.Combat.EnemiesWithinArea(combat.NewCircleHitOnTarget(c.Core.Combat.Player(), nil, 7), nil)
c.QueueCharTask(func() {
c.nightsoulState.GeneratePoints(float64(3 * len(enemies)))
c.ActivateItzpapa(c.itzpapaSrc)
}, spiritVesselSkullHitmark)
for _, enemy := range enemies {
c.Core.QueueAttack(aiSpiritVesselSkull, combat.NewSingleTargetHit(enemy.Key()), spiritVesselSkullHitmark, spiritVesselSkullHitmark)
}
return action.Info{
Frames: frames.NewAbilFunc(burstFrames),
AnimationLength: burstFrames[action.InvalidAction],
CanQueueAfter: burstFrames[action.ActionBurst],
State: action.BurstState,
}, nil
}
59 changes: 59 additions & 0 deletions internal/characters/citlali/citlali.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package citlali

// Citlali's Frostfall Storm applies once every 1.5s
// Initial E hit has no ICD.
// Initial burst has no ICD.
// Spiritvessel Skull ICD is default.
// C4 has no ICD.
// NA is default.
// CA has no ICD.
// 5 particles on initial E hit
import (
tmpl "github.com/genshinsim/gcsim/internal/template/character"
"github.com/genshinsim/gcsim/internal/template/nightsoul"
"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"
)

func init() {
core.RegisterCharFunc(keys.Citlali, NewChar)
}

type char struct {
*tmpl.Character
nightsoulState *nightsoul.State
itzpapaSrc int
skillShield *shd
numStellarBlades int
}

func NewChar(s *core.Core, w *character.CharWrapper, _ info.CharacterProfile) error {
c := char{}
c.Character = tmpl.NewWithWrapper(s, w)
c.EnergyMax = 60
c.NormalHitNum = 3
c.SkillCon = 3
c.BurstCon = 5
c.HasArkhe = false
w.Character = &c
c.nightsoulState = nightsoul.New(s, w)
c.nightsoulState.MaxPoints = 80 // TODO: the REAL one
c.itzpapaSrc = -1
return nil
}
func (c *char) Init() error {
c.a1()
c.a4()
c.c1()
return nil
}
func (c *char) Condition(fields []string) (any, error) {
switch fields[0] {
case "nightsoul":
return c.nightsoulState.Condition(fields)
default:
return c.Character.Condition(fields)
}
}
39 changes: 39 additions & 0 deletions internal/characters/citlali/citlali_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

87 changes: 87 additions & 0 deletions internal/characters/citlali/cons.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package citlali

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/event"
"github.com/genshinsim/gcsim/pkg/core/glog"
"github.com/genshinsim/gcsim/pkg/core/player/character"
"github.com/genshinsim/gcsim/pkg/modifier"
)

const c4SkullIcd = "c4-skull-icd"

// Additionally, when Citlali is using her leap, or is Aiming or using her
// Charged Attack in mid-air, her Phlogiston consumption is decreased by 45%.
// NOT IMPLEMENTED
func (c *char) c1() {
c.Core.Events.Subscribe(event.OnEnemyDamage, func(args ...interface{}) bool {
atk := args[1].(*combat.AttackEvent)
if c.Index == atk.Info.ActorIndex {
return false
}
if c.numStellarBlades > 0 {
em := c.NonExtraStat(attributes.EM)
amt := em * 2
if c.Core.Flags.LogDebug {
c.Core.Log.NewEvent("Citlali C1 proc dmg add", glog.LogPreDamageMod, atk.Info.ActorIndex).
Write("before", atk.Info.FlatDmg).
Write("addition", amt).
Write("Stellar Blades left", c.numStellarBlades)
}
atk.Info.FlatDmg += amt
c.numStellarBlades--
}
return false
}, "citlali-c1-on-dmg")
}

// For now, assuming her shield won't be destroyed ahead of time
func (c *char) c2() {
if c.Base.Cons < 2 {
return
}
chars := c.Core.Player.Chars()
for _, char := range chars {
char.AddStatMod(character.StatMod{
Base: modifier.NewBaseWithHitlag("citlali-c2-em", 20*60),
AffectedStat: attributes.EM,
Amount: func() ([]float64, bool) {
if c.Index == char.Index {
buffSelf := make([]float64, attributes.EndStatType)
buffSelf[attributes.EM] = 125
return buffSelf, true
}
buffOther := make([]float64, attributes.EndStatType)
buffOther[attributes.EM] = 250
return buffOther, true
},
})
}
}
func (c *char) c4Skull() {
if c.Base.Cons < 4 {
return
}
if c.StatusIsActive(c4SkullIcd) {
return
}
c.AddStatus(c4SkullIcd, 8*60, false)
c.nightsoulState.GeneratePoints(16)
aiSpiritVesselSkull := combat.AttackInfo{
ActorIndex: c.Index,
Abil: "Spiritvessel Skull DMG (C4)",
AttackTag: attacks.AttackTagNone,
AdditionalTags: []attacks.AdditionalTag{attacks.AdditionalTagNightsoul},
ICDTag: attacks.ICDTagElementalBurst, // TODO: check this
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeDefault,
Element: attributes.Cryo,
Durability: 25,
FlatDmg: 12 * c.NonExtraStat(attributes.EM),
}
// TODO: the actual hitmark
c.Core.QueueAttack(aiSpiritVesselSkull, combat.NewSingleTargetHit(c.Core.Combat.PrimaryTarget().Key()),
spiritVesselSkullHitmark-iceStormHitmark, spiritVesselSkullHitmark-iceStormHitmark)
}
Loading

0 comments on commit 6c8d76b

Please sign in to comment.