mirror of
https://github.com/genxium/DelayNoMore
synced 2025-10-09 08:36:52 +00:00
Enhanced multihit config.
This commit is contained in:
@@ -28,8 +28,8 @@ const (
|
||||
SNAP_INTO_PLATFORM_OVERLAP = float64(0.1)
|
||||
SNAP_INTO_PLATFORM_THRESHOLD = float64(0.5)
|
||||
|
||||
NO_SKILL = int32(-1)
|
||||
NO_SKILL_HIT = int32(-1)
|
||||
NO_SKILL = -1
|
||||
NO_SKILL_HIT = -1
|
||||
)
|
||||
|
||||
// These directions are chosen such that when speed is changed to "(speedX+delta, speedY+delta)" for any of them, the direction is unchanged.
|
||||
@@ -383,30 +383,9 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
As long as the current "CharacterState" is not in "noOpSet", we have 2 cases where attacking is allowed:
|
||||
1. it happens when the player is IDLE or Walking, i.e. "0 == currPlayerDownsync.FramesToRecover", which is just the normal case
|
||||
2. it happens when the player is having non-empty "ActiveSkillId" which might be cancellable
|
||||
*/
|
||||
patternId := PATTERN_ID_NO_OP
|
||||
if decodedInput.BtnALevel > prevBtnALevel {
|
||||
if currPlayerDownsync.InAir {
|
||||
patternId = 255
|
||||
} else {
|
||||
patternId = 1
|
||||
}
|
||||
}
|
||||
|
||||
if PATTERN_ID_NO_OP != patternId && 0 < currPlayerDownsync.FramesToRecover {
|
||||
// [WARN] Handle skill cancellation
|
||||
patternId = PATTERN_ID_NO_OP // First, reset the patternId to no-op as it should be by default not cancelling anything
|
||||
skillConfig := skills[int(currPlayerDownsync.ActiveSkillId)]
|
||||
switch v := skillConfig.Hits[currPlayerDownsync.ActiveSkillHit].(type) {
|
||||
case *MeleeBullet:
|
||||
if v.CancellableStFrame <= currPlayerDownsync.FramesInChState && currPlayerDownsync.FramesInChState < v.CancellableEdFrame {
|
||||
patternId = int(currPlayerDownsync.ActiveSkillId + 1) // if "currPlayerDownsync.InAir", it won't map to a valid skill in the next step and thus act as PATTERN_ID_NO_OP
|
||||
}
|
||||
}
|
||||
patternId = 1
|
||||
}
|
||||
|
||||
return patternId, jumpedOrNot, effDx, effDy
|
||||
@@ -463,38 +442,28 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
|
||||
jumpedOrNotList[i] = true
|
||||
}
|
||||
joinIndex := currPlayerDownsync.JoinIndex
|
||||
if PATTERN_ID_NO_OP != patternId {
|
||||
if skillId, existent := chConfig.PatternIdToSkillId[patternId]; existent {
|
||||
skillConfig := skills[skillId]
|
||||
thatPlayerInNextFrame.ActiveSkillId = int32(skillId)
|
||||
thatPlayerInNextFrame.ActiveSkillHit = 0
|
||||
skillId := chConfig.SkillMapper(patternId, currPlayerDownsync)
|
||||
if skillConfig, existent := skills[skillId]; existent {
|
||||
thatPlayerInNextFrame.ActiveSkillId = int32(skillId)
|
||||
thatPlayerInNextFrame.ActiveSkillHit = 0
|
||||
|
||||
// TODO: Respect non-zero "selfLockVel"
|
||||
// TODO: Respect non-zero "selfLockVel"
|
||||
|
||||
// Hardcoded to use only the first hit for now
|
||||
switch v := skillConfig.Hits[thatPlayerInNextFrame.ActiveSkillHit].(type) {
|
||||
case *MeleeBullet:
|
||||
var newBullet MeleeBullet = *v // Copied primitive fields into an onstack variable
|
||||
newBullet.OriginatedRenderFrameId = currRenderFrame.Id
|
||||
newBullet.OffenderJoinIndex = joinIndex
|
||||
nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, &newBullet)
|
||||
thatPlayerInNextFrame.FramesToRecover = skillConfig.RecoveryFrames
|
||||
}
|
||||
|
||||
// TODO: How to differentiate skill cancellable among different characters, e.g. some characters might be allowed to have 4-cancellation-combo or more?
|
||||
switch skillId {
|
||||
case 1:
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATK1
|
||||
case 2:
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATK2
|
||||
case 3:
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATK3
|
||||
}
|
||||
if false == currPlayerDownsync.InAir {
|
||||
thatPlayerInNextFrame.VelX = 0
|
||||
}
|
||||
continue // Don't allow movement if skill is used
|
||||
// Hardcoded to use only the first hit for now
|
||||
switch v := skillConfig.Hits[thatPlayerInNextFrame.ActiveSkillHit].(type) {
|
||||
case *MeleeBullet:
|
||||
var newBullet MeleeBullet = *v // Copied primitive fields into an onstack variable
|
||||
newBullet.OriginatedRenderFrameId = currRenderFrame.Id
|
||||
newBullet.OffenderJoinIndex = joinIndex
|
||||
nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, &newBullet)
|
||||
thatPlayerInNextFrame.FramesToRecover = skillConfig.RecoveryFrames
|
||||
}
|
||||
|
||||
thatPlayerInNextFrame.CharacterState = skillConfig.BoundChState
|
||||
if false == currPlayerDownsync.InAir {
|
||||
thatPlayerInNextFrame.VelX = 0
|
||||
}
|
||||
continue // Don't allow movement if skill is used
|
||||
}
|
||||
|
||||
if 0 == currPlayerDownsync.FramesToRecover {
|
||||
@@ -720,8 +689,8 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
|
||||
|
||||
// Remove any active skill if not attacking
|
||||
if _, existent := nonAttackingSet[thatPlayerInNextFrame.CharacterState]; existent {
|
||||
thatPlayerInNextFrame.ActiveSkillId = NO_SKILL
|
||||
thatPlayerInNextFrame.ActiveSkillHit = NO_SKILL_HIT
|
||||
thatPlayerInNextFrame.ActiveSkillId = int32(NO_SKILL)
|
||||
thatPlayerInNextFrame.ActiveSkillHit = int32(NO_SKILL_HIT)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package battle
|
||||
|
||||
type SkillMapperType func(patternId int, currPlayerDownsync *PlayerDownsync) int
|
||||
|
||||
type CharacterConfig struct {
|
||||
SpeciesId int
|
||||
SpeciesName string
|
||||
@@ -15,7 +17,7 @@ type CharacterConfig struct {
|
||||
|
||||
JumpingInitVelY int32
|
||||
|
||||
PatternIdToSkillId map[int]int
|
||||
SkillMapper SkillMapperType
|
||||
}
|
||||
|
||||
var Characters = map[int]*CharacterConfig{
|
||||
@@ -34,26 +36,89 @@ var Characters = map[int]*CharacterConfig{
|
||||
|
||||
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
|
||||
PatternIdToSkillId: map[int]int{
|
||||
1: 1, // Atk1
|
||||
2: 2, // Atk2
|
||||
3: 3, // Atk3
|
||||
255: 255, // InAirAtk1
|
||||
SkillMapper: func(patternId int, currPlayerDownsync *PlayerDownsync) int {
|
||||
if 1 == patternId {
|
||||
if 0 == currPlayerDownsync.FramesToRecover {
|
||||
if currPlayerDownsync.InAir {
|
||||
return 255
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
} else {
|
||||
// Now that "0 < FramesToRecover", we're only able to fire any skill if it's a cancellation
|
||||
if skillConfig, existent1 := skills[int(currPlayerDownsync.ActiveSkillId)]; existent1 {
|
||||
switch v := skillConfig.Hits[currPlayerDownsync.ActiveSkillHit].(type) {
|
||||
case *MeleeBullet:
|
||||
if v.CancellableStFrame <= currPlayerDownsync.FramesInChState && currPlayerDownsync.FramesInChState < v.CancellableEdFrame {
|
||||
if nextSkillId, existent2 := v.CancelTransit[patternId]; existent2 {
|
||||
return nextSkillId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// By default no skill can be fired
|
||||
return NO_SKILL
|
||||
},
|
||||
},
|
||||
1: &CharacterConfig{
|
||||
SpeciesId: 1,
|
||||
SpeciesName: "KnifeGirl",
|
||||
|
||||
InAirIdleFrameIdxTurningPoint: 9,
|
||||
InAirIdleFrameIdxTurnedCycle: 1,
|
||||
|
||||
LayDownFrames: int32(16),
|
||||
LayDownFramesToRecover: int32(16),
|
||||
|
||||
GetUpFrames: int32(30),
|
||||
GetUpFramesToRecover: int32(27), // 3 invinsible frames for just-blown-up character to make a comeback
|
||||
|
||||
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
|
||||
SkillMapper: func(patternId int, currPlayerDownsync *PlayerDownsync) int {
|
||||
if 1 == patternId {
|
||||
if 0 == currPlayerDownsync.FramesToRecover {
|
||||
if currPlayerDownsync.InAir {
|
||||
return 256
|
||||
} else {
|
||||
return 4
|
||||
}
|
||||
} else {
|
||||
// Now that "0 < FramesToRecover", we're only able to fire any skill if it's a cancellation
|
||||
if skillConfig, existent1 := skills[int(currPlayerDownsync.ActiveSkillId)]; existent1 {
|
||||
switch v := skillConfig.Hits[currPlayerDownsync.ActiveSkillHit].(type) {
|
||||
case *MeleeBullet:
|
||||
if v.CancellableStFrame <= currPlayerDownsync.FramesInChState && currPlayerDownsync.FramesInChState < v.CancellableEdFrame {
|
||||
if nextSkillId, existent2 := v.CancelTransit[patternId]; existent2 {
|
||||
return nextSkillId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// By default no skill can be fired
|
||||
return NO_SKILL
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var skills = map[int]*Skill{
|
||||
1: &Skill{
|
||||
RecoveryFrames: int32(20),
|
||||
RecoveryFramesOnBlock: int32(20),
|
||||
RecoveryFramesOnHit: int32(20),
|
||||
RecoveryFrames: int32(30),
|
||||
RecoveryFramesOnBlock: int32(30),
|
||||
RecoveryFramesOnHit: int32(30),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_ATK1,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: Bullet{
|
||||
StartupFrames: int32(5),
|
||||
ActiveFrames: int32(10),
|
||||
StartupFrames: int32(7),
|
||||
ActiveFrames: int32(22),
|
||||
HitStunFrames: int32(13),
|
||||
BlockStunFrames: int32(9),
|
||||
Damage: int32(5),
|
||||
@@ -63,8 +128,12 @@ var skills = map[int]*Skill{
|
||||
HitboxOffsetY: int32(0),
|
||||
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
CancellableStFrame: int32(8),
|
||||
CancellableEdFrame: int32(20),
|
||||
CancellableStFrame: int32(13),
|
||||
CancellableEdFrame: int32(30),
|
||||
|
||||
CancelTransit: map[int]int{
|
||||
1: 2,
|
||||
},
|
||||
// TODO: Use non-zero "selfLockVel"
|
||||
},
|
||||
},
|
||||
@@ -75,11 +144,12 @@ var skills = map[int]*Skill{
|
||||
RecoveryFramesOnBlock: int32(36),
|
||||
RecoveryFramesOnHit: int32(36),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_ATK2,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: Bullet{
|
||||
StartupFrames: int32(3),
|
||||
ActiveFrames: int32(20),
|
||||
StartupFrames: int32(18),
|
||||
ActiveFrames: int32(18),
|
||||
HitStunFrames: int32(18),
|
||||
BlockStunFrames: int32(9),
|
||||
Damage: int32(5),
|
||||
@@ -89,8 +159,11 @@ var skills = map[int]*Skill{
|
||||
HitboxOffsetY: int32(0),
|
||||
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
CancellableStFrame: int32(18),
|
||||
CancellableStFrame: int32(22),
|
||||
CancellableEdFrame: int32(36),
|
||||
CancelTransit: map[int]int{
|
||||
1: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -100,16 +173,102 @@ var skills = map[int]*Skill{
|
||||
RecoveryFramesOnBlock: int32(60),
|
||||
RecoveryFramesOnHit: int32(60),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_ATK3,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: Bullet{
|
||||
StartupFrames: int32(1),
|
||||
ActiveFrames: int32(30),
|
||||
StartupFrames: int32(15),
|
||||
ActiveFrames: int32(40),
|
||||
HitStunFrames: MAX_INT32,
|
||||
BlockStunFrames: int32(9),
|
||||
Damage: int32(10),
|
||||
PushbackVelX: int32(float64(1) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
PushbackVelY: int32(float64(4) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
PushbackVelX: int32(float64(2) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
PushbackVelY: int32(float64(7) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetY: int32(0),
|
||||
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
BlowUp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
4: &Skill{
|
||||
RecoveryFrames: int32(30),
|
||||
RecoveryFramesOnBlock: int32(30),
|
||||
RecoveryFramesOnHit: int32(30),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_ATK1,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: Bullet{
|
||||
StartupFrames: int32(7),
|
||||
ActiveFrames: int32(22),
|
||||
HitStunFrames: int32(13),
|
||||
BlockStunFrames: int32(9),
|
||||
Damage: int32(5),
|
||||
PushbackVelX: int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
PushbackVelY: int32(0),
|
||||
HitboxOffsetX: int32(float64(12) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetY: int32(0),
|
||||
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
CancellableStFrame: int32(13),
|
||||
CancellableEdFrame: int32(30),
|
||||
|
||||
CancelTransit: map[int]int{
|
||||
1: 5,
|
||||
},
|
||||
// TODO: Use non-zero "selfLockVel"
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
5: &Skill{
|
||||
RecoveryFrames: int32(36),
|
||||
RecoveryFramesOnBlock: int32(36),
|
||||
RecoveryFramesOnHit: int32(36),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_ATK2,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: Bullet{
|
||||
StartupFrames: int32(18),
|
||||
ActiveFrames: int32(18),
|
||||
HitStunFrames: int32(18),
|
||||
BlockStunFrames: int32(9),
|
||||
Damage: int32(5),
|
||||
PushbackVelX: int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
PushbackVelY: int32(0),
|
||||
HitboxOffsetX: int32(float64(18) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetY: int32(0),
|
||||
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
CancellableStFrame: int32(22),
|
||||
CancellableEdFrame: int32(36),
|
||||
CancelTransit: map[int]int{
|
||||
1: 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
6: &Skill{
|
||||
RecoveryFrames: int32(60),
|
||||
RecoveryFramesOnBlock: int32(60),
|
||||
RecoveryFramesOnHit: int32(60),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_ATK3,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: Bullet{
|
||||
StartupFrames: int32(15),
|
||||
ActiveFrames: int32(40),
|
||||
HitStunFrames: MAX_INT32,
|
||||
BlockStunFrames: int32(9),
|
||||
Damage: int32(10),
|
||||
PushbackVelX: int32(float64(2) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
PushbackVelY: int32(float64(7) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetY: int32(0),
|
||||
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
@@ -124,6 +283,31 @@ var skills = map[int]*Skill{
|
||||
RecoveryFramesOnBlock: int32(34),
|
||||
RecoveryFramesOnHit: int32(34),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_INAIR_ATK1,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: Bullet{
|
||||
StartupFrames: int32(3),
|
||||
ActiveFrames: int32(20),
|
||||
HitStunFrames: int32(18),
|
||||
BlockStunFrames: int32(9),
|
||||
Damage: int32(5),
|
||||
PushbackVelX: int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
PushbackVelY: int32(0),
|
||||
HitboxOffsetX: int32(float64(12) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetY: int32(0),
|
||||
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxSizeY: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
256: &Skill{
|
||||
RecoveryFrames: int32(34),
|
||||
RecoveryFramesOnBlock: int32(34),
|
||||
RecoveryFramesOnHit: int32(34),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_INAIR_ATK1,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: Bullet{
|
||||
|
@@ -79,6 +79,8 @@ type Bullet struct {
|
||||
HitboxSizeY int32
|
||||
|
||||
BlowUp bool
|
||||
|
||||
CancelTransit map[int]int
|
||||
}
|
||||
|
||||
type MeleeBullet struct {
|
||||
@@ -101,7 +103,8 @@ type Skill struct {
|
||||
RecoveryFrames int32
|
||||
RecoveryFramesOnBlock int32
|
||||
RecoveryFramesOnHit int32
|
||||
ReleaseTriggerType int32 // 1: rising-edge, 2: falling-edge
|
||||
ReleaseTriggerType int32 // 1: rising-edge, 2: falling-edge
|
||||
BoundChState int32
|
||||
Hits []interface{} // Hits within a "Skill" are automatically triggered
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user