diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 46ac7466..b537a057 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -208,6 +208,9 @@ type Info interface { // Metadata for the given enemy, such as their current level and weaknesses. EnemyInfo(target key.TargetID) (info.Enemy, error) + // Check if the character can use attack (Either arbitrary logic defined by char implementer, or unrestricted by default) + CanUseAttack(target key.TargetID) (bool, error) + // Check if the character can use the skill (enough Skill Points and not blocked by Skill.CanUse, // see implementation of each character) CanUseSkill(target key.TargetID) (bool, error) diff --git a/pkg/engine/target/character/config.go b/pkg/engine/target/character/config.go index 0fd6458a..d2bafcd0 100644 --- a/pkg/engine/target/character/config.go +++ b/pkg/engine/target/character/config.go @@ -49,12 +49,14 @@ type SkillInfo struct { Technique Technique } +type AttackValidateFunc func(engine engine.Engine, char info.CharInstance) bool type SkillValidateFunc func(engine engine.Engine, char info.CharInstance) bool type UltValidateFunc func(engine engine.Engine, char info.CharInstance) bool type Attack struct { SPAdd int TargetType model.TargetType + CanUse AttackValidateFunc `exhaustruct:"optional"` } type Skill struct { diff --git a/pkg/engine/target/character/execute.go b/pkg/engine/target/character/execute.go index 8a8cbd4e..fe71678e 100644 --- a/pkg/engine/target/character/execute.go +++ b/pkg/engine/target/character/execute.go @@ -83,6 +83,10 @@ func (mgr *Manager) ExecuteAction(id key.TargetID, isInsert bool) (target.Execut return target.ExecutableAction{}, err } + canUseAttack, err := mgr.engine.CanUseAttack(id) + if err != nil || !canUseAttack { + return target.ExecutableAction{}, err + } return target.ExecutableAction{ Execute: func() { char.Attack(primaryTarget, actionState{ diff --git a/pkg/mock/mock_engine.go b/pkg/mock/mock_engine.go index c82b9d35..86406472 100644 --- a/pkg/mock/mock_engine.go +++ b/pkg/mock/mock_engine.go @@ -105,6 +105,21 @@ func (mr *MockEngineMockRecorder) Attack(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Attack", reflect.TypeOf((*MockEngine)(nil).Attack), arg0) } +// CanUseAttack mocks base method. +func (m *MockEngine) CanUseAttack(arg0 key.TargetID) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CanUseAttack", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CanUseAttack indicates an expected call of CanUseAttack. +func (mr *MockEngineMockRecorder) CanUseAttack(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanUseAttack", reflect.TypeOf((*MockEngine)(nil).CanUseAttack), arg0) +} + // CanUseSkill mocks base method. func (m *MockEngine) CanUseSkill(arg0 key.TargetID) (bool, error) { m.ctrl.T.Helper() diff --git a/pkg/simulation/info.go b/pkg/simulation/info.go index 0bc34ec2..926e8add 100644 --- a/pkg/simulation/info.go +++ b/pkg/simulation/info.go @@ -17,6 +17,20 @@ func (sim *Simulation) EnemyInfo(id key.TargetID) (info.Enemy, error) { return sim.Enemy.Info(id) } +func (sim *Simulation) CanUseAttack(id key.TargetID) (bool, error) { + skillInfo, err := sim.Char.SkillInfo(id) + if err != nil { + return false, err + } + char, err := sim.Char.Get(id) + if err != nil { + return false, err + } + + check := skillInfo.Attack.CanUse + return (check == nil || check(sim, char)), nil +} + func (sim *Simulation) CanUseSkill(id key.TargetID) (bool, error) { skillInfo, err := sim.Char.SkillInfo(id) if err != nil { diff --git a/tests/mock/mock_engine.go b/tests/mock/mock_engine.go index c82b9d35..86406472 100644 --- a/tests/mock/mock_engine.go +++ b/tests/mock/mock_engine.go @@ -105,6 +105,21 @@ func (mr *MockEngineMockRecorder) Attack(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Attack", reflect.TypeOf((*MockEngine)(nil).Attack), arg0) } +// CanUseAttack mocks base method. +func (m *MockEngine) CanUseAttack(arg0 key.TargetID) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CanUseAttack", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CanUseAttack indicates an expected call of CanUseAttack. +func (mr *MockEngineMockRecorder) CanUseAttack(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanUseAttack", reflect.TypeOf((*MockEngine)(nil).CanUseAttack), arg0) +} + // CanUseSkill mocks base method. func (m *MockEngine) CanUseSkill(arg0 key.TargetID) (bool, error) { m.ctrl.T.Helper()