|  |  | @@ -716,7 +716,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} else if stoppingFromWalking { |  |  |  | 				} else if stoppingFromWalking { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					thatPlayerInNextFrame.FramesToRecover = chConfig.InertiaFramesToRecover |  |  |  | 					thatPlayerInNextFrame.FramesToRecover = chConfig.InertiaFramesToRecover | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} else { |  |  |  | 				} else { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					thatPlayerInNextFrame.FramesToRecover = (chConfig.InertiaFramesToRecover >> 1) |  |  |  | 					thatPlayerInNextFrame.FramesToRecover = ((chConfig.InertiaFramesToRecover >> 1) + (chConfig.InertiaFramesToRecover >> 2)) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} else { |  |  |  | 			} else { | 
			
		
	
		
		
			
				
					
					|  |  |  | 				thatPlayerInNextFrame.CapturedByInertia = false |  |  |  | 				thatPlayerInNextFrame.CapturedByInertia = false | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -757,8 +757,19 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if 0 >= thatPlayerInNextFrame.Hp && 0 == thatPlayerInNextFrame.FramesToRecover { |  |  |  | 		if 0 >= thatPlayerInNextFrame.Hp && 0 == thatPlayerInNextFrame.FramesToRecover { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// Revive from Dying |  |  |  | 			// Revive from Dying | 
			
		
	
		
		
			
				
					
					|  |  |  | 			newVx, newVy = currPlayerDownsync.RevivalVirtualGridX, currPlayerDownsync.RevivalVirtualGridY |  |  |  | 			newVx, newVy = currPlayerDownsync.RevivalVirtualGridX, currPlayerDownsync.RevivalVirtualGridY | 
			
		
	
		
		
			
				
					
					|  |  |  | 			thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1 |  |  |  | 			thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_GET_UP1 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			thatPlayerInNextFrame.FramesInChState = ATK_CHARACTER_STATE_GET_UP1 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			thatPlayerInNextFrame.FramesToRecover = chConfig.GetUpFramesToRecover | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			thatPlayerInNextFrame.FramesInvinsible = chConfig.GetUpInvinsibleFrames | 
			
		
	
		
		
			
				
					
					|  |  |  | 			thatPlayerInNextFrame.Hp = currPlayerDownsync.MaxHp |  |  |  | 			thatPlayerInNextFrame.Hp = currPlayerDownsync.MaxHp | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			// Hardcoded initial character orientation/facing | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			if 0 == (thatPlayerInNextFrame.JoinIndex % 2) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				thatPlayerInNextFrame.DirX = -2 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				thatPlayerInNextFrame.DirY = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			} else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				thatPlayerInNextFrame.DirX = +2 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				thatPlayerInNextFrame.DirY = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if jumpedOrNotList[i] { |  |  |  | 		if jumpedOrNotList[i] { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			// We haven't proceeded with "OnWall" calculation for "thatPlayerInNextFrame", thus use "currPlayerDownsync.OnWall" for checking |  |  |  | 			// We haven't proceeded with "OnWall" calculation for "thatPlayerInNextFrame", thus use "currPlayerDownsync.OnWall" for checking | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -899,8 +910,12 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if collision := playerCollider.Check(0, 0); nil != collision { |  |  |  | 		if collision := playerCollider.Check(0, 0); nil != collision { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			for _, obj := range collision.Objects { |  |  |  | 			for _, obj := range collision.Objects { | 
			
		
	
		
		
			
				
					
					|  |  |  | 				isBarrier, isAnotherPlayer, isBullet := false, false, false |  |  |  | 				isBarrier, isAnotherPlayer, isBullet := false, false, false | 
			
		
	
		
		
			
				
					
					|  |  |  | 				switch obj.Data.(type) { |  |  |  | 				switch v := obj.Data.(type) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 				case *PlayerDownsync: |  |  |  | 				case *PlayerDownsync: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					if ATK_CHARACTER_STATE_DYING == v.CharacterState { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 						// ignore collision with dying player | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 						continue | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					} | 
			
		
	
		
		
			
				
					
					|  |  |  | 					isAnotherPlayer = true |  |  |  | 					isAnotherPlayer = true | 
			
		
	
		
		
			
				
					
					|  |  |  | 				case *MeleeBullet, *FireballBullet: |  |  |  | 				case *MeleeBullet, *FireballBullet: | 
			
		
	
		
		
			
				
					
					|  |  |  | 					isBullet = true |  |  |  | 					isBullet = true | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -912,6 +927,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer | 
			
		
	
		
		
			
				
					
					|  |  |  | 					// ignore bullets for this step |  |  |  | 					// ignore bullets for this step | 
			
		
	
		
		
			
				
					
					|  |  |  | 					continue |  |  |  | 					continue | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				bShape := obj.Shape.(*resolv.ConvexPolygon) |  |  |  | 				bShape := obj.Shape.(*resolv.ConvexPolygon) | 
			
		
	
		
		
			
				
					
					|  |  |  | 				overlapped, pushbackX, pushbackY, overlapResult := calcPushbacks(0, 0, playerShape, bShape) |  |  |  | 				overlapped, pushbackX, pushbackY, overlapResult := calcPushbacks(0, 0, playerShape, bShape) | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if !overlapped { |  |  |  | 				if !overlapped { | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -1013,113 +1029,83 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer | 
			
		
	
		
		
			
				
					
					|  |  |  | 		collision := bulletCollider.Check(0, 0) |  |  |  | 		collision := bulletCollider.Check(0, 0) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		bulletCollider.Space.Remove(bulletCollider) // Make sure that the bulletCollider is always removed for each renderFrame |  |  |  | 		bulletCollider.Space.Remove(bulletCollider) // Make sure that the bulletCollider is always removed for each renderFrame | 
			
		
	
		
		
			
				
					
					|  |  |  | 		exploded := false |  |  |  | 		exploded := false | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if nil != collision { |  |  |  | 		explodedOnAnotherPlayer := false | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if nil == collision { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			continue | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		var bulletStaticAttr *BulletConfig = nil | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		var bulletBattleAttr *BulletBattleAttr = nil | 
			
		
	
		
		
			
				
					
					|  |  |  | 		switch v := bulletCollider.Data.(type) { |  |  |  | 		switch v := bulletCollider.Data.(type) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		case *MeleeBullet: |  |  |  | 		case *MeleeBullet: | 
			
		
	
		
		
			
				
					
					|  |  |  | 				bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon) |  |  |  | 			bulletStaticAttr = v.Bullet | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				offender := currRenderFrame.PlayersArr[v.BattleAttr.OffenderJoinIndex-1] |  |  |  | 			bulletBattleAttr = v.BattleAttr | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				for _, obj := range collision.Objects { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 					defenderShape := obj.Shape.(*resolv.ConvexPolygon) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 					switch t := obj.Data.(type) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 					case *PlayerDownsync: |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						if v.BattleAttr.OffenderJoinIndex == t.JoinIndex { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							continue |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						overlapped, _, _, _ := calcPushbacks(0, 0, bulletShape, defenderShape) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						if !overlapped { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							continue |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						exploded = true |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						if _, existent := invinsibleSet[t.CharacterState]; existent { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							continue |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						if 0 < t.FramesInvinsible { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							continue |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						xfac := int32(1) // By now, straight Punch offset doesn't respect "y-axis" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						if 0 > offender.DirX { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							xfac = -xfac |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						atkedPlayerInNextFrame := nextRenderFramePlayers[t.JoinIndex-1] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						atkedPlayerInNextFrame.Hp -= v.Bullet.Damage |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						if 0 >= atkedPlayerInNextFrame.Hp { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							// [WARNING] We don't have "dying in air" animation for now, and for better graphical recognition, play the same dying animation even in air |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							atkedPlayerInNextFrame.Hp = 0 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_DYING |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							atkedPlayerInNextFrame.FramesToRecover = DYING_FRAMES_TO_RECOVER |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						} else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							pushbackVelX, pushbackVelY := xfac*v.Bullet.PushbackVelX, v.Bullet.PushbackVelY |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							atkedPlayerInNextFrame.VelX = pushbackVelX |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							atkedPlayerInNextFrame.VelY = pushbackVelY |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							if v.Bullet.BlowUp { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 								atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_BLOWN_UP1 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							} else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 								atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATKED1 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							oldFramesToRecover := nextRenderFramePlayers[t.JoinIndex-1].FramesToRecover |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							if v.Bullet.HitStunFrames > oldFramesToRecover { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 								atkedPlayerInNextFrame.FramesToRecover = v.Bullet.HitStunFrames |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 							} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 						} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 					} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		case *FireballBullet: |  |  |  | 		case *FireballBullet: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			bulletStaticAttr = v.Bullet | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			bulletBattleAttr = v.BattleAttr | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon) |  |  |  | 		bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon) | 
			
		
	
		
		
			
				
					
					|  |  |  | 				offender := currRenderFrame.PlayersArr[v.BattleAttr.OffenderJoinIndex-1] |  |  |  | 		offender := currRenderFrame.PlayersArr[bulletBattleAttr.OffenderJoinIndex-1] | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		for _, obj := range collision.Objects { |  |  |  | 		for _, obj := range collision.Objects { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			defenderShape := obj.Shape.(*resolv.ConvexPolygon) |  |  |  | 			defenderShape := obj.Shape.(*resolv.ConvexPolygon) | 
			
		
	
		
		
			
				
					
					|  |  |  | 			switch t := obj.Data.(type) { |  |  |  | 			switch t := obj.Data.(type) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			case *PlayerDownsync: |  |  |  | 			case *PlayerDownsync: | 
			
		
	
		
		
			
				
					
					|  |  |  | 						if v.BattleAttr.OffenderJoinIndex == t.JoinIndex { |  |  |  | 				if bulletBattleAttr.OffenderJoinIndex == t.JoinIndex { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 					continue |  |  |  | 					continue | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 				overlapped, _, _, _ := calcPushbacks(0, 0, bulletShape, defenderShape) |  |  |  | 				overlapped, _, _, _ := calcPushbacks(0, 0, bulletShape, defenderShape) | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if !overlapped { |  |  |  | 				if !overlapped { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					continue |  |  |  | 					continue | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 						exploded = true |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if _, existent := invinsibleSet[t.CharacterState]; existent { |  |  |  | 				if _, existent := invinsibleSet[t.CharacterState]; existent { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					continue |  |  |  | 					continue | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if 0 < t.FramesInvinsible { |  |  |  | 				if 0 < t.FramesInvinsible { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					continue |  |  |  | 					continue | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				exploded = true | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				explodedOnAnotherPlayer = true | 
			
		
	
		
		
			
				
					
					|  |  |  | 				xfac := int32(1) // By now, straight Punch offset doesn't respect "y-axis" |  |  |  | 				xfac := int32(1) // By now, straight Punch offset doesn't respect "y-axis" | 
			
		
	
		
		
			
				
					
					|  |  |  | 				if 0 > offender.DirX { |  |  |  | 				if 0 > offender.DirX { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					xfac = -xfac |  |  |  | 					xfac = -xfac | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 				atkedPlayerInNextFrame := nextRenderFramePlayers[t.JoinIndex-1] |  |  |  | 				atkedPlayerInNextFrame := nextRenderFramePlayers[t.JoinIndex-1] | 
			
		
	
		
		
			
				
					
					|  |  |  | 						atkedPlayerInNextFrame.Hp -= v.Bullet.Damage |  |  |  | 				atkedPlayerInNextFrame.Hp -= bulletStaticAttr.Damage | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 				if 0 >= atkedPlayerInNextFrame.Hp { |  |  |  | 				if 0 >= atkedPlayerInNextFrame.Hp { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					// [WARNING] We don't have "dying in air" animation for now, and for better graphical recognition, play the same dying animation even in air |  |  |  | 					// [WARNING] We don't have "dying in air" animation for now, and for better graphical recognition, play the same dying animation even in air | 
			
		
	
		
		
			
				
					
					|  |  |  | 					atkedPlayerInNextFrame.Hp = 0 |  |  |  | 					atkedPlayerInNextFrame.Hp = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  | 					atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_DYING |  |  |  | 					atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_DYING | 
			
		
	
		
		
			
				
					
					|  |  |  | 					atkedPlayerInNextFrame.FramesToRecover = DYING_FRAMES_TO_RECOVER |  |  |  | 					atkedPlayerInNextFrame.FramesToRecover = DYING_FRAMES_TO_RECOVER | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} else { |  |  |  | 				} else { | 
			
		
	
		
		
			
				
					
					|  |  |  | 							pushbackVelX, pushbackVelY := xfac*v.Bullet.PushbackVelX, v.Bullet.PushbackVelY |  |  |  | 					pushbackVelX, pushbackVelY := xfac*bulletStaticAttr.PushbackVelX, bulletStaticAttr.PushbackVelY | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 					atkedPlayerInNextFrame.VelX = pushbackVelX |  |  |  | 					atkedPlayerInNextFrame.VelX = pushbackVelX | 
			
		
	
		
		
			
				
					
					|  |  |  | 					atkedPlayerInNextFrame.VelY = pushbackVelY |  |  |  | 					atkedPlayerInNextFrame.VelY = pushbackVelY | 
			
		
	
		
		
			
				
					
					|  |  |  | 							if v.Bullet.BlowUp { |  |  |  | 					if bulletStaticAttr.BlowUp { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 						atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_BLOWN_UP1 |  |  |  | 						atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_BLOWN_UP1 | 
			
		
	
		
		
			
				
					
					|  |  |  | 					} else { |  |  |  | 					} else { | 
			
		
	
		
		
			
				
					
					|  |  |  | 						atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATKED1 |  |  |  | 						atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATKED1 | 
			
		
	
		
		
			
				
					
					|  |  |  | 					} |  |  |  | 					} | 
			
		
	
		
		
			
				
					
					|  |  |  | 					oldFramesToRecover := nextRenderFramePlayers[t.JoinIndex-1].FramesToRecover |  |  |  | 					oldFramesToRecover := nextRenderFramePlayers[t.JoinIndex-1].FramesToRecover | 
			
		
	
		
		
			
				
					
					|  |  |  | 							if v.Bullet.HitStunFrames > oldFramesToRecover { |  |  |  | 					if bulletStaticAttr.HitStunFrames > oldFramesToRecover { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 								atkedPlayerInNextFrame.FramesToRecover = v.Bullet.HitStunFrames |  |  |  | 						atkedPlayerInNextFrame.FramesToRecover = bulletStaticAttr.HitStunFrames | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 					} |  |  |  | 					} | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			default: |  |  |  | 			default: | 
			
		
	
		
		
			
				
					
					|  |  |  | 				exploded = true |  |  |  | 				exploded = true | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  |  | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		if exploded { |  |  |  | 		if exploded { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			switch v := bulletCollider.Data.(type) { |  |  |  | 			switch v := bulletCollider.Data.(type) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			case *MeleeBullet: |  |  |  | 			case *MeleeBullet: | 
			
		
	
		
		
			
				
					
					|  |  |  | 				v.BlState = BULLET_EXPLODING |  |  |  | 				v.BlState = BULLET_EXPLODING | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				if explodedOnAnotherPlayer { | 
			
		
	
		
		
			
				
					
					|  |  |  | 					v.FramesInBlState = 0 |  |  |  | 					v.FramesInBlState = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				} else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					// When hitting a barrier, don't play explosion anim | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					v.FramesInBlState = v.Bullet.ExplosionFrames + 1 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 				//fmt.Printf("melee exploded @currRenderFrame.Id=%d, bulletLocalId=%d, blState=%d\n", currRenderFrame.Id, v.BattleAttr.BulletLocalId, v.BlState) |  |  |  | 				//fmt.Printf("melee exploded @currRenderFrame.Id=%d, bulletLocalId=%d, blState=%d\n", currRenderFrame.Id, v.BattleAttr.BulletLocalId, v.BlState) | 
			
		
	
		
		
			
				
					
					|  |  |  | 			case *FireballBullet: |  |  |  | 			case *FireballBullet: | 
			
		
	
		
		
			
				
					
					|  |  |  | 				v.BlState = BULLET_EXPLODING |  |  |  | 				v.BlState = BULLET_EXPLODING | 
			
		
	
	
		
		
			
				
					
					|  |  |   |