[nexuiz-commits] r6221 - in branches/nexuiz-2.0: . data data/qcsrc/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Thu Mar 19 08:23:00 EDT 2009


Author: div0
Date: 2009-03-19 08:23:00 -0400 (Thu, 19 Mar 2009)
New Revision: 6221

Modified:
   branches/nexuiz-2.0/.patchsets
   branches/nexuiz-2.0/data/defaultNexuiz.cfg
   branches/nexuiz-2.0/data/qcsrc/server/bots.qc
   branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc
   branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc
Log:
r6107 | mand1nga | 2009-03-12 04:56:37 +0100 (Thu, 12 Mar 2009) | 9 lines
Bots: Swimming support (only to get out of water)
Avoid evaluation of pick-ups under water
Adjusted detection of vertical jumpads
If there is no enemy at sight wear the laser instead of no weapon
Doors recognition (tested only with accident_v3)
Avoid another strategy think if an alternative goal was chosen on the same frame
Fixed some indents and trailing whitespaces (done automatically by codeblocks, sorry)
Other minor fixes/changes
r6126 | mand1nga | 2009-03-12 15:02:10 +0100 (Thu, 12 Mar 2009) | 2 lines
More bots related cvars descriptions
r6127 | mand1nga | 2009-03-12 16:42:05 +0100 (Thu, 12 Mar 2009) | 2 lines
Basic ladder handling for bots
r6128 | mand1nga | 2009-03-13 01:32:14 +0100 (Fri, 13 Mar 2009) | 1 line
Fixed addvote alias
r6159 | mand1nga | 2009-03-14 22:53:42 +0100 (Sat, 14 Mar 2009) | 1 line
Search for nearest waypoints more progressively. This reduces greatly the server load on some maps (mentalspace, reservoir)
r6161 | mand1nga | 2009-03-14 23:09:56 +0100 (Sat, 14 Mar 2009) | 1 line
Fixed typo in last commit
r6170 | mand1nga | 2009-03-15 02:01:55 +0100 (Sun, 15 Mar 2009) | 2 lines
Fixed bug in the routing to alternative goals. Don't rate enemies as goals when they're too close.
r6182 | mand1nga | 2009-03-15 21:41:24 +0100 (Sun, 15 Mar 2009) | 1 line
Narrow the search for nearest waypoints to no more than 1500 qu when the bot is not on the ground


Modified: branches/nexuiz-2.0/.patchsets
===================================================================
--- branches/nexuiz-2.0/.patchsets	2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/.patchsets	2009-03-19 12:23:00 UTC (rev 6221)
@@ -1,2 +1,2 @@
 master = svn://svn.icculus.org/nexuiz/trunk
-revisions_applied = 1-6039,6044-6106,6108-6125,6129-6158,6160-6160,6162-6169,6171-6181,6183-6208
+revisions_applied = 1-6039,6044-6208

Modified: branches/nexuiz-2.0/data/defaultNexuiz.cfg
===================================================================
--- branches/nexuiz-2.0/data/defaultNexuiz.cfg	2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/data/defaultNexuiz.cfg	2009-03-19 12:23:00 UTC (rev 6221)
@@ -340,11 +340,11 @@
 set bot_ai_thinkinterval 0.05
 set bot_ai_strategyinterval 2 "How often a new objective is chosen"
 set bot_ai_enemydetectioninterval 0.5 "How often bots pick a new target"
-set bot_ai_dodgeupdateinterval 0.1
-set bot_ai_chooseweaponinterval 0.3 "How often the weapon selection will be evaluated"
-set bot_ai_dangerdetectioninterval 0.1
-set bot_ai_dangerdetectionupdates 64
-set bot_ai_aimskill_blendrate 2	"How much correction is made to aim at the target"
+set bot_ai_dodgeupdateinterval 0.1 "How often scan for items to dodge. Currently not in use."
+set bot_ai_chooseweaponinterval 0.3 "How often the best weapon according to the situation will be chosen"
+set bot_ai_dangerdetectioninterval 0.1 "How often scan for waypoints with dangers near"
+set bot_ai_dangerdetectionupdates 64 "How many waypoints will be considered for danger detection"
+set bot_ai_aimskill_blendrate 2	"How much correction will be applied to the aiming angle"
 set bot_ai_aimskill_fixedrate 15
 set bot_ai_aimskill_firetolerance_distdegrees 180
 set bot_ai_aimskill_firetolerance_mindegrees 2 "Minimum angle tolerance. Used on large distances"
@@ -1054,7 +1054,7 @@
 alias gametype	"sv_cmd gametype $*"
 
 alias addfav "qc_cmd addtolist net_slist_favorites $*"
-alias addvote "qc_cmd addvote sv_vote_commands $*"
+alias addvote "qc_cmd addtolist sv_vote_commands $*"
 
 // key hunt
 set g_keyhunt 0

Modified: branches/nexuiz-2.0/data/qcsrc/server/bots.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/bots.qc	2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/data/qcsrc/server/bots.qc	2009-03-19 12:23:00 UTC (rev 6221)
@@ -3,7 +3,8 @@
 float AI_STATUS_ATTACKING		= 2;	// There are enemies at sight
 float AI_STATUS_RUNNING			= 4;	// Bot is bunny hopping
 float AI_STATUS_DANGER_AHEAD	= 8;	// There is lava/slime/abism ahead
-float AI_STATUS_BAD_JUMPPAD		= 16;	// Trying to get out of a "vertical" jump pad
+float AI_STATUS_OUT_JUMPPAD		= 16;	// Trying to get out of a "vertical" jump pad
+float AI_STATUS_OUT_WATER		= 32;	// Trying to get out of water
 
 .string netname_freeme;
 // rough simulation of walking from one point to another to test if a path
@@ -106,7 +107,6 @@
 					//particle(org, move * 64, 104, 4);
 					te_gunshot(org);
 				}
-				// failed
 				return 0;
 			}
 			org = trace_endpos;
@@ -115,8 +115,10 @@
 		{
 			move = dir * stepdist + org;
 			tracebox(org, m1, m2, move, movemode, e);
+			// hit something
 			if (trace_fraction < 1)
 			{
+				// check if we can walk over this obstacle
 				tracebox(org + stepheightvec, m1, m2, move + stepheightvec, movemode, e);
 				if (trace_fraction < 1 || trace_startsolid)
 				{
@@ -124,15 +126,33 @@
 					{
 						if (navigation_testtracewalk > 1)
 							dprint("hit-something\n");
-						//move = normalize(end - org);
-						//particle(org, move * 64, 104, 4);
-						te_gunshot(org);
+					//	move = normalize(end - org);
+					//	particle(org, move * 64, 104, 4);
+					//	te_gunshot(org);
 					}
-					// failed
-					return 0;
+
+					// check for doors
+					traceline( org, move, movemode, e);
+					if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
+					{
+						local vector nextmove;
+						move = trace_endpos;
+						while(trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
+						{
+							nextmove = move + (dir * stepdist);
+							traceline( move, nextmove, movemode, e);
+							move = nextmove;
+						}
+					}
+					else
+						return 0; // failed
 				}
+				else
+					move = trace_endpos;
 			}
-			move = trace_endpos;
+			else
+				move = trace_endpos;
+
 			// trace down from stepheight as far as possible and move there,
 			// if this starts in solid we try again without the stepup, and
 			// if that also fails we assume it is a wall
@@ -1092,7 +1112,7 @@
 	local entity head;
 	local vector v, m1, m2, diff;
 	local float c;
-	//navigation_testtracewalk = TRUE;
+//	navigation_testtracewalk = TRUE;
 	c = 0;
 	head = waylist;
 	while (head)
@@ -1173,11 +1193,17 @@
 		w.enemy = world;
 		w = w.chain;
 	}
-	// try a short range search for the nearest waypoints, and expand the
-	// search repeatedly if none are found
-	if (!navigation_markroutes_nearestwaypoints(waylist, 250))
-		if (!navigation_markroutes_nearestwaypoints(waylist, 1000))
-			navigation_markroutes_nearestwaypoints(waylist, 1000000);
+
+	// try a short range search for the nearest waypoints, and expand thesearch repeatedly if none are found
+	local float i, increment, maxdistance;
+	increment = 500;
+	if(self.flags & FL_ONGROUND)
+		maxdistance = 50000;
+	else
+		maxdistance = 1500;
+	
+	for(i=increment;!navigation_markroutes_nearestwaypoints(waylist, i)&&i<maxdistance;i+=increment);
+
 	searching = TRUE;
 	while (searching)
 	{
@@ -1553,10 +1579,10 @@
 
 	bot_distance_far = stof(argv(0));
 	bot_distance_close = stof(argv(1));
-	
+
 	if(bot_distance_far < bot_distance_close){
 		bot_distance_far = stof(argv(1));
-		bot_distance_close = stof(argv(0));	
+		bot_distance_close = stof(argv(0));
 	}
 
 	// Initialize list of weapons
@@ -1979,10 +2005,10 @@
 		{
 			self.BUTTON_JUMP = 1; // press jump to respawn
 			self.bot_strategytime = 0;
-			return;
 		}
+		return;
 	}
-	
+
 	// now call the current bot AI (havocbot for example)
 	self.bot_ai();
 };

Modified: branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc	2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc	2009-03-19 12:23:00 UTC (rev 6221)
@@ -68,7 +68,7 @@
 	local vector keyboard;
 	local float blend, maxspeed;
 
-	maxspeed = cvar("sv_maxspeed");	
+	maxspeed = cvar("sv_maxspeed");
 
 	if (time < self.havocbot_keyboardtime)
 		return;
@@ -153,6 +153,12 @@
 		return;
 	}
 
+	if(self.waterlevel > 1)
+	{
+		self.aistatus &~= AI_STATUS_RUNNING;
+		return;
+	}
+
 	if(self.bot_lastseengoal != self.goalcurrent && !(self.aistatus & AI_STATUS_RUNNING))
 	{
 		self.bot_canruntogoal = 0;
@@ -182,7 +188,7 @@
 					{
 						if(bunnyhopdistance > cvar("bot_ai_bunnyhop_startdistance"))
 							self.bot_canruntogoal = 1;
-						else	
+						else
 							self.bot_canruntogoal = -1;
 					}
 
@@ -240,7 +246,7 @@
 		if(self.velocity_z < 0)
 			self.BUTTON_JUMP = FALSE;
 
-		// Strafe 
+		// Strafe
 		local float maxspeed;
 		maxspeed = cvar("sv_maxspeed");
 
@@ -263,6 +269,8 @@
 //.vector bot_dodgevector;
 //.float bot_dodgevector_time;
 //.float bot_dodgevector_jumpbutton;
+.float ladder_time;
+.entity ladder_entity;
 void havocbot_movetogoal()
 {
 	local vector destorg;
@@ -287,12 +295,12 @@
 		if(self.flags & FL_ONGROUND)
 		{
 			self.jumppadcount = FALSE;
-			if(self.aistatus & AI_STATUS_BAD_JUMPPAD)
-				self.aistatus &~= AI_STATUS_BAD_JUMPPAD;
+			if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
+				self.aistatus &~= AI_STATUS_OUT_JUMPPAD;
 		}
 
 		// If got stuck on the jump pad try to reach the farther visible item
-		if(self.aistatus & AI_STATUS_BAD_JUMPPAD)
+		if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
 		{
 			if(fabs(self.velocity_z)<50)
 			{
@@ -325,7 +333,7 @@
 					self.ignoregoal = self.goalcurrent;
 					self.ignoregoaltime = time + cvar("bot_ai_ignoregoal_timeout");
 					navigation_routetogoal(newgoal);
-					self.aistatus &~= AI_STATUS_BAD_JUMPPAD;
+					self.aistatus &~= AI_STATUS_OUT_JUMPPAD;
 				}
 			}
 			else
@@ -336,32 +344,55 @@
 			if(self.velocity_z>0)
 			{
 				local float threshold;
-				threshold = maxspeed * 0.3;
+				threshold = maxspeed * 0.2;
 				if(fabs(self.velocity_x) < threshold  &&  fabs(self.velocity_y) < threshold)
-					self.aistatus |= AI_STATUS_BAD_JUMPPAD;
+					self.aistatus |= AI_STATUS_OUT_JUMPPAD;
 				return;
 			}
 		}
 	}
 
+	// If we are under water with no goals, swim up
+	if(self.waterlevel)
+	if(self.goalcurrent==world)
+	{
+		dir = '0 0 0';
+		if(self.waterlevel>2)
+			dir_z = 1;
+		else if(self.velocity_z >= 0 && !(self.waterlevel == 1 && self.watertype == CONTENT_WATER))
+			self.BUTTON_JUMP = TRUE;
+		else
+			self.BUTTON_JUMP = FALSE;
+		makevectors(self.v_angle_y * '0 1 0');
+		self.movement_x = dir * v_forward * maxspeed;
+		self.movement_y = dir * v_right * maxspeed;
+		self.movement_z = dir * v_up * maxspeed;
+	}
+
+	// if there is nowhere to go, exit
 	if (self.goalcurrent == world)
 		return;
 
-	navigation_poptouchedgoals();
+	if (self.goalcurrent)
+		navigation_poptouchedgoals();
 
+	// if ran out of goals try to use an alternative goal or get a new strategy asap
 	if(self.goalcurrent == world)
 	if(self.flags & FL_ONGROUND || self.aistatus & AI_STATUS_RUNNING || self.BUTTON_JUMP == TRUE)
 	{
 		if(self.alternativegoal==world)
 		{
-			// ran out of goals, rethink strategy as soon as possible
+			// ran out of goals
 			self.bot_strategytime = 0;
 			return;
 		}
-		// try to use the alternative goal
+
+		// use the alternative goal
 		navigation_findnearestwaypoint(self.alternativegoal, TRUE);
 		navigation_routetogoal(self.alternativegoal);
 		self.alternativegoal = world;
+		bot_strategytoken_taken = TRUE;
+
 		return;
 	}
 
@@ -387,14 +418,30 @@
 	//	self.bot_dodgevector_jumpbutton = 1;
 		evadeobstacle = '0 0 0';
 		evadelava = '0 0 0';
+
 		if (self.waterlevel)
 		{
-			makevectors(self.v_angle);
-			self.BUTTON_JUMP = TRUE;
-			evadelava_z = 1;
+			if(self.waterlevel>2)
+			{
+			//	flatdir_z = 1;
+				self.aistatus |= AI_STATUS_OUT_WATER;
+			}
+			else
+			{
+				if(self.velocity_z >= 0 && !(self.watertype == CONTENT_WATER && self.goalcurrent.origin_z < self.origin_z) &&
+					( !(self.waterlevel == 1 && self.watertype == CONTENT_WATER) || self.aistatus & AI_STATUS_OUT_WATER))
+					self.BUTTON_JUMP = TRUE;
+				else
+					self.BUTTON_JUMP = FALSE;
+			}
+			dir = normalize(flatdir);
+			makevectors(self.v_angle_y * '0 1 0');
 		}
 		else
 		{
+			if(self.aistatus & AI_STATUS_OUT_WATER)
+				self.aistatus &~= AI_STATUS_OUT_WATER;
+
 			// jump if going toward an obstacle that doesn't look like stairs we
 			// can walk up directly
 			tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 0.2, FALSE, self);
@@ -416,13 +463,13 @@
 			// avoiding dangers and obstacles
 			local vector dst_ahead, dst_down;
 			dst_ahead = self.origin + self.view_ofs + (self.velocity * 0.32);
-			dst_down = dst_ahead + '0 0 -1500';				
-			
+			dst_down = dst_ahead + '0 0 -1500';
+
 			// Look ahead
 			traceline(self.origin + self.view_ofs , dst_ahead, TRUE, world);
 
 			// Check head-banging against walls
-			if(vlen(self.origin + self.view_ofs - trace_endpos) < 2)
+			if(vlen(self.origin + self.view_ofs - trace_endpos) < 2 && !(self.aistatus & AI_STATUS_OUT_WATER))
 			{
 				if(self.facingwalltime && time > self.facingwalltime)
 				{
@@ -445,7 +492,7 @@
 					self.ignoregoaltime = 0;
 				}
 			}
-		
+
 			// Check for water/slime/lava and dangerous edges
 			// (only when the bot is on the ground or jumping intentionally)
 			self.aistatus &~= AI_STATUS_DANGER_AHEAD;
@@ -455,7 +502,7 @@
 			{
 				// Look downwards
 				traceline(dst_ahead , dst_down, TRUE, world);
-				//	te_lightning2(world, self.origin, dst_ahead);	// Draw "ahead" look 
+				//	te_lightning2(world, self.origin, dst_ahead);	// Draw "ahead" look
 				//	te_lightning2(world, dst_ahead, dst_down);		// Draw "downwards" look
 				if(trace_endpos_z < self.origin_z + self.mins_z)
 				{
@@ -465,7 +512,7 @@
 						evadelava = normalize(self.velocity) * -1;
 					else if (s == CONTENT_SKY)
 						evadeobstacle = normalize(self.velocity) * -1;
-					else if (!boxesoverlap(dst_ahead - self.view_ofs + self.mins, dst_ahead - self.view_ofs + self.maxs, 
+					else if (!boxesoverlap(dst_ahead - self.view_ofs + self.mins, dst_ahead - self.view_ofs + self.maxs,
 								self.goalcurrent.absmin, self.goalcurrent.absmax))
 					{
 						// if ain't a safe goal with "holes" (like the jumpad on soylent)
@@ -504,6 +551,20 @@
 	//	self.bot_dodgevector_jumpbutton = self.BUTTON_JUMP;
 	}
 
+	if(time < self.ladder_time)
+	{
+		if(self.goalcurrent.origin_z + self.goalcurrent.mins_z > self.origin_z + self.mins_z)
+		{
+			if(self.origin_z + self.mins_z  < self.ladder_entity.origin_z + self.ladder_entity.maxs_z)
+				dir = '0 0 1';
+		}
+		else
+		{
+			if(self.origin_z + self.mins_z  > self.ladder_entity.origin_z + self.ladder_entity.mins_z)
+				dir = '0 0 -1';
+		}
+	}
+
 	//dir = self.bot_dodgevector;
 	//if (self.bot_dodgevector_jumpbutton)
 	//	self.BUTTON_JUMP = 1;
@@ -601,7 +662,9 @@
 	// TODO: clean this up by moving it to weapon code
 	if(self.enemy.classname!="player")
 	{
-		self.switchweapon = w_getbestweapon(self);
+	//	self.switchweapon = w_getbestweapon(self);
+		if(client_hasweapon(self, WEP_LASER, TRUE, FALSE))
+			self.switchweapon = WEP_LASER;
 		return;
 	}
 
@@ -629,7 +692,7 @@
 
 	traceline(self.enemy.origin,self.enemy.origin-'0 0 1000',TRUE,world);
 	distancefromfloor = self.enemy.origin_z - trace_endpos_z;
-	
+
 	af = ATTACK_FINISHED(self);
 	ct = cvar("bot_ai_weapon_combo_threshold");
 
@@ -699,70 +762,70 @@
 		minstanex = (1000/cvar("g_balance_minstanex_refire")*1.0)
 			* (0.5);
 
-	if (client_hasweapon(self, WEP_ROCKET_LAUNCHER, TRUE, FALSE)  && 
-		!(	cvar("bot_ai_weapon_combo") && self.weapon == WEP_ROCKET_LAUNCHER && 
+	if (client_hasweapon(self, WEP_ROCKET_LAUNCHER, TRUE, FALSE)  &&
+		!(	cvar("bot_ai_weapon_combo") && self.weapon == WEP_ROCKET_LAUNCHER &&
 			af > combo_time
 		)
 	)
 		rocket = (cvar("g_balance_rocketlauncher_damage")/cvar("g_balance_rocketlauncher_refire")*0.75)
 			* bound(0,(cvar("g_balance_rocketlauncher_speed")/distance*maxdelaytime),1)*1.5;
-			
-	if (client_hasweapon(self, WEP_NEX, TRUE, FALSE)  && 
-		!( 	cvar("bot_ai_weapon_combo") && self.weapon == WEP_NEX && 
+
+	if (client_hasweapon(self, WEP_NEX, TRUE, FALSE)  &&
+		!( 	cvar("bot_ai_weapon_combo") && self.weapon == WEP_NEX &&
 			af > combo_time
 		)
 	)
 		nex = (cvar("g_balance_nex_damage")/cvar("g_balance_nex_refire")*1.0)
 			* (0.5);
-			
-	if (client_hasweapon(self, WEP_HAGAR, TRUE, FALSE) ) // && 
+
+	if (client_hasweapon(self, WEP_HAGAR, TRUE, FALSE) ) // &&
 	//	!( cvar("bot_ai_weapon_combo") && self.weapon == WEP_HAGAR &&  time < self.bot_lastshot + cvar("g_balance_hagar_primary_refire") ))
 		hagar = (cvar("g_balance_hagar_primary_damage")/cvar("g_balance_hagar_primary_refire")*1.0)
 			* bound(0,(cvar("g_balance_hagar_primary_speed")/distance*maxdelaytime),1)*0.2;
-			
-	if (client_hasweapon(self, WEP_GRENADE_LAUNCHER, TRUE, FALSE) && 
-		!( 
-			cvar("bot_ai_weapon_combo") && self.weapon == WEP_GRENADE_LAUNCHER && 
+
+	if (client_hasweapon(self, WEP_GRENADE_LAUNCHER, TRUE, FALSE) &&
+		!(
+			cvar("bot_ai_weapon_combo") && self.weapon == WEP_GRENADE_LAUNCHER &&
 			af > combo_time
 		)
 	)
 		grenade = (cvar("g_balance_grenadelauncher_primary_damage")/cvar("g_balance_grenadelauncher_primary_refire")*1.0)
 			* bound(0,(cvar("g_balance_grenadelauncher_primary_speed")/distance*maxdelaytime),1)*1.1;
-			
-	if (client_hasweapon(self, WEP_ELECTRO, TRUE, FALSE) && 
-		!( 	cvar("bot_ai_weapon_combo") && self.weapon == WEP_ELECTRO && 
+
+	if (client_hasweapon(self, WEP_ELECTRO, TRUE, FALSE) &&
+		!( 	cvar("bot_ai_weapon_combo") && self.weapon == WEP_ELECTRO &&
 			af > combo_time
 		)
 	)
 		electro = (cvar("g_balance_electro_primary_damage")/cvar("g_balance_electro_primary_refire")*0.75)
 			* bound(0,(cvar("g_balance_electro_primary_speed")/distance*maxdelaytime),1)*1.0;
-			
-	if (client_hasweapon(self, WEP_CRYLINK, TRUE, FALSE) ) // && 
+
+	if (client_hasweapon(self, WEP_CRYLINK, TRUE, FALSE) ) // &&
 	//	!( self.weapon == WEP_CRYLINK &&  time < self.bot_lastshot + cvar("g_balance_crylink_primary_refire") ))
 		crylink = (cvar("g_balance_crylink_primary_damage")/cvar("g_balance_crylink_primary_refire")*1.0)
 			* bound(0,(cvar("g_balance_crylink_primary_speed")/distance*maxdelaytime),1)*(64/(32+cvar("g_balance_crylink_primary_spread")*distance))*1.0;
-			
-	if (client_hasweapon(self, WEP_UZI, TRUE, FALSE) ) // && 
+
+	if (client_hasweapon(self, WEP_UZI, TRUE, FALSE) ) // &&
 	//	!( self.weapon == WEP_UZI &&  time < self.bot_lastshot + cvar("g_balance_uzi_sustained_refire") ))
 		uzi = (cvar("g_balance_uzi_sustained_damage")/cvar("g_balance_uzi_sustained_refire")*1.0)
 			* bound(0,32/(32+cvar("g_balance_uzi_sustained_spread")*distance),1);
-			
-	if (client_hasweapon(self, WEP_SHOTGUN, TRUE, FALSE) && 
-		!(	cvar("bot_ai_weapon_combo") && self.weapon == WEP_SHOTGUN && 
+
+	if (client_hasweapon(self, WEP_SHOTGUN, TRUE, FALSE) &&
+		!(	cvar("bot_ai_weapon_combo") && self.weapon == WEP_SHOTGUN &&
 			af > combo_time
 		)
 	)
 		shotgun = (cvar("g_balance_shotgun_primary_damage")*cvar("g_balance_shotgun_primary_bullets")/cvar("g_balance_shotgun_primary_refire")*1.0)
 			* bound(0,32/(32+cvar("g_balance_shotgun_primary_spread")*distance),1);
-			
-	if (client_hasweapon(self, WEP_LASER, FALSE, FALSE) && 
-		!(	cvar("bot_ai_weapon_combo") && self.weapon == WEP_LASER && 
+
+	if (client_hasweapon(self, WEP_LASER, FALSE, FALSE) &&
+		!(	cvar("bot_ai_weapon_combo") && self.weapon == WEP_LASER &&
 			af > combo_time
 		)
 	)
 		laser = (cvar("g_balance_laser_primary_damage")/cvar("g_balance_laser_primary_refire")*1.0)
 			* bound(0,cvar("g_balance_laser_primary_speed")/distance*maxdelaytime,1);
-			
+
 	if((self.enemy.flags & FL_ONGROUND)==FALSE){
 		rocket = rocket   * (1.5-bound(0, distancefromfloor/cvar("g_balance_rocketlauncher_radius"         ),0.9)); //slight bigger change
 		grenade = grenade * (1.5-bound(0,distancefromfloor/cvar("g_balance_grenadelauncher_primary_radius"),0.95));
@@ -796,7 +859,7 @@
 	// switch if the best weapon would provide a significant damage increase
 	if (bestscore > currentscore*1.5){
 		self.switchweapon = bestweapon;
-		
+
 		// buys time for detonating the rocket. not tested yet
 		if ( cvar("bot_ai_weapon_combo") && bestweapon == WEP_ROCKET_LAUNCHER )
 			self.bot_chooseweapontime += (distance  / cvar("g_balance_rocketlauncher_speed"));
@@ -807,8 +870,8 @@
 void havocbot_aim()
 {
 	local vector selfvel, enemyvel;
-	if(self.flags & FL_INWATER)
-		return;
+//	if(self.flags & FL_INWATER)
+//		return;
 	if (time < self.nextaim)
 		return;
 	self.nextaim = time + 0.1;
@@ -832,12 +895,55 @@
 	if (!bot_strategytoken_taken)
 	{
 		self.havocbot_role();
+
+		// TODO: tracewalk() should take care of this job (better path finding under water)
+		// if we don't have a goal and we're under water look for a waypoint near the "shore" and push it
+		if(self.goalcurrent==world)
+		if(self.waterlevel==2 || self.aistatus & AI_STATUS_OUT_WATER)
+		{
+			// Look for the closest waypoint out of water
+			local entity newgoal, head;
+			local float bestdistance, distance;
+
+			newgoal = world;
+			bestdistance = 10000;
+			for (head = findchain(classname, "waypoint"); head; head = head.chain)
+			{
+				distance = vlen(head.origin - self.origin);
+				if(distance>10000)
+					continue;
+
+				if(head.origin_z < self.origin_z)
+					continue;
+
+				if(head.origin_z - self.origin_z - self.view_ofs_z > 100)
+					continue;
+
+				if (pointcontents(head.origin + head.maxs + '0 0 1') != CONTENT_EMPTY)
+					continue;
+
+				traceline(self.origin + self.view_ofs , head.origin, TRUE, head);
+
+				if(trace_fraction<1)
+					continue;
+
+				if(distance<bestdistance)
+				{
+					newgoal = head;
+					bestdistance = distance;
+				}
+			}
+
+			if(newgoal)
+			{
+			//	te_wizspike(newgoal.origin);
+				navigation_pushroute(newgoal);
+			}
+		}
+
 		// token has been used this frame
 		bot_strategytoken_taken = TRUE;
 	}
-	if(self.deadflag)
-		return;
-
 	havocbot_chooseenemy();
 	if (self.bot_chooseweapontime < time )
 	{

Modified: branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc	2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc	2009-03-19 12:23:00 UTC (rev 6221)
@@ -28,10 +28,10 @@
 			rating = 0.5 + bound(0, skill / 20, 0.5);
 		else
 			rating = 1;
-		
+
 		if( bot_custom_weapon )
 		{
-			for(i = WEP_FIRST; i < WEP_LAST ; ++i){		
+			for(i = WEP_FIRST; i < WEP_LAST ; ++i){
 				if( power2of(i-1) & item.weapons  != item.weapons )
 					continue;
 
@@ -48,7 +48,7 @@
 					}
 				}
 
-				if (position >= 0 ) 
+				if (position >= 0 )
 				{
 					position = WEP_LAST - position;
 					// item.bot_pickupbasevalue is overwritten here
@@ -86,28 +86,28 @@
 	}
 
 	// TODO: if the item is not recognized then default to item.bot_pickupevalfunc(self, item);
-		
+
 	return base * rating;
 };
 
 void havocbot_goalrating_items(float ratingscale, vector org, float sradius)
 {
 	local entity head;
-	local entity player;	
+	local entity player;
 	local float rating, d, discard, distance, friend_distance, enemy_distance;
 	ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
 	head = findchainfloat(bot_pickup, TRUE);
-	
+
 	while (head)
 	{
 		distance = vlen(head.origin - org);
 		friend_distance = 10000; enemy_distance = 10000;
 		rating = 0;
-	
+
 		if(!head.solid || distance > sradius || (head == self.ignoregoal && time < self.ignoregoaltime) )
 		{
 			head = head.chain;
-			continue;		
+			continue;
 		}
 
 		// Check if the item can be picked up safely
@@ -119,7 +119,7 @@
 			if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
 			{
 				head = head.chain;
-				continue;		
+				continue;
 			}
 			if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
 			{
@@ -127,11 +127,21 @@
 				continue;
 			}
 		}
-		
+		else
+		{
+			// Ignore items under water
+			traceline(head.origin + head.maxs, head.origin + head.maxs, MOVE_NORMAL, head);
+			if(trace_dpstartcontents & DPCONTENTS_LIQUIDSMASK)
+			{
+				head = head.chain;
+				continue;
+			}
+		}
+
 		if(teams_matter)
 		{
 			discard = FALSE;
-			
+
 			FOR_EACH_PLAYER(player)
 			{
 
@@ -147,17 +157,17 @@
 
 					if( d > friend_distance)
 						continue;
-					
+
 					friend_distance = d;
 
 					discard = TRUE;
-					
+
 					if( head.health && player.health > self.health )
 						continue;
 
 					if( head.armorvalue && player.armorvalue > self.armorvalue)
 						continue;
-											
+
 					if( head.weapons )
 					if( (player.weapons & head.weapons) != head.weapons)
 						continue;
@@ -191,7 +201,7 @@
 			{
 			//	rating = head.bot_pickupevalfunc(self, head);
 				rating = havocbot_pickupevalfunc(head);
-			}				
+			}
 		}
 		else
 		{
@@ -201,7 +211,6 @@
 
 		if(rating > 0)
 			navigation_routerating(head, rating * ratingscale, 2000);
-
 		head = head.chain;
 	}
 };
@@ -245,9 +254,13 @@
 void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius)
 {
 	local entity head;
-	local float t, noteam;
+	local float t, noteam, distance;
 	noteam = ((self.team == 0) || !teams_matter); // fteqcc sucks
 
+	// don't chase players if we're under water
+	if(self.waterlevel>1)
+		return;
+
 	FOR_EACH_PLAYER(head)
 	{
 		// TODO: Merge this logic with the bot_shouldattack function
@@ -255,23 +268,24 @@
 		if (head.health > 0)
 		if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
 		{
-			if (vlen(head.origin - org) > sradius)
+			distance = vlen(head.origin - org);
+			if (distance < 100 || distance > sradius)
 				continue;
 
 			if(g_minstagib)
 			if(head.items & IT_STRENGTH)
 				continue;
-				
+
 			// rate only visible enemies
 			/*
 			traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
 			if (trace_fraction < 1 || trace_ent != head)
 				continue;
 			*/
-			
+
 			if(head.flags & FL_INWATER || head.flags & FL_PARTIALGROUND)
 				continue;
-			
+
 			// not falling
 			if(head.flags & FL_ONGROUND == 0)
 			{
@@ -721,7 +735,7 @@
 		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
 		navigation_goalrating_start();
 		havocbot_goalrating_items(10000, self.origin, 10000);
-		havocbot_goalrating_enemyplayers(20000, self.origin, 20000);
+		havocbot_goalrating_enemyplayers(20000, self.origin, 10000);
 		//havocbot_goalrating_waypoints(1, self.origin, 1000);
 		navigation_goalrating_end();
 	}
@@ -753,7 +767,7 @@
 				navigation_routerating(e, 1000000, 5000);
 			}
 		}
-		
+
 		navigation_goalrating_end();
 	}
 };



More information about the nexuiz-commits mailing list