r2362 - in branches/nexuiz-2.0/data: . qcsrc/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Fri Apr 20 07:34:36 EDT 2007


Author: div0
Date: 2007-04-20 07:34:36 -0400 (Fri, 20 Apr 2007)
New Revision: 2362

Modified:
   branches/nexuiz-2.0/data/default.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/miscfunctions.qc
Log:
spawnpoints drop on g_spawnpoints_autodrop; merged Qantourisc's bot AI


Modified: branches/nexuiz-2.0/data/default.cfg
===================================================================
--- branches/nexuiz-2.0/data/default.cfg	2007-04-20 11:34:00 UTC (rev 2361)
+++ branches/nexuiz-2.0/data/default.cfg	2007-04-20 11:34:36 UTC (rev 2362)
@@ -149,10 +149,27 @@
 set bot_ai_strategyinterval 2
 set bot_ai_enemydetectioninterval 0.5
 set bot_ai_aimskill_blendrate 2
-set bot_ai_aimskill_fixedrate 30
+set bot_ai_aimskill_fixedrate 15
 set bot_ai_aimskill_firetolerance_distdegrees 180
 set bot_ai_aimskill_firetolerance_mindegrees 2
-set bot_ai_aimskill_firetolerance_maxdegrees 30
+set bot_ai_aimskill_firetolerance_maxdegrees 45
+set bot_ai_aimskill_mouse 1
+set bot_ai_keyboard_distance 250
+set bot_ai_keyboard_treshold 0.94
+set bot_ai_aimskill_offset 1
+set bot_ai_aimskill_think 1
+// 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
+set bot_ai_aimskill_order_mix_3th 0.01
+set bot_ai_aimskill_order_mix_4th 0.05
+set bot_ai_aimskill_order_mix_5th 0.01
+set bot_ai_aimskill_order_filter_1st 0.2
+set bot_ai_aimskill_order_filter_2nd 0.2
+set bot_ai_aimskill_order_filter_3th 0.05
+set bot_ai_aimskill_order_filter_4th 0.25
+set bot_ai_aimskill_order_filter_5th 0.3
+
 // waypoint editor enable
 set g_waypointeditor 0
 set bot_ignore_bots 0
@@ -184,6 +201,7 @@
 set g_midair 0
 set g_midair_shieldtime 0.3
 set g_spawnshieldtime 0
+set g_spawnpoints_autodrop 1
 set g_forced_respawn 0
 set g_fullbrightplayers 0
 set g_fullbrightitems 0

Modified: branches/nexuiz-2.0/data/qcsrc/server/bots.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/bots.qc	2007-04-20 11:34:00 UTC (rev 2361)
+++ branches/nexuiz-2.0/data/qcsrc/server/bots.qc	2007-04-20 11:34:36 UTC (rev 2362)
@@ -326,7 +326,13 @@
 };
 
 
+// Random skill system
+.float bot_thinkskill;
+.float bot_mouseskill;
+.float bot_predictionskill;
+.float bot_offsetskill;
 
+
 // waypoint navigation system
 
 // itemscore = (howmuchmoreIwant / howmuchIcanwant) / itemdistance
@@ -1496,7 +1502,15 @@
 };
 
 .float bot_badaimtime;
+.float bot_aimthinktime;
+.vector bot_mouseaim;
 .vector bot_badaimoffset;
+.vector bot_1st_order_aimfilter;
+.vector bot_2nd_order_aimfilter;
+.vector bot_3th_order_aimfilter;
+.vector bot_4th_order_aimfilter;
+.vector bot_5th_order_aimfilter;
+.vector bot_olddesiredang;
 float(vector v, float maxfiredeviation) bot_aimdir =
 {
 /*
@@ -1551,9 +1565,9 @@
 	if (time >= self.bot_badaimtime)
 	{
 		self.bot_badaimtime = max(self.bot_badaimtime + 0.3, time);
-		self.bot_badaimoffset = randomvec() * bound(0, 5 - 0.5 * skill, 5);
+		self.bot_badaimoffset = randomvec() * bound(0, 5 - 0.5 * (skill+self.bot_offsetskill), 5);
 	}
-	desiredang = vectoangles(v) + self.bot_badaimoffset;
+	desiredang = vectoangles(v) + self.bot_badaimoffset*cvar("bot_ai_aimskill_offset");
 	//dprint(" desired:", vtos(desiredang));
 	if (desiredang_x >= 180)
 		desiredang_x = desiredang_x - 360;
@@ -1570,6 +1584,64 @@
 	//}
 
 	// calculate turn angles
+	diffang = (desiredang - self.bot_olddesiredang)*(1/frametime);
+	self.bot_olddesiredang = desiredang;
+	//dprint(" diff:", vtos(diffang));
+
+	// wrap yaw turn
+	while (diffang_y < -180)
+		diffang_y = diffang_y + 360;
+	while (diffang_y >  180)
+		diffang_y = diffang_y - 360;
+
+	// Here we will try to anticipate the comming aiming direction
+	self.bot_1st_order_aimfilter= self.bot_1st_order_aimfilter
+		+ (diffang                      - self.bot_1st_order_aimfilter) * bound(0, cvar("bot_ai_aimskill_order_filter_1st"),1);
+	self.bot_2nd_order_aimfilter= self.bot_2nd_order_aimfilter
+		+ (self.bot_1st_order_aimfilter - self.bot_2nd_order_aimfilter) * bound(0, cvar("bot_ai_aimskill_order_filter_2nd"),1);
+	self.bot_3th_order_aimfilter= self.bot_3th_order_aimfilter
+		+ (self.bot_2nd_order_aimfilter - self.bot_3th_order_aimfilter) * bound(0, cvar("bot_ai_aimskill_order_filter_3th"),1);
+	self.bot_4th_order_aimfilter= self.bot_4th_order_aimfilter
+		+ (self.bot_3th_order_aimfilter - self.bot_4th_order_aimfilter) * bound(0, cvar("bot_ai_aimskill_order_filter_4th"),1);
+	self.bot_5th_order_aimfilter= self.bot_5th_order_aimfilter
+		+ (self.bot_4th_order_aimfilter - self.bot_5th_order_aimfilter) * bound(0, cvar("bot_ai_aimskill_order_filter_5th"),1);
+
+	local float blend;
+	//blend = (bound(0,skill,10)*0.1)*pow(1-bound(0,skill,10)*0.05,2.5)*5.656854249; //Plot formule before changing !
+	blend = bound(0,skill,10)*0.1;
+	desiredang = desiredang + blend *
+	(
+		  self.bot_1st_order_aimfilter * cvar("bot_ai_aimskill_order_mix_1st")
+		+ self.bot_2nd_order_aimfilter * cvar("bot_ai_aimskill_order_mix_2nd")
+		+ self.bot_3th_order_aimfilter * cvar("bot_ai_aimskill_order_mix_3th")
+		+ self.bot_4th_order_aimfilter * cvar("bot_ai_aimskill_order_mix_4th")
+		+ self.bot_5th_order_aimfilter * cvar("bot_ai_aimskill_order_mix_5th")
+	);
+	while (desiredang_z < -180)
+		desiredang_z = desiredang_z + 360;
+	while (desiredang_z >  180)
+		desiredang_z = desiredang_z - 360;
+	// calculate turn angles
+	diffang = desiredang - self.bot_mouseaim;
+	//dprint(" diff:", vtos(diffang));
+
+	// wrap yaw turn
+	while (diffang_y < -180)
+		diffang_y = diffang_y + 360;
+	while (diffang_y >  180)
+		diffang_y = diffang_y - 360;
+
+	if (time >= self.bot_aimthinktime)
+	{
+		self.bot_aimthinktime = max(self.bot_aimthinktime + 0.5 - 0.05*(skill+self.bot_thinkskill), time);
+		self.bot_mouseaim = self.bot_mouseaim + diffang * (1-random()*0.1*bound(1,10-skill,10));
+	}
+
+	//self.v_angle = self.v_angle + diffang * bound(0, r * frametime * (skill * 0.5 + 2), 1);
+
+	desiredang = self.bot_mouseaim*bound(0,cvar("bot_ai_aimskill_think"),1) + desiredang * bound(0,(1-cvar("bot_ai_aimskill_think")),1);
+
+	// calculate turn angles
 	diffang = desiredang - self.v_angle;
 	//dprint(" diff:", vtos(diffang));
 
@@ -1578,17 +1650,30 @@
 		diffang_y = diffang_y + 360;
 	while (diffang_y >  180)
 		diffang_y = diffang_y - 360;
+	// calculate turn angles
+	diffang = desiredang - self.v_angle;
+	//dprint(" diff:", vtos(diffang));
 
+	// wrap yaw turn
+	while (diffang_y < -180)
+		diffang_y = diffang_y + 360;
+	while (diffang_y >  180)
+		diffang_y = diffang_y - 360;
+
 	// jitter tracking
 	dist = vlen(diffang);
 	//diffang = diffang + randomvec() * (dist * 0.05 * (3.5 - bound(0, skill, 3)));
 
 	// turn
 	local float r, fixedrate, blendrate;
-	fixedrate = cvar("bot_ai_aimskill_fixedrate") / max(1, dist);
+	fixedrate = cvar("bot_ai_aimskill_fixedrate") / bound(1,dist,1000);
 	blendrate = cvar("bot_ai_aimskill_blendrate");
 	r = max(fixedrate, blendrate);
-	self.v_angle = self.v_angle + diffang * bound(0, r * frametime * (skill * 0.5 + 2), 1);
+	//self.v_angle = self.v_angle + diffang * bound(frametime, r * frametime * (2+skill*skill*0.05-random()*0.05*(10-skill)), 1);
+	self.v_angle = self.v_angle + diffang * bound(frametime, r * frametime * (2+pow(skill+self.bot_mouseskill,3)*0.005-random()), 1);
+	self.v_angle = self.v_angle * bound(0,cvar("bot_ai_aimskill_mouse"),1) + desiredang * bound(0,(1-cvar("bot_ai_aimskill_mouse")),1);
+	//self.v_angle = self.v_angle + diffang * bound(0, r * frametime * (skill * 0.5 + 2), 1);
+	//self.v_angle = self.v_angle + diffang * (1/ blendrate);
 	self.v_angle_z = 0;
 	while (self.v_angle_y < -180)
 		self.v_angle_y = self.v_angle_y + 360;
@@ -1599,6 +1684,7 @@
 	makevectors(self.v_angle);
 	shotorg = self.origin + self.view_ofs;
 	shotdir = v_forward;
+
 	//dprint(" dir:", vtos(v_forward));
 	//te_lightning2(world, shotorg, shotorg + shotdir * 100);
 
@@ -1612,8 +1698,14 @@
 	//bprint("e ");bprintvector(diffang);bprint(" < ");bprintfloat(maxfiredeviation);bprint("\n");
 
 	// decide whether to fire this time
-	if ((normalize(v) * shotdir) >= cos(maxfiredeviation))
-		self.bot_firetimer = time + 0.3;
+	// note the maxfiredeviation is in degrees so this has to convert to radians first
+	//if ((normalize(v) * shotdir) >= cos(maxfiredeviation * (3.14159265358979323846 / 180)))
+	if ((normalize(v) * shotdir) >= cos(maxfiredeviation * (3.14159265358979323846 / 180)))
+			self.bot_firetimer = time + 0.3/bound(1,skill*0.3,3);
+	traceline(shotorg,shotorg+shotdir*1000,FALSE,world);
+	if ( vlen(trace_endpos-shotorg)>bound(0,skill*20,20) && random()<bound(0,skill*0.5,10)*frametime*2 )
+		self.bot_canfire = 0;
+	//dprint(ftos(maxfiredeviation),"\n");
 	//dprint(" diff:", vtos(diffang), "\n");
 
 	return self.bot_canfire && (time < self.bot_firetimer);
@@ -1621,6 +1713,7 @@
 
 vector(vector targorigin, vector targvelocity, float shotspeed, float shotdelay) bot_shotlead =
 {
+	// Try to add code here that predicts gravity effect here, no clue HOW to though ... well not yet atleast...
 	return targorigin + targvelocity * (shotdelay + vlen(targorigin - shotorg) / shotspeed);
 };
 
@@ -1650,7 +1743,11 @@
 	shotorg = self.origin + self.view_ofs;
 	shotdir = v_forward;
 	v = bot_shotlead(self.bot_aimtargorigin, self.bot_aimtargvelocity, shotspeed, self.bot_aimlatency);
-	r = bound(cvar("bot_ai_aimskill_firetolerance_mindegrees"), cvar("bot_ai_aimskill_firetolerance_distdegrees") / ((vlen(v - shotorg) + 100) * (skill + 2)), cvar("bot_ai_aimskill_firetolerance_maxdegrees"));
+	local float distanceratio;
+	distanceratio =sqrt(bound(0,skill,10000))*0.3*(vlen(v-shotorg)-100)/cvar("bot_ai_aimskill_firetolerance_distdegrees");
+	distanceratio = bound(0,distanceratio,1);
+	r =  (cvar("bot_ai_aimskill_firetolerance_maxdegrees")-cvar("bot_ai_aimskill_firetolerance_mindegrees"))
+		* (1-distanceratio) + cvar("bot_ai_aimskill_firetolerance_mindegrees");
 	if (applygravity && self.bot_aimtarg)
 	{
 		if (!findtrajectorywithleading(shotorg, '0 0 0', '0 0 0', self.bot_aimtarg, shotspeed, shotspeedupward, maxshottime, 0, self))
@@ -1705,7 +1802,9 @@
 
 	// calculate an aiming latency based on the skill setting
 	// (simulated network latency + naturally delayed reflexes)
-	self.ping = 0.7 - bound(0, 0.05 * skill, 0.6);
+	//self.ping = 0.7 - bound(0, 0.05 * skill, 0.5); // moved the reflexes to bot_aimdir (under the name 'think')
+	// minimum ping 20+10 random
+	self.ping = bound(0,0.07 - bound(0, skill * 0.005,0.05)+random()*0.01,0.65); // Now holds real lag to server, and higer skill players take a less laggy server
 	// skill 10 = ping 0.2 (adrenaline)
 	// skill 0 = ping 0.7 (slightly drunk)
 
@@ -1767,6 +1866,7 @@
 
 void() havocbot_setupbot;
 float JoinBestTeam(entity pl, float only_return_best);
+
 void() bot_clientconnect =
 {
 	if (clienttype(self) != CLIENTTYPE_BOT)
@@ -1776,6 +1876,10 @@
 	self.createdtime = self.nextthink;
 	JoinBestTeam(self, FALSE);
 	havocbot_setupbot();
+	self.bot_mouseskill=random()-0.5;
+	self.bot_thinkskill=random()-0.5;
+	self.bot_predictionskill=random()-0.5;
+	self.bot_offsetskill=random()-0.5;
 };
 
 entity() bot_spawn =

Modified: branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc	2007-04-20 11:34:00 UTC (rev 2361)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc	2007-04-20 11:34:36 UTC (rev 2362)
@@ -1,6 +1,7 @@
 
 .void() havocbot_role;
 void() havocbot_chooserole;
+.float havocbot_keyboardskill;
 
 vector() havocbot_dodge =
 {
@@ -51,6 +52,9 @@
 };
 
 //.float havocbotignoretime;
+.float havocbot_keyboardtime;
+.float havocbot_ducktime;
+.vector havocbot_keyboard;
 void() havocbot_movetogoal =
 {
 	local vector destorg;
@@ -67,6 +71,15 @@
 	//if (self.goalentity)
 	//	te_lightning2(self, self.origin, (self.goalentity.absmin + self.goalentity.absmax) * 0.5);
 	self.movement = '0 0 0';
+
+	if(self.jumppadcount)
+	{
+		if(self.flags & FL_ONGROUND)
+			self.jumppadcount = FALSE;
+		else
+			return;
+	}
+
 	if (self.goalcurrent == world)
 		return;
 	navigation_poptouchedgoals();
@@ -91,13 +104,14 @@
 	flatdir = normalize(flatdir);
 	if (!self.waterlevel)
 	{
-		if (!(self.flags & FL_ONGROUND))
-		{
-			// prevent goal checks when we can't walk
-			if (self.bot_strategytime < time + 0.1)
-				self.bot_strategytime = time + 0.1;
-			return;
-		}
+		// Since new update in air contol, we can move in air
+		//if (!(self.flags & FL_ONGROUND))
+		//{
+		//	// prevent goal checks when we can't walk
+		//	if (self.bot_strategytime < time + 0.1)
+		//		self.bot_strategytime = time + 0.1;
+		//	return;
+		//}
 
 		// jump if going toward an obstacle that doesn't look like stairs we
 		// can walk up directly
@@ -125,14 +139,80 @@
 		dir = flatdir;
 	}
 	dodge = havocbot_dodge();
-	dir = normalize(dir + dodge + evadeobstacle + evadelava) * 400;
-	makevectors(self.v_angle);
+	dodge = dodge * bound(0,3+skill*0.1,1);
+	evadelava = evadelava * bound(1,3-skill,3); //Noobs fear lava a lot and take more distance from it
+	traceline(self.origin, self.enemy.origin, TRUE, world);
+	if(trace_ent.classname == "player")
+		dir = dir * bound(0,skill/7,1);
+
+	dir = normalize(dir + dodge + evadeobstacle + evadelava);
+
+
+
+	// Emulate keyboard interface;
+	local vector keyboard,flatangle;
+	local float blend;
+	keyboard = self.havocbot_keyboard;
+	if (time >= self.havocbot_keyboardtime)
+	{
+		flatdir=dir; flatdir_z = 0;
+		self.havocbot_keyboardtime =
+			max(
+				self.havocbot_keyboardtime
+					+ bound(0,0.05/(skill+self.havocbot_keyboardskill),0.05)
+					+random()*bound(0,0.025/(skill+self.havocbot_keyboardskill),100)
+			, time);
+		keyboard = '0 0 0';
+		
+		flatangle = self.v_angle; flatangle_z=0;
+		makevectors(flatangle);
+		
+		local float trigger;
+		local vector v_forward_right;
+		local vector v_forward_left;
+		blend = bound(0,skill*0.1,1);
+		trigger = cvar("bot_ai_keyboard_treshold");
+		v_forward_right = normalize(v_forward + v_right);
+		v_forward_left  = normalize(v_forward - v_right);
+		// Place in reverse order !! least important direction FIRST
+		
+		if (skill > 4.5)
+		{
+			if (flatdir * v_forward_right * -1 > trigger) keyboard = v_forward_right * -1;
+			if (flatdir * v_forward_left  * -1 > trigger) keyboard = v_forward_left  * -1;
+		}
+		if (skill > 2.5)
+		{
+			if (flatdir * v_forward_right      > trigger) keyboard = v_forward_right;
+			if (flatdir * v_forward_left       > trigger) keyboard = v_forward_left;
+			if (flatdir * v_forward       *  1 > trigger) keyboard = v_forward * -1;
+		}
+		if (skill > 1.5)
+		{
+			if (flatdir * v_right              > trigger) keyboard = v_right;
+			if (flatdir * v_right         * -1 > trigger) keyboard = v_right   * -1;
+		}
+			if (flatdir * v_forward            > trigger) keyboard = v_forward;
+		//dprint(ftos(flatdir * v_forward),"\n");
+		keyboard = normalize(keyboard);
+		self.havocbot_keyboard = keyboard;
+		if (self.havocbot_ducktime>time) self.button5=TRUE;
+	}
+	blend = bound(0,vlen(self.goalcurrent.origin-self.origin)/cvar("bot_ai_keyboard_distance"),1); // When getting close move with 360 degree
+	dir = (keyboard * blend + dir * (1-blend))*cvar("sv_maxspeed");
+
 	self.movement_x = dir * v_forward;
 	self.movement_y = dir * v_right;
-	self.movement_z = dir * v_up;
+	if (self.flags & FL_INWATER) self.movement_z = dir * v_up; else self.movement_z = 0;
+
+	if ((dir * v_up) >= cvar("g_balance_jumpheight")*0.5 && (self.flags & FL_ONGROUND)) self.button2=1;
+	if (((dodge * v_up) > 0) && random()*frametime >= 0.2*bound(0,(10-skill)*0.1,1)) self.button2=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);
+	
 };
 
 .float havocbot_chooseenemy_finished;
+.float havocbot_stickenemy;
 void() havocbot_chooseenemy =
 {
 	local entity head, best;
@@ -143,9 +223,30 @@
 		self.enemy = world;
 		return;
 	}
+	traceline(self.origin+self.view_ofs, self.enemy.origin+self.enemy.view_ofs*0.5,FALSE,world);
+	if (trace_ent.classname != "player")
+		self.havocbot_stickenemy =0;
+	else	if ( (trace_ent != self.enemy) || (vlen(self.enemy.origin - self.origin) > 1000) )
+		{
+			self.havocbot_stickenemy =0;
+			if( (self.health < 30) || (self.enemy.health < 0))
+			self.havocbot_chooseenemy_finished = time;
+		}
+	//dprint(ftos(self.havocbot_stickenemy));dprint(etos(self.enemy),"\n");
+	//dprint(ftos(time),"-");dprint(ftos(self.havocbot_chooseenemy_finished),"\n");
+	if (self.havocbot_stickenemy == 1)
+	{
+		// remain tracking him for a shot while (case he went after a small corner or pilar
+		self.havocbot_chooseenemy_finished = time + bound(0,skill*0.1,1)*1.8;
+		return;
+	}
 	if (time < self.havocbot_chooseenemy_finished)
+	{
+		self.havocbot_stickenemy = 1;
 		return;
-	self.havocbot_chooseenemy_finished = time + cvar("bot_ai_enemydetectioninterval");
+	}
+	self.havocbot_chooseenemy_finished = time + cvar("bot_ai_enemydetectioninterval")*bound(0,(11-skill)*0.1,1);
+	self.havocbot_chooseenemy_finished = time + 0.01;
 	eye = (self.origin + self.view_ofs);
 	best = world;
 	bestrating = 100000000;
@@ -167,12 +268,108 @@
 		head = head.chain;
 	}
 	self.enemy = best;
+	self.havocbot_stickenemy = 1;
 };
 
 float(entity e) w_getbestweapon;
+.float havocbot_chooseweapon_timer;
+.float havocbot_chooseweapon_lastbestscore;
 void() havocbot_chooseweapon =
 {
-	self.switchweapon = w_getbestweapon(self);
+	// TODO: clean this up by moving it to weapon code
+	if(self.enemy.classname!="player")
+	{
+		self.switchweapon = w_getbestweapon(self);
+		return;
+	}
+
+	local float rocket  ; rocket   =-1000;
+	local float nex     ; nex      =-1000;
+	local float hagar   ; hagar    =-1000;
+	local float grenade ; grenade  =-1000;
+	local float electro ; electro  =-1000;
+	local float crylink ; crylink  =-1000;
+	local float uzi     ; uzi      =-1000;
+	local float shotgun ; shotgun  =-1000;
+	local float laser   ; laser    =-1000;
+	local float bestscore; bestscore = 0;
+	local float bestweapon; bestweapon=self.switchweapon;
+	local float distance; distance=bound(10,vlen(self.origin-self.enemy.origin)-200,10000);
+	local float maxdelaytime=0.5;
+	local float spreadpenalty=10;
+	local float distancefromfloor;
+	traceline(self.enemy.origin,self.enemy.origin-'0 0 1000',TRUE,world);
+	distancefromfloor = self.enemy.origin_z - trace_endpos_z;
+	// Formula:
+	//	(Damage/Sec * Weapon spefic change to get that damage)
+	//	*(Time to get to target * weapon specfic hitchange bonus) / (in a time of maxdelaytime)
+	//	*(Spread change of hit) // if it applies
+	//	*(Penality for target beeing in air)
+	if (client_hasweapon(self, WEP_ROCKET_LAUNCHER, TRUE, FALSE))
+		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))
+		nex = (cvar("g_balance_nex_damage")/cvar("g_balance_nex_refire")*1.0)
+			* (0.5);
+	if (client_hasweapon(self, WEP_HAGAR, TRUE, FALSE))
+		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))
+		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))
+		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))
+		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)*1.0
+			* bound(0,1/cvar("g_balance_crylink_primary_spread")/distance*spreadpenalty,1);
+	if (client_hasweapon(self, WEP_UZI, TRUE, FALSE))
+		uzi = (cvar("g_balance_uzi_sustained_damage")/cvar("g_balance_uzi_sustained_refire")*1.0)
+			* bound(0,1/cvar("g_balance_uzi_sustained_spread")/distance*spreadpenalty,1)*0.5;
+	if (client_hasweapon(self, WEP_SHOTGUN, TRUE, FALSE))
+		shotgun = (cvar("g_balance_shotgun_primary_damage")*cvar("g_balance_shotgun_primary_bullets")/cvar("g_balance_shotgun_primary_refire")*1.0)
+			* bound(0,1/cvar("g_balance_shotgun_primary_spread")/distance*spreadpenalty,1);
+	if (client_hasweapon(self, WEP_LASER, FALSE, FALSE))
+		laser = (cvar("g_balance_laser_damage")/cvar("g_balance_laser_refire")*1.0)
+			* bound(0,cvar("g_balance_laser_speed")/distance*0.2*maxdelaytime,1);
+	if((self.enemy.flags & FL_ONGROUND)==FALSE){
+		rocket = rocket   * (1-bound(0, distancefromfloor/cvar("g_balance_rocketlauncher_radius"         ),0.9)); //slight bigger change
+		grenade = grenade * (1-bound(0,distancefromfloor/cvar("g_balance_grenadelauncher_primary_radius"),0.95));
+		electro = electro * (1-bound(0,distancefromfloor/cvar("g_balance_electro_primary_radius"        ),0.95));
+		laser = laser     * (1-bound(0,distancefromfloor/cvar("g_balance_laser_radius"                  ),0.95));
+	}
+/*
+	dprint("Floor distance: ",ftos(distancefromfloor),"\n");
+	dprint("Rocket: " , ftos(rocket  ), "\n");
+	dprint("Nex: "    , ftos(nex     ), "\n");
+	dprint("Hagar: "  , ftos(hagar   ), "\n");
+	dprint("Grenade: ", ftos(grenade ), "\n");
+	dprint("Electro: ", ftos(electro ), "\n");
+	dprint("Crylink: ", ftos(crylink ), "\n");
+	dprint("Uzi: "    , ftos(uzi     ), "\n");
+	dprint("Shotgun :", ftos(shotgun ), "\n");
+	dprint("Laser   :", ftos(laser   ), "\n\n");
+*/
+	if (rocket  > bestscore){ bestscore = rocket  ; bestweapon = WEP_ROCKET_LAUNCHER  ;}
+	if (nex     > bestscore){ bestscore = nex     ; bestweapon = WEP_NEX              ;}
+	if (hagar   > bestscore){ bestscore = hagar   ; bestweapon = WEP_HAGAR            ;}
+	if (grenade > bestscore){ bestscore = grenade ; bestweapon = WEP_GRENADE_LAUNCHER ;}
+	if (electro > bestscore){ bestscore = electro ; bestweapon = WEP_ELECTRO          ;}
+	if (crylink > bestscore){ bestscore = crylink ; bestweapon = WEP_CRYLINK          ;}
+	if (uzi     > bestscore){ bestscore = uzi     ; bestweapon = WEP_UZI              ;}
+	if (shotgun > bestscore){ bestscore = shotgun ; bestweapon = WEP_SHOTGUN          ;}
+	if (laser   > bestscore){ bestscore = laser   ; bestweapon = WEP_LASER            ;}
+
+	if(time>self.havocbot_chooseweapon_timer || self.havocbot_chooseweapon_lastbestscore<bestscore/10) //Or when the new damage is SOO much larger ! Or my gun runs out of ammo
+	{
+		self.havocbot_chooseweapon_timer=max(self.havocbot_chooseweapon_timer+cvar("g_balance_weaponswitchdelay")*120*(10-skill)*0.1,time);
+		if( self.havocbot_chooseweapon_lastbestscore*1.5<bestscore*bound(1,1+(skill*skill)*0.01,2))
+		{
+			self.switchweapon = bestweapon; 
+			self.havocbot_chooseweapon_lastbestscore=bestscore;
+		}
+	}
 };
 
 .float nextaim;
@@ -208,9 +405,20 @@
 		weapon_action(self.weapon, WR_AIM);
 	else if (self.goalcurrent)
 	{
-		local vector v;
-		v = self.goalcurrent.origin - self.origin;
-		//v = self.velocity;
+		local vector now,v,next;//,heading;
+		local float distance,skillblend,distanceblend;
+		now = self.goalcurrent.origin - self.origin;
+		distance = vlen(now);
+		//heading = self.velocity;
+		//dprint(self.goalstack01.classname,etos(self.goalstack01),"\n");
+		if(self.goalstack01 != self && self.goalstack01 != world)
+			next = self.goalstack01.origin - self.origin;
+		else
+			next = now;
+		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); 
+		v = (now * (distanceblend) + next * (1-distanceblend)) * (skillblend) + now * (1-skillblend);
+		//v = now * (distanceblend) + next * (1-distanceblend);
 		if (self.waterlevel < 2)
 			v_z = 0;
 		//dprint("walk at:", vtos(v), "\n");
@@ -224,5 +432,7 @@
 {
 	self.bot_ai = havocbot_ai;
 	// will be updated by think code
+	//Generate some random skill levels
+	self.havocbot_keyboardskill=random()-0.5;
 	havocbot_chooserole();
 }

Modified: branches/nexuiz-2.0/data/qcsrc/server/miscfunctions.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/miscfunctions.qc	2007-04-20 11:34:00 UTC (rev 2361)
+++ branches/nexuiz-2.0/data/qcsrc/server/miscfunctions.qc	2007-04-20 11:34:36 UTC (rev 2362)
@@ -187,11 +187,6 @@
 
 void relocate_spawnpoint()
 {
-	vector o;
-	o = self.origin;
-
-	setsize(self, PL_MIN, PL_MAX);
-
 	// nudge off the floor
 	setorigin(self, self.origin + '0 0 1');
 
@@ -202,9 +197,11 @@
 		return;
 	}
 
-	// drop the spawn point onto the floor
-	// NOTE: a later version might not do this any more
-	droptofloor();
+	if(cvar("g_spawnpoints_autodrop"))
+	{
+		setsize(self, PL_MIN, PL_MAX);
+		droptofloor();
+	}
 }
 
 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.




More information about the nexuiz-commits mailing list