diff --git a/client/levels/test/game.gd b/client/levels/test/game.gd
index 08680e37e70bd30e3b2c5bfc31a7243f63cb1e6a..22df655c47eeae36399f4b40f2ce9746fe38a280 100644
--- a/client/levels/test/game.gd
+++ b/client/levels/test/game.gd
@@ -44,7 +44,8 @@ func getPlayerInput():
 
 	# Sent without safety resend
 	rpc_unreliable_id(1, "sendPlayerInputs", movementInput, jumpInput, jumpId, sprintInput, attackStateInput)
-	
+
+
 puppet func backToLobby():
 	#get_node("/root/lobby").show()
 	get_tree().quit()
diff --git a/server/entities/characters/player.gd b/server/entities/characters/player.gd
index 93d5ddd6a3fae55f57f9bd5b2264b642a6f58805..39850324c7b105af1f7467bf467019c0177b48a3 100644
--- a/server/entities/characters/player.gd
+++ b/server/entities/characters/player.gd
@@ -5,6 +5,7 @@ onready var ownId:int = int(self.name)
 ######## MOVEMENT AND POSITION VARS ########
 
 onready var collisionShape:CollisionShape = $collisionShape
+var bodyRotation:int = 1
 
 # Speed values
 const MAX_SPEED:float = 8.0
@@ -15,7 +16,8 @@ var isSprinting:bool = false
 # Acceleration values
 const ACCEL:float = 8.5
 const SPRINT_ACCEL:float = 16.0
-const DEACCEL:float = 16.0
+const MVMNT_MOMENTUM:float = 10.0
+const THROW_MOMENTUM:float = 2.0
 
 # Jump and fall values
 const JUMP_SPEED:float = 16.0
@@ -48,39 +50,45 @@ var idleTime:float = 0      # Stun when hitted + prevent spam
 
 # Primary attack parameters
 onready var primaryHitArea:Area = $primaryHitArea
-var primaryAttackDmg:int = 30
+var primaryAttackDmg:float = 15.0
 var primaryAttackDist:float = 1.2
 var primaryAttackDuration:float = 0.4
+# General direction (normalized anyway)
+var primaryAttackDirection:Vector3 = Vector3(3,1,0)
+# Strength of the attack (multiply the normalized vector)
+var primaryAttackStrength:float = 1.5
 
 # Secondary attack parameters
 onready var secondaryHitArea:Area = $secondaryHitArea
-var secondaryAttackDmg:int = 15
+var secondaryAttackDmg:float = 5.0
 var secondaryAttackDist:float = 1.2
 var secondaryAttackDuration:float = 0.2
+var secondaryAttackDirection:Vector3 = Vector3(1,5,0)
+var secondaryAttackStrength:float = 0.8
 
 # Health points related values
-var hp:int = 0
+var hp:float = 0.0
 
 ######## FUNCTIONS ########
 
 # called by the engine
-func _physics_process(delta):
+func _physics_process(delta:float):
 	processMovement(delta)
 	broadcastMovement()
 
 
 # Called from the game script to update the vars
-func getPlayerInputs(movementInput, jumpInput, jumpId, sprintInput, attackTypeInput):
+func getPlayerInputs(movementInput:int, jumpInput:bool, jumpId:int, sprintInput:bool, attackTypeInput:int):
 	motion = 0
-
 	# Prevent the player from moving when attacking
 	if isAttacking:
 		return
-	
+
 	motion = movementInput
+
 	isSprinting = sprintInput
 	isJumping = false
-	
+
 	# Differentiate a new jump from a reemitted one
 	if lastJumpId != jumpId:
 		lastJumpId = jumpId
@@ -92,11 +100,13 @@ func getPlayerInputs(movementInput, jumpInput, jumpId, sprintInput, attackTypeIn
 		processAttack(attackTypeInput)
 
 
-func processMovement(delta):
+func processMovement(delta:float):
 	# Set the side faced by the character
 	if motion > 0:
+		bodyRotation = 1
 		set_rotation_degrees(Vector3(0, 0, 0))
 	elif motion < 0:
+		bodyRotation = -1
 		set_rotation_degrees(Vector3(0, 180, 0))
 
 	if self.is_on_floor():
@@ -104,6 +114,7 @@ func processMovement(delta):
 		currentJump = 0
 		# Reset the last striker
 		lastStrikerId = ownId
+
 	elif currentJump == 0 && !isJumping:
 		# Initial jump prevented
 		currentJump = 1
@@ -134,8 +145,10 @@ func processMovement(delta):
 			accel = SPRINT_ACCEL
 		else:
 			accel = ACCEL
+	elif !is_on_floor()&&!isJumping:
+		accel = THROW_MOMENTUM
 	else:
-		accel = DEACCEL
+		accel = MVMNT_MOMENTUM
 
 	# Interpolating speed and acceleration through time and getting it
 	vel.x = hvel.linear_interpolate(target, accel * delta).x
@@ -143,6 +156,11 @@ func processMovement(delta):
 	# Update the velocity after the collisions (physical engine ftw)
 	vel = self.move_and_slide(vel, FLOOR_NORMAL)
 
+#	if get_slide_count() > 0:
+#      var collision = get_slide_collision(0)
+#      if collision != null:
+#         vel = vel.bounce(collision.normal)
+
 
 # Send the position of the player
 func broadcastMovement():
@@ -150,7 +168,7 @@ func broadcastMovement():
 
 
 # Check and trigger the type of attack requested
-func processAttack(attackType):
+func processAttack(attackType:int):
 	# Turn off the other attacks input for the time being
 	isAttacking = true
 
@@ -195,10 +213,18 @@ func secondaryAttack():
 
 
 # Called when detected by an attack's hitbox
-func hurt(damages:int, sourceId:int):
+func hurt(damages:int, sourceId:int, direction:Vector3, strength:float):
+	# Add damages to your bar
 	hp += damages
+
+	# Projection: normalized vector * direction * strength added to the velocity of the player
+	vel += strength*hp*direction
+
+	# Update the last played who hit you
 	lastStrikerId = sourceId
-	rpc_unreliable("hurt", hp)
+
+	# Feedback on the player's client
+	rpc_unreliable_id(ownId, "hurt", hp)
 
 func die():
 	rpc("die", lastStrikerId)
@@ -207,19 +233,29 @@ func die():
 
 ######## SIGNALS ########
 
-# Primary hit has landed on something
-func _on_primaryHitArea_body_entered(body):
+# General function on attack's hitboxes
+func _on_generalHitArea_entered(damageVar:int, directionVar:Vector3, strengthVar:float, body:Node):
+	# Don't hurt yourself
 	if int(body.name)==ownId:
 		return
 
+	# Normalized projection vector
+	var direction:Vector3 = directionVar.normalized()
+
+	# Rotate the vector depending on the player orientation
+	direction.x*=bodyRotation
+
 	print("body named " + body.name + " hit: primary")
-	body.hurt(primaryAttackDmg, ownId)
 
+	# Call the function on the affected player
+	body.hurt(damageVar, ownId, direction, strengthVar)
 
-# Secondary hit has landed on something
-func _on_secondaryHitArea_body_entered(body):
-	if int(body.name)==ownId:
-		return
 
-	print("body named " + body.name + " hit: secondary")
-	body.hurt(secondaryAttackDmg, ownId)
+# Primary hit has landed on something
+func _on_primaryHitArea_body_entered(body:Node):
+	_on_generalHitArea_entered(primaryAttackDmg, primaryAttackDirection, primaryAttackStrength, body)
+
+
+# Secondary hit has landed on something
+func _on_secondaryHitArea_body_entered(body:Node):
+	_on_generalHitArea_entered(secondaryAttackDmg, secondaryAttackDirection, secondaryAttackStrength, body)