extends Node2D

# HITSTOP VARIABLES
var hitstop_delta_multiplier = 0.05
var hitstop_time_left = 0.0

# BREATHING VARIABLES

# noise used to sway the camera when breathing
var breathing_simplex

# if true - decreases amlitude linearly & exponentially
# speed determined by decay_linear and decay_exponential
# if false - approaches amplitude_target 
# speed determined by amplitude_changespeed
var breathing_decay = false
var breathing_amplitude = Vector2.ONE

# how fast the motion happens, similar to decreasing the period of simplex noise
# except can be seamlessly done on the fly
var breathing_speed = 10.0

var breathing_amplitude_target = Vector2.ONE*10.0
var breathing_amplitude_changespeed = 0.5
var breathing_decay_linear = 0.5
var breathing_decay_exponential = 0.5

# SHIVERING VARIABLES

# current amplitude of shivers
var shivering_amplitude = 0.0
# determines if shivers are random, go back and forth, or are a mix of the two
var shivering_directionality = 0.5
var shivering_decay_linear = 10
var shivering_decay_exponential = 5
# used internally setting from outside produces no noticable results
var shivering_direction = Vector2.RIGHT


# SLAPPING VARIABLES

# the current slap offset of the camera, set this for immediate sharp motion
var slapping_position = Vector2.ZERO
# the current speed of the camera, set this for a sudden yet smooth followthrough motion
var slapping_speed = Vector2.ZERO
# how fast the camera returns to its resting position, overly enthusiastic cameras may have trouble sitting still
var slapping_enthusiasm = 20
# resting position of camera, keep at zero unless you are using this to look to the side(dont)
var slapping_target = Vector2.ZERO
# determines if the camera will slow down before approaching the resting postion or overshoot
# affects movement speed, compensate by changing enthusiasm in the opposite direction
var slapping_springiness = 20 

# if true - cracks in the screen strobe with value & saturation set below and a random hue
# if false - cracks in the screen are of stable_color
var background_strobe = true
var background_stable_color = Color.red
var background_saturation = 1.0
var background_value = 1.0

export (NodePath) var background_color_path
onready var background_color_node = get_node(background_color_path) 

# increases with time, used for breathing
# TODO possible overflow after a while, consider using a rotating 2d noise sampler that seamlessly loops after a while
var elapsed_time = 0.0

# must be set to a node that you want moved by screenshake
# untill it is set nothing visible will happen
var target_camera

# these are used in pass through functions
export (NodePath) var shatter_path
onready var shatter = get_node(shatter_path)


func _ready():
	randomize()
	# set up the breathing simplex noise
	# feel free to experiment with the values
	breathing_simplex = OpenSimplexNoise.new()
	breathing_simplex.seed = randi()
	breathing_simplex.octaves = 3
	breathing_simplex.period = 10
	breathing_simplex.persistence = 0.2
	pass


func _process(delta):
	# HANDLE HITSTOP
	if hitstop_time_left > 0.0:
		Engine.time_scale = hitstop_delta_multiplier
		hitstop_time_left -= delta/hitstop_delta_multiplier
	else:
		Engine.time_scale = 1.0
		hitstop_time_left = 0.0
	
	
	# STROBE IN THE CRACKS SECTION

	if background_strobe:
		background_color_node.color = Color.from_hsv(randf(), background_saturation, background_value, 1.0)
	else:
		background_color_node.color = background_stable_color
	
	
	var total_offset = Vector2.ZERO
	
	# BREATHING SECTION
	elapsed_time += delta
	# when not decaying approach target
	if (breathing_amplitude - breathing_amplitude_target).length() > 0.2 and not breathing_decay:
		breathing_amplitude = lerp(breathing_amplitude, breathing_amplitude_target, delta * breathing_amplitude_changespeed)
	else:
		breathing_amplitude = breathing_amplitude_target
	# when decaying decrease and approach target, do not surpass target
	if breathing_decay and (breathing_amplitude - breathing_amplitude_target).length() > 0.05:
		breathing_amplitude = breathing_amplitude.normalized() * max(breathing_amplitude.length() - delta * breathing_decay_linear, 0)
		breathing_amplitude = lerp(breathing_amplitude, breathing_amplitude_target, breathing_decay_exponential * delta)
		breathing_amplitude = breathing_amplitude.normalized() * max(breathing_amplitude.length(), breathing_amplitude_target.length())
	# derive offset from simplex noise generated above
	var breathing_offset = Vector2(breathing_simplex.get_noise_1d(elapsed_time * breathing_speed), 
			breathing_simplex.get_noise_1d(- elapsed_time * breathing_speed))
	
	# add breathing results to the cumulative offset
	total_offset += breathing_offset * breathing_amplitude

	# SHIVERING SECTION
	shivering_amplitude -= delta * shivering_decay_linear
	shivering_amplitude = lerp(shivering_amplitude, 0, shivering_decay_exponential * delta)
	shivering_amplitude = max(0, shivering_amplitude)
	# low directionality = random directions
	# high directionality = opposite direction from last frame
	shivering_direction = shivering_direction.rotated(TAU/2 + (rand_range(-1.0,1.0) * TAU/4 * shivering_directionality ))
	
	# also possible: golden ration screenshake, 3 directional screenshake
	# uncomment preferred one, remember to only use one version at a time

	# golden ratio - looks pleasant but weird
#	shivering_direction = shivering_direction.rotated(TAU * 0.6180339887)

	# triangle - surprisingly good, included bc a homie loves and uses it a lot
#	shivering_direction = shivering_direction.rotated(TAU/3)

	# add shivering to cumulative offset
	total_offset += shivering_amplitude * shivering_direction
	
	# SLAPPING SECTION
	slapping_speed = lerp(slapping_speed, (slapping_target-slapping_position) * slapping_springiness, delta * slapping_enthusiasm )
	slapping_position += slapping_speed * delta
	# add slapping offset to cumulative offset
	total_offset += slapping_position
	
	# apply offset to camera if there is one currently set
	if target_camera != null:
		target_camera.position = total_offset
	
	pass

# setter functions if you prefer using them
func shiver_at_amplitude(amplitude):
	shivering_amplitude = amplitude

func breath_at_amplitude(amplitude):
	breathing_amplitude = amplitude

func breath_target_amplitude(amplitude):
	breathing_amplitude_target = amplitude

func be_slapped_pos(offset):
	slapping_position = offset

func be_slapped_speed(speed):
	slapping_speed = speed

func be_slapped(offset, speed):
	slapping_position = offset
	slapping_speed = speed

# passthrough functions
func split_at_position(point, direction):
	shatter.split_at_position(point, direction)
	pass

func split_all(point, direction):
	shatter.split_all(point, direction)
	pass

func shatter_at_position(point, full_splits, shard_splits, shard_radius):
	shatter.shatter_at_position(point,full_splits,shard_splits,shard_radius)
	pass

func hitstop(how_long):
	hitstop_time_left = how_long
	pass
