r5918 - in trunk/data: . qcsrc/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sat Feb 21 17:55:27 EST 2009


Author: mand1nga
Date: 2009-02-21 17:55:27 -0500 (Sat, 21 Feb 2009)
New Revision: 5918

Modified:
   trunk/data/defaultNexuiz.cfg
   trunk/data/qcsrc/server/bots.qc
   trunk/data/qcsrc/server/havocbot.qc
   trunk/data/qcsrc/server/havocbot_roles.qc
Log:
Bots: Added bunny-hopping support :)
Added function to debug the goal stack visually
Added .aistatus field
Lowered ammo/health eagerness a bit
Lowered enemy rating radius from 20000 to 10000


Modified: trunk/data/defaultNexuiz.cfg
===================================================================
--- trunk/data/defaultNexuiz.cfg	2009-02-20 18:28:59 UTC (rev 5917)
+++ trunk/data/defaultNexuiz.cfg	2009-02-21 22:55:27 UTC (rev 5918)
@@ -340,7 +340,7 @@
 seta skill_auto 0	"when 1, \"skill\" gets adjusted to match the best player on the map"
 // general bot AI cvars
 set bot_ai_thinkinterval 0.05
-set bot_ai_strategyinterval 2
+set bot_ai_strategyinterval 5
 set bot_ai_enemydetectioninterval 0.5
 set bot_ai_dodgeupdateinterval 0.1
 set bot_ai_chooseweaponinterval 0.3
@@ -364,6 +364,10 @@
 set bot_ai_weapon_combo_threshold 0.3	"Try to make a combo N seconds after the last attack"
 set bot_ai_friends_aware_pickup_radius "500"	"Bots will not pickup items if a team mate is this distance near the item"
 set bot_ai_ignoregoal_timeout 3	"Ignore goals making bots to get stuck in front of a wall for N seconds"
+set bot_ai_bunnyhop_skilloffset 7	"Bots with skill equal or greater than this value will perform the  \"bunnyhop\" technique"
+set bot_ai_bunnyhop_startdistance 250 "Run to goals located further than this distance"
+set bot_ai_bunnyhop_stopdistance 200 "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"
 // Better don't touch these, there are hard to tweak!
 set bot_ai_aimskill_order_mix_1st 0.01
 set bot_ai_aimskill_order_mix_2nd 0.1

Modified: trunk/data/qcsrc/server/bots.qc
===================================================================
--- trunk/data/qcsrc/server/bots.qc	2009-02-20 18:28:59 UTC (rev 5917)
+++ trunk/data/qcsrc/server/bots.qc	2009-02-21 22:55:27 UTC (rev 5918)
@@ -1,8 +1,13 @@
+.float aistatus;
+float AI_STATUS_ROAMING		= 1;
+float AI_STATUS_ATTACKING	= 2;
+float AI_STATUS_RUNNING		= 4;
+
+.string netname_freeme;
+
 // rough simulation of walking from one point to another to test if a path
 // can be traveled, used by havocbot
 
-.string netname_freeme;
-
 vector stepheightvec;
 float navigation_testtracewalk;
 float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode)
@@ -1310,6 +1315,21 @@
 	org = self.origin;// + self.velocity * 0.1;
 	m1 = org + self.mins;
 	m2 = org + self.maxs;
+
+	// Loose goal touching check for running state
+	if(self.aistatus & AI_STATUS_RUNNING)
+	if(self.goalcurrent.classname=="waypoint")
+	{
+		if(vlen(self.origin - self.goalcurrent.origin)<150)
+		{
+				traceline(self.origin + self.view_ofs , self.goalcurrent.origin, TRUE, world);
+				if(trace_fraction==1)
+				{
+					navigation_poproute();
+				}
+		}
+	}
+
 	while (self.goalcurrent && boxesoverlap(m1, m2, self.goalcurrent.absmin, self.goalcurrent.absmax))
 		navigation_poproute();
 }

Modified: trunk/data/qcsrc/server/havocbot.qc
===================================================================
--- trunk/data/qcsrc/server/havocbot.qc	2009-02-20 18:28:59 UTC (rev 5917)
+++ trunk/data/qcsrc/server/havocbot.qc	2009-02-21 22:55:27 UTC (rev 5918)
@@ -1,10 +1,13 @@
-
 .void() havocbot_role;
 void() havocbot_chooserole;
 .float havocbot_keyboardskill;
 .float facingwalltime, ignoregoaltime;
 .entity ignoregoal;
 
+#ifdef DEBUG_BOT_GOALSTACK
+void debuggoalstack();
+#endif
+
 vector havocbot_dodge()
 {
 	// LordHavoc: disabled because this is too expensive
@@ -132,6 +135,123 @@
 	self.movement = self.movement + (keyboard - self.movement) * blend;
 };
 
+.entity bot_lastseengoal;
+.float bot_timelastseengoal;
+.float bot_canruntogoal;
+void havocbot_bunnyhop(vector dir)
+{
+	local float distance;
+	local vector deviation;
+
+	if(self.goalcurrent.classname == "player")
+		return;
+
+	if(self.bot_lastseengoal != self.goalcurrent && !(self.aistatus & AI_STATUS_RUNNING))
+	{
+		self.bot_canruntogoal = 0;
+		self.bot_timelastseengoal = 0;
+	}
+
+	distance = vlen(self.origin - self.goalcurrent.origin);
+
+	// Run only to visible goals
+	traceline(self.origin + self.view_ofs , self.goalcurrent.origin, TRUE, world);
+	if(self.flags & FL_ONGROUND)
+	if(trace_fraction == 1)
+	{
+			self.bot_lastseengoal = self.goalcurrent;
+
+			// seen it before
+			if(self.bot_timelastseengoal)
+			{
+				// for a period of time
+				if(time - self.bot_timelastseengoal > cvar("bot_ai_bunnyhop_firstjumpdelay"))
+				{
+					local float checkdistance;
+					checkdistance = TRUE;
+
+					// don't run if it is too close
+					if(self.bot_canruntogoal==0)
+					{
+						if(distance > cvar("bot_ai_bunnyhop_startdistance"))
+							self.bot_canruntogoal = 1;
+						else	
+							self.bot_canruntogoal = -1;
+					}
+
+					if(self.bot_canruntogoal != 1)
+						return;
+
+					if(self.aistatus & AI_STATUS_ROAMING)
+					if(self.goalcurrent.classname=="waypoint")
+					if(fabs(self.goalcurrent.origin_z - self.origin_z) < self.maxs_z - self.mins_z)
+					if(self.goalstack01!=world)
+					{
+						deviation = self.goalstack01.origin - (self.origin + self.view_ofs);
+						deviation = vectoangles(deviation) - self.v_angle;
+						while (deviation_y < -180) deviation_y = deviation_y + 360;
+						while (deviation_y > 180) deviation_y = deviation_y - 360;
+
+						if(deviation_y < 20 && deviation_y > -20)
+						if(distance < vlen(self.origin - self.goalstack01.origin))
+						if(fabs(self.goalstack01.origin_z - self.goalcurrent.origin_z) < self.maxs_z - self.mins_z)
+						{
+							traceline(self.origin + self.view_ofs , self.goalstack01.origin, TRUE, world);
+							if(trace_fraction==1)
+							{
+								checkdistance = FALSE;
+							}
+						}
+					}
+
+					if(checkdistance)
+					{
+						self.aistatus &~= AI_STATUS_RUNNING;
+						if(distance > cvar("bot_ai_bunnyhop_stopdistance"))
+							self.BUTTON_JUMP = TRUE;
+					}
+					else
+					{
+						self.aistatus |= AI_STATUS_RUNNING;
+						self.BUTTON_JUMP = TRUE;
+					}
+				}
+			}
+			else
+			{
+				self.bot_timelastseengoal = time;
+			}
+	}
+	else
+	{
+		self.bot_timelastseengoal = 0;
+	}
+
+	// Release jump button
+	if(self.flags & FL_ONGROUND == 0)
+	{
+		if(self.velocity_z < 0)
+			self.BUTTON_JUMP = FALSE;
+
+		// Strafe 
+		local float maxspeed;
+		maxspeed = cvar("sv_maxspeed");
+
+		if(self.aistatus & AI_STATUS_RUNNING)
+		if(vlen(self.velocity)>maxspeed)
+		{
+			deviation = vectoangles(dir) - self.v_angle;
+			while (deviation_y < -180) deviation_y = deviation_y + 360;
+			while (deviation_y > 180) deviation_y = deviation_y - 360;
+
+			if ( deviation_y > 2 )
+				self.movement_y = maxspeed;
+			if ( deviation_y < -2 )
+				self.movement_y = maxspeed * -1;
+		}
+	}
+};
+
 //.float havocbotignoretime;
 //.vector bot_dodgevector;
 //.float bot_dodgevector_time;
@@ -182,8 +302,10 @@
 		return;
 	}
 
-//	te_wizspike(self.goalcurrent.origin);
-//	te_lightning2(world, self.origin, self.goalcurrent.origin);
+#ifdef DEBUG_BOT_GOALSTACK
+	debuggoalstack();
+#endif
+//	te_lightning2(world, self.goalcurrent.origin + self.goalcurrent.mins, self.goalcurrent.origin + self.goalcurrent.maxs);
 
 	m1 = self.goalcurrent.origin + self.goalcurrent.mins;
 	m2 = self.goalcurrent.origin + self.goalcurrent.maxs;
@@ -313,7 +435,6 @@
 	//dir = self.bot_dodgevector;
 	//if (self.bot_dodgevector_jumpbutton)
 	//	self.BUTTON_JUMP = 1;
-
 	self.movement_x = dir * v_forward * maxspeed;
 	self.movement_y = dir * v_right * maxspeed;
 	self.movement_z = dir * v_up * maxspeed;
@@ -322,6 +443,11 @@
 	if (skill < 10)
 		havocbot_keyboard_movement(destorg);
 
+	// Bunnyhop!
+//	if(self.aistatus & AI_STATUS_ROAMING)
+	if(skill >= cvar("bot_ai_bunnyhop_skilloffset"))
+		havocbot_bunnyhop(dir);
+
 	if ((dir * v_up) >= cvar("sv_jumpvelocity")*0.5 && (self.flags & FL_ONGROUND)) self.BUTTON_JUMP=1;
 	if (((dodge * v_up) > 0) && random()*frametime >= 0.2*bound(0,(10-skill)*0.1,1)) self.BUTTON_JUMP=TRUE;
 	if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill)*0.1,1)) self.havocbot_ducktime=time+0.3/bound(0.1,skill,10);
@@ -650,6 +776,9 @@
 	lag_update();
 	if (self.bot_aimtarg)
 	{
+		self.aistatus |= AI_STATUS_ATTACKING;
+		self.aistatus &~= AI_STATUS_ROAMING;
+
 		weapon_action(self.weapon, WR_AIM);
 		if (cvar("bot_nofire") || IS_INDEPENDENT_PLAYER(self))
 		{
@@ -659,13 +788,16 @@
 	}
 	else if (self.goalcurrent)
 	{
+		self.aistatus |= AI_STATUS_ROAMING;
+		self.aistatus &~= AI_STATUS_ATTACKING;
+
 		local vector now,v,next;//,heading;
 		local float distance,skillblend,distanceblend,blend;
 		next = now = self.goalcurrent.origin - (self.origin + self.view_ofs);
 		distance = vlen(now);
 		//heading = self.velocity;
 		//dprint(self.goalstack01.classname,etos(self.goalstack01),"\n");
-		if(self.goalstack01 != self && self.goalstack01 != world)
+		if(self.goalstack01 != self && self.goalstack01 != world && self.aistatus & AI_STATUS_RUNNING == 0)
 			next = self.goalstack01.origin - (self.origin + self.view_ofs);
 		skillblend=bound(0,(skill-2.5)*0.5,1); //lower skill player can't preturn
 		distanceblend=bound(0,distance/cvar("bot_ai_keyboard_distance"),1);
@@ -694,3 +826,69 @@
 	self.havocbot_keyboardskill=random()-0.5;
 	havocbot_chooserole();
 }
+
+
+#ifdef DEBUG_BOT_GOALSTACK
+
+.float goalcounter;
+.vector lastposition;
+
+// Debug the goal stack visually
+void debuggoalstack()
+{
+	local entity target;
+	local vector org;
+
+	if(self.goalcounter==0)target=self.goalcurrent;
+	else if(self.goalcounter==1)target=self.goalstack01;
+	else if(self.goalcounter==2)target=self.goalstack02;
+	else if(self.goalcounter==3)target=self.goalstack03;
+	else if(self.goalcounter==4)target=self.goalstack04;
+	else if(self.goalcounter==5)target=self.goalstack05;
+	else if(self.goalcounter==6)target=self.goalstack06;
+	else if(self.goalcounter==7)target=self.goalstack07;
+	else if(self.goalcounter==8)target=self.goalstack08;
+	else if(self.goalcounter==9)target=self.goalstack09;
+	else if(self.goalcounter==10)target=self.goalstack10;
+	else if(self.goalcounter==11)target=self.goalstack11;
+	else if(self.goalcounter==12)target=self.goalstack12;
+	else if(self.goalcounter==13)target=self.goalstack13;
+	else if(self.goalcounter==14)target=self.goalstack14;
+	else if(self.goalcounter==15)target=self.goalstack15;
+	else if(self.goalcounter==16)target=self.goalstack16;
+	else if(self.goalcounter==17)target=self.goalstack17;
+	else if(self.goalcounter==18)target=self.goalstack18;
+	else if(self.goalcounter==19)target=self.goalstack19;
+	else if(self.goalcounter==20)target=self.goalstack20;
+	else if(self.goalcounter==21)target=self.goalstack21;
+	else if(self.goalcounter==22)target=self.goalstack22;
+	else if(self.goalcounter==23)target=self.goalstack23;
+	else if(self.goalcounter==24)target=self.goalstack24;
+	else if(self.goalcounter==25)target=self.goalstack25;
+	else if(self.goalcounter==26)target=self.goalstack26;
+	else if(self.goalcounter==27)target=self.goalstack27;
+	else if(self.goalcounter==28)target=self.goalstack28;
+	else if(self.goalcounter==29)target=self.goalstack29;
+	else if(self.goalcounter==30)target=self.goalstack30;
+	else if(self.goalcounter==31)target=self.goalstack31;
+
+	if(target==world)
+	{
+		self.goalcounter = 0;
+		self.lastposition='0 0 0';
+		return;
+	}
+
+	if(self.lastposition=='0 0 0')
+		org = self.origin;
+	else
+		org = self.lastposition;
+
+
+	te_lightning2(world, org, target.origin);
+	self.lastposition = target.origin;
+
+	self.goalcounter++;
+}
+
+#endif
\ No newline at end of file

Modified: trunk/data/qcsrc/server/havocbot_roles.qc
===================================================================
--- trunk/data/qcsrc/server/havocbot_roles.qc	2009-02-20 18:28:59 UTC (rev 5917)
+++ trunk/data/qcsrc/server/havocbot_roles.qc	2009-02-21 22:55:27 UTC (rev 5918)
@@ -76,12 +76,14 @@
 		rating = rating + max(0, 1 - self.ammo_cells / g_pickup_cells_max);
 
 	if (item.armorvalue)
-	if (self.armorvalue < item.max_armorvalue)
-		rating = rating + max(0, 1 - self.armorvalue / item.max_armorvalue);
+	if (self.armorvalue < item.max_armorvalue * 0.5)
+		rating = rating + max(0, 1 - self.armorvalue / (item.max_armorvalue * 0.5));
 
 	if (item.health)
-	if (self.health < item.max_health)
-		rating = rating + max(0, 1 - self.health / item.max_health);
+	if (self.health < item.max_health * 0.5)
+	{
+		rating = rating + max(0, 1 - self.health / (item.max_health * 0.5));
+	}
 
 	// TODO: if the item is not recognized then default to item.bot_pickupevalfunc(self, item);
 		
@@ -199,7 +201,7 @@
 
 		if(rating > 0)
 			navigation_routerating(head, rating * ratingscale, 2000);
-			
+
 		head = head.chain;
 	}
 };
@@ -714,7 +716,7 @@
 		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
 		navigation_goalrating_start();
 		havocbot_goalrating_items(10000, self.origin, 10000);
-		havocbot_goalrating_enemyplayers(5000, self.origin, 20000);
+		havocbot_goalrating_enemyplayers(5000, self.origin, 10000);
 		//havocbot_goalrating_waypoints(1, self.origin, 1000);
 		navigation_goalrating_end();
 	}




More information about the nexuiz-commits mailing list