class_name CharacterStateProperties extends Resource
## Descriptor of how a Character's properties should change in some given state.

## How the character should self-orient in this state.
enum OrientationMode {
	## Do not self-orient in this state / other code will handle it.
	MANUAL,
	## Self-orient toward the direction we are actually moving in.
	FOLLOW_VELOCITY,
	## Self-orient toward the direction we are trying to move in.
	FOLLOW_ACCELERATION,
	## Self-orient according to the normal of the contact surface.
	FOLLOW_NORMAL
}

## How the character should move in this state.
enum PhysicsMode {
	## Character responds to impetus projected onto ground plane.
	NORMAL,
	## Character responds to impetus unmodified.
	FREE,
	## Character does not respond to impetus.
	NO_IMPETUS,
	## Character is not subject to physics at all.
	FREEZE
}

@export_group("Transitions")
## Whether to use a timer to prevent stopping this state too quickly.
@export var use_coyote_time := false
## Value to assign to the timer on state start if use_coyote_time is true.
@export var coyote_time: float = 0.0
## Whether to disallow interrupting this state.
## [br][br]
## Even if true, can be overruled with force_change_state.
## For example, the logic of the uninterruptible state itself
## can use this strategy for sanctioned state transitions.
@export var uninterruptible := false
## Whether this state is to be used while carrying an object.
## [br][br]
## If true, it cannot be entered while not carrying an object.
## If false, entering it will force any carried object to be dropped,
## unless equivalent_carrying_state is specified,
## in which case that state will be entered instead.
@export var is_carrying_state := false
## State to enter instead of this state if carrying an object.
@export var equivalent_carrying_state := &''

@export_group("Animation")
## Animation to play in this state.
@export var animation_name: StringName = &'idle'
## If specified, 50% random chance to use this animation instead.
@export var animation_alt_name: StringName = &''
## Animation playback rate when not moving.
@export var animation_base_speed: float = 1.0
## Animation blend time in seconds.
@export var animation_blend_time: float = 0.25
## When moving, actual playback rate is base plus this times speed.
@export var animation_speedup_with_velocity: float = 0.0

@export_group("Audio")
## Audio stream to play when entering this state.
@export var audio: AudioStream = null
## Volume to use for the audio stream played when entering this state.
@export var audio_volume_db: float = 0.0

@export_group("Collision")
## Collider length in meters in this state.
@export var collider_length: float = 1.0
## Collider radius in meters in this state.
@export var collider_radius: float = 0.5
## Whether collider length axis should be local z rather than local y.
@export var collider_horizontal := false

@export_group("Orientation")
## Self-orientation strategy for deciding yaw.
@export var yaw_orientation := OrientationMode.MANUAL
## Self-orientation strategy for deciding pitch.
@export var pitch_orientation := OrientationMode.MANUAL
## Multiplier for calculated angular velocity required to self-orient.
@export var orientation_speed: float = 600.0

@export_group("Physics")
## Whether this state counts as being supported by solid ground.
## [br][br]
## The character node also separately tracks empirically
## whether it is currently supported by solid ground in actuality,
## but for some purposes, particularly self-righting,
## it's better to go with whether the current state thinks we are grounded
## than whether we actually are.
@export var counts_as_grounded := false
## How the character should move in this state.
@export var physics_mode := PhysicsMode.NORMAL

@export_group("Combat")
## Whether this state is an attack.
@export var is_attack := false
## Base damage dealt by this attack.
@export var attack_base_damage: float = 0.0
## Base impact for knockback dealt by this attack.
@export var attack_base_knockback: float = 0.0
## Whether the character ignores attacks received while in this state.
@export var invulnerable := false

@export_group("Etc")
## Properties to override while the character is in this state.
## [br][br]
## Each key should be a property path relative to the character node,
## and the corresponding value should be the desired value
## to be assigned to the named property.
## [br][br]
## The keys are typed as String instead of NodePath to avoid confusion,
## because, at the time of writing, Godot offers a streamlined way
## to point an exported NodePath to a Node, but no streamlined way
## to point it to a property. The API user would have to manually type in
## the property path anyway, and even then, only the node portion of the path
## would show in the inspector. Exporting as String instead,
## while less correct, eliminates potential confusion
## caused by NodePath's Node-oriented inspector UI.
@export var etc: Dictionary[String, Variant]
