:Character:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

## Base-Attacks: This file hold helper functions for the attack module.


## CASTDO: Sort states better with Physics
:Specs-PhysicsMovement:
# Automatic creation
:Variables-Internals-Attacks:
## Internal variables for the attack module

internal _AttackDuration
#internal _AttackMomentumX
#internal _AttackMomentumY

## CASTDO: Make standard
#internal _AttackAnimInterruptableFrames
var _AttackAnimInterruptableFrames int() = 0


var Meter int() = 100
var MeterMax int() = 100
var ATTACK_CancelFlags int() = 11

var SimpleAttack_ActiveEnd int() = 12
var SimpleAttack_Duration int() = 22

var ATTACK_HitstunDuration int() = 0
var ATTACK_BlockstunDuration int() = 0

var Throw_Teching int() = 0
var Throw_Lockout int() = 0

var HPMax int() = 10000
var HP int() = 1


def ATTACK_Throw_ConfirmPriority int() = 100100
def ATTACK_Throw_TechingPriority int() = 100000

def ATTACK_Throw_GoToHoldingPriority int() = 200000
def ATK_HITSTUN_PRIORITY int() = 50000

def ATK_BLOCKSTUN_PRIORITY int() = 40000


var ATTACK_GroundbouncesRemaining int() = 0
var ATTACK_ProrationDamage int() = 1000
var ATTACK_ProrationHitstun int() = 1000
var ATTACK_ComboCounter int() = 0

def ATTACK_Proration_Scale int() = 1000
:AirThrowB:
## Air Throw Backward attack, by default the same as throw forward but flipped
_Category(Attacks/AirThrowFollowup)
_Overridable(If you want another attack instead)

Call(AirThrowF)
## CASTDO Warinings
:AirThrowF:
## Air Throw Forward attack, to be overriden
_Overridable(Put your own attack here instead)

AttackRegister(AirThrowFollowup)

AttackDamage(0)
AttackDuration(10)
AttackMomentum(600, 600)
AttackKnockdown()

F1:
	Hitbox(0, 20000, -10000, 20000)
endif
:AirThrowHeld:
## State where got hit with an air throw, and have a chance to tech it
_Category(States/Reacts/Throws)
Call(Common)
Call(ThrowHeld-Common)

Call(AnimAirThrowHeld)

LThrowConfirmed:
else
	LThrowTeching:
		Transition(ATTACK_Throw_Air_TechingState, ATTACK_Throw_TechingPriority)
	endif
endif
:AirThrowHolding:
## State where you hit an air throw, and are waiting to confirm it
_Category(States/Reacts/Throws)
Call(Common)

SetTargetPosition(ATTACK_Throw_Air_HoldPointX, ATTACK_Throw_Air_HoldPointY)

FATTACK_Throw_Air_TimeHold+:
	Flag(ThrowConfirmed)
endif

Call(ThrowHolding-Common)

LThrowConfirmed:
	LThrowBack:
		VATTACK_Throw_Air_ThrowBAutoFlip:
			FlipFacing()
		endif

		Transition(ATTACK_Throw_Air_ThrowBState, ATTACK_Throw_ConfirmPriority)
	else
		Transition(ATTACK_Throw_Air_ThrowFState, ATTACK_Throw_ConfirmPriority)
	endif
else
	LThrowTeching:
		Transition(ATTACK_Throw_Air_TechedState, ATTACK_Throw_TechingPriority)
	endif
endif


Call(AnimAirThrowHolding)
:AirThrowTeched:
## State for when you hit with a airborne throw and it has been teched
_Category(States/Reacts/Throws)
Call(Common)

FMOVE_Teched_Air_Time+:
	Call(TransitionToNeutralState)
endif

F1:
	SetMomentum(MOVE_Teched_Air_MomentumX, MOVE_Teched_Air_MomentumY)
endif

Call(AnimAirThrowTeched)
:AirThrowTeching:
## State for when you got hit by a airborne throw and teched it
_Category(States/Reacts/Throws)
Call(Common)

FMOVE_Teching_Air_Time+:
	Call(TransitionToNeutralState)
endif

F1:
	SetMomentum(MOVE_Teching_Air_MomentumX, MOVE_Teching_Air_MomentumY)
endif

Call(AnimAirThrowTeched)
:AnimBlockstun:
## Helper script to select the correct blockstun animation
_Category(Animations/Reacts/Blockstun)
_Overridable(If you want custom logic to select your blockstun animation)
_Helper()

LPF_Airborne:
	Flag(_AirStunAnim)
endif

LAF_Launcher:
	Flag(_AirStunAnim)
endif

L_AirStunAnim:
	Call(AnimBlockstunAirborne)
else
	LCrouching:
		Call(AnimBlockstunCrouching)
	else
		Call(AnimBlockstunStanding)
	endif
endif


EEnter:
	LPF_Airborne:
		Flag(_AirStunAnim)
	endif

	LAF_Launcher:
		Flag(_AirStunAnim)
	endif

	L_AirStunAnim:
		Call(AnimBlockstunAirborne)
	else
		LCrouching:
			Call(AnimBlockstunCrouching)
		else
			Call(AnimBlockstunStanding)
		endif
	endif
endif
:AnimBlockstunAirborne:
## Animation for the airborne blockstun state
_Overridable(If you want to put your own animation logic instead)
_Helper()
_Category(Animations/Reacts/Blockstun)
:AnimBlockstunCrouching:
## Animation for the crouching blockstun state
_Overridable(If you want to put your own animation logic instead)
_Helper()
_Category(Animations/Reacts/Blockstun)
:AnimBlockstunStanding:
## Animation for the standing blockstun state
_Overridable(If you want to put your own animation logic instead)
_Helper()
_Category(Animations/Reacts/Blockstun)
:AnimDead:
_Helper()
_Overridable()
_Category(Animations/Reacts)
:AnimHitstun:
## Helper state to select which hitstun animation to play
_Category(Animations/Reacts/Hitstun)
_Helper()
_Overridable(If you want custom logic for how hitstun's animation works)

LPF_Airborne:
	Flag(_AirStunAnim)
endif

LAF_Launcher:
	Flag(_AirStunAnim)
endif

L_AirStunAnim:
	Call(AnimHitstunAirborne)
else
	LCrouching:
		Call(AnimHitstunCrouching)
	else
		Call(AnimHitstunStanding)
	endif
endif

EEnter:
	LPF_Airborne:
		Flag(_AirStunAnim)
	endif

	LAF_Launcher:
		Flag(_AirStunAnim)
	endif

	L_AirStunAnim:
		Call(AnimHitstunAirborne)
	else
		LCrouching:
			Call(AnimHitstunCrouching)
		else
			Call(AnimHitstunStanding)
		endif
	endif
endif
:AnimHitstunAirborne:
## Animation for the airborne hitstun state
_Overridable(If you want to put your own animation logic instead)
_Helper()
_Category(Animations/Reacts/Hitstun)
:AnimHitstunCrouching:
## Animation for the crouching hitstun state
_Overridable(If you want to put your own animation logic instead)
_Helper()
_Category(Animations/Reacts/Hitstun)
:AnimHitstunStanding:
## Animation for the standing hitstun state
_Overridable(If you want to put your own animation logic instead)
_Helper()
_Category(Animations/Reacts/Hitstun)
:Attack-BlockingLogic:
## Handles blocking inputs
_Category(Internals/Attacks/Helpers)
_Helper()

## CASTDO: Make more flexible and add crossup protection
VATTACK_HoldBackToBlock:
	IBack:
		Flag(Blocking)
	endif
endif

LPF_Airborne:
	Flag(Blocking-Low)
	Flag(Blocking-Overhead)
else
	IDown:
		Flag(Blocking-Low)
	else
		Flag(Blocking-Overhead)
	endif
endif
:Attack-CanBlock:
## Adds the basic CanBlock flags
_Category(Internals/Attacks/Helpers)
_Helper()

LPF_Airborne:
	VATTACK_CanBlockInAir:
		Flag(CanBlock)
	endif
else
	Flag(CanBlock)
endif
Flag(CanBlock-Overhead)
Flag(CanBlock-Low)
:Attack-JumpCancel:
## Manages jump cancels through an After state. The actual jump is in the physics CASP, this is just the logic that determines if you can jump cancel or not. Happens in reaction phase in order to be able to react to attacks hitting on the current frame / during hitstop.
## Flags:
## - CanJumpCancel: Set manually by the user, forces the action to be jump cancellable
## - CanJumpCancel-OnHit / CanJumpCancel-OnBlock: Often added by default, sets CanJumpCancel on specific conditions
## - NoJumpCancels: Removes jump cancels automatically
_Helper()
_Category(Internals/Attacks/Helpers)

PReaction:
	LNoJumpCancels:
		Unflag(CanJumpCancel)
	else
		LCanJumpCancel-OnHit:
			LAttackHasHit:
				Flag(CanJumpCancel)
			endif
		endif
		LCanJumpCancel-OnBlock:
			LAttackWasBlocked:
				Flag(CanJumpCancel)
			endif
		endif
	endif
endif
:Attack-ThrowTechingManagement:
## Handles teching windows
_Category(Internals/Attacks/Throws)
_Helper()

VThrow_Lockout<=0:
	IThrowPress:
		Set(Throw_Teching, ATTACK_Throw_Tech_ActiveTime)
		Set(Throw_Lockout, ATTACK_Throw_Tech_LockoutTime)
	endif
else
	Sub(Throw_Lockout, 1)
endif


VThrow_Teching>0:
	Sub(Throw_Teching, 1)
endif
:AttackCancels-All:
## Helper function to quickly add all attack cancels to a move. Will also add throws unless NoThrowCancels flag is active.
_Helper()
_Category(Attacks/Helpers/Cancels)

Call(AttackCancels-Normals-All)
Call(AttackCancels-Specials-All)

LNoThrowCancels:
else
	Call(AttackCancels-Throws)
endif
:AttackCancels-Normals-All:
## Helper function to quickly add all normal cancels to a move. Flags given by the ATTACK_CancelFlags variable
_Helper()
_Category(Attacks/Helpers/Cancels)

Call(AttackCancels-Normals-Lights)
Call(AttackCancels-Normals-Mediums)
Call(AttackCancels-Normals-Heavies)
:AttackCancels-Normals-Heavies:
## Helper function to quickly add all heavy normal cancels to a move.
_Helper()
_Category(Attacks/Helpers/Cancels)
_Overridable(If you want to manually add or remove attacks)

AttackAddRegisteredCancels(Heavy, ATTACK_CancelFlags)
AttackAddRegisteredCancels(AirHeavy, ATTACK_CancelFlags)
:AttackCancels-Normals-Lights:
## Helper function to quickly add all light normal cancels to a move.
_Helper()
_Category(Attacks/Helpers/Cancels)
_Overridable(If you want to manually add or remove attacks)

AttackAddRegisteredCancels(Light, ATTACK_CancelFlags)
AttackAddRegisteredCancels(AirLight, ATTACK_CancelFlags)
:AttackCancels-Normals-Mediums:
## Helper function to quickly add all medium normal cancels to a move.
_Helper()
_Category(Attacks/Helpers/Cancels)
_Overridable(If you want to manually add or remove attacks)

AttackAddRegisteredCancels(Medium, ATTACK_CancelFlags)
AttackAddRegisteredCancels(AirMedium, ATTACK_CancelFlags)
:AttackCancels-Specials-All:
## Helper function to quickly add all special cancels to a move. Flags given by the ATTACK_CancelFlags variable
_Helper()
_Category(Attacks/Helpers/Cancels)

Call(AttackCancels-Specials-Specials)
Call(AttackCancels-Specials-EX)
Call(AttackCancels-Specials-Supers)
:AttackCancels-Specials-EX:
## Helper function to quickly add all EX special cancels to a move.
_Helper()
_Category(Attacks/Helpers/Cancels)
_Overridable(If you want to manually add or remove attacks)

VMeter>ATTACK_EX_MeterCost:
	AttackAddRegisteredCancels(EX, ATTACK_CancelFlags)
	AttackAddRegisteredCancels(AirEX, ATTACK_CancelFlags)
endif
:AttackCancels-Specials-Specials:
## Helper function to quickly add all regular special cancels to a move.
_Helper()
_Category(Attacks/Helpers/Cancels)
_Overridable(If you want to manually add or remove attacks)

AttackAddRegisteredCancels(Special, ATTACK_CancelFlags)
AttackAddRegisteredCancels(AirSpecial, ATTACK_CancelFlags)
:AttackCancels-Specials-Supers:
## Helper function to quickly add all super cancels to a move.
_Helper()
_Category(Attacks/Helpers/Cancels)
_Overridable(If you want to manually add or remove attacks)

VMeter>ATTACK_Super_MeterCost:
	AttackAddRegisteredCancels(Super, ATTACK_CancelFlags)
	AttackAddRegisteredCancels(AirSuper, ATTACK_CancelFlags)
endif
:AttackCancels-Throws:
## Helper function to quickly add all throw cancels to a move (or more likely, in neutral). Flags given by the ATTACK_CancelFlags variable
_Helper()
_Category(Attacks/Helpers/Cancels)
_Overridable(If you want to manually add or remove attacks)

AttackAddRegisteredCancels(Throw, ATTACK_CancelFlags)
AttackAddRegisteredCancels(AirThrow, ATTACK_CancelFlags)
:AttackPrefixSetup:
## Internal helper that handles switching between airborne and grounded attacks.
_Category(Internals/Attacks/Helpers)
_Helper()

LAirborne:
	AttackCancelPrefix(j)
else
	AttackCancelPrefix()
endif
:AttackReactEvents:
## Helper state that will call the other helper states related to attack events
_Category(Internals/Attacks/React)
_Helper()

Call(AttackReactEvents-Overrides)
Call(AttackReactEvents-Attacker)
Call(AttackReactEvents-Defender)
:AttackReactEvents-Attacker:
## Helper state that reacts to attacking
_Category(Internals/Attacks/React)
_Helper()
_Overridable(To add behavior when an attack connects from the attacker side. Don't forget to use E branches)

Call(AttackReactEvents-Attacker-Stuns)
:AttackReactEvents-Attacker-Stuns:
## Handles hitstop for the attacker
_Category(Internals/Attacks/React)
_Helper()

EOnAttackHit:
	AttackInflictedGetParam(Hitstop, CAST_REG_A)
	FreezeFrames(CAST_REG_A)
endif
EOnAttackBlocked:
	AttackInflictedGetParam(Blockstop, CAST_REG_A)
	FreezeFrames(CAST_REG_A)
endif
:AttackReactEvents-Defender:
## Helper state that reacts to getting attacked
_Category(Internals/Attacks/React)
_Helper()
_Overridable(To add behavior when an attack connects from the defender side. Don't forget to use E branches)

Call(AttackReactEvents-Defender-FirstHit)

Call(AttackReactEvents-Defender-Damage)
Call(AttackReactEvents-Defender-Stun)
Call(AttackReactEvents-Defender-Proration)
Call(AttackReactEvents-Defender-Transition)
:AttackReactEvents-Defender-Damage:
## Handles damage computations
_Category(Internals/Attacks/React)
_Helper()

EOnGetHit:
	AttackRecievedGetParam(Damage, CAST_REG_A)

	LAF_IgnoreProration:
	else
		LAF_IgnoreProrationDamage:
		else
			Mul(CAST_REG_A, ATTACK_ProrationDamage)
			Div(CAST_REG_A, ATTACK_Proration_Scale)
		endif
	endif

	AttackRecievedGetParam(MinDamage, CAST_REG_B)
	Max(CAST_REG_A, CAST_REG_B)

	Sub(HP, CAST_REG_A)
endif

## CASTDO Chip damage
:AttackReactEvents-Defender-FirstHit:
## Helper called on the first hit of a combo
_Category(Internals/Attacks/React)
_Helper()

EOnGetHit:
	LAF_FirstHit:
		Set(ATTACK_ComboCounter, 0)
		Set(ATTACK_ProrationDamage, 1000)
		Set(ATTACK_ProrationHitstun, 1000)
		#Set(ATTACK_GroundbouncesRemaining, ATTACK_GroundbouncesMaxPerCombo)
	endif
endif
:AttackReactEvents-Defender-Misc:
## Handles miscellaneous effects on hit, like combo count
_Category(Internals/Attacks/React)
_Helper()

EOnGetHit:
	LAF_ComboCounterStatic:
	else
		Add(ATTACK_ComboCounter, 1)
	endif
endif
:AttackReactEvents-Defender-Proration:
## Handles increasing proration when recieving an attack
_Category(Internals/Attacks/React)
_Helper()

EOnGetHit:
	LAF_IgnoreProration:
	else
		LAF_IgnoreProrationHitstun:
		else
			AttackRecievedGetParam(ProrationHitstun, CAST_REG_A)
			Mul(ATTACK_ProrationHitstun, CAST_REG_A)
			Div(ATTACK_ProrationHitstun, ATTACK_Proration_Scale)
		endif
		
		LAF_IgnoreProrationDamage:
		else
			AttackRecievedGetParam(ProrationDamage, CAST_REG_A)
			Mul(ATTACK_ProrationDamage, CAST_REG_A)
			Div(ATTACK_ProrationDamage, ATTACK_Proration_Scale)
		endif
	endif
endif
:AttackReactEvents-Defender-Stun:
## Handles setting the stun correctly
_Category(Internals/Attacks/React)
_Helper()


EOnGetHit:
	AttackRecievedGetParam(Hitstun, CAST_REG_A)

	LAF_IgnoreProration:
	else
		LAF_IgnoreProrationHitstun:
		else
			Mul(CAST_REG_A, ATTACK_ProrationHitstun)
			Div(CAST_REG_A, ATTACK_Proration_Scale)
		endif
	endif

	AttackRecievedGetParam(MinHitstun, CAST_REG_B)
	Max(CAST_REG_A, CAST_REG_B)

	Set(ATTACK_HitstunDuration, CAST_REG_A)

	AttackRecievedGetParam(Hitstop, CAST_REG_A)
	FreezeFrames(CAST_REG_A)
endif

EOnBlocking:
	#F_BlockstunDuration
	AttackRecievedGetParam(Blockstun, ATTACK_BlockstunDuration)

	## TODO new freeze
	AttackRecievedGetParam(Blockstop, CAST_REG_A)
	FreezeFrames(CAST_REG_A)
endif
:AttackReactEvents-Defender-Transition:
## Handles going to the hitstun state or a custom one
## TODO
_Category(Internals/Attacks/React)
_Helper()

EOnGetHit:
	VHP<=0:
		Transition(Dead, ATK_HITSTUN_PRIORITY, 1)
	else
		AttackRecievedGetParam(TransitionTo, CAST_REG_A_STR)
		Transition(CAST_REG_A_STR, ATK_HITSTUN_PRIORITY, 1)
	endif
endif

EOnBlocking:
	Transition(Blockstun, ATK_BLOCKSTUN_PRIORITY, 1)
endif
:AttackReactEvents-Overrides:
## Helper state that will activate attack overrides
_Category(Internals/Attacks/React)
_Helper()
_Overridable(To add behavior on an attack connecting -mainly overrides. Don't forget to use E branches)

EDefenderAttackOverrides:
	LAF_Blocked:
		AttackRecievedOverride(Block)
	else
		AttackRecievedOverride(Hit)
		
		LHitstun:
		else
			AttackRecievedFlag(FirstHit)
			AttackRecievedOverride(FirstHit)
			
			LAttackStartup:
				AttackRecievedFlag(CounterHit)
				AttackRecievedOverride(CounterHit)
			endif
			LAttackWasActive:
				AttackRecievedFlag(Punish)
				AttackRecievedOverride(Punish)
			endif
			
		endif
	endif
endif
:AttackState:
## Base behavior for attacks. You wont usually call it directly, it is instead called by the AttackType- states through AttackRegister
## AttackDuration needs to be called before frame 180 by default, since there is a failsafe there.

_Category(Internals/Attacks)
_BaseState()

AttackInit()
Flag(Attacking)
FlagNext(AttackStateLastFrame)

F1:
	Set(_AttackDuration, 180)
	AttackRearm()
	Set(_AttackAnimInterruptableFrames, 0)
endif
## CASTDO EEnter causes issues here ? Leaving it at F1 breaks TranstitionToFrame but less important than base behavior

# Counter hit / punish management
LAttackHasTouched:
	Flag(AttackWasActive)
endif
LAttackHasWhiffed:
	Flag(AttackWasActive)
endif
LAttackWasActive:
else
	Flag(AttackStartup)
endif


Call(StandardState)
Unflag(FaceTarget)

Call(AttackState-DefaultParams)

F_AttackDuration+:
	Call(AttackTransitionToNeutralState)
endif

## CASTDO Find a way to remove the warning
:AttackState-After:
## Handles some additional checks for attacks, like jump cancels
_Helper()
_Category(Internals/Attacks)

Call(Attack-JumpCancel)
:AttackState-DefaultParams:
## Helper to set general parameters for all attacks
_Category(Internals/Attacks)
_Helper()

AttackMinDamage(ATTACK_MinDamage)

AttackOverride(Multihit)
AttackProrationHitstun(1000)
AttackProrationDamage(1000)

AttackOverrideMultiple(FirstHit)
AttackProrationHitstun(1000)
AttackProrationDamage(1000)

AttackOverride()
:AttackTransitionToNeutralState:
# Allows attacks to go back to a neutral state
_Category(Internals/Attacks/Helpers)
_Helper()

V_AttackAnimInterruptableFrames>0:
	LPF_Airborne:
		FlagNext(IdleAnimOverride_Airborne)
	else
		LCrouching:
			FlagNext(IdleAnimOverride_Crouching)
		else
			FlagNext(IdleAnimOverride_Stand)
		endif
	endif
endif

Call(TransitionToNeutralState)
:AttackType-AirEX:
## Base behavior for airborne EX special attacks, which cost meter to use. Used by calling AttackRegister(AirEX)

def SSTATE_CancelOnLanding bool() = 1
_Category(Internals/Attacks/Types/Specials)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-AirEX)

AttackProrationDamage(ATTACK_EX_ProrationDamage, ATTACK_EX_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_EX_ProrationHitstun, ATTACK_EX_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-EX)
endif
:AttackType-AirHeavy:
## Base behavior for airborne heavy normal attacks, which are usually your slowest and strongest normals. Used by calling AttackRegister(AirHeavy)

def SSTATE_CancelOnLanding bool() = 1
_Category(Internals/Attacks/Types/Normals)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-AirHeavy)

AttackProrationDamage(ATTACK_Heavy_ProrationDamage, ATTACK_Heavy_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Heavy_ProrationHitstun, ATTACK_Heavy_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Heavy)
endif
:AttackType-AirLight:
## Base behavior for airborne light normal attacks, which are usually your fastest options. Used by calling AttackRegister(AirLight)

def SSTATE_CancelOnLanding bool() = 1
_Category(Internals/Attacks/Types/Normals)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-AirLight)

AttackProrationDamage(ATTACK_Light_ProrationDamage, ATTACK_Light_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Light_ProrationHitstun, ATTACK_Light_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Light)
endif
:AttackType-AirMedium:
## Base behavior for airborne medium normal attacks, which are usually middleground, reliable options. Used by calling AttackRegister(AirMedium)

def SSTATE_CancelOnLanding bool() = 1
_Category(Internals/Attacks/Types/Normals)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-AirMedium)

AttackProrationDamage(ATTACK_Medium_ProrationDamage, ATTACK_Medium_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Medium_ProrationHitstun, ATTACK_Medium_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Medium)
endif
:AttackType-AirSpecial:
## Base behavior for airborne special attacks, which are unique to your character. Used by calling AttackRegister(AirSpecial)

def SSTATE_CancelOnLanding bool() = 1
_Category(Internals/Attacks/Types/Specials)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-AirSpecial)

AttackProrationDamage(ATTACK_Special_ProrationDamage, ATTACK_Special_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Special_ProrationHitstun, ATTACK_Special_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Special)
endif
:AttackType-AirSuper:
## Base behavior for airborne super attacks, which are usually costly, strong attacks. Used by calling AttackRegister(AirSuper)

def SSTATE_CancelOnLanding bool() = 1
_Category(Internals/Attacks/Types/Specials)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-AirSuper)

AttackProrationDamage(ATTACK_Super_ProrationDamage, ATTACK_Super_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Super_ProrationHitstun, ATTACK_Super_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Super)
endif
:AttackType-AirThrow:
## Base behavior for air throws attacks, which can beat airborne blocking opponents. Used by calling AttackRegister(AirThrow)

def SSTATE_CancelOnLanding bool() = 1
_Category(Internals/Attacks/Types/Throws)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-AirThrow)
_Helper()

AttackDamage(0)
AttackFlag(Throw)
AttackFlag(AirThrow)
AttackUnblockableAirborne()
AttackTransitionTo(AirThrowHeld)

# No throw cancels here, it automatically transitions.

IBack:
	FlagNext(ThrowBack)
endif

LAttackHasHit:
	Transition(ATTACK_Throw_Air_HoldingState, ATTACK_Throw_GoToHoldingPriority)
endif
:AttackType-AirThrowFollowup:
## Attack type for attacks that followup confirmed grounded throws.
_Category(Internals/Attacks/Types/Throws)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-AirThrowFollowup)

F1:
	SetTargetPosition(ATTACK_Throw_Air_HoldPointX, ATTACK_Throw_Air_HoldPointY)
endif

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Throw)
endif
:AttackType-EX:
## Base behavior for EX special attacks, which are specials that cost meter. Used by calling AttackRegister(EX)

_Category(Internals/Attacks/Types/Specials)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-EX)

AttackProrationDamage(ATTACK_EX_ProrationDamage, ATTACK_EX_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_EX_ProrationHitstun, ATTACK_EX_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-EX)
endif
:AttackType-Heavy:
## Base behavior for heavy normal attacks, which are usually your strongest normals. Used by calling AttackRegister(Heavy)

_Category(Internals/Attacks/Types/Normals)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-Heavy)

AttackProrationDamage(ATTACK_Heavy_ProrationDamage, ATTACK_Heavy_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Heavy_ProrationHitstun, ATTACK_Heavy_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Heavy)
endif
:AttackType-Light:
## Base behavior for light normal attacks, which are usually your fastest options. Used by calling AttackRegister(Light)

_Category(Internals/Attacks/Types/Normals)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-Light)

AttackProrationDamage(ATTACK_Light_ProrationDamage, ATTACK_Light_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Light_ProrationHitstun, ATTACK_Light_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Light)
endif
:AttackType-Medium:
## Base behavior for medium normal attacks, which are usually your middleground, reliable attacks. Used by calling AttackRegister(Medium)

_Category(Internals/Attacks/Types/Normals)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-Medium)

AttackProrationDamage(ATTACK_Medium_ProrationDamage, ATTACK_Medium_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Medium_ProrationHitstun, ATTACK_Medium_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Medium)
endif
:AttackType-Special:
## Base behavior for special attacks, which are unique to your character. Used by calling AttackRegister(Special)

_Category(Internals/Attacks/Types/Specials)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-Special)

AttackProrationDamage(ATTACK_Special_ProrationDamage, ATTACK_Special_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Special_ProrationHitstun, ATTACK_Special_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Special)
endif
:AttackType-Super:
## Base behavior for super attacks, which are costly, strong attacks. Used by calling AttackRegister(Super)

_Category(Internals/Attacks/Types/Specials)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-Super)

AttackProrationDamage(ATTACK_Super_ProrationDamage, ATTACK_Super_ProrationDamageStarter)
AttackProrationHitstun(ATTACK_Super_ProrationHitstun, ATTACK_Super_ProrationHitstunStarter)

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Super)
endif
:AttackType-Throw:
## Base behavior for throw, which can beat grounded opponents. Used by calling AttackRegister(Throw)

_Category(Internals/Attacks/Types/Throws)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-Throw)
_Helper()

AttackDamage(0)
AttackFlag(Throw)
AttackUnblockableGround()
AttackTransitionTo(ThrowHeld)

# No throw cancels here, it automatically transitions.

IBack:
	FlagNext(ThrowBack)
endif


LAttackHasHit:
	Transition(ATTACK_Throw_Ground_HoldingState, ATTACK_Throw_GoToHoldingPriority)
endif
:AttackType-ThrowFollowup:
## Attack type for attacks that followup confirmed grounded throws.
_Category(Internals/Attacks/Types/Throws)
Call(AttackState)
_BaseState()
_StateFlag(AttackType-ThrowFollowup)

F1:
	SetTargetPosition(ATTACK_Throw_Ground_HoldPointX, ATTACK_Throw_Ground_HoldPointY)
endif

LNoDefaultCancels:
else
	Call(AttackTypeHelper-CancelRules-Throw)
endif
:AttackTypeHelper-CancelRules-Common:
## Attack helper that computes the possible cancel situations. Activate the AttackWhiffCancel flag to automatically allow attacks to cancel on whiff.
_Category(Internals/Attacks/Types/Cancels)
_Helper()

## CASTDO constants

Set(ATTACK_CancelFlags, 11)
# ATTACKCANCEL_ON_TOUCH_NEUTRAL

LAttackWhiffCancel:
	Add(ATTACK_CancelFlags, 4)
	# ATTACKCANCEL_ON_WHIFF
endif
:AttackTypeHelper-CancelRules-EX:
## Defines default cancels for EX / AirEX attacks. Activate the NoDefaultCancels flag to disable.
_Category(Internals/Attacks/Types/Cancels)
_Helper()
_Overridable(If you want to change the default cancel rules for EX specials)

Call(AttackTypeHelper-CancelRules-Common)

VATTACK_EX_CanCancelIntoEX:
	Call(AttackCancels-Specials-EX)
endif
VATTACK_EX_CanCancelIntoSuper:
	Call(AttackCancels-Specials-Supers)
endif


VATTACK_EX_CanJumpCancelOnHit:
	Flag(CanJumpCancel-OnHit)
endif
VATTACK_EX_CanJumpCancelOnBlock:
	Flag(CanJumpCancel-OnBlock)
endif
:AttackTypeHelper-CancelRules-Heavy:
## Defines default cancels for Heavy / AirHeavy attacks. Activate the NoDefaultCancels flag to disable.
_Category(Internals/Attacks/Types/Cancels)
_Helper()
_Overridable(If you want to change the default cancel rules for heavy attacks)

Call(AttackTypeHelper-CancelRules-Common)

VATTACK_Heavy_CanCancelIntoLights:
	Call(AttackCancels-Normals-Lights)
endif
VATTACK_Heavy_CanCancelIntoMediums:
	Call(AttackCancels-Normals-Mediums)
endif
VATTACK_Heavy_CanCancelIntoHeavies:
	Call(AttackCancels-Normals-Heavies)
endif
VATTACK_Heavy_CanCancelIntoSpecials:
	Call(AttackCancels-Specials-All)
endif


VATTACK_Heavy_CanJumpCancelOnHit:
	Flag(CanJumpCancel-OnHit)
endif
VATTACK_Heavy_CanJumpCancelOnBlock:
	Flag(CanJumpCancel-OnBlock)
endif
:AttackTypeHelper-CancelRules-Light:
## Defines default cancels for Light / AirLight attacks. Activate the NoDefaultCancels flag to disable.
_Category(Internals/Attacks/Types/Cancels)
_Helper()
_Overridable(If you want to change the default cancel rules for light attacks)

Call(AttackTypeHelper-CancelRules-Common)

VATTACK_Light_CanCancelIntoLights:
	Call(AttackCancels-Normals-Lights)
endif
VATTACK_Light_CanCancelIntoMediums:
	Call(AttackCancels-Normals-Mediums)
endif
VATTACK_Light_CanCancelIntoHeavies:
	Call(AttackCancels-Normals-Heavies)
endif
VATTACK_Light_CanCancelIntoSpecials:
	Call(AttackCancels-Specials-All)
endif

VATTACK_Light_CanJumpCancelOnHit:
	Flag(CanJumpCancel-OnHit)
endif
VATTACK_Light_CanJumpCancelOnBlock:
	Flag(CanJumpCancel-OnBlock)
endif
:AttackTypeHelper-CancelRules-Medium:
## Defines default cancels for Medium / AirMedium attacks. Activate the NoDefaultCancels flag to disable.
_Category(Internals/Attacks/Types/Cancels)
_Helper()
_Overridable(If you want to change the default cancel rules for medium attacks)

Call(AttackTypeHelper-CancelRules-Common)

VATTACK_Medium_CanCancelIntoLights:
	Call(AttackCancels-Normals-Lights)
endif
VATTACK_Medium_CanCancelIntoMediums:
	Call(AttackCancels-Normals-Mediums)
endif
VATTACK_Medium_CanCancelIntoHeavies:
	Call(AttackCancels-Normals-Heavies)
endif
VATTACK_Medium_CanCancelIntoSpecials:
	Call(AttackCancels-Specials-All)
endif


VATTACK_Medium_CanJumpCancelOnHit:
	Flag(CanJumpCancel-OnHit)
endif
VATTACK_Medium_CanJumpCancelOnBlock:
	Flag(CanJumpCancel-OnBlock)
endif
:AttackTypeHelper-CancelRules-Special:
## Defines default cancels for Special / AirSpecial attacks. Activate the NoDefaultCancels flag to disable.
_Category(Internals/Attacks/Types/Cancels)
_Helper()
_Overridable(If you want to change the default cancel rules for specials)

Call(AttackTypeHelper-CancelRules-Common)

VATTACK_Special_CanCancelIntoEX:
	Call(AttackCancels-Specials-EX)
endif
VATTACK_Special_CanCancelIntoSuper:
	Call(AttackCancels-Specials-Supers)
endif


VATTACK_Special_CanJumpCancelOnHit:
	Flag(CanJumpCancel-OnHit)
endif
VATTACK_Special_CanJumpCancelOnBlock:
	Flag(CanJumpCancel-OnBlock)
endif
:AttackTypeHelper-CancelRules-Super:
## Defines default cancels for Super / AirSuper attacks. Activate the NoDefaultCancels flag to disable.
_Category(Internals/Attacks/Types/Cancels)
_Helper()
_Overridable(If you want to change the default cancel rules for supers)

Call(AttackTypeHelper-CancelRules-Common)
:AttackTypeHelper-CancelRules-Throw:
## Defines default cancels for Throw / AirThrow attacks. Activate the NoDefaultCancels flag to disable.
## This is actually called by the Throw Followup state, since the Throw attack is meant for the start
_Category(Internals/Attacks/Types/Cancels)
_Helper()
_Overridable(If you want to change the default cancel rules for throws)

Call(AttackTypeHelper-CancelRules-Common)

VATTACK_Throw_CanCancelIntoSpecials:
	Call(AttackCancels-Specials-Specials)
endif
VATTACK_Throw_CanCancelIntoEX:
	Call(AttackCancels-Specials-EX)
endif
VATTACK_Throw_CanCancelIntoSuper:
	Call(AttackCancels-Specials-Supers)
endif


VATTACK_Throw_CanJumpCancelOnHit:
	Flag(CanJumpCancel-OnHit)
endif
VATTACK_Throw_CanJumpCancelOnBlock:
	Flag(CanJumpCancel-OnBlock)
endif
:Blockstun:
## Blockstun state behavior, which happens when you block an attack.
_Category(States/Reacts/Blockstun)
_BaseState()

Call(Common)

Call(Attack-CanBlock)

VATTACK_ContinueBlockingAfterFirstHit:
	Flag(Blocking)
endif

Flag(Blockstun)

LCrouching:
	FlagNext(Crouching)
endif

FATTACK_BlockstunDuration+:
	Call(TransitionToNeutralState)
endif

Call(AnimBlockstun)
:Common:
CallParent()

Call(Attack-ThrowTechingManagement)
Call(Attack-BlockingLogic)
Call(AttackReactEvents)
:CommonAfter:
CallParent()

Call(AttackState-After)
:Dead:
Flag(NoHurtbox)
SetColboxPhantom()
Call(Common)

Call(AnimDead)
:Hitstun:
## Hitstun state, for when you have been hit by an attack.

_Category(States/Reacts/Hitstun)
Flag(Hitstun)
Call(Common)

PReaction:
	LAF_ForceLanding:
		LPF_Grounded:
			Flag(PF_Landing)
		endif
	endif
endif

LPF_Landing:
	Call(HitstunLanding)
else
	FATTACK_HitstunDuration+:
		Call(HitstunEnd)
	endif
endif

LCrouching:
	FlagNext(Crouching)
endif

Call(AnimHitstun)

F1:
	Flag(FaceTarget)
endif
:HitstunEnd:
## Ends hitstun and goes back to a neutral state

_Category(States/Reacts/Hitstun)
_Helper()

LPF_Airborne:
	VATTACK_Hitstun_CanRecoverInAir:
		Call(StartAirTech)
	endif
else
	Call(ApplyPhysics-Regular)
	Call(TransitionToNeutralState)
endif
:HitstunLanding:
## Called when landing in hitstun, which will initiate a soft tech
_Category(States/Reacts/Hitstun)
_Helper()

ModelShaderParamF(ModulationColor, 1000, 1000, 1000, 1000)

# Check for groundbounces
LAF_Groundbounce:
	VATTACK_GroundbouncesRemaining>0:
		Sub(ATTACK_GroundbouncesRemaining, 1)
		LAF_ForceGroundbounce:
		else
			AttackRecievedUnflag(Groundbounce)
		endif
	endif
endif

LAF_Groundbounce:
	Transition(Groundbounce)
else
	LAF_Knockdown:
		Transition(Knockdown)
	else
		Call(StartGroundTech)
	endif
endif
:NeutralStateCommon:
CallParent()

Call(Attack-CanBlock)

Call(AttackCancels-All)
:OnReturnToNeutral:
_Helper()
CallParent()

AttackResetDoneCancels()
:OnRoundStart:
CallParent()
Call(OnRoundStart-Attacks)
:OnRoundStart-Attacks:
_Helper()
Set(HP, HPMax)
:SimpleAttack-Standard:
## Helper for the simple attack system, which allows edition of attacks through custom editors easily.
## CASTDO
_Category(Internals/Attacks/SimpleAttack)
_Helper()

# Variables

def Attack_Damage int() = 1000

def Attack_Startup int() = 10
def Attack_ActiveFrames int() = 1
def Attack_Recovery int() = 10

def Attack_Hitstun int() = 30
def Attack_FrameAdvantageBlock int() = 0

def Animation_Name str() = 5B

def Hitbox_Back int() = 0
def Hitbox_Front int() = 16000
def Hitbox_Bottom int() = 5000
def Hitbox_Top int() = 15000

def Properties_Low bool() = 0
def Properties_Overhead bool() = 0

# Computations
Add(Attack_Startup, Attack_ActiveFrames, SimpleAttack_ActiveEnd)
Sub(SimpleAttack_ActiveEnd, 1)
Add(SimpleAttack_ActiveEnd, Attack_Recovery, SimpleAttack_Duration)


# Attack params
AttackDamage(Attack_Damage)
AttackDuration(SimpleAttack_Duration)

VProperties_Low:
	AttackFlag(Low)
endif
VProperties_Overhead:
	AttackFlag(Overhead)
endif

Anim(Animation_Name)

# Active frames and hitboxes
FAttack_Startup-SimpleAttack_ActiveEnd:
	Hitbox(Hitbox_Back, Hitbox_Front, Hitbox_Bottom, Hitbox_Top)
endif
:StandardState:
CallParent()

Call(AttackPrefixSetup)
:StateTemplate-Attack-Normal:
# Simple medium attack template
AttackRegister(Medium)

# Adjust parameters here
AttackDamage(1000)
AttackDuration(60)
# AttackMustBlock(Low)

# Put your animation here
#Anim(5B)

# Active frames and hitboxes
F10-12:
	Hitbox(0, 15000, 5000, 15000)
endif
:StateTemplate-Attack-Projectile:
# Projectile-throwing move template. Needs a separate entity you'll have to create!

## TODO: Create the entity required using [New Entity]! Remove this comment once done.

def ProjectileName str() = Projectile
def ProjectileStartX int() = 0
def ProjectileStartY int() = 10000
def ProjectileStartup int() = 20
def AttackDuration int() = 60

AttackRegister(Special)

AttackDuration(AttackDuration)

FProjectileStartup:
	CreateEntity(ProjectileName)
	SetTargetPosition(ProjectileStartX, ProjectileStartY)
endif
:StateTemplate-Attack-Sequential:
# Simple medium attack template using an S branch (sequential)
AttackRegister(Medium)

# Adjust parameters here
AttackDamage(1000)
# AttackMustBlock(Low)

# Put your animation here
#Anim(5B)

SATK9:
	# Startup
S3
	# Active
	Hitbox(0, 15000, 5000, 15000)
S50
	# Recovery
endif
:StateTemplate-Attack-Simple:
# Template for attacks you can customize through custom editors.
# /!\ This is still limited! Some improvements need to be made to achieve it fully, so you need a bit of manual editing still at times.
AttackRegister(Medium)

Call(SimpleAttack-Standard)
:ThrowB:
## Grounded Throw Backward attack, by default the same as throw forward but flipped
_Category(Attacks/ThrowFollowup)
_Overridable(If you want another attack instead)

Call(ThrowF)
## CASTDO Warinings
:ThrowF:
## Grounded Throw Forward attack, to be overriden
_Overridable(Put your own attack here instead)

AttackRegister(ThrowFollowup)

AttackDamage(0)
AttackDuration(10)
AttackMomentum(600, 600)
AttackKnockdown()

F1:
	Hitbox(0, 20000, -10000, 20000)
endif
:ThrowHeld:
## State where got hit with a throw, and have a chance to tech it
_Category(States/Reacts/Throws)
Call(Common)
Call(ThrowHeld-Common)

Call(AnimGroundThrowHeld)

LThrowConfirmed:
else
	LThrowTeching:
		Transition(ATTACK_Throw_Ground_TechingState, ATTACK_Throw_TechingPriority)
	endif
endif
:ThrowHeld-Common:
## Common behavior for the throw held states.
##
## This works in collaboration with ThrowHolding states.
## ThrowHeld states handle teching, and will send the ThrowTeching flag to the other
## If the throw is confirmed, we add an hurtbox
_Category(States/Reacts/Throws)
_Helper()

Flag(NoHurtbox)
Flag(NoColbox)
Flag(HaltMomentum)

PReaction:
	LThrowConfirmed:
		FlagNext(ThrowConfirmed)
	endif
endif

Flag(FaceTarget)

LThrowConfirmed:
	Unflag(ThrowTeching)
else
	VThrow_Teching>0:
		Flag(ThrowTeching)
		FlagInTarget(ThrowTeching)
	endif
endif
:ThrowHolding:
## State where you hit with a throw, and are waiting for it to confirm
_Category(States/Reacts/Throws)
Call(Common)

SetTargetPosition(ATTACK_Throw_Ground_HoldPointX, ATTACK_Throw_Ground_HoldPointY)

FATTACK_Throw_Ground_TimeHold+:
	Flag(ThrowConfirmed)
endif

Call(ThrowHolding-Common)

LThrowConfirmed:
	LThrowBack:
		VATTACK_Throw_Ground_ThrowBAutoFlip:
			FlipFacing()
		endif

		Transition(ATTACK_Throw_Ground_ThrowBState, ATTACK_Throw_ConfirmPriority)
	else
		Transition(ATTACK_Throw_Ground_ThrowFState, ATTACK_Throw_ConfirmPriority)
	endif
else
	LThrowTeching:
		Transition(ATTACK_Throw_Ground_TechedState, ATTACK_Throw_TechingPriority)
	endif
endif

Call(AnimGroundThrowHolding)
:ThrowHolding-Common:
## Helper to handle back/forward management and teching.
##
## This works in collaboration with ThrowHeld states.
## This state handles confirmation of throws, and back/forward management.
## A fair amount of the behavior is in the holding states themselves to be able to handle variables correctly
_Category(States/Reacts/Throws)
_Helper()

Flag(NoHurtbox)
Flag(NoColbox)
Flag(HaltMomentum)

IBack:
	Flag(ThrowBack)
endif

IForward:
	Unflag(ThrowBack)
endif

LThrowBack:
	FlagNext(ThrowBack)
endif

LThrowConfirmed:
	FlagInTarget(ThrowConfirmed)
endif
:ThrowTeched:
## State for when you hit with a grounded throw and it has been teched
_Category(States/Reacts/Throws)
Call(Common)

FMOVE_Teched_Ground_Time+:
	Call(TransitionToNeutralState)
endif

F1:
	SetMomentum(MOVE_Teched_Ground_MomentumX, MOVE_Teched_Ground_MomentumY)
endif

Call(AnimGroundThrowTeched)
:ThrowTeching:
## State for when you got hit by a grounded throw and teched it
_Category(States/Reacts/Throws)
Call(Common)

FMOVE_Teching_Ground_Time+:
	Call(TransitionToNeutralState)
endif

F1:
	SetMomentum(MOVE_Teching_Ground_MomentumX, MOVE_Teching_Ground_MomentumY)
endif

Call(AnimGroundThrowTeching)
:Base---Subentity:
# Autogenerated
:Base---SEAttackReactEvents:
## Helper state that handles attack reaction events for subentities
_Helper()

# Overrides
Call(SEAttackReactEvents-Overrides)

# Attacker
Call(SEAttackReactEvents-Attacker)

# Defender
Call(SEAttackReactEvents-Defender)
:Base---SEAttackReactEvents-Attacker:
## Helper state that handles attack overrides for subentities
_Helper()

EOnAttackHit:
	VSUBENTITY_DestroyOnHit:
		DestroyEntity()
	endif
endif

EOnAttackBlocked:
	VSUBENTITY_DestroyOnBlock:
		DestroyEntity()
	endif
endif
:Base---SEAttackReactEvents-Defender:
## Helper state that handles attack overrides for subentities
_Helper()

EOnGetHit:
	VSUBENTITY_DestroyWhenHit:
		DestroyEntity()
	endif
endif
:Base---SEAttackReactEvents-Overrides:
## Helper state that handles attack overrides for subentities
_Helper()
:Base---SECommon:
CallParent()
Call(SEAttackReactEvents)
