# HG changeset patch
# User Peewee
# Date 1286309131 14400
# Node ID e9fac2f07888cb5f0f2b250e7536eec8ef72245e
# Parent  8303fbe41d32d4c52a9db82688ad4ad234d15cd0
Tutorial 4: Toyed with aiming
(fixed wobbling all over the place while playing aim animation)

diff -r 8303fbe41d32 -r e9fac2f07888 planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIBowAttack.c
--- a/planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIBowAttack.c	Tue Oct 05 18:08:23 2010 +0200
+++ b/planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIBowAttack.c	Tue Oct 05 16:05:31 2010 -0400
@@ -2,16 +2,17 @@
 
 #appendto Bow
 
+public func AI_WeaponSpray() { return 5; }
 public func AI_IsRangedWeapon() { return true; }
 public func AI_IsLoaded() { return !!FindObject(Find_Container(this), Find_ID(Arrow)); }
 public func AI_CommandString() { return "AI_BowAttack"; }
-public func AI_TargetHittable(object target)
+public func AI_CanHitTarget(object target)
 {
-	var xDist = target->GetX() - Contained()->GetX();
-	var yDist = target->GetY() - Contained()->GetY();
-	// (vel*vel*vel*vel - g*(g*x*x + 2*y*vel*vel)) <see: AI_BowFirePos()>
-	// vel = 100, g = 20
-	return Max(1, 100000000 - (400*xDist*xDist + yDist*400000)); 
+	var x = target->GetX() - Contained()->GetX();
+	var y = target->GetY() - Contained()->GetY();
+	if (AI_AimPos(x, y, 100) == nil)
+		return false;
+	return true;
 }
 
 protected func AI_BowAttack(object clonk, int x, int y, object target)
@@ -39,15 +40,14 @@
 	EffectVar(0, clonk, num) = target;
 	var dx = target->GetX() - clonk->GetX();
 	var dy = target->GetY() - clonk->GetY();
-	//var dist = Distance(0, 0, dx, dy);
-	//dy -= dist / 10;
-	//ControlUseStart(clonk, dx, dy);
-	var aimVector = AI_AimPos(dx, dy, 100, 5);
-	if(aimVector == -1) {
-		ControlUseCancel(clonk,nil,nil);
-	}else{
-		ControlUseStart(clonk, aimVector[0], aimVector[1]);
+	var angle = AI_AimPos(dx, dy, 100, AI_WeaponSpray());
+	if (angle == nil)
+	{
+		ControlUseCancel(clonk);
+		return -1;
 	}
+	ControlUseStart(clonk, angle[0], angle[1]);
+	return 1;
 }
 
 protected func FxAI_BowAimTimer(object clonk, int num, int time)
@@ -57,16 +57,14 @@
 	var target = EffectVar(0, clonk, num);
 	var dx = target->GetX() - clonk->GetX();
 	var dy = target->GetY() - clonk->GetY();
-	//var dist = Distance(0, 0, dx, dy);
-	//dy -= dist / 10;
-	//ControlUseHolding(clonk, dx, dy);
-	var aimVector = AI_AimPos(dx, dy, 100, 5);
-	if(aimVector == -1) {
-		ControlUseCancel(clonk,nil,nil);
-	}else{
-		ControlUseHolding(clonk, aimVector[0], aimVector[1]);
-		return 1;
+	var angle = AI_AimPos(dx, dy, 100, AI_WeaponSpray());
+	if (angle == nil)
+	{
+		ControlUseCancel(clonk);
+		return -1;
 	}
+	ControlUseHolding(clonk, angle[0], angle[1]);
+	return 1;
 }
 
 protected func FxAI_BowAimStop(object clonk, int num, int reason, bool temporary)
@@ -74,27 +72,25 @@
 	var target = EffectVar(0, clonk, num);
 	var dx = target->GetX() - clonk->GetX();
 	var dy = target->GetY() - clonk->GetY();
-	//var dist = Distance(0, 0, dx, dy);
-	//dy -= dist / 10;
-	//ControlUseStop(clonk, dx, dy);
-	var aimVector = AI_AimPos(dx, dy, 100, 5);
-	if(aimVector == -1) {
-		ControlUseCancel(clonk,nil,nil);
-	}else{
-		ControlUseStop(clonk, aimVector[0], aimVector[1]);
-		return 1;
+	var angle = AI_AimPos(dx, dy, 100, AI_WeaponSpray());
+	if (angle == nil)
+	{
+		ControlUseCancel(clonk);
+		return -1;
 	}
+	ControlUseStop(clonk, angle[0], angle[1]);
+	return 1;
 }
 
-//vel = "muzzle velocity" (speed at which the projectile is launched)
+//v = "muzzle speed" (speed at which the projectile is launched)
 //spread = variation in aim
-private func AI_AimPos(int x, int y, int vel, int spread)
+private func AI_AimPos(int x, int y, int v, int spread)
 {
-	y = -y;
 	var g = GetGravity()/5; //FnGetGravity() multiplies actual gravity by 500
-	var root = (vel*vel*vel*vel - g*(g*x*x + 2*y*vel*vel));
+	var root = (v**4 - g*(g*x*x - 2*y*v*v));
 	if(root < 0)
 		return -1;
-	var angle = Angle(0,0,(g*x),vel*vel-Sqrt(root));
+	var angle = Angle(0,0,(g*x),v*v-Sqrt(root));
+	//allows for finer variation than adding Random(2*spread)-spread to the angle
     return [Sin(angle, 100)+Random(2*spread)-spread, Cos(angle, 100)+Random(2*spread)-spread];
 }
\ No newline at end of file
diff -r 8303fbe41d32 -r e9fac2f07888 planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIJavelinAttack.c
--- a/planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIJavelinAttack.c	Tue Oct 05 18:08:23 2010 +0200
+++ b/planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIJavelinAttack.c	Tue Oct 05 16:05:31 2010 -0400
@@ -2,13 +2,19 @@
 
 #appendto Javelin
 
+
+public func AI_WeaponSpray() { return 10; }
 public func AI_IsRangedWeapon() { return true; }
 public func AI_IsLoaded() { return true; }
 public func AI_CommandString() { return "AI_JavelinAttack"; }
-public func AI_TargetHittable(object target) 
+public func AI_CanHitTarget(object target) 
 {
-	var x = ObjectDistance(target, Contained());
-	return Max(0, - x * (x - 100) / 25);
+	var v = Contained()->GetPhysical("Throw") / 800;
+	var x = target->GetX() - Contained()->GetX();
+	var y = target->GetY() - Contained()->GetY() + 10;
+	if (AI_AimPos(x, y, v) == nil)
+		return false;
+	return true;
 }
 
 protected func AI_JavelinAttack(object clonk, int x, int y, object target)
@@ -28,16 +34,15 @@
 		return;
 	EffectVar(0, clonk, num) = target;
 	var dx = target->GetX() - clonk->GetX();
-	var dy = target->GetY() - (clonk->GetY()-5);
-	//var dist = Distance(0, 0, dx, dy);
-	//dy -= dist / 10;
-	//ControlUseStart(clonk, dx, dy);
-	var aimVector = AI_AimPos(dx, dy, clonk->GetPhysical("Throw") / 800, 0);
-	if(aimVector == -1) {
-		ControlUseCancel(clonk,nil,nil);
-	}else{
-		ControlUseStart(clonk, aimVector[0], aimVector[1]);
+	var dy = target->GetY() - clonk->GetY() + 10;
+	var angle = AI_AimPos(dx, dy, clonk->GetPhysical("Throw") / 800, AI_WeaponSpray());
+	if (angle == nil)
+	{
+		ControlUseCancel(clonk);
+		return -1;
 	}
+	ControlUseStart(clonk, angle[0], angle[1]);
+	return 1;
 }
 
 protected func FxAI_JavelinAimTimer(object clonk, int num, int time)
@@ -46,16 +51,14 @@
 		return -1;
 	var target = EffectVar(0, clonk, num);
 	var dx = target->GetX() - clonk->GetX();
-	var dy = target->GetY() - (clonk->GetY()-5);
-	//var dist = Distance(0, 0, dx, dy);
-	//dy -= dist / 10;
-	//ControlUseHolding(clonk, dx, dy);
-	var aimVector = AI_AimPos(dx, dy, clonk->GetPhysical("Throw") / 800, 0);
-	if(aimVector == -1) {
-		ControlUseCancel(clonk,nil,nil);
-	}else{
-		ControlUseHolding(clonk, aimVector[0], aimVector[1]);
+	var dy = target->GetY() - clonk->GetY() + 10;
+	var angle = AI_AimPos(dx, dy, clonk->GetPhysical("Throw") / 800, AI_WeaponSpray());
+	if (angle == nil)
+	{
+		ControlUseCancel(clonk);
+		return -1;
 	}
+	ControlUseHolding(clonk, angle[0], angle[1]);
 	return 1;
 }
 
@@ -63,28 +66,26 @@
 {
 	var target = EffectVar(0, clonk, num);
 	var dx = target->GetX() - clonk->GetX();
-	var dy = target->GetY() - (clonk->GetY()-5);
-	//var dist = Distance(0, 0, dx, dy);
-	//dy -= dist / 10;
-	//ControlUseStop(clonk, dx, dy);
-	var aimVector = AI_AimPos(dx, dy, clonk->GetPhysical("Throw") / 800, 0);
-	if(aimVector == -1) {
-		ControlUseCancel(clonk,nil,nil);
-	}else{
-		ControlUseStop(clonk, aimVector[0], aimVector[1]);
+	var dy = target->GetY() - clonk->GetY() + 10;
+	var angle = AI_AimPos(dx, dy, clonk->GetPhysical("Throw") / 800, AI_WeaponSpray());
+	if (angle == nil)
+	{
+		ControlUseCancel(clonk);
+		return -1;
 	}
+	ControlUseStop(clonk, angle[0], angle[1]);
 	return 1;
 }
 
-//vel = "muzzle velocity" (speed at which the projectile is launched)
+//v = "muzzle speed" (speed at which the projectile is launched)
 //spread = variation in aim
-private func AI_AimPos(int x, int y, int vel, int spread)
+private func AI_AimPos(int x, int y, int v, int spread)
 {
-	y = -y;
 	var g = GetGravity()/5; //FnGetGravity() multiplies actual gravity by 500
-	var root = (vel*vel*vel*vel - g*(g*x*x + 2*y*vel*vel));
-	if(root < 0)
-		return -1;
-	var angle = Angle(0,0,(g*x),vel*vel-Sqrt(root));
+	var root = (v**4 - g*(g*x*x - 2*y*v*v));
+	if (root < 0)
+		return nil;
+	var angle = Angle(0,0,(g*x),v*v-Sqrt(root));
+	//allows for finer variation than adding Random(2*spread)-spread to the angle
     return [Sin(angle, 100)+Random(2*spread)-spread, Cos(angle, 100)+Random(2*spread)-spread];
 }
\ No newline at end of file
diff -r 8303fbe41d32 -r e9fac2f07888 planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIMusketAttack.c
--- a/planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIMusketAttack.c	Tue Oct 05 18:08:23 2010 +0200
+++ b/planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIMusketAttack.c	Tue Oct 05 16:05:31 2010 -0400
@@ -5,10 +5,10 @@
 public func AI_IsRangedWeapon() { return true; }
 public func AI_IsLoaded() { return !!FindObject(Find_Container(this), Find_ID(LeadShot)); }
 public func AI_CommandString() { return "AI_MusketAttack"; }
-public func AI_TargetHittable(object target) 
+public func AI_CanHitTarget(object target) 
 {
-	var x = ObjectDistance(target, Contained());
-	return Max(0, - x * (x - 400) / 400);
+	var dist = ObjectDistance(target, Contained());
+	return dist < 400;
 }
 
 protected func AI_MusketAttack(object clonk, int x, int y, object target)
diff -r 8303fbe41d32 -r e9fac2f07888 planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIRangedAttack.c
--- a/planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIRangedAttack.c	Tue Oct 05 18:08:23 2010 +0200
+++ b/planet/Tutorial.c4f/Tutorial04.c4s/System.c4g/AIRangedAttack.c	Tue Oct 05 16:05:31 2010 -0400
@@ -7,7 +7,7 @@
 	clonk->AI_LogCommandStack();
 	clonk->AI_Log("Ranged attack on %v", target);
 	// target in range?
-	if (ObjectDistance(clonk, target) > 1000 || target->Contained())
+	if (ObjectDistance(clonk, target) > 600 || target->Contained())
 		return clonk->AI_Log("Target %v out of range", target);
 		
 	// target still alive?
@@ -15,23 +15,23 @@
 		return clonk->AI_Log("Target %v has died", target);
 		
 	// Look for ranged weapon in contents.
-	for (var weapon in FindObjects(Find_Container(clonk), Find_Func("AI_IsRangedWeapon"), Sort_Reverse(Sort_Func("AI_TargetHittable", target))))
+	for (var weapon in FindObjects(Find_Container(clonk), Find_Func("AI_IsRangedWeapon"), Find_Func("AI_CanHitTarget", target)))
 	{
-		// Check if weapon can hit the target.
+		// Check if weapon is loaded.
 		if (weapon->~AI_IsLoaded())
 		{
-			clonk->AI_Log("Use ranged weapon %v with %d hit", weapon, weapon->AI_TargetHittable(target));
+			clonk->AI_Log("Use ranged weapon %v", weapon);
 			clonk->AppendCommand("Call", weapon, nil, nil, target, nil, weapon->AI_CommandString()); //add+finish
 			return;
 		}		
 	}
 	// Maybe an ranged weapon can be acquired easily.
-	for (var weapon in FindObjects(Find_Distance(100), Find_Func("AI_IsRangedWeapon"), Find_Not(Find_Container(clonk))))
-	{
-		clonk->AppendCommand("Get", weapon);
-		clonk->AppendCommand("Call", clonk, nil, nil, target, nil, "AI_RangedAttack");
-		return;
-	}
+	//for (var weapon in FindObjects(Find_Distance(100), Find_Func("AI_IsRangedWeapon"), Find_Not(Find_Container(clonk))))
+	//{
+	//	clonk->AppendCommand("Get", weapon);
+	//	clonk->AppendCommand("Call", clonk, nil, nil, target, nil, "AI_RangedAttack");
+	//	return;
+	//}
 	
 	// Return to basic attacks.
 
