Skip to content

Commit a63a48c

Browse files
authored
Merge branch 'main' into varesa
2 parents 0f3dfe6 + 0efb594 commit a63a48c

167 files changed

Lines changed: 7508 additions & 68 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/wasm/main.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import (
1111

1212
"github.com/genshinsim/gcsim/pkg/agg"
1313
"github.com/genshinsim/gcsim/pkg/core/info"
14-
"github.com/genshinsim/gcsim/pkg/gcs"
1514
"github.com/genshinsim/gcsim/pkg/gcs/ast"
15+
"github.com/genshinsim/gcsim/pkg/gcs/eval"
16+
"github.com/genshinsim/gcsim/pkg/gcs/parser"
1617
"github.com/genshinsim/gcsim/pkg/model"
1718
"github.com/genshinsim/gcsim/pkg/simulation"
1819
"github.com/genshinsim/gcsim/pkg/simulator"
@@ -133,7 +134,7 @@ func simulate(this js.Value, args []js.Value) (out interface{}) {
133134
if err != nil {
134135
return marshal(err)
135136
}
136-
eval, err := gcs.NewEvaluator(program, core)
137+
eval, err := eval.NewEvaluator(program, core)
137138
if err != nil {
138139
return marshal(err)
139140
}
@@ -279,7 +280,7 @@ func flush(this js.Value, args []js.Value) (out interface{}) {
279280
// internal helper functions
280281

281282
func initialize(raw string) error {
282-
parser := ast.New(raw)
283+
parser := parser.New(raw)
283284
out, prog, err := parser.Parse()
284285
if err != nil {
285286
return err

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/genshinsim/gcsim
22

3-
go 1.22
3+
go 1.22.0
44

55
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
66

internal/characters/ayato/ayato.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ func (c *char) Snapshot(ai *combat.AttackInfo) combat.Snapshot {
8787
default:
8888
return ds
8989
}
90+
ai.Element = attributes.Hydro
9091
// namisen doesn't affect c6
9192
if ai.Abil == c6Abil {
9293
return ds
9394
}
94-
ai.Element = attributes.Hydro
9595
// add namisen stack
9696
flatdmg := c.MaxHP() * skillpp[c.TalentLvlSkill()] * float64(c.stacks)
9797
ai.FlatDmg += flatdmg

internal/characters/ayato/cons.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (c *char) makeC6CB() combat.AttackCBFunc {
7474
Abil: c6Abil,
7575
ActorIndex: c.Index,
7676
AttackTag: attacks.AttackTagNormal,
77-
ICDTag: attacks.ICDTagNormalAttack,
77+
ICDTag: attacks.ICDTagNone,
7878
ICDGroup: attacks.ICDGroupDefault,
7979
StrikeType: attacks.StrikeTypeSlash,
8080
Element: attributes.Hydro,
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package escoffier
2+
3+
import (
4+
"github.com/genshinsim/gcsim/pkg/core/attributes"
5+
"github.com/genshinsim/gcsim/pkg/core/combat"
6+
"github.com/genshinsim/gcsim/pkg/core/info"
7+
"github.com/genshinsim/gcsim/pkg/core/targets"
8+
"github.com/genshinsim/gcsim/pkg/enemy"
9+
"github.com/genshinsim/gcsim/pkg/modifier"
10+
)
11+
12+
const a1Scaling = 1.3824
13+
const a1key = "escoffier-a1"
14+
const a1Count = 9
15+
const a1FirstTick = 157
16+
const a1Interval = 58.5
17+
const a4Dur = 12 * 60
18+
19+
var a4Shred = []float64{0.0, 0.05, 0.10, 0.15, 0.55}
20+
21+
func (c *char) a1() {
22+
if c.Base.Ascension < 1 {
23+
return
24+
}
25+
c.a1Src = c.Core.F
26+
ticks := a1Count + c.c4ExtraCount()
27+
for i := 0; i < ticks; i++ {
28+
c.QueueCharTask(c.a1Tick(c.a1Src), a1FirstTick+ceil(a1Interval*float64(i)))
29+
}
30+
// this status is purely cosmetic and doesn't do anything right now
31+
c.AddStatus(a1key, a1FirstTick+ceil(float64(ticks-1)*a1Interval), true)
32+
}
33+
34+
func (c *char) a1Tick(src int) func() {
35+
return func() {
36+
if src != c.a1Src {
37+
return
38+
}
39+
scale := a1Scaling + c.c4ExtraHeal()
40+
heal := scale * c.TotalAtk()
41+
c.Core.Player.Heal(info.HealInfo{
42+
Caller: c.Index,
43+
Target: c.Core.Player.Active(),
44+
Message: "Rehab Diet",
45+
Src: heal,
46+
Bonus: c.Stat(attributes.Heal),
47+
})
48+
}
49+
}
50+
51+
func (c *char) a4Init() {
52+
c.a4HydroCryoCount = 0
53+
for _, char := range c.Core.Player.Chars() {
54+
switch char.Base.Element {
55+
case attributes.Hydro, attributes.Cryo:
56+
c.a4HydroCryoCount++
57+
default:
58+
}
59+
}
60+
}
61+
62+
func (c *char) makeA4CB() combat.AttackCBFunc {
63+
if c.Base.Ascension < 4 {
64+
return nil
65+
}
66+
return func(a combat.AttackCB) {
67+
if a.Target.Type() != targets.TargettableEnemy {
68+
return
69+
}
70+
e, ok := a.Target.(*enemy.Enemy)
71+
if !ok {
72+
return
73+
}
74+
shred := a4Shred[c.a4HydroCryoCount]
75+
e.AddResistMod(combat.ResistMod{
76+
Base: modifier.NewBaseWithHitlag("escoffier-a4-shred-cryo", a4Dur),
77+
Ele: attributes.Cryo,
78+
Value: -shred,
79+
})
80+
e.AddResistMod(combat.ResistMod{
81+
Base: modifier.NewBaseWithHitlag("escoffier-a4-shred-hydro", a4Dur),
82+
Ele: attributes.Hydro,
83+
Value: -shred,
84+
})
85+
}
86+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package escoffier
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/genshinsim/gcsim/internal/frames"
7+
"github.com/genshinsim/gcsim/pkg/core/action"
8+
"github.com/genshinsim/gcsim/pkg/core/attacks"
9+
"github.com/genshinsim/gcsim/pkg/core/attributes"
10+
"github.com/genshinsim/gcsim/pkg/core/combat"
11+
"github.com/genshinsim/gcsim/pkg/core/geometry"
12+
)
13+
14+
var (
15+
attackFrames [][]int
16+
attackHitmarks = [][]int{{7}, {16}, {27, 40}}
17+
attackHitlagHaltFrame = [][]float64{{0.06}, {0.06}, {0.06, 0.06}}
18+
attackDefHalt = [][]bool{{true}, {true}, {true, true}}
19+
attackHitboxes = [][][]float64{{{1.6, 2}}, {{2}}, {{2.5}, {2.5}}}
20+
attackOffsets = [][]float64{{1}, {-0.2}, {-0.2, -0.2}}
21+
)
22+
23+
const normalHitNum = 3
24+
25+
func init() {
26+
attackFrames = make([][]int, normalHitNum)
27+
28+
attackFrames[0] = frames.InitNormalCancelSlice(attackHitmarks[0][0], 17)
29+
attackFrames[0][action.ActionCharge] = 20
30+
attackFrames[0][action.ActionWalk] = 22
31+
32+
attackFrames[1] = frames.InitNormalCancelSlice(attackHitmarks[1][0], 21)
33+
attackFrames[1][action.ActionAttack] = 29
34+
attackFrames[1][action.ActionWalk] = 30
35+
36+
attackFrames[2] = frames.InitNormalCancelSlice(attackHitmarks[2][1], 62)
37+
attackFrames[2][action.ActionWalk] = 61
38+
attackFrames[2][action.ActionCharge] = 500 //TODO: this action is illegal; need better way to handle it
39+
}
40+
41+
// Normal attack damage queue generator
42+
// relatively standard with no major differences versus other characters
43+
func (c *char) Attack(p map[string]int) (action.Info, error) {
44+
for i, mult := range attack[c.NormalCounter] {
45+
ai := combat.AttackInfo{
46+
ActorIndex: c.Index,
47+
Abil: fmt.Sprintf("Normal %v", c.NormalCounter),
48+
AttackTag: attacks.AttackTagNormal,
49+
ICDTag: attacks.ICDTagNormalAttack,
50+
ICDGroup: attacks.ICDGroupDefault,
51+
StrikeType: attacks.StrikeTypeSlash,
52+
Element: attributes.Physical,
53+
Durability: 25,
54+
Mult: mult[c.TalentLvlAttack()],
55+
HitlagFactor: 0.01,
56+
HitlagHaltFrames: attackHitlagHaltFrame[c.NormalCounter][i] * 60,
57+
CanBeDefenseHalted: attackDefHalt[c.NormalCounter][i],
58+
}
59+
60+
ap := combat.NewCircleHitOnTarget(
61+
c.Core.Combat.Player(),
62+
geometry.Point{Y: attackOffsets[c.NormalCounter][i]},
63+
attackHitboxes[c.NormalCounter][i][0],
64+
)
65+
if c.NormalCounter == 0 {
66+
ai.StrikeType = attacks.StrikeTypeSpear
67+
ap = combat.NewBoxHitOnTarget(
68+
c.Core.Combat.Player(),
69+
geometry.Point{Y: attackOffsets[c.NormalCounter][i]},
70+
attackHitboxes[c.NormalCounter][i][0],
71+
attackHitboxes[c.NormalCounter][i][1],
72+
)
73+
}
74+
c.QueueCharTask(func() {
75+
c.Core.QueueAttack(ai, ap, 0, 0)
76+
}, attackHitmarks[c.NormalCounter][i])
77+
}
78+
79+
defer c.AdvanceNormalIndex()
80+
81+
return action.Info{
82+
Frames: frames.NewAttackFunc(c.Character, attackFrames),
83+
AnimationLength: attackFrames[c.NormalCounter][action.InvalidAction],
84+
CanQueueAfter: attackHitmarks[c.NormalCounter][len(attackHitmarks[c.NormalCounter])-1],
85+
State: action.NormalAttackState,
86+
}, nil
87+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package escoffier
2+
3+
import (
4+
"github.com/genshinsim/gcsim/internal/frames"
5+
"github.com/genshinsim/gcsim/pkg/core/action"
6+
"github.com/genshinsim/gcsim/pkg/core/attacks"
7+
"github.com/genshinsim/gcsim/pkg/core/attributes"
8+
"github.com/genshinsim/gcsim/pkg/core/combat"
9+
"github.com/genshinsim/gcsim/pkg/core/geometry"
10+
"github.com/genshinsim/gcsim/pkg/core/info"
11+
)
12+
13+
var burstFrames []int
14+
15+
const (
16+
initialHeal = 97 // depends on ping
17+
hitmark = 92
18+
)
19+
20+
func init() {
21+
burstFrames = frames.InitAbilSlice(110)
22+
burstFrames[action.ActionSkill] = 109
23+
burstFrames[action.ActionSwap] = 108
24+
}
25+
26+
func (c *char) Burst(p map[string]int) (action.Info, error) {
27+
ai := combat.AttackInfo{
28+
ActorIndex: c.Index,
29+
Abil: "Scoring Cuts",
30+
AttackTag: attacks.AttackTagElementalBurst,
31+
ICDTag: attacks.ICDTagNone,
32+
ICDGroup: attacks.ICDGroupDefault,
33+
StrikeType: attacks.StrikeTypeDefault,
34+
Element: attributes.Cryo,
35+
Durability: 50,
36+
Mult: burst[c.TalentLvlBurst()],
37+
}
38+
c.QueueCharTask(func() {
39+
c.Core.QueueAttack(ai, combat.NewCircleHitOnTarget(c.Core.Combat.Player(), geometry.Point{Y: -1.5}, 7), 0, 0, c.makeA4CB())
40+
}, hitmark)
41+
42+
// initial heal
43+
c.QueueCharTask(func() {
44+
heal := burstHealFlat[c.TalentLvlBurst()] + burstHealPer[c.TalentLvlBurst()]*c.TotalAtk()
45+
c.Core.Player.Heal(info.HealInfo{
46+
Caller: c.Index,
47+
Target: -1,
48+
Message: "Scoring Cuts (Healing)",
49+
Src: heal,
50+
Bonus: c.Stat(attributes.Heal),
51+
})
52+
}, initialHeal)
53+
54+
c.a1()
55+
56+
c.SetCD(action.ActionBurst, int(burstCD[c.TalentLvlBurst()])*60)
57+
c.ConsumeEnergy(5)
58+
59+
c.c1()
60+
return action.Info{
61+
Frames: frames.NewAbilFunc(burstFrames),
62+
AnimationLength: burstFrames[action.InvalidAction],
63+
CanQueueAfter: burstFrames[action.ActionSwap], // earliest cancel
64+
State: action.BurstState,
65+
}, nil
66+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package escoffier
2+
3+
import (
4+
"github.com/genshinsim/gcsim/internal/frames"
5+
"github.com/genshinsim/gcsim/pkg/core/action"
6+
"github.com/genshinsim/gcsim/pkg/core/attacks"
7+
"github.com/genshinsim/gcsim/pkg/core/attributes"
8+
"github.com/genshinsim/gcsim/pkg/core/combat"
9+
"github.com/genshinsim/gcsim/pkg/core/geometry"
10+
)
11+
12+
var chargeFrames []int
13+
14+
const chargeHitmark = 20
15+
16+
func init() {
17+
chargeFrames = frames.InitAbilSlice(65)
18+
chargeFrames[action.ActionAttack] = 53
19+
chargeFrames[action.ActionSkill] = 52
20+
chargeFrames[action.ActionBurst] = 52
21+
chargeFrames[action.ActionDash] = chargeHitmark
22+
chargeFrames[action.ActionJump] = chargeHitmark
23+
chargeFrames[action.ActionSwap] = 52
24+
}
25+
26+
// Charge attack damage queue generator
27+
// Very standard - consistent with other characters like Xiangling
28+
func (c *char) ChargeAttack(p map[string]int) (action.Info, error) {
29+
ai := combat.AttackInfo{
30+
ActorIndex: c.Index,
31+
Abil: "Charge",
32+
AttackTag: attacks.AttackTagExtra,
33+
ICDTag: attacks.ICDTagNone,
34+
ICDGroup: attacks.ICDGroupPoleExtraAttack,
35+
StrikeType: attacks.StrikeTypeSlash,
36+
Element: attributes.Physical,
37+
Durability: 25,
38+
Mult: charge[c.TalentLvlAttack()],
39+
HitlagHaltFrames: 0.10,
40+
HitlagFactor: 0.01,
41+
CanBeDefenseHalted: true,
42+
}
43+
44+
c.Core.QueueAttack(
45+
ai,
46+
combat.NewBoxHit(
47+
c.Core.Combat.Player(),
48+
c.Core.Combat.PrimaryTarget(),
49+
geometry.Point{Y: 1.5},
50+
3.3,
51+
3,
52+
),
53+
chargeHitmark,
54+
chargeHitmark,
55+
)
56+
57+
return action.Info{
58+
Frames: frames.NewAbilFunc(chargeFrames),
59+
AnimationLength: chargeFrames[action.InvalidAction],
60+
CanQueueAfter: chargeHitmark,
61+
State: action.ChargeAttackState,
62+
}, nil
63+
}

0 commit comments

Comments
 (0)