Skip to content

Commit 7c32445

Browse files
committed
added test
1 parent f8714c1 commit 7c32445

1 file changed

Lines changed: 241 additions & 0 deletions

File tree

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
package can_queue_after
2+
3+
import (
4+
"errors"
5+
"testing"
6+
"time"
7+
8+
// we import simulation like this so that import.go is pulled in
9+
10+
"github.com/genshinsim/gcsim/pkg/avatar"
11+
"github.com/genshinsim/gcsim/pkg/core"
12+
"github.com/genshinsim/gcsim/pkg/core/action"
13+
"github.com/genshinsim/gcsim/pkg/core/attributes"
14+
"github.com/genshinsim/gcsim/pkg/core/geometry"
15+
"github.com/genshinsim/gcsim/pkg/core/info"
16+
"github.com/genshinsim/gcsim/pkg/core/keys"
17+
"github.com/genshinsim/gcsim/pkg/core/player"
18+
"github.com/genshinsim/gcsim/pkg/core/player/character"
19+
"github.com/genshinsim/gcsim/pkg/enemy"
20+
_ "github.com/genshinsim/gcsim/pkg/simulation"
21+
)
22+
23+
// purpose of this test is to check that characters abilities have correct can queue after
24+
func TestCanQueue(t *testing.T) {
25+
baseActions := [][]action.Action{
26+
{action.ActionSkill},
27+
{action.ActionSkill},
28+
{action.ActionBurst},
29+
{action.ActionAttack},
30+
{action.ActionDash},
31+
{action.ActionJump},
32+
{action.ActionAttack, action.ActionCharge},
33+
{action.ActionAim},
34+
{action.ActionAim},
35+
{action.ActionAim},
36+
{action.ActionAim},
37+
{action.ActionSkill, action.ActionSkill},
38+
{action.ActionSkill, action.ActionBurst},
39+
{action.ActionSkill, action.ActionAttack},
40+
{action.ActionSkill, action.ActionDash},
41+
{action.ActionSkill, action.ActionJump},
42+
{action.ActionSkill, action.ActionAttack, action.ActionCharge},
43+
{action.ActionSkill, action.ActionAim},
44+
{action.ActionBurst, action.ActionSkill},
45+
{action.ActionBurst, action.ActionBurst},
46+
{action.ActionBurst, action.ActionAttack},
47+
{action.ActionBurst, action.ActionDash},
48+
{action.ActionBurst, action.ActionJump},
49+
{action.ActionBurst, action.ActionAttack, action.ActionCharge},
50+
{action.ActionBurst, action.ActionAim},
51+
}
52+
53+
emptyParams := make(map[string]int)
54+
55+
baseParams := [][]map[string]int{
56+
{emptyParams},
57+
{map[string]int{"hold": 1}},
58+
{emptyParams},
59+
{emptyParams},
60+
{emptyParams},
61+
{emptyParams},
62+
{emptyParams, emptyParams},
63+
{emptyParams},
64+
{map[string]int{"hold": 0}},
65+
{map[string]int{"hold": 1}},
66+
{map[string]int{"hold": 2}},
67+
{emptyParams, emptyParams},
68+
{emptyParams, emptyParams},
69+
{emptyParams, emptyParams},
70+
{emptyParams, emptyParams},
71+
{emptyParams, emptyParams},
72+
{emptyParams, emptyParams, emptyParams},
73+
{emptyParams, emptyParams},
74+
{emptyParams, emptyParams},
75+
{emptyParams, emptyParams},
76+
{emptyParams, emptyParams},
77+
{emptyParams, emptyParams},
78+
{emptyParams, emptyParams},
79+
{emptyParams, emptyParams, emptyParams},
80+
{emptyParams, emptyParams},
81+
}
82+
83+
for k := range core.NewCharFuncMap {
84+
actions := make([][]action.Action, len(baseActions))
85+
_ = copy(actions, baseActions)
86+
// insert character specific combos, params
87+
for i, a := range actions {
88+
testQueue(t, k, a, baseParams[i])
89+
}
90+
}
91+
}
92+
93+
func testQueue(t *testing.T, k keys.Char, acts []action.Action, params []map[string]int) {
94+
c, trg := makeCore(2)
95+
prof := defProfile(k)
96+
prof.Base.Cons = 6
97+
idx, err := c.AddChar(prof)
98+
if err != nil {
99+
t.Errorf("error adding char: %v", err)
100+
t.FailNow()
101+
}
102+
c.Player.SetActive(idx)
103+
err = c.Init()
104+
if err != nil {
105+
t.Errorf("error initializing core: %v", err)
106+
t.FailNow()
107+
}
108+
// initialize some settings
109+
c.Combat.DefaultTarget = trg[0].Key()
110+
c.Flags.IgnoreBurstEnergy = true
111+
112+
advanceCoreFrame(t, c)
113+
114+
for i, a := range acts {
115+
p := params[i]
116+
for {
117+
err := c.Player.ReadyCheck(a, k, p)
118+
if err == nil {
119+
break
120+
}
121+
switch {
122+
case errors.Is(err, player.ErrActionNotReady):
123+
case errors.Is(err, player.ErrPlayerNotReady):
124+
case errors.Is(err, player.ErrActionNoOp):
125+
break
126+
default:
127+
t.Errorf("unexpected error waiting for action to be ready: %v", err)
128+
t.FailNow()
129+
}
130+
advanceCoreFrame(t, c)
131+
}
132+
133+
// c.Player.Exec(a, k, p)
134+
135+
evt, err := getAction(c.Player.ActiveChar(), a)(p)
136+
if err != nil {
137+
return
138+
}
139+
for act := range action.EndActionType {
140+
// Normal attacks trigger this panic when there is atkspd
141+
if evt.State == action.NormalAttackState && c.Player.ActiveChar().Stat(attributes.AtkSpd) > 0 {
142+
break
143+
}
144+
145+
// Charge attacks for Itto/Wanderer trigger this
146+
if evt.State == action.ChargeAttackState && c.Player.ActiveChar().Stat(attributes.AtkSpd) > 0 {
147+
break
148+
}
149+
if evt.Frames(act) < evt.CanQueueAfter {
150+
t.Errorf("character %s action %s params: %v CanQueueAfter (%d) is larger than the output of evt.Frames[%s] (%d)", c.Player.ActiveChar().Base.Key.String(), a, p, evt.CanQueueAfter, act.String(), evt.Frames(act))
151+
}
152+
}
153+
for !c.Player.CanQueueNextAction() {
154+
advanceCoreFrame(t, c)
155+
}
156+
}
157+
}
158+
159+
func getAction(char *character.CharWrapper, t action.Action) func(p map[string]int) (action.Info, error) {
160+
switch t {
161+
case action.ActionCharge:
162+
return char.ChargeAttack
163+
case action.ActionDash:
164+
return char.Dash
165+
case action.ActionJump:
166+
return char.Jump
167+
case action.ActionWalk:
168+
return char.Walk
169+
case action.ActionAim:
170+
return char.Aimed
171+
case action.ActionSkill:
172+
return char.Skill
173+
case action.ActionBurst:
174+
return char.Burst
175+
case action.ActionAttack:
176+
return char.Attack
177+
case action.ActionHighPlunge:
178+
return char.HighPlungeAttack
179+
case action.ActionLowPlunge:
180+
return char.LowPlungeAttack
181+
default:
182+
return char.Walk
183+
}
184+
}
185+
186+
func makeCore(trgCount int) (*core.Core, []*enemy.Enemy) {
187+
c, _ := core.New(core.Opt{
188+
Seed: time.Now().Unix(),
189+
Debug: true,
190+
})
191+
a := avatar.New(c, geometry.Point{X: 0, Y: 0}, 1)
192+
c.Combat.SetPlayer(a)
193+
var trgs []*enemy.Enemy
194+
195+
for i := 0; i < trgCount; i++ {
196+
e := enemy.New(c, info.EnemyProfile{
197+
Level: 100,
198+
Resist: make(map[attributes.Element]float64),
199+
Pos: info.Coord{
200+
X: 0,
201+
Y: 0,
202+
R: 1,
203+
},
204+
})
205+
trgs = append(trgs, e)
206+
c.Combat.AddEnemy(e)
207+
}
208+
209+
c.Player.SetActive(0)
210+
211+
return c, trgs
212+
}
213+
214+
func defProfile(key keys.Char) info.CharacterProfile {
215+
p := info.CharacterProfile{}
216+
p.Base.Key = key
217+
p.Stats = make([]float64, attributes.EndStatType)
218+
p.StatsByLabel = make(map[string][]float64)
219+
p.Params = make(map[string]int)
220+
p.Sets = make(map[keys.Set]int)
221+
p.SetParams = make(map[keys.Set]map[string]int)
222+
p.Weapon.Params = make(map[string]int)
223+
p.Base.Element = keys.CharKeyToEle[key]
224+
p.Weapon.Key = keys.DullBlade
225+
226+
p.Stats[attributes.EM] = 100
227+
p.Base.Level = 90
228+
p.Base.MaxLevel = 90
229+
p.Talents = info.TalentProfile{Attack: 1, Skill: 1, Burst: 1}
230+
231+
return p
232+
}
233+
234+
func advanceCoreFrame(t *testing.T, c *core.Core) {
235+
c.F++
236+
c.Tick()
237+
238+
if c.F > 10000 {
239+
t.Errorf("Test did not complete after 10000 frames. Check if IgnoreBurstEnergy is correctly taken into account. Otherwise check if all actions can be exec'd")
240+
}
241+
}

0 commit comments

Comments
 (0)