Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/characters/traveler/common/anemo/traveleranemo.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
c.SkillCon = 5
c.NormalHitNum = normalHitNum

common.TravelerBaseAtkIncrease(w, p)
common.TravelerStoryBuffs(w, p)
return &c, nil
}

Expand Down
28 changes: 0 additions & 28 deletions internal/characters/traveler/common/baseatk.go

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
c.SkillCon = 3
c.NormalHitNum = normalHitNum

common.TravelerBaseAtkIncrease(w, p)
common.TravelerStoryBuffs(w, p)
return &c, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
c.SkillCon = 5
c.NormalHitNum = normalHitNum

common.TravelerBaseAtkIncrease(w, p)
common.TravelerStoryBuffs(w, p)
return &c, nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/characters/traveler/common/geo/travelergeo.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
c.NormalHitNum = normalHitNum
c.skillCD = 6 * 60

common.TravelerBaseAtkIncrease(w, p)
common.TravelerStoryBuffs(w, p)
return &c, nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/characters/traveler/common/hydro/travelerhydro.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func NewTraveler(s *core.Core, w *character.CharWrapper, p info.CharacterProfile
c.HasArkhe = true
c.NormalHitNum = normalHitNum

common.TravelerBaseAtkIncrease(w, p)
common.TravelerStoryBuffs(w, p)
return &c, nil
}

Expand Down
40 changes: 40 additions & 0 deletions internal/characters/traveler/common/pyro/asc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package pyro

import "github.com/genshinsim/gcsim/pkg/core/event"

const a4OnReactICD = "travelerpyro-a4-icd"

func (c *Traveler) a4Init() {
if c.Base.Ascension < 4 {
return
}
fReactionHook := func(args ...interface{}) bool {
// if PMC is in NS Blessing, then the active character should
// be inside a Blazing Threshold or Scorching Threshold since it
// always follows active character
if !c.nightsoulState.HasBlessing() {
return false
}
if c.StatusIsActive(a4OnReactICD) {
return false
}

c.AddStatus(a4OnReactICD, 12, true)
c.AddEnergy("travelerpyro-a4-energy", 5)
return false
}

fNSHook := func(args ...interface{}) bool {
c.AddEnergy("travelerpyro-a4-energy", 4)
return false
}

c.Core.Events.Subscribe(event.OnBurning, fReactionHook, "travelerpyro-a4-onburning")
c.Core.Events.Subscribe(event.OnVaporize, fReactionHook, "travelerpyro-a4-onvaporize")
c.Core.Events.Subscribe(event.OnMelt, fReactionHook, "travelerpyro-a4-onmelt")
c.Core.Events.Subscribe(event.OnOverload, fReactionHook, "travelerpyro-a4-onoverload")
c.Core.Events.Subscribe(event.OnBurgeon, fReactionHook, "travelerpyro-a4-onburgeon")
c.Core.Events.Subscribe(event.OnSwirlPyro, fReactionHook, "travelerpyro-a4-onswirlpyro")
c.Core.Events.Subscribe(event.OnCrystallizePyro, fReactionHook, "travelerpyro-a4-oncrystallizepyro")
c.Core.Events.Subscribe(event.OnNightsoulBurst, fNSHook, "travelerpyro-a4-onnsburst")
}
115 changes: 115 additions & 0 deletions internal/characters/traveler/common/pyro/attack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package pyro

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

var (
attackFrames [][][]int
attackHitmarks = [][]int{{13, 13, 16, 30, 25}, {16, 10, 19, 23, 14}}
attackHitlagHaltFrame = [][]float64{{0.03, 0.03, 0.06, 0.09, 0.12}, {0.03, 0.03, 0.06, 0.06, 0.10}}
attackHitboxes = [][][]float64{{{1.4, 2.2}, {1.7}, {1.5, 2.2}, {1.7}, {1.75}}, {{1.6}, {1.4, 2.2}, {1.5}, {1.5}, {1.6}}}
attackOffsets = [][]float64{{0, 0.6, 0.4, 0.6, 0.6}, {1, 0, 0.7, 0.7, 1}}
attackFanAngles = [][]float64{{360, 180, 360, 360, 240}, {360, 360, 360, 360, 360}}
)

const normalHitNum = 5

func init() {
attackFrames = make([][][]int, 2)

// Male
attackFrames[0] = make([][]int, normalHitNum)

attackFrames[0][0] = frames.InitNormalCancelSlice(attackHitmarks[0][0], 28) // N1 -> CA
attackFrames[0][0][action.ActionAttack] = 17 // N1 -> N2

attackFrames[0][1] = frames.InitNormalCancelSlice(attackHitmarks[0][1], 28) // N2 -> CA
attackFrames[0][1][action.ActionAttack] = 26 // N2 -> N3

attackFrames[0][2] = frames.InitNormalCancelSlice(attackHitmarks[0][2], 36) // N3 -> CA
attackFrames[0][2][action.ActionAttack] = 32 // N3 -> N4

attackFrames[0][3] = frames.InitNormalCancelSlice(attackHitmarks[0][3], 45) // N4 -> CA
attackFrames[0][3][action.ActionAttack] = 39 // N4 -> N5

attackFrames[0][4] = frames.InitNormalCancelSlice(attackHitmarks[0][4], 69) // N5 -> N1
attackFrames[0][4][action.ActionCharge] = 500 // N5 -> CA, TODO: this action is illegal; need better way to handle it

// Female
attackFrames[1] = make([][]int, normalHitNum)

attackFrames[1][0] = frames.InitNormalCancelSlice(attackHitmarks[1][0], 32) // N1 -> CA
attackFrames[1][0][action.ActionAttack] = 24 // N1 -> N2

attackFrames[1][1] = frames.InitNormalCancelSlice(attackHitmarks[1][1], 23) // N2 -> CA
attackFrames[1][1][action.ActionAttack] = 21 // N2 -> N3

attackFrames[1][2] = frames.InitNormalCancelSlice(attackHitmarks[1][2], 39) // N3 -> CA
attackFrames[1][2][action.ActionAttack] = 27 // N3 -> N4

attackFrames[1][3] = frames.InitNormalCancelSlice(attackHitmarks[1][3], 45) // N4 -> CA
attackFrames[1][3][action.ActionAttack] = 38 // N4 -> N5

attackFrames[1][4] = frames.InitNormalCancelSlice(attackHitmarks[1][4], 64) // N5 -> N1
attackFrames[1][4][action.ActionCharge] = 500 // N5 -> CA, TODO: this action is illegal; need better way to handle it
}

func (c *Traveler) Attack(p map[string]int) (action.Info, error) {
ai := combat.AttackInfo{
ActorIndex: c.Index,
Abil: fmt.Sprintf("Normal %v", c.NormalCounter),
AttackTag: attacks.AttackTagNormal,
ICDTag: attacks.ICDTagNormalAttack,
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeSlash,
Element: attributes.Physical,
Durability: 25,
Mult: attack[c.NormalCounter][c.TalentLvlAttack()],
HitlagFactor: 0.01,
HitlagHaltFrames: attackHitlagHaltFrame[c.gender][c.NormalCounter] * 60,
CanBeDefenseHalted: true,
}
if c.Base.Cons >= 6 && c.nightsoulState.HasBlessing() {
ai.Element = attributes.Pyro
ai.IgnoreInfusion = true
ai.AdditionalTags = []attacks.AdditionalTag{attacks.AdditionalTagNightsoul}
}
ap := combat.NewCircleHitOnTargetFanAngle(
c.Core.Combat.Player(),
geometry.Point{Y: attackOffsets[c.gender][c.NormalCounter]},
attackHitboxes[c.gender][c.NormalCounter][0],
attackFanAngles[c.gender][c.NormalCounter],
)
if (c.gender == 0 && (c.NormalCounter == 0 || c.NormalCounter == 2)) ||
(c.gender == 1 && c.NormalCounter == 1) {
ap = combat.NewBoxHitOnTarget(
c.Core.Combat.Player(),
geometry.Point{Y: attackOffsets[c.gender][c.NormalCounter]},
attackHitboxes[c.gender][c.NormalCounter][0],
attackHitboxes[c.gender][c.NormalCounter][1],
)
}
c.Core.QueueAttack(
ai,
ap,
attackHitmarks[c.gender][c.NormalCounter],
attackHitmarks[c.gender][c.NormalCounter],
)

defer c.AdvanceNormalIndex()

return action.Info{
Frames: frames.NewAttackFunc(c.Character, attackFrames[c.gender]),
AnimationLength: attackFrames[c.gender][c.NormalCounter][action.InvalidAction],
CanQueueAfter: attackHitmarks[c.gender][c.NormalCounter],
State: action.NormalAttackState,
}, nil
}
78 changes: 78 additions & 0 deletions internal/characters/traveler/common/pyro/burst.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package pyro

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

var burstFrames [][]int

const (
burstHitmark = 40
)

var (
nightsoulGainDelays = []int{42, 52, 59, 59}
)

func init() {
burstFrames = make([][]int, 2)

// Male
burstFrames[0] = frames.InitAbilSlice(49) // Q -> N1
burstFrames[0][action.ActionSkill] = 48 // Q -> E, Eh
burstFrames[0][action.ActionSwap] = 47

// Female
burstFrames[1] = frames.InitAbilSlice(49) // Q -> N1
burstFrames[1][action.ActionSkill] = 48 // Q -> E, Eh
burstFrames[1][action.ActionSwap] = 47
}

func (c *Traveler) Burst(p map[string]int) (action.Info, error) {
c.SetCD(action.ActionBurst, 18*60)
c.ConsumeEnergy(19)

c.c4AddMod()

ai := combat.AttackInfo{
ActorIndex: c.Index,
Abil: "Plains Scorcher",
AttackTag: attacks.AttackTagElementalBurst,
AdditionalTags: []attacks.AdditionalTag{attacks.AdditionalTagNightsoul},
ICDTag: attacks.ICDTagNone,
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeDefault,
Element: attributes.Pyro,
Durability: 25,
Mult: burst[c.TalentLvlBurst()],
}

c.Core.QueueAttack(
ai,
combat.NewCircleHitOnTarget(c.Core.Combat.PrimaryTarget(), nil, 4.5),
burstHitmark,
burstHitmark,
)

c.QueueCharTask(c.nightsoulGainFunc(0), nightsoulGainDelays[0])

return action.Info{
Frames: frames.NewAbilFunc(burstFrames[c.gender]),
AnimationLength: burstFrames[c.gender][action.InvalidAction],
CanQueueAfter: burstFrames[c.gender][action.ActionSwap], // earliest cancel
State: action.BurstState,
}, nil
}

func (c *Traveler) nightsoulGainFunc(count int) func() {
return func() {
c.nightsoulState.GeneratePoints(7)
if count < 3 {
c.QueueCharTask(c.nightsoulGainFunc(count+1), nightsoulGainDelays[count+1])
}
}
}
68 changes: 68 additions & 0 deletions internal/characters/traveler/common/pyro/charge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package pyro

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

var chargeFrames [][]int
var chargeHitmarks = [][]int{{9, 20}, {14, 25}}

func init() {
chargeFrames = make([][]int, 2)
// Male
chargeFrames[0] = frames.InitAbilSlice(55) // CA -> N1
chargeFrames[0][action.ActionSkill] = 37 // CA -> E
chargeFrames[0][action.ActionBurst] = 36 // CA -> Q
chargeFrames[0][action.ActionDash] = chargeHitmarks[0][len(chargeHitmarks[0])-1] // CA -> D
chargeFrames[0][action.ActionJump] = chargeHitmarks[0][len(chargeHitmarks[0])-1] // CA -> J
chargeFrames[0][action.ActionSwap] = 44 // CA -> Swap

// Female
chargeFrames[1] = frames.InitAbilSlice(58) // CA -> N1
chargeFrames[1][action.ActionSkill] = 34 // CA -> E
chargeFrames[1][action.ActionBurst] = 35 // CA -> Q
chargeFrames[1][action.ActionDash] = chargeHitmarks[1][len(chargeHitmarks[1])-1] // CA -> D
chargeFrames[1][action.ActionJump] = chargeHitmarks[1][len(chargeHitmarks[1])-1] // CA -> J
chargeFrames[1][action.ActionSwap] = chargeHitmarks[1][len(chargeHitmarks[1])-1] // CA -> Swap
}

func (c *Traveler) ChargeAttack(p map[string]int) (action.Info, error) {
ai := combat.AttackInfo{
ActorIndex: c.Index,
AttackTag: attacks.AttackTagExtra,
ICDTag: attacks.ICDTagNormalAttack,
ICDGroup: attacks.ICDGroupDefault,
StrikeType: attacks.StrikeTypeSlash,
Element: attributes.Physical,
Durability: 25,
}
if c.Base.Cons >= 6 && c.nightsoulState.HasBlessing() {
ai.Element = attributes.Pyro
ai.IgnoreInfusion = true
ai.AdditionalTags = []attacks.AdditionalTag{attacks.AdditionalTagNightsoul}
}

for i, mult := range charge[c.gender] {
ai.Mult = mult[c.TalentLvlAttack()]
ai.Abil = fmt.Sprintf("Charge %v", i)
c.Core.QueueAttack(
ai,
combat.NewCircleHitOnTarget(c.Core.Combat.Player(), nil, 2.2),
chargeHitmarks[c.gender][i],
chargeHitmarks[c.gender][i],
)
}

return action.Info{
Frames: frames.NewAbilFunc(chargeFrames[c.gender]),
AnimationLength: chargeFrames[c.gender][action.InvalidAction],
CanQueueAfter: chargeHitmarks[c.gender][len(chargeHitmarks[c.gender])-1],
State: action.ChargeAttackState,
}, nil
}
Loading