[nexuiz-commits] r7384 - in trunk/data: . qcsrc/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Fri Aug 7 12:51:39 EDT 2009


Author: mand1nga
Date: 2009-08-07 12:51:39 -0400 (Fri, 07 Aug 2009)
New Revision: 7384

Modified:
   trunk/data/defaultNexuiz.cfg
   trunk/data/qcsrc/server/bots.qc
   trunk/data/qcsrc/server/havocbot.qc
Log:
Added jetpack support for bots
To use it add -DBOT_JETPACK_NAVIGATION to FTQECCFLAGS in data/Makefile (will be enabled by default after the next release)


Modified: trunk/data/defaultNexuiz.cfg
===================================================================
--- trunk/data/defaultNexuiz.cfg	2009-08-07 14:28:48 UTC (rev 7383)
+++ trunk/data/defaultNexuiz.cfg	2009-08-07 16:51:39 UTC (rev 7384)
@@ -396,6 +396,9 @@
 set bot_ai_bunnyhop_startdistance 250 "Run to goals located further than this distance"
 set bot_ai_bunnyhop_stopdistance 220 "Stop jumping after reaching this distance to the goal"
 set bot_ai_bunnyhop_firstjumpdelay 0.5 "Start running to the goal only if it was seen for more than N seconds"
+set bot_god 0 "god mode for bots"
+set bot_ai_navigation_jetpack 1 "Enable bots to navigat maps using the jetpack"
+set bot_ai_navigation_jetpack_mindistance 2500 "Bots will try fly to objects located farther than this distance"
 // Better don't touch these, there are hard to tweak!
 set bot_ai_aimskill_order_mix_1st 0.01 "Amount of the 1st filter output to apply to the aiming angle"
 set bot_ai_aimskill_order_mix_2nd 0.1 "Amount of the 1st filter output to apply to the aiming angle"
@@ -407,7 +410,6 @@
 set bot_ai_aimskill_order_filter_3th 0.2 "Acceleration filter"
 set bot_ai_aimskill_order_filter_4th 0.4 "Position prediction filter. Used rarely"
 set bot_ai_aimskill_order_filter_5th 0.5 "Movement prediction filter. Used rarely"
-set bot_god 0 "god mode for bots"
 
 // waypoint editor enable
 set g_waypointeditor 0

Modified: trunk/data/qcsrc/server/bots.qc
===================================================================
--- trunk/data/qcsrc/server/bots.qc	2009-08-07 14:28:48 UTC (rev 7383)
+++ trunk/data/qcsrc/server/bots.qc	2009-08-07 16:51:39 UTC (rev 7384)
@@ -8,6 +8,10 @@
 float AI_STATUS_WAYPOINT_PERSONAL_LINKING	= 64;	// Waiting for the personal waypoint to be linked
 float AI_STATUS_WAYPOINT_PERSONAL_GOING		= 128;	// Going to a personal waypoint
 float AI_STATUS_WAYPOINT_PERSONAL_REACHED	= 256;	// Personal waypoint reached
+#ifdef BOT_JETPACK_NAVIGATION
+float AI_STATUS_JETPACK_FLYING			= 512;
+float AI_STATUS_JETPACK_LANDING			= 1024;
+#endif
 
 // utilities for path debugging
 #ifdef DEBUG_TRACEWALK
@@ -1745,6 +1749,12 @@
 	return ent;
 }
 
+#ifdef BOT_JETPACK_NAVIGATION
+// fields required for jetpack navigation
+.entity navigation_jetpack_goal;
+.vector navigation_jetpack_point;
+#endif
+
 // updates the best goal according to a weighted calculation of travel cost and item value of a new proposed item
 .void() havocbot_role;
 void() havocbot_role_ctf_offense;
@@ -1752,6 +1762,98 @@
 {
 	if (!e)
 		return;
+
+#ifdef BOT_JETPACK_NAVIGATION
+	// Evaluate path using jetpack
+	if(g_jetpack)
+	if(self.items & IT_JETPACK)
+	if(cvar("bot_ai_navigation_jetpack"))
+	if(vlen(self.origin - e.origin) > cvar("bot_ai_navigation_jetpack_mindistance"))
+	{
+		vector pointa, pointb;
+
+	//	dprint("jetpack ai: evaluating path for ", e.classname,"\n");
+
+		// Point A
+		traceline(self.origin, self.origin + '0 0 65535', MOVE_NORMAL, self);
+		pointa = trace_endpos - '0 0 1';
+
+		// Point B
+		traceline(e.origin, e.origin + '0 0 65535', MOVE_NORMAL, e);
+		pointb = trace_endpos - '0 0 1';
+
+		// Can I see these two points from the sky?
+		traceline(pointa, pointb, MOVE_NORMAL, self);
+
+		if(trace_fraction==1)
+		{
+		//	dprint("jetpack ai: can bridge these two points\n");
+
+			// Lower the altitude of these points as much as possible
+			local float zdistance, xydistance, cost, t, fuel;
+			local vector down, npa, npb;
+
+			down = '0 0 -1' * (PL_MAX_z - PL_MIN_z) * 10;
+
+			do{
+				npa = pointa + down;
+				npb = pointb + down;
+
+				if(npa_z<=self.absmax_z)
+					break;
+
+				if(npb_z<=e.absmax_z)
+					break;
+
+				traceline(npa, npb, MOVE_NORMAL, self);
+				if(trace_fraction==1)
+				{
+					pointa = npa;
+					pointb = npb;
+				}
+			}
+			while(trace_fraction == 1);
+
+
+			// Rough estimation of fuel consumption
+			// (ignores acceleration and current xyz velocity)
+			xydistance = vlen(pointa - pointb);
+			zdistance = fabs(pointa_z - self.origin_z);
+
+			t = zdistance / cvar("g_jetpack_maxspeed_up");
+			t += xydistance / cvar("g_jetpack_maxspeed_side");
+			fuel = t * cvar("g_jetpack_fuel") * 0.8;
+
+		//	dprint("jetpack ai: required fuel ", ftos(fuel), " self.ammo_fuel ", ftos(self.ammo_fuel),"\n");
+
+			// enough fuel ?
+			if(self.ammo_fuel>fuel)
+			{
+				// Estimate cost
+				// (as onground costs calculation is mostly based on distances, here we do the same establishing some relationship
+				//  - between air and ground speeds)
+
+				cost = xydistance / (cvar("g_jetpack_maxspeed_side")/cvar("sv_maxspeed"));
+				cost += zdistance / (cvar("g_jetpack_maxspeed_up")/cvar("sv_maxspeed"));
+				cost *= 1.5;
+
+				// Compare against other goals
+				f = f * rangebias / (rangebias + cost);
+
+				if (navigation_bestrating < f)
+				{
+			//		dprint("jetpack path: added goal", e.classname, " (with rating ", ftos(f), ")\n");
+					navigation_bestrating = f;
+					navigation_add_bestgoal(e);
+					self.navigation_jetpack_goal = e;
+					self.navigation_jetpack_point = pointb;
+				}
+				return;
+			}
+		}
+	}
+	#endif
+
 	//te_wizspike(e.origin);
 	//bprint(etos(e));
 	//bprint("\n");
@@ -1772,13 +1874,14 @@
 	if (e.nearestwaypoint.wpcost < 10000000)
 	{
 		//te_wizspike(e.nearestwaypoint.wpnearestpoint);
-		//dprint(e.classname, " ", ftos(f), "/(1+", ftos((e.nearestwaypoint.wpcost + vlen(e.origin - e.nearestwaypoint.wpnearestpoint))), "/", ftos(rangebias), ") = ");
+	//	dprint(e.classname, " ", ftos(f), "/(1+", ftos((e.nearestwaypoint.wpcost + vlen(e.origin - e.nearestwaypoint.wpnearestpoint))), "/", ftos(rangebias), ") = ");
 		f = f * rangebias / (rangebias + (e.nearestwaypoint.wpcost + vlen(e.origin - e.nearestwaypoint.wpnearestpoint)));
 		//if (self.havocbot_role == havocbot_role_ctf_offense)
 		//dprint("considering ", e.classname, " (with rating ", ftos(f), ")\n");
 		//dprint(ftos(f));
 		if (navigation_bestrating < f)
 		{
+		//	dprint("ground path: added goal ", e.classname, " (with rating ", ftos(f), ")\n");
 			navigation_bestrating = f;
 			navigation_add_bestgoal(e);
 		}
@@ -1800,6 +1903,12 @@
 	// put the entity on the goal stack
 	navigation_pushroute(e);
 
+#ifdef BOT_JETPACK_NAVIGATION
+	if(g_jetpack)
+	if(e==self.navigation_jetpack_goal)
+		return TRUE;
+#endif
+
 	// if it can reach the goal there is nothing more to do
 	if (tracewalk(self, startposition, PL_MIN, PL_MAX, e.origin, bot_navigation_movemode))
 		return TRUE;
@@ -1913,6 +2022,9 @@
 // begin a goal selection session (queries spawnfunc_waypoint network)
 void navigation_goalrating_start()
 {
+#ifdef BOT_JETPACK_NAVIGATION
+	self.navigation_jetpack_goal = world;
+#endif
 	navigation_bestrating = -1;
 	self.navigation_hasgoals = FALSE;
 	navigation_bestgoals_reset();
@@ -1923,6 +2035,7 @@
 void navigation_goalrating_end()
 {
 	navigation_routetogoals();
+//	dprint("best goal ", self.goalcurrent.classname , "\n");
 
 	// Hack: if it can't walk to any goal just move blindly to the first visible waypoint
 	if not (self.navigation_hasgoals)

Modified: trunk/data/qcsrc/server/havocbot.qc
===================================================================
--- trunk/data/qcsrc/server/havocbot.qc	2009-08-07 14:28:48 UTC (rev 7383)
+++ trunk/data/qcsrc/server/havocbot.qc	2009-08-07 16:51:39 UTC (rev 7384)
@@ -308,6 +308,70 @@
 	self.movement = '0 0 0';
 	maxspeed = cvar("sv_maxspeed");
 
+#ifdef BOT_JETPACK_NAVIGATION
+	// Jetpack navigation
+	if(self.navigation_jetpack_goal)
+	if(self.goalcurrent==self.navigation_jetpack_goal)
+	if(self.ammo_fuel)
+	{
+		#ifdef DEBUG_BOT_GOALSTACK
+			debuggoalstack();
+			te_wizspike(self.navigation_jetpack_point);
+		#endif
+
+		// Take off
+		if not(self.aistatus & AI_STATUS_JETPACK_FLYING)
+		{
+			// Brake almost completely so it can get a good direction
+			if(vlen(self.velocity)>10)
+				return;
+			self.aistatus |= AI_STATUS_JETPACK_FLYING;
+		}
+
+		makevectors(self.v_angle_y * '0 1 0');
+		dir = normalize(self.navigation_jetpack_point - self.origin);
+
+		// Landing
+		if(self.aistatus & AI_STATUS_JETPACK_LANDING)
+		{
+			// TODO: more accurate landing (with optimum fuel usage)
+			vector p = self.origin - self.goalcurrent.origin; p_z = 0;
+			if( vlen(p) < max(cvar("g_jetpack_maxspeed_side"), vlen(self.velocity)))
+			{
+				// Brake
+				if(fabs(self.velocity_x)>maxspeed)
+				{
+					self.BUTTON_HOOK = TRUE;
+					self.movement_x = dir * v_forward * -maxspeed;
+					return;
+				}
+				// Switch to normal mode
+				self.navigation_jetpack_goal = world;
+				self.aistatus &~= AI_STATUS_JETPACK_LANDING;
+				self.aistatus &~= AI_STATUS_JETPACK_FLYING;
+				return;
+			}
+		}
+		else if(checkpvs(self.origin,self.goalcurrent))
+		{
+			// If I can see the goal switch to landing code
+			self.aistatus &~= AI_STATUS_JETPACK_FLYING;
+			self.aistatus |= AI_STATUS_JETPACK_LANDING;
+			return;
+		}
+
+		// Flying
+		self.BUTTON_HOOK = TRUE;
+		if(self.navigation_jetpack_point_z - PL_MAX_z + PL_MIN_z < self.origin_z)
+		{
+			self.movement_x = dir * v_forward * maxspeed;
+			self.movement_y = dir * v_right * maxspeed;
+		}
+		return;
+	}
+#endif
+
+	// Handling of jump pads
 	if(self.jumppadcount)
 	{
 		if(self.flags & FL_ONGROUND)



More information about the nexuiz-commits mailing list