{
id: "hittable",
prototype: ["standard_values"],

mass: 5,
properties: {
	flinch_threshold: 3,
	hurt_velocity_y: -400,
	hurt_velocity_x: -200,
	attack_knockback: 0,
	attack_damage: 0,
	damage_cooldown: 0,
	get_hit_by: "def(collide_with) execute(me, [
						handle_special_damage_response(collide_with),
	
						if((not is_invincible) and (collide_with.attack_damage > 0) and collide_with.hitpoints > 0 and (collide_with.attack_damage >= armor) and (collide_with.damage_cooldown < (cycle - vars.time_last_hit)),
								[display_hurt_visuals(),
								display_posthit_invincibility_flash_sequence(),
								handle_flinch(collide_with),
								handle_damage(collide_with),
								set(vars.time_last_hit, me.cycle)]),
						
						handle_damage_type(collide_with),
						handle_knockback(collide_with)])",

	#
	#
	# behavior handlers

	handle_special_damage_response: "def(collide_with) null #virtual#", //meant for unique actions after taking damage, like losing wings
	handle_flinch: "def(collide_with) 
			execute(me, if(collide_with.attack_damage >= flinch_threshold, cause_flinch(collide_with)))",
	cause_flinch: "def(collide_with) execute(me, [
			add(me.velocity_x,me.hurt_velocity_x * sign(me.midpoint_x - collide_with.midpoint_x)), 
			add(me.velocity_y,me.hurt_velocity_y),
			cause_hurt_anim(collide_with)
			])",
	cause_hurt_anim: "def(collide_with) execute(me, if('hurt' in available_animations,set(me.animation, 'hurt')))",
	
	handle_damage: "def(collide_with) execute(me,add(me.hitpoints, - collide_with.attack_damage))",
	handle_knockback: "def(collide_with) execute(me,add(velocity_x, collide_with.facing * collide_with.attack_knockback))",
	handle_damage_type: "def(collide_with) null #virtual#",

	# sole caveat is an inability to make monsters immune to a given damage type;  the most we can do is add-back the damage taken; they'll still flinch.  If we want that, we'll change the logic.
	is_invincible_posthit: "if(vars.time_last_hit and (abs(vars.time_last_hit - me.cycle) < consts.posthit_invicibility_period), 1, 0)",
	is_invincible: "if(invincible or level.in_dialog or is_invincible_posthit, 1, 0)",

	#
	#
	# cosmetic functions					  
	display_hurt_visuals: "def() execute(me, 
					[
					hurt_flash_sequence()
					])",
	hurt_flash_sequence: "def()	[	flash_bright(),
									schedule(3, flash_red()),
									schedule(6, flash_bright()),
									schedule(9, flash_red()),
									schedule(12, flash_bright()),
									schedule(15, flash_off())]",
	display_posthit_invincibility_flash_sequence: "def() if(consts.posthit_invicibility_period, 
			map(range(consts.posthit_invicibility_period/2), 'step' ,schedule(step*2, if(step%2=0,set(alpha,50),set(alpha,255))  ) ) )",
	flash_bright: "def() [set(me.brightness, 1023)]",
	flash_red: "def() [set(me.red, 255),set(me.green, 100), set(me.blue, 100)]",
	flash_off: "def() [set(me.brightness, 255),set(me.red, 255),set(me.green, 255), set(me.blue, 255)]",
},

	on_outside_level: "[if(y > level.dimensions[3], add(hitpoints,-1))]",


#two special exceptions here besides the 'no friendly-fire' rule;
# evil_harmless is a special team for thrown enemies wherein they can't hurt anyone, regardless of the target's team, but also - stuff from team 'evil' won't friendly-fire them.  They can and will be hurt by any player actions, though, and any traps/neutral damage sources.
on_collide_object_body: "if(collide_with.team != team and collide_with.team != 'evil_harmless' and (not (collide_with.team = 'evil' and team = 'evil_harmless')), if(collide_with_area in ['attack','thrown'], get_hit_by(collide_with)))",

#
#
# error condition handling:
on_change_solid_dimensions_fail: "fire_event('solidity_fail')",
on_change_animation_failure: "fire_event('solidity_fail')",

# if the level starts, and we're embedded in solid stuff, try moving upwards to get out of it.
# this should catch any errors introduced by changes to solid area or handling thereof
on_solidity_fail: "if(tmp.in_solidity_fail, die(),
	          [set(tmp.in_solidity_fail, 1),
			   resolve_solid(me),
			   set(tmp.in_solidity_fail, 0)
			  ])",
on_add_object_fail: "[if(collide_with.team != team and collide_with.get_hit_by, collide_with.get_hit_by(me)), die()]",
}
