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

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Wed Sep 23 06:28:19 EDT 2009


Author: div0
Date: 2009-09-23 06:28:19 -0400 (Wed, 23 Sep 2009)
New Revision: 7880

Added:
   branches/nexuiz-2.0/data/qcsrc/server/bot/
Removed:
   branches/nexuiz-2.0/data/qcsrc/server/bots.qc
   branches/nexuiz-2.0/data/qcsrc/server/bots_scripting.qc
   branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc
   branches/nexuiz-2.0/data/qcsrc/server/havocbot_ctf.qc
   branches/nexuiz-2.0/data/qcsrc/server/havocbot_ons.qc
   branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc
Modified:
   branches/nexuiz-2.0/.patchsets
   branches/nexuiz-2.0/data/physicsQ.cfg
   branches/nexuiz-2.0/data/qcsrc/server/progs.src
   branches/nexuiz-2.0/data/qcsrc/server/w_electro.qc
   branches/nexuiz-2.0/data/qcsrc/server/w_rocketlauncher.qc
   branches/nexuiz-2.0/data/weapons.cfg
   branches/nexuiz-2.0/data/weaponsHavoc.cfg
   branches/nexuiz-2.0/server/rcon2irc/rcon2irc.pl
   branches/nexuiz-2.0/server/server.cfg
Log:
r7849 | div0 | 2009-09-20 07:04:57 -0400 (Sun, 20 Sep 2009) | 2 lines
friction is 4, not 5
r7851 | mand1nga | 2009-09-20 17:43:29 -0400 (Sun, 20 Sep 2009) | 1 line
Major reorganization of bots code (not finished yet)
r7852 | div0 | 2009-09-21 02:39:34 -0400 (Mon, 21 Sep 2009) | 2 lines
improve RL
r7853 | div0 | 2009-09-21 02:48:12 -0400 (Mon, 21 Sep 2009) | 3 lines
mand1nga really shouldn't do a revert-fight against LordHavoc, as LordHavoc can revoke svn access and mand1nga can't :)
bring the non-array lag function handling back, as it compiles to way faster code and bots cause enough of a performance hit already
r7854 | samual | 2009-09-21 04:14:57 -0400 (Mon, 21 Sep 2009) | 1 line
Add vcproject files to Nexuiz qcsrc - todo: add compile support with fteqcc
r7855 | div0 | 2009-09-21 08:32:26 -0400 (Mon, 21 Sep 2009) | 2 lines
fix for weird IRC clients
r7856 | div0 | 2009-09-21 08:36:52 -0400 (Mon, 21 Sep 2009) | 2 lines
fix one more place wiht color code
r7857 | div0 | 2009-09-21 08:49:11 -0400 (Mon, 21 Sep 2009) | 2 lines
recommend (commented out) my ban sync provider URI in server.cfg
r7858 | div0 | 2009-09-21 09:09:24 -0400 (Mon, 21 Sep 2009) | 2 lines
fix think function call for electro


Modified: branches/nexuiz-2.0/.patchsets
===================================================================
--- branches/nexuiz-2.0/.patchsets	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/.patchsets	2009-09-23 10:28:19 UTC (rev 7880)
@@ -1,2 +1,2 @@
 master = svn://svn.icculus.org/nexuiz/trunk
-revisions_applied = 1-7563,7565-7586,7589-7589,7592-7592,7595-7595,7597-7597,7599-7602,7605-7610,7612-7615,7619-7620,7623-7623,7626-7628,7630-7630,7644-7651,7656-7656,7658-7660,7663-7665,7670-7670,7672-7676,7678-7680,7686-7687,7689-7698,7701-7701,7703-7714,7717-7723,7731-7731,7735-7741,7744-7745,7752-7754,7756-7758,7761-7764,7771-7773,7775-7775,7778-7778,7781-7788,7795-7816,7818-7834,7836-7838,7840-7848
+revisions_applied = 1-7563,7565-7586,7589-7589,7592-7592,7595-7595,7597-7597,7599-7602,7605-7610,7612-7615,7619-7620,7623-7623,7626-7628,7630-7630,7644-7651,7656-7656,7658-7660,7663-7665,7670-7670,7672-7676,7678-7680,7686-7687,7689-7698,7701-7701,7703-7714,7717-7723,7731-7731,7735-7741,7744-7745,7752-7754,7756-7758,7761-7764,7771-7773,7775-7775,7778-7778,7781-7788,7795-7816,7818-7834,7836-7838,7840-7849,7851-7858

Modified: branches/nexuiz-2.0/data/physicsQ.cfg
===================================================================
--- branches/nexuiz-2.0/data/physicsQ.cfg	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/physicsQ.cfg	2009-09-23 10:28:19 UTC (rev 7880)
@@ -5,7 +5,7 @@
 sv_accelerate 10
 sv_airaccelerate 106.66666666666666666666
 // it is 10 in Quake 1, but the Nexuiz player physics code does not 100% match an oddity of Quake 1, but matches Quake 2 and 3 more
-sv_friction 5
+sv_friction 4
 edgefriction 1
 sv_stepheight 18
 sv_jumpvelocity 270

Copied: branches/nexuiz-2.0/data/qcsrc/server/bot (from rev 7858, trunk/data/qcsrc/server/bot)

Deleted: branches/nexuiz-2.0/data/qcsrc/server/bots.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/bots.qc	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/bots.qc	2009-09-23 10:28:19 UTC (rev 7880)
@@ -1,3119 +0,0 @@
-.float aistatus;
-float AI_STATUS_ROAMING				= 1;	// Bot is just crawling the map. No enemies at sight
-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/trigger_hurt ahead
-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
-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
-float AI_STATUS_JETPACK_FLYING			= 512;
-float AI_STATUS_JETPACK_LANDING			= 1024;
-
-// utilities for path debugging
-#ifdef DEBUG_TRACEWALK
-
-float DEBUG_NODE_SUCCESS	= 1;
-float DEBUG_NODE_WARNING	= 2;
-float DEBUG_NODE_FAIL		= 3;
-
-vector debuglastnode;
-
-void debugresetnodes()
-{
-	debuglastnode = '0 0 0';
-}
-
-void debugnode(vector node)
-{
-	if not(self.classname=="player")
-		return;
-
-	if(debuglastnode=='0 0 0')
-	{
-		debuglastnode = node;
-		return;
-	}
-
-	te_lightning2(world, node, debuglastnode);
-	debuglastnode = node;
-}
-
-void debugnodestatus(vector position, float status)
-{
-	vector color;
-
-	switch (status)
-	{
-		case DEBUG_NODE_SUCCESS:
-			color = '0 15 0';
-			break;
-		case DEBUG_NODE_WARNING:
-			color = '15 15 0';
-			break;
-		case DEBUG_NODE_FAIL:
-			color = '15 0 0';
-			break;
-		default:
-			color = '15 15 15';
-	}
-
-	te_customflash(position, 40,  2, color);
-}
-
-#endif
-
-// rough simulation of walking from one point to another to test if a path
-// can be traveled, used for waypoint linking and havocbot
-
-vector stepheightvec;
-float bot_navigation_movemode;
-float navigation_testtracewalk;
-float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode)
-{
-	local vector org;
-	local vector move;
-	local vector dir;
-	local float dist;
-	local float totaldist;
-	local float stepdist;
-	local float yaw;
-	local float ignorehazards;
-	local float swimming;
-
-	#ifdef DEBUG_TRACEWALK
-		debugresetnodes();
-		debugnode(start);
-	#endif
-
-	move = end - start;
-	move_z = 0;
-	org = start;
-	dist = totaldist = vlen(move);
-	dir = normalize(move);
-	stepdist = 32;
-	ignorehazards = FALSE;
-
-	// Analyze starting point
-	traceline(start, start, MOVE_NORMAL, e);
-	if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
-		ignorehazards = TRUE;
-	else
-	{
-		traceline( start, start + '0 0 -65536', MOVE_NORMAL, e);
-		if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
-		{
-			ignorehazards = TRUE;
-			swimming = TRUE;
-		}
-	}
-	tracebox(start, m1, m2, start, MOVE_NOMONSTERS, e);
-	if (trace_startsolid)
-	{
-		// Bad start
-		#ifdef DEBUG_TRACEWALK
-			debugnodestatus(start, DEBUG_NODE_FAIL);
-		#endif
-		//print("tracewalk: ", vtos(start), " is a bad start\n");
-		return FALSE;
-	}
-
-	// Movement loop
-	yaw = vectoyaw(move);
-	move = end - org;
-	for (;;)
-	{
-		if (boxesoverlap(end, end, org + m1 + '-1 -1 -1', org + m2 + '1 1 1'))
-		{
-			// Succeeded
-			#ifdef DEBUG_TRACEWALK
-				debugnodestatus(org, DEBUG_NODE_SUCCESS);
-			#endif
-			//print("tracewalk: ", vtos(start), " can reach ", vtos(end), "\n");
-			return TRUE;
-		}
-		#ifdef DEBUG_TRACEWALK
-			debugnode(org);
-		#endif
-
-		if (dist <= 0)
-			break;
-		if (stepdist > dist)
-			stepdist = dist;
-		dist = dist - stepdist;
-		traceline(org, org, MOVE_NORMAL, e);
-		if (!ignorehazards)
-		{
-			if (trace_dpstartcontents & (DPCONTENTS_SLIME | DPCONTENTS_LAVA))
-			{
-				// hazards blocking path
-				#ifdef DEBUG_TRACEWALK
-					debugnodestatus(org, DEBUG_NODE_FAIL);
-				#endif
-				//print("tracewalk: ", vtos(start), " hits a hazard when trying to reach ", vtos(end), "\n");
-				return FALSE;
-			}
-		}
-		if (trace_dpstartcontents & DPCONTENTS_LIQUIDSMASK)
-		{
-			move = normalize(end - org);
-			tracebox(org, m1, m2, org + move * stepdist, movemode, e);
-
-			#ifdef DEBUG_TRACEWALK
-				debugnode(trace_endpos);
-			#endif
-
-			if (trace_fraction < 1)
-			{
-				swimming = TRUE;
-				org = trace_endpos - normalize(org - trace_endpos) * stepdist;
-				for(; org_z < end_z + self.maxs_z; org_z += stepdist)
-				{
-						#ifdef DEBUG_TRACEWALK
-							debugnode(org);
-						#endif
-				        if(pointcontents(org) == CONTENT_EMPTY)
-							break;
-				}
-
-				if not (pointcontents(org + '0 0 1') == CONTENT_EMPTY)
-				{
-					#ifdef DEBUG_TRACEWALK
-						debugnodestatus(org, DEBUG_NODE_FAIL);
-					#endif
-					return FALSE;
-					//print("tracewalk: ", vtos(start), " failed under water\n");
-				}
-				continue;
-
-			}
-			else
-				org = trace_endpos;
-		}
-		else
-		{
-			move = dir * stepdist + org;
-			tracebox(org, m1, m2, move, movemode, e);
-
-			#ifdef DEBUG_TRACEWALK
-				debugnode(trace_endpos);
-			#endif
-
-			// 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)
-				{
-					#ifdef DEBUG_TRACEWALK
-						debugnodestatus(trace_endpos, DEBUG_NODE_WARNING);
-					#endif
-
-					// 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
-					{
-						#ifdef DEBUG_TRACEWALK
-							debugnodestatus(trace_endpos, DEBUG_NODE_FAIL);
-						#endif
-						//print("tracewalk: ", vtos(start), " hit something when trying to reach ", vtos(end), "\n");
-						//te_explosion(trace_endpos);
-						//print(ftos(e.dphitcontentsmask), "\n");
-						return FALSE; // failed
-					}
-				}
-				else
-					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
-			// (this is the same logic as the Quake walkmove function used)
-			tracebox(move, m1, m2, move + '0 0 -65536', movemode, e);
-
-			// moved successfully
-			if(swimming)
-			{
-				local float c;
-				c = pointcontents(org + '0 0 1');
-				if not(c == CONTENT_WATER || c == CONTENT_LAVA || c == CONTENT_SLIME)
-					swimming = FALSE;
-				else
-					continue;
-			}
-
-			org = trace_endpos;
-		}
-	}
-
-	//print("tracewalk: ", vtos(start), " did not arrive at ", vtos(end), " but at ", vtos(org), "\n");
-
-	// moved but didn't arrive at the intended destination
-	#ifdef DEBUG_TRACEWALK
-		debugnodestatus(org, DEBUG_NODE_FAIL);
-	#endif
-
-	return FALSE;
-};
-
-
-// grenade tracing to decide the best pitch to fire at
-
-entity tracetossent;
-entity tracetossfaketarget;
-
-// traces multiple trajectories to find one that will impact the target
-// 'end' vector is the place it aims for,
-// returns TRUE only if it hit targ (don't target non-solid entities)
-vector findtrajectory_velocity;
-float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, float shotspeed, float shotspeedupward, float maxtime, float shotdelay, entity ignore)
-{
-	local float c, savesolid, shottime;
-	local vector dir, end, v;
-	if (shotspeed < 1)
-		return FALSE; // could cause division by zero if calculated
-	if (targ.solid < SOLID_BBOX) // SOLID_NOT and SOLID_TRIGGER
-		return FALSE; // could never hit it
-	if (!tracetossent)
-		tracetossent = spawn();
-	tracetossent.owner = ignore;
-	setsize(tracetossent, m1, m2);
-	savesolid = targ.solid;
-	targ.solid = SOLID_NOT;
-	shottime = ((vlen(targ.origin - org) / shotspeed) + shotdelay);
-	v = targ.velocity * shottime + targ.origin;
-	tracebox(targ.origin, targ.mins, targ.maxs, v, FALSE, targ);
-	v = trace_endpos;
-	end = v + (targ.mins + targ.maxs) * 0.5;
-	if ((vlen(end - org) / shotspeed + 0.2) > maxtime)
-	{
-		// out of range
-		targ.solid = savesolid;
-		return FALSE;
-	}
-
-	if (!tracetossfaketarget)
-		tracetossfaketarget = spawn();
-	tracetossfaketarget.solid = savesolid;
-	tracetossfaketarget.movetype = targ.movetype;
-	setmodel(tracetossfaketarget, targ.model); // no low precision
-	tracetossfaketarget.model = targ.model;
-	tracetossfaketarget.modelindex = targ.modelindex;
-	setsize(tracetossfaketarget, targ.mins, targ.maxs);
-	setorigin(tracetossfaketarget, v);
-
-	c = 0;
-	dir = normalize(end - org);
-	while (c < 10) // 10 traces
-	{
-		setorigin(tracetossent, org); // reset
-		tracetossent.velocity = findtrajectory_velocity = normalize(dir) * shotspeed + shotspeedupward * '0 0 1';
-		tracetoss(tracetossent, ignore); // love builtin functions...
-		if (trace_ent == tracetossfaketarget) // done
-		{
-			targ.solid = savesolid;
-
-			// make it disappear
-			tracetossfaketarget.solid = SOLID_NOT;
-			tracetossfaketarget.movetype = MOVETYPE_NONE;
-			tracetossfaketarget.model = "";
-			tracetossfaketarget.modelindex = 0;
-			// relink to remove it from physics considerations
-			setorigin(tracetossfaketarget, v);
-
-			return TRUE;
-		}
-		dir_z = dir_z + 0.1; // aim up a little more
-		c = c + 1;
-	}
-	targ.solid = savesolid;
-
-	// make it disappear
-	tracetossfaketarget.solid = SOLID_NOT;
-	tracetossfaketarget.movetype = MOVETYPE_NONE;
-	tracetossfaketarget.model = "";
-	tracetossfaketarget.modelindex = 0;
-	// relink to remove it from physics considerations
-	setorigin(tracetossfaketarget, v);
-
-	// leave a valid one even if it won't reach
-	findtrajectory_velocity = normalize(end - org) * shotspeed + shotspeedupward * '0 0 1';
-	return FALSE;
-};
-
-
-
-// Lag simulation
-#define LAG_QUEUE_LENGTH 4
-
-.void(float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4) lag_func;
-
-.float lag_time[LAG_QUEUE_LENGTH];
-.float lag_float1[LAG_QUEUE_LENGTH];
-.float lag_float2[LAG_QUEUE_LENGTH];
-.vector lag_vec1[LAG_QUEUE_LENGTH];
-.vector lag_vec2[LAG_QUEUE_LENGTH];
-.vector lag_vec3[LAG_QUEUE_LENGTH];
-.vector lag_vec4[LAG_QUEUE_LENGTH];
-.entity lag_entity1[LAG_QUEUE_LENGTH];
-
- void lag_update()
- {
-	float i;
-	for(i=0;i<LAG_QUEUE_LENGTH;++i)
-	{
-		if (self.lag_time[i])
-		if (time > self.lag_time[i])
-		{
-			self.lag_func(
-				self.lag_time[i], self.lag_float1[i], self.lag_float2[i],
-				self.lag_entity1[i], self.lag_vec1[i], self.lag_vec2[i], self.lag_vec3[i],
-				self.lag_vec4[i]
-			);
-			// Clear this position on the queue
-			self.(lag_time[i]) = 0;
-		}
-	}
- };
-
- float lag_additem(float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
- {
-	float i;
-	for(i=0;i<LAG_QUEUE_LENGTH;++i)
-	{
-		// Find a free position on the queue
-		if (self.lag_time[i] == 0)
-		{
-			self.(lag_time[i]) = t;
-			self.(lag_vec1[i]) = v1;
-			self.(lag_vec2[i]) = v2;
-			self.(lag_vec3[i]) = v3;
-			self.(lag_vec4[i]) = v4;
-			self.(lag_float1[i]) = f1;
-			self.(lag_float2[i]) = f2;
-			self.(lag_entity1[i]) = e1;
-			return TRUE;
-		}
-	}
- 	return FALSE;
- };
-
-// Random skill system
-.float bot_thinkskill;
-.float bot_mouseskill;
-.float bot_predictionskill;
-.float bot_offsetskill;
-
-
-// spawnfunc_waypoint navigation system
-
-// itemscore = (howmuchmoreIwant / howmuchIcanwant) / itemdistance
-// waypointscore = 0.7 / waypointdistance
-
-.entity wp00, wp01, wp02, wp03, wp04, wp05, wp06, wp07;
-.entity wp08, wp09, wp10, wp11, wp12, wp13, wp14, wp15;
-.entity wp16, wp17, wp18, wp19, wp20, wp21, wp22, wp23, wp24, wp25, wp26, wp27, wp28, wp29, wp30, wp31;
-.float wp00mincost, wp01mincost, wp02mincost, wp03mincost, wp04mincost, wp05mincost, wp06mincost, wp07mincost;
-.float wp08mincost, wp09mincost, wp10mincost, wp11mincost, wp12mincost, wp13mincost, wp14mincost, wp15mincost;
-.float wp16mincost, wp17mincost, wp18mincost, wp19mincost, wp20mincost, wp21mincost, wp22mincost, wp23mincost, wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
-.float wpfire, wpcost, wpconsidered;
-.float wpisbox;
-.float wpflags;
-.vector wpnearestpoint;
-.float wplinked;
-
-// stack of current goals (the last one of which may be an item or other
-// desirable object, the rest are typically waypoints to reach it)
-.entity goalcurrent, goalstack01, goalstack02, goalstack03;
-.entity goalstack04, goalstack05, goalstack06, goalstack07;
-.entity goalstack08, goalstack09, goalstack10, goalstack11;
-.entity goalstack12, goalstack13, goalstack14, goalstack15;
-.entity goalstack16, goalstack17, goalstack18, goalstack19;
-.entity goalstack20, goalstack21, goalstack22, goalstack23;
-.entity goalstack24, goalstack25, goalstack26, goalstack27;
-.entity goalstack28, goalstack29, goalstack30, goalstack31;
-
-.entity nearestwaypoint;
-.float nearestwaypointtimeout;
-
-// used during navigation_goalrating_begin/end sessions
-#define MAX_BESTGOALS 3
-float bestgoalswindex;
-float bestgoalsrindex;
-float navigation_bestrating;
-entity navigation_bestgoals[MAX_BESTGOALS];
-.float navigation_hasgoals;
-
-/////////////////////////////////////////////////////////////////////////////
-// spawnfunc_waypoint management
-/////////////////////////////////////////////////////////////////////////////
-
-// waypoints with this flag are not saved, they are automatically generated
-// waypoints like jump pads, teleporters, and items
-float WAYPOINTFLAG_GENERATED = 8388608;
-float WAYPOINTFLAG_ITEM = 4194304;
-float WAYPOINTFLAG_TELEPORT = 2097152;
-float WAYPOINTFLAG_NORELINK = 1048576;
-float WAYPOINTFLAG_PERSONAL = 524288;
-
-// add a new link to the spawnfunc_waypoint, replacing the furthest link it already has
-void waypoint_addlink(entity from, entity to)
-{
-	local float c;
-
-	if (from == to)
-		return;
-	if (from.wpflags & WAYPOINTFLAG_NORELINK)
-		return;
-
-	if (from.wp00 == to) return;if (from.wp01 == to) return;if (from.wp02 == to) return;if (from.wp03 == to) return;
-	if (from.wp04 == to) return;if (from.wp05 == to) return;if (from.wp06 == to) return;if (from.wp07 == to) return;
-	if (from.wp08 == to) return;if (from.wp09 == to) return;if (from.wp10 == to) return;if (from.wp11 == to) return;
-	if (from.wp12 == to) return;if (from.wp13 == to) return;if (from.wp14 == to) return;if (from.wp15 == to) return;
-	if (from.wp16 == to) return;if (from.wp17 == to) return;if (from.wp18 == to) return;if (from.wp19 == to) return;
-	if (from.wp20 == to) return;if (from.wp21 == to) return;if (from.wp22 == to) return;if (from.wp23 == to) return;
-	if (from.wp24 == to) return;if (from.wp25 == to) return;if (from.wp26 == to) return;if (from.wp27 == to) return;
-	if (from.wp28 == to) return;if (from.wp29 == to) return;if (from.wp30 == to) return;if (from.wp31 == to) return;
-
-	if (to.wpisbox || from.wpisbox)
-	{
-		// if either is a box we have to find the nearest points on them to
-		// calculate the distance properly
-		local vector v1, v2, m1, m2;
-		v1 = from.origin;
-		m1 = to.absmin;
-		m2 = to.absmax;
-		v1_x = bound(m1_x, v1_x, m2_x);
-		v1_y = bound(m1_y, v1_y, m2_y);
-		v1_z = bound(m1_z, v1_z, m2_z);
-		v2 = to.origin;
-		m1 = from.absmin;
-		m2 = from.absmax;
-		v2_x = bound(m1_x, v2_x, m2_x);
-		v2_y = bound(m1_y, v2_y, m2_y);
-		v2_z = bound(m1_z, v2_z, m2_z);
-		v2 = to.origin;
-		c = vlen(v2 - v1);
-	}
-	else
-		c = vlen(to.origin - from.origin);
-
-	if (from.wp31mincost < c) return;
-	if (from.wp30mincost < c) {from.wp31 = to;from.wp31mincost = c;return;} from.wp31 = from.wp30;from.wp31mincost = from.wp30mincost;
-	if (from.wp29mincost < c) {from.wp30 = to;from.wp30mincost = c;return;} from.wp30 = from.wp29;from.wp30mincost = from.wp29mincost;
-	if (from.wp28mincost < c) {from.wp29 = to;from.wp29mincost = c;return;} from.wp29 = from.wp28;from.wp29mincost = from.wp28mincost;
-	if (from.wp27mincost < c) {from.wp28 = to;from.wp28mincost = c;return;} from.wp28 = from.wp27;from.wp28mincost = from.wp27mincost;
-	if (from.wp26mincost < c) {from.wp27 = to;from.wp27mincost = c;return;} from.wp27 = from.wp26;from.wp27mincost = from.wp26mincost;
-	if (from.wp25mincost < c) {from.wp26 = to;from.wp26mincost = c;return;} from.wp26 = from.wp25;from.wp26mincost = from.wp25mincost;
-	if (from.wp24mincost < c) {from.wp25 = to;from.wp25mincost = c;return;} from.wp25 = from.wp24;from.wp25mincost = from.wp24mincost;
-	if (from.wp23mincost < c) {from.wp24 = to;from.wp24mincost = c;return;} from.wp24 = from.wp23;from.wp24mincost = from.wp23mincost;
-	if (from.wp22mincost < c) {from.wp23 = to;from.wp23mincost = c;return;} from.wp23 = from.wp22;from.wp23mincost = from.wp22mincost;
-	if (from.wp21mincost < c) {from.wp22 = to;from.wp22mincost = c;return;} from.wp22 = from.wp21;from.wp22mincost = from.wp21mincost;
-	if (from.wp20mincost < c) {from.wp21 = to;from.wp21mincost = c;return;} from.wp21 = from.wp20;from.wp21mincost = from.wp20mincost;
-	if (from.wp19mincost < c) {from.wp20 = to;from.wp20mincost = c;return;} from.wp20 = from.wp19;from.wp20mincost = from.wp19mincost;
-	if (from.wp18mincost < c) {from.wp19 = to;from.wp19mincost = c;return;} from.wp19 = from.wp18;from.wp19mincost = from.wp18mincost;
-	if (from.wp17mincost < c) {from.wp18 = to;from.wp18mincost = c;return;} from.wp18 = from.wp17;from.wp18mincost = from.wp17mincost;
-	if (from.wp16mincost < c) {from.wp17 = to;from.wp17mincost = c;return;} from.wp17 = from.wp16;from.wp17mincost = from.wp16mincost;
-	if (from.wp15mincost < c) {from.wp16 = to;from.wp16mincost = c;return;} from.wp16 = from.wp15;from.wp16mincost = from.wp15mincost;
-	if (from.wp14mincost < c) {from.wp15 = to;from.wp15mincost = c;return;} from.wp15 = from.wp14;from.wp15mincost = from.wp14mincost;
-	if (from.wp13mincost < c) {from.wp14 = to;from.wp14mincost = c;return;} from.wp14 = from.wp13;from.wp14mincost = from.wp13mincost;
-	if (from.wp12mincost < c) {from.wp13 = to;from.wp13mincost = c;return;} from.wp13 = from.wp12;from.wp13mincost = from.wp12mincost;
-	if (from.wp11mincost < c) {from.wp12 = to;from.wp12mincost = c;return;} from.wp12 = from.wp11;from.wp12mincost = from.wp11mincost;
-	if (from.wp10mincost < c) {from.wp11 = to;from.wp11mincost = c;return;} from.wp11 = from.wp10;from.wp11mincost = from.wp10mincost;
-	if (from.wp09mincost < c) {from.wp10 = to;from.wp10mincost = c;return;} from.wp10 = from.wp09;from.wp10mincost = from.wp09mincost;
-	if (from.wp08mincost < c) {from.wp09 = to;from.wp09mincost = c;return;} from.wp09 = from.wp08;from.wp09mincost = from.wp08mincost;
-	if (from.wp07mincost < c) {from.wp08 = to;from.wp08mincost = c;return;} from.wp08 = from.wp07;from.wp08mincost = from.wp07mincost;
-	if (from.wp06mincost < c) {from.wp07 = to;from.wp07mincost = c;return;} from.wp07 = from.wp06;from.wp07mincost = from.wp06mincost;
-	if (from.wp05mincost < c) {from.wp06 = to;from.wp06mincost = c;return;} from.wp06 = from.wp05;from.wp06mincost = from.wp05mincost;
-	if (from.wp04mincost < c) {from.wp05 = to;from.wp05mincost = c;return;} from.wp05 = from.wp04;from.wp05mincost = from.wp04mincost;
-	if (from.wp03mincost < c) {from.wp04 = to;from.wp04mincost = c;return;} from.wp04 = from.wp03;from.wp04mincost = from.wp03mincost;
-	if (from.wp02mincost < c) {from.wp03 = to;from.wp03mincost = c;return;} from.wp03 = from.wp02;from.wp03mincost = from.wp02mincost;
-	if (from.wp01mincost < c) {from.wp02 = to;from.wp02mincost = c;return;} from.wp02 = from.wp01;from.wp02mincost = from.wp01mincost;
-	if (from.wp00mincost < c) {from.wp01 = to;from.wp01mincost = c;return;} from.wp01 = from.wp00;from.wp01mincost = from.wp00mincost;
-	from.wp00 = to;from.wp00mincost = c;return;
-};
-
-// fields you can query using prvm_global server to get some statistics about waypoint linking culling
-float relink_total, relink_walkculled, relink_pvsculled, relink_lengthculled;
-
-// relink this spawnfunc_waypoint
-// (precompile a list of all reachable waypoints from this spawnfunc_waypoint)
-// (SLOW!)
-void waypoint_think()
-{
-	local entity e;
-	local vector sv, sm1, sm2, ev, em1, em2, dv;
-
-	stepheightvec = cvar("sv_stepheight") * '0 0 1';
-	bot_navigation_movemode = ((cvar("bot_navigation_ignoreplayers")) ? MOVE_NOMONSTERS : MOVE_NORMAL);
-
-	//dprint("waypoint_think wpisbox = ", ftos(self.wpisbox), "\n");
-	sm1 = self.origin + self.mins;
-	sm2 = self.origin + self.maxs;
-	for(e = world; (e = find(e, classname, "waypoint")); )
-	{
-		if (boxesoverlap(self.absmin, self.absmax, e.absmin, e.absmax))
-		{
-			waypoint_addlink(self, e);
-			waypoint_addlink(e, self);
-		}
-		else
-		{
-			++relink_total;
-			if(!checkpvs(self.origin, e))
-			{
-				++relink_pvsculled;
-				continue;
-			}
-			sv = e.origin;
-			sv_x = bound(sm1_x, sv_x, sm2_x);
-			sv_y = bound(sm1_y, sv_y, sm2_y);
-			sv_z = bound(sm1_z, sv_z, sm2_z);
-			ev = self.origin;
-			em1 = e.origin + e.mins;
-			em2 = e.origin + e.maxs;
-			ev_x = bound(em1_x, ev_x, em2_x);
-			ev_y = bound(em1_y, ev_y, em2_y);
-			ev_z = bound(em1_z, ev_z, em2_z);
-			dv = ev - sv;
-			dv_z = 0;
-			if (vlen(dv) >= 1050) // max search distance in XY
-			{
-				++relink_lengthculled;
-				continue;
-			}
-			navigation_testtracewalk = 0;
-			if (!self.wpisbox)
-			{
-				tracebox(sv - PL_MIN_z * '0 0 1', PL_MIN, PL_MAX, sv, FALSE, self);
-				if (!trace_startsolid)
-				{
-					//dprint("sv deviation", vtos(trace_endpos - sv), "\n");
-					sv = trace_endpos + '0 0 1';
-				}
-			}
-			if (!e.wpisbox)
-			{
-				tracebox(ev - PL_MIN_z * '0 0 1', PL_MIN, PL_MAX, ev, FALSE, e);
-				if (!trace_startsolid)
-				{
-					//dprint("ev deviation", vtos(trace_endpos - ev), "\n");
-					ev = trace_endpos + '0 0 1';
-				}
-			}
-			//traceline(self.origin, e.origin, FALSE, world);
-			//if (trace_fraction == 1)
-			if (!self.wpisbox && tracewalk(self, sv, PL_MIN, PL_MAX, ev, MOVE_NOMONSTERS))
-				waypoint_addlink(self, e);
-			else
-				relink_walkculled += 0.5;
-			if (!e.wpisbox && tracewalk(e, ev, PL_MIN, PL_MAX, sv, MOVE_NOMONSTERS))
-				waypoint_addlink(e, self);
-			else
-				relink_walkculled += 0.5;
-		}
-	}
-	navigation_testtracewalk = 0;
-	self.wplinked = TRUE;
-};
-
-void waypoint_clearlinks(entity wp)
-{
-	// clear links to other waypoints
-	local float f;
-	f = 10000000;
-	wp.wp00 = wp.wp01 = wp.wp02 = wp.wp03 = wp.wp04 = wp.wp05 = wp.wp06 = wp.wp07 = world;wp.wp00mincost = wp.wp01mincost = wp.wp02mincost = wp.wp03mincost = wp.wp04mincost = wp.wp05mincost = wp.wp06mincost = wp.wp07mincost = f;
-	wp.wp08 = wp.wp09 = wp.wp10 = wp.wp11 = wp.wp12 = wp.wp13 = wp.wp14 = wp.wp15 = world;wp.wp08mincost = wp.wp09mincost = wp.wp10mincost = wp.wp11mincost = wp.wp12mincost = wp.wp13mincost = wp.wp14mincost = wp.wp15mincost = f;
-	wp.wp16 = wp.wp17 = wp.wp18 = wp.wp19 = wp.wp20 = wp.wp21 = wp.wp22 = wp.wp23 = world;wp.wp16mincost = wp.wp17mincost = wp.wp18mincost = wp.wp19mincost = wp.wp20mincost = wp.wp21mincost = wp.wp22mincost = wp.wp23mincost = f;
-	wp.wp24 = wp.wp25 = wp.wp26 = wp.wp27 = wp.wp28 = wp.wp29 = wp.wp30 = wp.wp31 = world;wp.wp24mincost = wp.wp25mincost = wp.wp26mincost = wp.wp27mincost = wp.wp28mincost = wp.wp29mincost = wp.wp30mincost = wp.wp31mincost = f;
-	wp.wplinked = FALSE;
-};
-
-// tell a spawnfunc_waypoint to relink
-void waypoint_schedulerelink(entity wp)
-{
-	if (wp == world)
-		return;
-	// TODO: add some sort of visible box in edit mode for box waypoints
-	if (cvar("g_waypointeditor"))
-	{
-		local vector m1, m2;
-		m1 = wp.mins;
-		m2 = wp.maxs;
-		setmodel(wp, "models/runematch/rune.mdl"); wp.effects = EF_LOWPRECISION;
-		setsize(wp, m1, m2);
-		if (wp.wpflags & WAYPOINTFLAG_ITEM)
-			wp.colormod = '1 0 0';
-		else if (wp.wpflags & WAYPOINTFLAG_GENERATED)
-			wp.colormod = '1 1 0';
-		else
-			wp.colormod = '1 1 1';
-	}
-	else
-		wp.model = "";
-	wp.wpisbox = vlen(wp.size) > 0;
-	wp.enemy = world;
-	if (!(wp.wpflags & WAYPOINTFLAG_PERSONAL))
-		wp.owner = world;
-	if (!(wp.wpflags & WAYPOINTFLAG_NORELINK))
-		waypoint_clearlinks(wp);
-	// schedule an actual relink on next frame
-	wp.think = waypoint_think;
-	wp.nextthink = time;
-	wp.effects = EF_LOWPRECISION;
-}
-
-// create a new spawnfunc_waypoint and automatically link it to other waypoints, and link
-// them back to it as well
-// (suitable for spawnfunc_waypoint editor)
-entity waypoint_spawn(vector m1, vector m2, float f)
-{
-	local entity w;
-	local vector org;
-	w = find(world, classname, "waypoint");
-
-	if not(f & WAYPOINTFLAG_PERSONAL)
-	while (w)
-	{
-		// if a matching spawnfunc_waypoint already exists, don't add a duplicate
-		if (boxesoverlap(m1, m2, w.absmin, w.absmax))
-			return w;
-		w = find(w, classname, "waypoint");
-	}
-
-	w = spawn();
-	w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
-	w.classname = "waypoint";
-	w.wpflags = f;
-	setorigin(w, (m1 + m2) * 0.5);
-	setsize(w, m1 - w.origin, m2 - w.origin);
-	if (vlen(w.size) > 0)
-		w.wpisbox = TRUE;
-
-	if(!(f & WAYPOINTFLAG_GENERATED))
-	if(!w.wpisbox)
-	{
-		traceline(w.origin + '0 0 1', w.origin + PL_MIN_z * '0 0 1' - '0 0 1', MOVE_NOMONSTERS, w);
-		if (trace_fraction < 1)
-			setorigin(w, trace_endpos - PL_MIN_z * '0 0 1');
-
-		// check if the start position is stuck
-		tracebox(w.origin, PL_MIN + '-1 -1 -1', PL_MAX + '1 1 1', w.origin, MOVE_NOMONSTERS, w);
-		if (trace_startsolid)
-		{
-			org = w.origin + '0 0 26';
-			tracebox(org, PL_MIN, PL_MAX, w.origin, MOVE_WORLDONLY, w);
-			if(trace_startsolid)
-			{
-				org = w.origin + '2 2 2';
-				tracebox(org, PL_MIN, PL_MAX, w.origin, MOVE_WORLDONLY, w);
-				if(trace_startsolid)
-				{
-					org = w.origin + '-2 -2 2';
-					tracebox(org, PL_MIN, PL_MAX, w.origin, MOVE_WORLDONLY, w);
-					if(trace_startsolid)
-					{
-						org = w.origin + '-2 2 2';
-						tracebox(org, PL_MIN, PL_MAX, w.origin, MOVE_WORLDONLY, w);
-						if(trace_startsolid)
-						{
-							org = w.origin + '2 -2 2';
-							tracebox(org, PL_MIN, PL_MAX, w.origin, MOVE_WORLDONLY, w);
-							if(trace_startsolid)
-							{
-								// this WP is in solid, refuse it
-								dprint("Killed a waypoint that was stuck in solid at ", vtos(org), "\n");
-								remove(w);
-								return world;
-							}
-						}
-					}
-				}
-			}
-			setorigin(w, org * 0.05 + trace_endpos * 0.95); // don't trust the trace fully
-		}
-
-		tracebox(w.origin, PL_MIN, PL_MAX, w.origin - '0 0 128', MOVE_WORLDONLY, w);
-		if(trace_startsolid)
-		{
-			dprint("Killed a waypoint that was stuck in solid ", vtos(w.origin), "\n");
-			remove(w);
-			return world;
-		}
-		if (!trace_inwater)
-		{
-			if(trace_fraction == 1)
-			{
-				dprint("Killed a waypoint that was stuck in air at ", vtos(w.origin), "\n");
-				remove(w);
-				return world;
-			}
-			trace_endpos_z += 0.1; // don't trust the trace fully
-//			dprint("Moved waypoint at ", vtos(w.origin), " by ", ftos(vlen(w.origin - trace_endpos)));
-//			dprint(" direction: ", vtos((trace_endpos - w.origin)), "\n");
-			setorigin(w, trace_endpos);
-		}
-	}
-
-	waypoint_clearlinks(w);
-	//waypoint_schedulerelink(w);
-
-	if (cvar("g_waypointeditor"))
-	{
-		m1 = w.mins;
-		m2 = w.maxs;
-		setmodel(w, "models/runematch/rune.mdl"); w.effects = EF_LOWPRECISION;
-		setsize(w, m1, m2);
-		if (w.wpflags & WAYPOINTFLAG_ITEM)
-			w.colormod = '1 0 0';
-		else if (w.wpflags & WAYPOINTFLAG_GENERATED)
-			w.colormod = '1 1 0';
-		else
-			w.colormod = '1 1 1';
-	}
-	else
-		w.model = "";
-
-	return w;
-};
-
-// spawnfunc_waypoint map entity
-void spawnfunc_waypoint()
-{
-	setorigin(self, self.origin);
-	// schedule a relink after other waypoints have had a chance to spawn
-	waypoint_clearlinks(self);
-	//waypoint_schedulerelink(self);
-};
-
-// remove a spawnfunc_waypoint, and schedule all neighbors to relink
-void waypoint_remove(entity e)
-{
-	// tell all linked waypoints that they need to relink
-	waypoint_schedulerelink(e.wp00);
-	waypoint_schedulerelink(e.wp01);
-	waypoint_schedulerelink(e.wp02);
-	waypoint_schedulerelink(e.wp03);
-	waypoint_schedulerelink(e.wp04);
-	waypoint_schedulerelink(e.wp05);
-	waypoint_schedulerelink(e.wp06);
-	waypoint_schedulerelink(e.wp07);
-	waypoint_schedulerelink(e.wp08);
-	waypoint_schedulerelink(e.wp09);
-	waypoint_schedulerelink(e.wp10);
-	waypoint_schedulerelink(e.wp11);
-	waypoint_schedulerelink(e.wp12);
-	waypoint_schedulerelink(e.wp13);
-	waypoint_schedulerelink(e.wp14);
-	waypoint_schedulerelink(e.wp15);
-	waypoint_schedulerelink(e.wp16);
-	waypoint_schedulerelink(e.wp17);
-	waypoint_schedulerelink(e.wp18);
-	waypoint_schedulerelink(e.wp19);
-	waypoint_schedulerelink(e.wp20);
-	waypoint_schedulerelink(e.wp21);
-	waypoint_schedulerelink(e.wp22);
-	waypoint_schedulerelink(e.wp23);
-	waypoint_schedulerelink(e.wp24);
-	waypoint_schedulerelink(e.wp25);
-	waypoint_schedulerelink(e.wp26);
-	waypoint_schedulerelink(e.wp27);
-	waypoint_schedulerelink(e.wp28);
-	waypoint_schedulerelink(e.wp29);
-	waypoint_schedulerelink(e.wp30);
-	waypoint_schedulerelink(e.wp31);
-	// and now remove the spawnfunc_waypoint
-	remove(e);
-};
-
-// empties the map of waypoints
-void waypoint_removeall()
-{
-	local entity head, next;
-	head = findchain(classname, "waypoint");
-	while (head)
-	{
-		next = head.chain;
-		remove(head);
-		head = next;
-	}
-};
-
-// tell all waypoints to relink
-// (is this useful at all?)
-void waypoint_schedulerelinkall()
-{
-	local entity head;
-	relink_total = relink_walkculled = relink_pvsculled = relink_lengthculled = 0;
-	head = findchain(classname, "waypoint");
-	while (head)
-	{
-		waypoint_schedulerelink(head);
-		head = head.chain;
-	}
-};
-
-// Load waypoint links from file
-float botframe_cachedwaypointlinks;
-float waypoint_load_links()
-{
-	local string filename, s;
-	local float file, tokens, c, found;
-	local entity wp_from, wp_to;
-	local vector wp_to_pos, wp_from_pos;
-	filename = strcat("maps/", mapname);
-	filename = strcat(filename, ".waypoints.cache");
-	file = fopen(filename, FILE_READ);
-
-	if (file < 0)
-	{
-		dprint("waypoint links load from ");
-		dprint(filename);
-		dprint(" failed\n");
-		return FALSE;
-	}
-
-	while (1)
-	{
-		s = fgets(file);
-		if (!s)
-			break;
-
-		tokens = tokenizebyseparator(s, "*");
-
-		if (tokens!=2)
-		{
-			// bad file format
-			fclose(file);
-			return FALSE;
-		}
-
-		wp_from_pos	= stov(argv(0));
-		wp_to_pos	= stov(argv(1));
-
-		// Search "from" waypoint
-		if(wp_from.origin!=wp_from_pos)
-		{
-			wp_from = findradius(wp_from_pos, 1);
-			found = FALSE;
-			while(wp_from)
-			{
-				if(vlen(wp_from.origin-wp_from_pos)<1)
-				if(wp_from.classname == "waypoint")
-				{
-					found = TRUE;
-					break;
-				}
-				wp_from = wp_from.chain;
-			}
-
-			if(!found)
-			{
-				// can't find that waypoint
-				fclose(file);
-				return FALSE;
-			}
-		}
-
-		// Search "to" waypoint
-		wp_to = findradius(wp_to_pos, 1);
-		found = FALSE;
-		while(wp_to)
-		{
-			if(vlen(wp_to.origin-wp_to_pos)<1)
-			if(wp_to.classname == "waypoint")
-			{
-				found = TRUE;
-				break;
-			}
-			wp_to = wp_to.chain;
-		}
-
-		if(!found)
-		{
-			// can't find that waypoint
-			fclose(file);
-			return FALSE;
-		}
-
-		++c;
-		waypoint_addlink(wp_from, wp_to);
-	}
-
-	fclose(file);
-
-	dprint("loaded ");
-	dprint(ftos(c));
-	dprint(" waypoint links from maps/");
-	dprint(mapname);
-	dprint(".waypoints.cache\n");
-
-	botframe_cachedwaypointlinks = TRUE;
-	return TRUE;
-};
-
-float botframe_loadedforcedlinks;
-void waypoint_load_links_hardwired()
-{
-	local string filename, s;
-	local float file, tokens, c, found;
-	local entity wp_from, wp_to;
-	local vector wp_to_pos, wp_from_pos;
-	filename = strcat("maps/", mapname);
-	filename = strcat(filename, ".waypoints.hardwired");
-	file = fopen(filename, FILE_READ);
-
-	botframe_loadedforcedlinks = TRUE;
-
-	if (file < 0)
-	{
-		dprint("waypoint links load from ");
-		dprint(filename);
-		dprint(" failed\n");
-		return;
-	}
-
-	for (;;)
-	{
-		s = fgets(file);
-		if (!s)
-			break;
-
-		if(substring(s, 0, 2)=="//")
-			continue;
-
-		if(substring(s, 0, 1)=="#")
-			continue;
-
-		tokens = tokenizebyseparator(s, "*");
-
-		if (tokens!=2)
-			continue;
-
-		wp_from_pos	= stov(argv(0));
-		wp_to_pos	= stov(argv(1));
-
-		// Search "from" waypoint
-		if(wp_from.origin!=wp_from_pos)
-		{
-			wp_from = findradius(wp_from_pos, 1);
-			found = FALSE;
-			while(wp_from)
-			{
-				if(vlen(wp_from.origin-wp_from_pos)<1)
-				if(wp_from.classname == "waypoint")
-				{
-					found = TRUE;
-					break;
-				}
-				wp_from = wp_from.chain;
-			}
-
-			if(!found)
-			{
-				print(strcat("NOTICE: Can not find waypoint at ", vtos(wp_from_pos), ". Path skipped\n"));
-				continue;
-			}
-		}
-
-		// Search "to" waypoint
-		wp_to = findradius(wp_to_pos, 1);
-		found = FALSE;
-		while(wp_to)
-		{
-			if(vlen(wp_to.origin-wp_to_pos)<1)
-			if(wp_to.classname == "waypoint")
-			{
-				found = TRUE;
-				break;
-			}
-			wp_to = wp_to.chain;
-		}
-
-		if(!found)
-		{
-			print(strcat("NOTICE: Can not find waypoint at ", vtos(wp_to_pos), ". Path skipped\n"));
-			continue;
-		}
-
-		++c;
-		waypoint_addlink(wp_from, wp_to);
-	}
-
-	fclose(file);
-
-	dprint("loaded ");
-	dprint(ftos(c));
-	dprint(" waypoint links from maps/");
-	dprint(mapname);
-	dprint(".waypoints.hardwired\n");
-};
-
-
-// Save all waypoint links to a file
-void waypoint_save_links()
-{
-	local string filename, s;
-	local float file, c, i;
-	local entity w, link;
-	filename = strcat("maps/", mapname);
-	filename = strcat(filename, ".waypoints.cache");
-	file = fopen(filename, FILE_WRITE);
-	if (file < 0)
-	{
-		print("waypoint links save to ");
-		print(filename);
-		print(" failed\n");
-	}
-	c = 0;
-	w = findchain(classname, "waypoint");
-	while (w)
-	{
-		for(i=0;i<32;++i)
-		{
-			// :S
-			switch(i)
-			{
-				//	for i in $(seq -w 0 31); do echo "case $i:link = w.wp$i; break;"; done;
-				case 00:link = w.wp00; break;
-				case 01:link = w.wp01; break;
-				case 02:link = w.wp02; break;
-				case 03:link = w.wp03; break;
-				case 04:link = w.wp04; break;
-				case 05:link = w.wp05; break;
-				case 06:link = w.wp06; break;
-				case 07:link = w.wp07; break;
-				case 08:link = w.wp08; break;
-				case 09:link = w.wp09; break;
-				case 10:link = w.wp10; break;
-				case 11:link = w.wp11; break;
-				case 12:link = w.wp12; break;
-				case 13:link = w.wp13; break;
-				case 14:link = w.wp14; break;
-				case 15:link = w.wp15; break;
-				case 16:link = w.wp16; break;
-				case 17:link = w.wp17; break;
-				case 18:link = w.wp18; break;
-				case 19:link = w.wp19; break;
-				case 20:link = w.wp20; break;
-				case 21:link = w.wp21; break;
-				case 22:link = w.wp22; break;
-				case 23:link = w.wp23; break;
-				case 24:link = w.wp24; break;
-				case 25:link = w.wp25; break;
-				case 26:link = w.wp26; break;
-				case 27:link = w.wp27; break;
-				case 28:link = w.wp28; break;
-				case 29:link = w.wp29; break;
-				case 30:link = w.wp30; break;
-				case 31:link = w.wp31; break;
-			}
-
-			if(link==world)
-				continue;
-
-			s = strcat(vtos(w.origin), "*", vtos(link.origin), "\n");
-			fputs(file, s);
-			++c;
-		}
-		w = w.chain;
-	}
-	fclose(file);
-	botframe_cachedwaypointlinks = TRUE;
-
-	print("saved ");
-	print(ftos(c));
-	print(" waypoints links to maps/");
-	print(mapname);
-	print(".waypoints.cache\n");
-};
-
-// save waypoints to gamedir/data/maps/mapname.waypoints
-void waypoint_saveall()
-{
-	local string filename, s;
-	local float file, c;
-	local entity w;
-	filename = strcat("maps/", mapname);
-	filename = strcat(filename, ".waypoints");
-	file = fopen(filename, FILE_WRITE);
-	if (file >= 0)
-	{
-		c = 0;
-		w = findchain(classname, "waypoint");
-		while (w)
-		{
-			if (!(w.wpflags & WAYPOINTFLAG_GENERATED))
-			{
-				s = strcat(vtos(w.origin + w.mins), "\n");
-				s = strcat(s, vtos(w.origin + w.maxs));
-				s = strcat(s, "\n");
-				s = strcat(s, ftos(w.wpflags));
-				s = strcat(s, "\n");
-				fputs(file, s);
-				c = c + 1;
-			}
-			w = w.chain;
-		}
-		fclose(file);
-		bprint("saved ");
-		bprint(ftos(c));
-		bprint(" waypoints to maps/");
-		bprint(mapname);
-		bprint(".waypoints\n");
-	}
-	else
-	{
-		bprint("waypoint save to ");
-		bprint(filename);
-		bprint(" failed\n");
-	}
-	waypoint_save_links();
-	botframe_loadedforcedlinks = FALSE;
-};
-
-// load waypoints from file
-float waypoint_loadall()
-{
-	local string filename, s;
-	local float file, cwp, cwb, fl;
-	local vector m1, m2;
-	cwp = 0;
-	cwb = 0;
-	filename = strcat("maps/", mapname);
-	filename = strcat(filename, ".waypoints");
-	file = fopen(filename, FILE_READ);
-	if (file >= 0)
-	{
-		while (1)
-		{
-			s = fgets(file);
-			if (!s)
-				break;
-			m1 = stov(s);
-			s = fgets(file);
-			if (!s)
-				break;
-			m2 = stov(s);
-			s = fgets(file);
-			if (!s)
-				break;
-			fl = stof(s);
-			waypoint_spawn(m1, m2, fl);
-			if (m1 == m2)
-				cwp = cwp + 1;
-			else
-				cwb = cwb + 1;
-		}
-		fclose(file);
-		dprint("loaded ");
-		dprint(ftos(cwp));
-		dprint(" waypoints and ");
-		dprint(ftos(cwb));
-		dprint(" wayboxes from maps/");
-		dprint(mapname);
-		dprint(".waypoints\n");
-	}
-	else
-	{
-		dprint("waypoint load from ");
-		dprint(filename);
-		dprint(" failed\n");
-	}
-	return cwp + cwb;
-};
-
-void waypoint_spawnforitem_force(entity e, vector org)
-{
-	local entity w;
-
-	// Fix the waypoint altitude if necessary
-	traceline(org, org + '0 0 -65535', TRUE, e);
-	if(
-		org_z - trace_endpos_z > PL_MAX_z - PL_MIN_z + 10 // If middle of entiy is above player heigth
-		|| org_z - trace_endpos_z < (PL_MAX_z - PL_MIN_z) * 0.5 // or below half player height
-	)
-		org_z = trace_endpos_z + PL_MAX_z - PL_MIN_z;
-
-	// don't spawn an item spawnfunc_waypoint if it already exists
-	w = findchain(classname, "waypoint");
-	while (w)
-	{
-		if (w.wpisbox)
-		{
-			if (boxesoverlap(org, org, w.absmin, w.absmax))
-			{
-				e.nearestwaypoint = w;
-				return;
-			}
-		}
-		else
-		{
-			if (vlen(w.origin - org) < 16)
-			{
-				e.nearestwaypoint = w;
-				return;
-			}
-		}
-		w = w.chain;
-	}
-	e.nearestwaypoint = waypoint_spawn(org, org, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_ITEM);
-}
-
-void waypoint_spawnforitem(entity e)
-{
-	if(!bot_waypoints_for_items)
-		return;
-
-	waypoint_spawnforitem_force(e, e.origin);
-};
-
-void waypoint_spawnforteleporter(entity e, vector destination, float timetaken)
-{
-	local entity w;
-	local entity dw;
-	w = waypoint_spawn(e.absmin, e.absmax, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_NORELINK);
-	dw = waypoint_spawn(destination, destination, WAYPOINTFLAG_GENERATED);
-	// one way link to the destination
-	w.wp00 = dw;
-	w.wp00mincost = timetaken; // this is just for jump pads
-	// the teleporter's nearest spawnfunc_waypoint is this one
-	// (teleporters are not goals, so this is probably useless)
-	e.nearestwaypoint = w;
-	e.nearestwaypointtimeout = time + 1000000000;
-};
-
-entity waypoint_spawnpersonal(vector position)
-{
-	entity w;
-
-	// drop the waypoint to a proper location:
-	//   first move it up by a player height
-	//   then move it down to hit the floor with player bbox size
-	traceline(position, position + '0 0 1' * (PL_MAX_z - PL_MIN_z), MOVE_NOMONSTERS, world);
-	tracebox(trace_endpos, PL_MIN, PL_MAX, trace_endpos + '0 0 -1024', MOVE_NOMONSTERS, world);
-	if(trace_fraction < 1)
-		position = trace_endpos;
-
-	w = waypoint_spawn(position, position, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_PERSONAL);
-	w.nearestwaypoint = world;
-	w.nearestwaypointtimeout = 0;
-	w.owner = self;
-
-	waypoint_schedulerelink(w);
-
-	return w;
-};
-
-/////////////////////////////////////////////////////////////////////////////
-// goal stack
-/////////////////////////////////////////////////////////////////////////////
-
-// completely empty the goal stack, used when deciding where to go
-void navigation_clearroute()
-{
-	//print("bot ", etos(self), " clear\n");
-	self.navigation_hasgoals = FALSE;
-	self.goalcurrent = world;
-	self.goalstack01 = world;
-	self.goalstack02 = world;
-	self.goalstack03 = world;
-	self.goalstack04 = world;
-	self.goalstack05 = world;
-	self.goalstack06 = world;
-	self.goalstack07 = world;
-	self.goalstack08 = world;
-	self.goalstack09 = world;
-	self.goalstack10 = world;
-	self.goalstack11 = world;
-	self.goalstack12 = world;
-	self.goalstack13 = world;
-	self.goalstack14 = world;
-	self.goalstack15 = world;
-	self.goalstack16 = world;
-	self.goalstack17 = world;
-	self.goalstack18 = world;
-	self.goalstack19 = world;
-	self.goalstack20 = world;
-	self.goalstack21 = world;
-	self.goalstack22 = world;
-	self.goalstack23 = world;
-	self.goalstack24 = world;
-	self.goalstack25 = world;
-	self.goalstack26 = world;
-	self.goalstack27 = world;
-	self.goalstack28 = world;
-	self.goalstack29 = world;
-	self.goalstack30 = world;
-	self.goalstack31 = world;
-};
-
-// add a new goal at the beginning of the stack
-// (in other words: add a new prerequisite before going to the later goals)
-void navigation_pushroute(entity e)
-{
-	//print("bot ", etos(self), " push ", etos(e), "\n");
-	self.goalstack31 = self.goalstack30;
-	self.goalstack30 = self.goalstack29;
-	self.goalstack29 = self.goalstack28;
-	self.goalstack28 = self.goalstack27;
-	self.goalstack27 = self.goalstack26;
-	self.goalstack26 = self.goalstack25;
-	self.goalstack25 = self.goalstack24;
-	self.goalstack24 = self.goalstack23;
-	self.goalstack23 = self.goalstack22;
-	self.goalstack22 = self.goalstack21;
-	self.goalstack21 = self.goalstack20;
-	self.goalstack20 = self.goalstack19;
-	self.goalstack19 = self.goalstack18;
-	self.goalstack18 = self.goalstack17;
-	self.goalstack17 = self.goalstack16;
-	self.goalstack16 = self.goalstack15;
-	self.goalstack15 = self.goalstack14;
-	self.goalstack14 = self.goalstack13;
-	self.goalstack13 = self.goalstack12;
-	self.goalstack12 = self.goalstack11;
-	self.goalstack11 = self.goalstack10;
-	self.goalstack10 = self.goalstack09;
-	self.goalstack09 = self.goalstack08;
-	self.goalstack08 = self.goalstack07;
-	self.goalstack07 = self.goalstack06;
-	self.goalstack06 = self.goalstack05;
-	self.goalstack05 = self.goalstack04;
-	self.goalstack04 = self.goalstack03;
-	self.goalstack03 = self.goalstack02;
-	self.goalstack02 = self.goalstack01;
-	self.goalstack01 = self.goalcurrent;
-	self.goalcurrent = e;
-};
-
-// remove first goal from stack
-// (in other words: remove a prerequisite for reaching the later goals)
-// (used when a spawnfunc_waypoint is reached)
-void navigation_poproute()
-{
-	//print("bot ", etos(self), " pop\n");
-	self.goalcurrent = self.goalstack01;
-	self.goalstack01 = self.goalstack02;
-	self.goalstack02 = self.goalstack03;
-	self.goalstack03 = self.goalstack04;
-	self.goalstack04 = self.goalstack05;
-	self.goalstack05 = self.goalstack06;
-	self.goalstack06 = self.goalstack07;
-	self.goalstack07 = self.goalstack08;
-	self.goalstack08 = self.goalstack09;
-	self.goalstack09 = self.goalstack10;
-	self.goalstack10 = self.goalstack11;
-	self.goalstack11 = self.goalstack12;
-	self.goalstack12 = self.goalstack13;
-	self.goalstack13 = self.goalstack14;
-	self.goalstack14 = self.goalstack15;
-	self.goalstack15 = self.goalstack16;
-	self.goalstack16 = self.goalstack17;
-	self.goalstack17 = self.goalstack18;
-	self.goalstack18 = self.goalstack19;
-	self.goalstack19 = self.goalstack20;
-	self.goalstack20 = self.goalstack21;
-	self.goalstack21 = self.goalstack22;
-	self.goalstack22 = self.goalstack23;
-	self.goalstack23 = self.goalstack24;
-	self.goalstack24 = self.goalstack25;
-	self.goalstack25 = self.goalstack26;
-	self.goalstack26 = self.goalstack27;
-	self.goalstack27 = self.goalstack28;
-	self.goalstack28 = self.goalstack29;
-	self.goalstack29 = self.goalstack30;
-	self.goalstack30 = self.goalstack31;
-	self.goalstack31 = world;
-};
-
-// find the spawnfunc_waypoint near a dynamic goal such as a dropped weapon
-entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
-{
-	local entity waylist, w, best;
-	local float dist, bestdist;
-	local vector v, org, pm1, pm2;
-	pm1 = ent.origin + PL_MIN;
-	pm2 = ent.origin + PL_MAX;
-	waylist = findchain(classname, "waypoint");
-
-	// do two scans, because box test is cheaper
-	w = waylist;
-	while (w)
-	{
-		// if object is touching spawnfunc_waypoint
-		if(w != ent)
-			if (boxesoverlap(pm1, pm2, w.absmin, w.absmax))
-				return w;
-		w = w.chain;
-	}
-
-	org = ent.origin + (ent.mins_z - PL_MIN_z) * '0 0 1';
-	if(ent.tag_entity)
-		org = org + ent.tag_entity.origin;
-	if (navigation_testtracewalk)
-		te_plasmaburn(org);
-
-	best = world;
-	bestdist = 1050;
-
-	// box check failed, try walk
-	w = waylist;
-	while (w)
-	{
-		// if object can walk from spawnfunc_waypoint
-		if(w != ent)
-		{
-			if (w.wpisbox)
-			{
-				local vector wm1, wm2;
-				wm1 = w.origin + w.mins;
-				wm2 = w.origin + w.maxs;
-				v_x = bound(wm1_x, org_x, wm2_x);
-				v_y = bound(wm1_y, org_y, wm2_y);
-				v_z = bound(wm1_z, org_z, wm2_z);
-			}
-			else
-				v = w.origin;
-			dist = vlen(v - org);
-			if (bestdist > dist)
-			{
-				traceline(v, org, TRUE, ent);
-				if (trace_fraction == 1)
-				{
-					if (walkfromwp)
-					{
-						//print("^1can I reach ", vtos(org), " from ", vtos(v), "?\n");
-						if (tracewalk(ent, v, PL_MIN, PL_MAX, org, bot_navigation_movemode))
-						{
-							bestdist = dist;
-							best = w;
-						}
-					}
-					else
-					{
-						if (tracewalk(ent, org, PL_MIN, PL_MAX, v, bot_navigation_movemode))
-						{
-							bestdist = dist;
-							best = w;
-						}
-					}
-				}
-			}
-		}
-		w = w.chain;
-	}
-	return best;
-}
-
-// finds the waypoints near the bot initiating a navigation query
-float navigation_markroutes_nearestwaypoints(entity waylist, float maxdist)
-{
-	local entity head;
-	local vector v, m1, m2, diff;
-	local float c;
-//	navigation_testtracewalk = TRUE;
-	c = 0;
-	head = waylist;
-	while (head)
-	{
-		if (!head.wpconsidered)
-		{
-			if (head.wpisbox)
-			{
-				m1 = head.origin + head.mins;
-				m2 = head.origin + head.maxs;
-				v = self.origin;
-				v_x = bound(m1_x, v_x, m2_x);
-				v_y = bound(m1_y, v_y, m2_y);
-				v_z = bound(m1_z, v_z, m2_z);
-			}
-			else
-				v = head.origin;
-			diff = v - self.origin;
-			diff_z = max(0, diff_z);
-			if (vlen(diff) < maxdist)
-			{
-				head.wpconsidered = TRUE;
-				if (tracewalk(self, self.origin, self.mins, self.maxs, v, bot_navigation_movemode))
-				{
-					head.wpnearestpoint = v;
-					head.wpcost = vlen(v - self.origin) + head.dmg;
-					head.wpfire = 1;
-					head.enemy = world;
-					c = c + 1;
-				}
-			}
-		}
-		head = head.chain;
-	}
-	//navigation_testtracewalk = FALSE;
-	return c;
-}
-
-// updates a path link if a spawnfunc_waypoint link is better than the current one
-void navigation_markroutes_checkwaypoint(entity w, entity wp, float cost2, vector p)
-{
-	local vector m1;
-	local vector m2;
-	local vector v;
-	if (wp.wpisbox)
-	{
-		m1 = wp.absmin;
-		m2 = wp.absmax;
-		v_x = bound(m1_x, p_x, m2_x);
-		v_y = bound(m1_y, p_y, m2_y);
-		v_z = bound(m1_z, p_z, m2_z);
-	}
-	else
-		v = wp.origin;
-	cost2 = cost2 + vlen(v - p);
-	if (wp.wpcost > cost2)
-	{
-		wp.wpcost = cost2;
-		wp.enemy = w;
-		wp.wpfire = 1;
-		wp.wpnearestpoint = v;
-	}
-};
-
-// queries the entire spawnfunc_waypoint network for pathes leading away from the bot
-void navigation_markroutes()
-{
-	local entity w, wp, waylist;
-	local float searching, cost, cost2;
-	local vector p;
-	w = waylist = findchain(classname, "waypoint");
-	while (w)
-	{
-		w.wpconsidered = FALSE;
-		w.wpnearestpoint = '0 0 0';
-		w.wpcost = 10000000;
-		w.wpfire = 0;
-		w.enemy = world;
-		w = w.chain;
-	}
-
-	// try a short range search for the nearest waypoints, and expand the search repeatedly if none are found
-	// as this search is expensive we will use lower values if the bot is on the air
-	local float i, increment, maxdistance;
-	if(self.flags & FL_ONGROUND)
-	{
-		increment = 750;
-		maxdistance = 50000;
-	}
-	else
-	{
-		increment = 500;
-		maxdistance = 1500;
-	}
-
-	for(i=increment;!navigation_markroutes_nearestwaypoints(waylist, i)&&i<maxdistance;i+=increment);
-
-	searching = TRUE;
-	while (searching)
-	{
-		searching = FALSE;
-		w = waylist;
-		while (w)
-		{
-			if (w.wpfire)
-			{
-				searching = TRUE;
-				w.wpfire = 0;
-				cost = w.wpcost;
-				p = w.wpnearestpoint;
-				wp = w.wp00;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp00mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp01;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp01mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp02;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp02mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp03;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp03mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp04;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp04mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp05;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp05mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp06;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp06mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp07;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp07mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp08;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp08mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp09;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp09mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp10;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp10mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp11;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp11mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp12;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp12mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp13;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp13mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp14;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp14mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp15;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp15mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp16;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp16mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp17;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp17mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp18;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp18mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp19;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp19mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp20;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp20mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp21;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp21mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp22;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp22mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp23;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp23mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp24;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp24mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp25;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp25mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp26;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp26mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp27;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp27mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp28;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp28mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp29;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp29mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp30;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp30mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				wp = w.wp31;if (wp){cost2 = cost + wp.dmg;if (wp.wpcost > cost2 + w.wp31mincost) navigation_markroutes_checkwaypoint(w, wp, cost2, p);
-				}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
-			}
-			w = w.chain;
-		}
-	}
-};
-
-void navigation_bestgoals_reset()
-{
-	local float i;
-
-	bestgoalswindex = 0;
-	bestgoalsrindex = 0;
-
-	for(i=0;i>MAX_BESTGOALS-1;++i)
-	{
-		navigation_bestgoals[i] = world;
-	}
-}
-
-void navigation_add_bestgoal(entity goal)
-{
-	if(bestgoalsrindex>0)
-	{
-		++bestgoalsrindex;
-
-		if(bestgoalsrindex==MAX_BESTGOALS)
-			bestgoalsrindex = 0;
-	}
-
-	if(bestgoalswindex==MAX_BESTGOALS)
-	{
-		bestgoalswindex=0;
-		if(bestgoalsrindex==0)
-			bestgoalsrindex=1;
-	}
-
-	navigation_bestgoals[bestgoalswindex] = goal;
-
-	++bestgoalswindex;
-}
-
-entity navigation_get_bestgoal()
-{
-	local entity ent;
-
-	ent = navigation_bestgoals[bestgoalsrindex];
-	navigation_bestgoals[bestgoalsrindex] = world;
-
-	++bestgoalsrindex;
-
-	if(bestgoalsrindex==MAX_BESTGOALS)
-		bestgoalsrindex = 0;
-
-	return ent;
-}
-
-// fields required for jetpack navigation
-.entity navigation_jetpack_goal;
-.vector navigation_jetpack_point;
-
-// 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;
-void navigation_routerating(entity e, float f, float rangebias)
-{
-	entity nwp;
-	if (!e)
-		return;
-
-	// 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;
-			}
-		}
-	}
-
-	//te_wizspike(e.origin);
-	//bprint(etos(e));
-	//bprint("\n");
-	// update the cached spawnfunc_waypoint link on a dynamic item entity
-	if(e.classname == "waypoint" && !(e.wpflags & WAYPOINTFLAG_PERSONAL))
-	{
-		nwp = e;
-	}
-	else
-	{
-		if (time > e.nearestwaypointtimeout)
-		{
-			e.nearestwaypoint = navigation_findnearestwaypoint(e, TRUE);
-
-			// TODO: Cleaner solution, probably handling this timeout from ctf.qc
-			if(e.classname=="item_flag_team")
-				e.nearestwaypointtimeout = time + 2;
-			else
-				e.nearestwaypointtimeout = time + random() * 3 + 5;
-		}
-		nwp = e.nearestwaypoint;
-	}
-
-	//dprint("-- checking ", e.classname, " (with cost ", ftos(nwp.wpcost), ")\n");
-	if (nwp)
-	if (nwp.wpcost < 10000000)
-	{
-		//te_wizspike(nwp.wpnearestpoint);
-	//	dprint(e.classname, " ", ftos(f), "/(1+", ftos((nwp.wpcost + vlen(e.origin - nwp.wpnearestpoint))), "/", ftos(rangebias), ") = ");
-		f = f * rangebias / (rangebias + (nwp.wpcost + vlen(e.origin - nwp.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);
-		}
-	}
-	//dprint("\n");
-};
-
-// adds an item to the the goal stack with the path to a given item
-float navigation_routetogoal(entity e, vector startposition)
-{
-	self.goalentity = e;
-
-	// if there is no goal, just exit
-	if (!e)
-		return FALSE;
-
-	self.navigation_hasgoals = TRUE;
-
-	// put the entity on the goal stack
-	navigation_pushroute(e);
-
-	if(g_jetpack)
-	if(e==self.navigation_jetpack_goal)
-		return TRUE;
-
-	// 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;
-
-	// see if there are waypoints describing a path to the item
-	if(e.classname != "waypoint" || (e.wpflags & WAYPOINTFLAG_PERSONAL))
-		e = e.nearestwaypoint;
-	else
-		e = e.enemy; // we already have added it, so...
-
-	if(e == world)
-		return FALSE;
-
-	for (;;)
-	{
-		// add the spawnfunc_waypoint to the path
-		navigation_pushroute(e);
-		e = e.enemy;
-
-		if(e==world)
-			break;
-	}
-
-	return FALSE;
-};
-
-void navigation_routetogoals()
-{
-	entity g1, g2;
-
-	navigation_clearroute();
-
-	g1 = navigation_get_bestgoal();
-	for(;;)
-	{
-		if(g2==world)
-			g2 = navigation_get_bestgoal();
-
-		if(g2==world)
-		{
-			navigation_routetogoal(g1, self.origin);
-			return;
-		}
-
-		if(navigation_routetogoal(g1, g2.origin))
-		{
-			g1 = g2;
-			g2 = world;
-			continue;
-		}
-
-		navigation_clearroute();
-		g1 = g2;
-		g2 = world;
-	}
-}
-
-// removes any currently touching waypoints from the goal stack
-// (this is how bots detect if they have reached a goal)
-.float lastteleporttime;
-
-void navigation_poptouchedgoals()
-{
-	local vector org, m1, m2;
-	org = self.origin;
-	m1 = org + self.mins;
-	m2 = org + self.maxs;
-
-	if(self.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
-	{
-		if(self.lastteleporttime>0)
-		if(time-self.lastteleporttime<0.15)
-		{
-			navigation_poproute();
-			return;
-		}
-	}
-
-	// Loose goal touching check when running
-	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)
-			{
-				// Detect personal waypoints
-				if(self.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
-				if(self.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && self.goalcurrent.owner==self)
-				{
-					self.aistatus &~= AI_STATUS_WAYPOINT_PERSONAL_GOING;
-					self.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
-				}
-
-				navigation_poproute();
-			}
-		}
-	}
-
-	while (self.goalcurrent && boxesoverlap(m1, m2, self.goalcurrent.absmin, self.goalcurrent.absmax))
-	{
-		// Detect personal waypoints
-		if(self.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
-		if(self.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL && self.goalcurrent.owner==self)
-		{
-			self.aistatus &~= AI_STATUS_WAYPOINT_PERSONAL_GOING;
-			self.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
-		}
-
-		navigation_poproute();
-	}
-}
-
-// begin a goal selection session (queries spawnfunc_waypoint network)
-void navigation_goalrating_start()
-{
-	self.navigation_jetpack_goal = world;
-	navigation_bestrating = -1;
-	self.navigation_hasgoals = FALSE;
-	navigation_bestgoals_reset();
-	navigation_markroutes();
-};
-
-// ends a goal selection session (updates goal stack to the best goal)
-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)
-	{
-		dprint(self.netname, " can't walk to any goal, going to a near waypoint\n");
-
-		entity head;
-
-		RandomSelection_Init();
-		head = findradius(self.origin,1000);
-		while(head)
-		{
-			if(head.classname=="waypoint")
-			if(!(head.wpflags & WAYPOINTFLAG_GENERATED))
-			if(vlen(self.origin-head.origin)>100)
-			if(checkpvs(self.view_ofs,head))
-				RandomSelection_Add(head, 0, string_null, 1 + (vlen(self.origin-head.origin)<500), 0);
-			head = head.chain;
-		}
-		if(RandomSelection_chosen_ent)
-			navigation_routetogoal(RandomSelection_chosen_ent, self.origin);
-
-		self.navigation_hasgoals = FALSE; // Reset this value
-	}
-};
-
-
-//////////////////////////////////////////////////////////////////////////////
-// general bot functions
-//////////////////////////////////////////////////////////////////////////////
-
-.float isbot; // true if this client is actually a bot
-
-float skill;
-entity bot_list;
-.entity nextbot;
-.string netname_freeme;
-.string playermodel_freeme;
-.string playerskin_freeme;
-
-float sv_maxspeed;
-.float createdtime;
-
-.float bot_preferredcolors;
-
-.float bot_attack;
-.float bot_dodge;
-.float bot_dodgerating;
-
-//.float bot_painintensity;
-.float bot_firetimer;
-//.float bot_oldhealth;
-.void() bot_ai;
-
-.entity bot_aimtarg;
-.float bot_aimlatency;
-.vector bot_aimselforigin;
-.vector bot_aimselfvelocity;
-.vector bot_aimtargorigin;
-.vector bot_aimtargvelocity;
-
-.float bot_pickup;
-.float(entity player, entity item) bot_pickupevalfunc;
-.float bot_pickupbasevalue;
-.float bot_canfire;
-.float bot_strategytime;
-
-// used for aiming currently
-// FIXME: make the weapon code use these and then replace the calculations here with a call to the weapon code
-vector shotorg;
-vector shotdir;
-
-.float bot_forced_team;
-.float bot_config_loaded;
-
-void bot_setnameandstuff()
-{
-	string readfile, s;
-	float file, tokens, prio;
-	entity p;
-
-	string bot_name, bot_model, bot_skin, bot_shirt, bot_pants;
-	string name, prefix, suffix;
-
- 	if(cvar("g_campaign"))
-	{
-		prefix = "";
-		suffix = "";
-	}
-	else
-	{
-		prefix = cvar_string("bot_prefix");
-		suffix = cvar_string("bot_suffix");
-	}
-
-	file = fopen(cvar_string("bot_config_file"), FILE_READ);
-
-	if(file < 0)
-		print(strcat("Error: Can not open the bot configuration file '",cvar_string("bot_config_file"),"'\n"));
-	else
-	{
-		RandomSelection_Init();
-		for(;;)
-		{
-			readfile = fgets(file);
-			if(!readfile)
-				break;
-			if(substring(readfile, 0, 2) == "//")
-				continue;
-			if(substring(readfile, 0, 1) == "#")
-				continue;
-			tokens = tokenizebyseparator(readfile, "\t");
-			s = argv(0);
-			prio = 1;
-			FOR_EACH_CLIENT(p)
-			{
-				if(strcat(prefix, s, suffix) == p.netname)
-				{
-					prio = 0;
-					break;
-				}
-			}
-			RandomSelection_Add(world, 0, readfile, 1, prio);
-		}
-		readfile = RandomSelection_chosen_string;
-		fclose(file);
-	}
-
-	tokens = tokenizebyseparator(readfile, "\t");
-	if(argv(0) != "") bot_name = argv(0);
-	else bot_name = "Bot";
-
-	if(argv(1) != "") bot_model = argv(1);
-	else bot_model = "marine";
-
-	if(argv(2) != "") bot_skin = argv(2);
-	else bot_skin = "0";
-
-	if(argv(3) != "" && stof(argv(3)) >= 0) bot_shirt = argv(3);
-	else bot_shirt = ftos(floor(random() * 15));
-
-	if(argv(4) != "" && stof(argv(4)) >= 0) bot_pants = argv(4);
-	else bot_pants = ftos(floor(random() * 15));
-
-	self.bot_forced_team = stof(argv(5));
-	self.bot_config_loaded = TRUE;
-
-	// this is really only a default, JoinBestTeam is called later
-	setcolor(self, stof(bot_shirt) * 16 + stof(bot_pants));
-	self.bot_preferredcolors = self.clientcolors;
-
-	// pick the name
-	if (cvar("bot_usemodelnames"))
-		name = bot_model;
-	else
-		name = bot_name;
-
-	// pick the model and skin
-	if(substring(bot_model, -4, 1) != ".")
-		bot_model = strcat(bot_model, ".zym");
-	self.playermodel = self.playermodel_freeme = strzone(strcat("models/player/", bot_model));
-	self.playerskin = self.playerskin_freeme = strzone(bot_skin);
-
-	self.netname = self.netname_freeme = strzone(strcat(prefix, name, suffix));
-};
-
-float bot_custom_weapon;
-float bot_distance_far;
-float bot_distance_close;
-
-float bot_weapons_far[WEP_LAST];
-float bot_weapons_mid[WEP_LAST];
-float bot_weapons_close[WEP_LAST];
-
-void bot_custom_weapon_priority_setup()
-{
-	local float tokens, i, c, w;
-
-	bot_custom_weapon = FALSE;
-
-	if(	cvar_string("bot_ai_custom_weapon_priority_far") == "" ||
-		cvar_string("bot_ai_custom_weapon_priority_mid") == "" ||
-		cvar_string("bot_ai_custom_weapon_priority_close") == "" ||
- 		cvar_string("bot_ai_custom_weapon_priority_distances") == ""
-	)
-		return;
-
-	// Parse distances
-	tokens = tokenizebyseparator(cvar_string("bot_ai_custom_weapon_priority_distances")," ");
-
-	if (tokens!=2)
-		return;
-
-	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));
-	}
-
-	// Initialize list of weapons
-	bot_weapons_far[0] = -1;
-	bot_weapons_mid[0] = -1;
-	bot_weapons_close[0] = -1;
-
-	// Parse far distance weapon priorities
-	tokens = tokenizebyseparator(cvar_string("bot_ai_custom_weapon_priority_far")," ");
-
-	c = 0;
-	for(i=0; i < tokens && c < WEP_COUNT; ++i){
-		w = stof(argv(i));
-		if ( w >= WEP_FIRST && w <= WEP_LAST) {
-			bot_weapons_far[c] = w;
-			++c;
-		}
-	}
-	if(c < WEP_COUNT)
-		bot_weapons_far[c] = -1;
-
-	// Parse mid distance weapon priorities
-	tokens = tokenizebyseparator(cvar_string("bot_ai_custom_weapon_priority_mid")," ");
-
-	c = 0;
-	for(i=0; i < tokens && c < WEP_COUNT; ++i){
-		w = stof(argv(i));
-		if ( w >= WEP_FIRST && w <= WEP_LAST) {
-			bot_weapons_mid[c] = w;
-			++c;
-		}
-	}
-	if(c < WEP_COUNT)
-		bot_weapons_mid[c] = -1;
-
-	// Parse close distance weapon priorities
-	tokens = tokenizebyseparator(cvar_string("bot_ai_custom_weapon_priority_close")," ");
-
-	c = 0;
-	for(i=0; i < tokens && i < WEP_COUNT; ++i){
-		w = stof(argv(i));
-		if ( w >= WEP_FIRST && w <= WEP_LAST) {
-			bot_weapons_close[c] = w;
-			++c;
-		}
-	}
-	if(c < WEP_COUNT)
-		bot_weapons_close[c] = -1;
-
-	bot_custom_weapon = TRUE;
-};
-
-
-void bot_endgame()
-{
-	local entity e;
-	//dprint("bot_endgame\n");
-	e = bot_list;
-	while (e)
-	{
-		setcolor(e, e.bot_preferredcolors);
-		e = e.nextbot;
-	}
-	// if dynamic waypoints are ever implemented, save them here
-};
-
-float bot_ignore_bots; // let bots not attack other bots (only works in non-teamplay)
-float bot_shouldattack(entity e)
-{
-	if (e.team == self.team)
-	{
-		if (e == self)
-			return FALSE;
-		if (teams_matter)
-		if (e.team != 0)
-			return FALSE;
-	}
-
-	if(teams_matter)
-	{
-		if(e.team==0)
-			return FALSE;
-	}
-	else if(bot_ignore_bots)
-		if(clienttype(e) == CLIENTTYPE_BOT)
-			return FALSE;
-
-	if (!e.takedamage)
-		return FALSE;
-	if (e.deadflag)
-		return FALSE;
-	if (e.BUTTON_CHAT)
-		return FALSE;
-	if(g_minstagib)
-	if(e.items & IT_STRENGTH)
-		return FALSE;
-	if(e.flags & FL_NOTARGET)
-		return FALSE;
-	return TRUE;
-};
-
-void bot_lagfunc(float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
-{
-	if(self.flags & FL_INWATER)
-	{
-		self.bot_aimtarg = world;
-		return;
-	}
-	self.bot_aimtarg = e1;
-	self.bot_aimlatency = self.ping; // FIXME?  Shouldn't this be in the lag item?
-	self.bot_aimselforigin = v1;
-	self.bot_aimselfvelocity = v2;
-	self.bot_aimtargorigin = v3;
-	self.bot_aimtargvelocity = v4;
-	if(skill <= 0)
-		self.bot_canfire = (random() < 0.8);
-	else if(skill <= 1)
-		self.bot_canfire = (random() < 0.9);
-	else if(skill <= 2)
-		self.bot_canfire = (random() < 0.95);
-	else
-		self.bot_canfire = 1;
-};
-
-.float bot_nextthink;
-.float bot_badaimtime;
-.float bot_aimthinktime;
-.float bot_prevaimtime;
-.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 bot_aimdir(vector v, float maxfiredeviation)
-{
-	local float dist, delta_t, blend;
-	local vector desiredang, diffang;
-
-	//dprint("aim ", self.netname, ": old:", vtos(self.v_angle));
-	// make sure v_angle is sane first
-	self.v_angle_y = self.v_angle_y - floor(self.v_angle_y / 360) * 360;
-	self.v_angle_z = 0;
-
-	// get the desired angles to aim at
-	//dprint(" at:", vtos(v));
-	v = normalize(v);
-	//te_lightning2(world, self.origin + self.view_ofs, self.origin + self.view_ofs + v * 200);
-	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+self.bot_offsetskill), 5) * cvar("bot_ai_aimskill_offset");
-	}
-	desiredang = vectoangles(v) + self.bot_badaimoffset;
-	//dprint(" desired:", vtos(desiredang));
-	if (desiredang_x >= 180)
-		desiredang_x = desiredang_x - 360;
-	desiredang_x = bound(-90, 0 - desiredang_x, 90);
-	desiredang_z = self.v_angle_z;
-	//dprint(" / ", vtos(desiredang));
-
-	//// pain throws off aim
-	//if (self.bot_painintensity)
-	//{
-	//	// shake from pain
-	//	desiredang = desiredang + randomvec() * self.bot_painintensity * 0.2;
-	//}
-
-	// calculate turn angles
-	diffang = (desiredang - self.bot_olddesiredang);
-	// wrap yaw turn
-	diffang_y = diffang_y - floor(diffang_y / 360) * 360;
-	if (diffang_y >= 180)
-		diffang_y = diffang_y - 360;
-	self.bot_olddesiredang = desiredang;
-	//dprint(" diff:", vtos(diffang));
-
-	delta_t = time-self.bot_prevaimtime;
-	self.bot_prevaimtime = time;
-	// Here we will try to anticipate the comming aiming direction
-	self.bot_1st_order_aimfilter= self.bot_1st_order_aimfilter
-		+ (diffang * (1 / delta_t)    - 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);
-
-	//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")
-	);
-
-	// calculate turn angles
-	diffang = desiredang - self.bot_mouseaim;
-	// wrap yaw turn
-	diffang_y = diffang_y - floor(diffang_y / 360) * 360;
-	if (diffang_y >= 180)
-		diffang_y = diffang_y - 360;
-	//dprint(" diff:", vtos(diffang));
-
-	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);
-
-	diffang = self.bot_mouseaim - desiredang;
-	// wrap yaw turn
-	diffang_y = diffang_y - floor(diffang_y / 360) * 360;
-	if (diffang_y >= 180)
-		diffang_y = diffang_y - 360;
-	desiredang = desiredang + diffang * bound(0,cvar("bot_ai_aimskill_think"),1);
-
-	// calculate turn angles
-	diffang = desiredang - self.v_angle;
-	// wrap yaw turn
-	diffang_y = diffang_y - floor(diffang_y / 360) * 360;
-	if (diffang_y >= 180)
-		diffang_y = diffang_y - 360;
-	//dprint(" diff:", vtos(diffang));
-
-	// 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") / bound(1,dist,1000);
-	blendrate = cvar("bot_ai_aimskill_blendrate");
-	r = max(fixedrate, blendrate);
-	//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(delta_t, r * delta_t * (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;
-	self.v_angle_y = self.v_angle_y - floor(self.v_angle_y / 360) * 360;
-	//dprint(" turn:", vtos(self.v_angle));
-
-	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);
-
-	// calculate turn angles again
-	//diffang = desiredang - self.v_angle;
-	//diffang_y = diffang_y - floor(diffang_y / 360) * 360;
-	//if (diffang_y >= 180)
-	//	diffang_y = diffang_y - 360;
-
-	//dprint("e ", vtos(diffang), " < ", ftos(maxfiredeviation), "\n");
-
-	// decide whether to fire this time
-	// 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)))
-	if (vlen(trace_endpos-shotorg) < 500+500*bound(0, skill, 10) || random()*random()>bound(0,skill*0.05,1))
-		self.bot_firetimer = time + bound(0.1, 0.5-skill*0.05, 0.5);
-	//traceline(shotorg,shotorg+shotdir*1000,FALSE,world);
-	//dprint(ftos(maxfiredeviation),"\n");
-	//dprint(" diff:", vtos(diffang), "\n");
-
-	return self.bot_canfire && (time < self.bot_firetimer);
-};
-
-vector bot_shotlead(vector targorigin, vector targvelocity, float shotspeed, float shotdelay)
-{
-	// 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);
-};
-
-float bot_aim(float shotspeed, float shotspeedupward, float maxshottime, float applygravity)
-{
-	local float f, r;
-	local vector v;
-	/*
-	eprint(self);
-	dprint("bot_aim(", ftos(shotspeed));
-	dprint(", ", ftos(shotspeedupward));
-	dprint(", ", ftos(maxshottime));
-	dprint(", ", ftos(applygravity));
-	dprint(");\n");
-	*/
-	shotspeed *= g_weaponspeedfactor;
-	shotspeedupward *= g_weaponspeedfactor;
-	if (!shotspeed)
-	{
-		dprint("bot_aim: WARNING: weapon ", W_Name(self.weapon), " shotspeed is zero!\n");
-		shotspeed = 1000000;
-	}
-	if (!maxshottime)
-	{
-		dprint("bot_aim: WARNING: weapon ", W_Name(self.weapon), " maxshottime is zero!\n");
-		maxshottime = 1;
-	}
-	makevectors(self.v_angle);
-	shotorg = self.origin + self.view_ofs;
-	shotdir = v_forward;
-	v = bot_shotlead(self.bot_aimtargorigin, self.bot_aimtargvelocity, shotspeed, self.bot_aimlatency);
-	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))
-			return FALSE;
-		f = bot_aimdir(findtrajectory_velocity - shotspeedupward * '0 0 1', r);
-	}
-	else
-	{
-		f = bot_aimdir(v - shotorg, r);
-		//dprint("AIM: ");dprint(vtos(self.bot_aimtargorigin));dprint(" + ");dprint(vtos(self.bot_aimtargvelocity));dprint(" * ");dprint(ftos(self.bot_aimlatency + vlen(self.bot_aimtargorigin - shotorg) / shotspeed));dprint(" = ");dprint(vtos(v));dprint(" : aimdir = ");dprint(vtos(normalize(v - shotorg)));dprint(" : ");dprint(vtos(shotdir));dprint("\n");
-		traceline(shotorg, shotorg + shotdir * 10000, FALSE, self);
-		if (trace_ent.takedamage)
-		if (trace_fraction < 1)
-		if (!bot_shouldattack(trace_ent))
-			return FALSE;
-		traceline(shotorg, self.bot_aimtargorigin, FALSE, self);
-		if (trace_fraction < 1)
-		if (trace_ent != self.enemy)
-		if (!bot_shouldattack(trace_ent))
-			return FALSE;
-	}
-	if (r > maxshottime * shotspeed)
-		return FALSE;
-	return f;
-};
-
-// TODO: move this painintensity code to the player damage code
-void bot_think()
-{
-	if (self.bot_nextthink > time)
-		return;
-
-	self.flags &~= FL_GODMODE;
-	if(cvar("bot_god"))
-		self.flags |= FL_GODMODE;
-
-	self.bot_nextthink = self.bot_nextthink + cvar("bot_ai_thinkinterval");
-	//if (self.bot_painintensity > 0)
-	//	self.bot_painintensity = self.bot_painintensity - (skill + 1) * 40 * frametime;
-
-	//self.bot_painintensity = self.bot_painintensity + self.bot_oldhealth - self.health;
-	//self.bot_painintensity = bound(0, self.bot_painintensity, 100);
-
-	if(time < game_starttime || ((cvar("g_campaign") && !campaign_bots_may_start)))
-	{
-		self.nextthink = time + 0.5;
-		return;
-	}
-
-	if (self.fixangle)
-	{
-		self.v_angle = self.angles;
-		self.v_angle_z = 0;
-		self.fixangle = FALSE;
-	}
-
-	self.dmg_take = 0;
-	self.dmg_save = 0;
-	self.dmg_inflictor = world;
-
-	// 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.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)
-
-	// clear buttons
-	self.BUTTON_ATCK = 0;
-	self.button1 = 0;
-	self.BUTTON_JUMP = 0;
-	self.BUTTON_ATCK2 = 0;
-	self.BUTTON_ZOOM = 0;
-	self.BUTTON_CROUCH = 0;
-	self.BUTTON_HOOK = 0;
-	self.BUTTON_INFO = 0;
-	self.button8 = 0;
-	self.BUTTON_CHAT = 0;
-	self.BUTTON_USE = 0;
-
-	// if dead, just wait until we can respawn
-	if (self.deadflag)
-	{
-		if (self.deadflag == DEAD_DEAD)
-		{
-			self.BUTTON_JUMP = 1; // press jump to respawn
-			self.bot_strategytime = 0;
-		}
-	}
-
-	// now call the current bot AI (havocbot for example)
-	self.bot_ai();
-};
-
-entity bot_strategytoken;
-float bot_strategytoken_taken;
-entity player_list;
-.entity nextplayer;
-void bot_relinkplayerlist()
-{
-	local entity e;
-	local entity prevbot;
-	player_count = 0;
-	currentbots = 0;
-	player_list = e = findchainflags(flags, FL_CLIENT);
-	bot_list = world;
-	prevbot = world;
-	while (e)
-	{
-		player_count = player_count + 1;
-		e.nextplayer = e.chain;
-		if (clienttype(e) == CLIENTTYPE_BOT)
-		{
-			if (prevbot)
-				prevbot.nextbot = e;
-			else
-			{
-				bot_list = e;
-				bot_list.nextbot = world;
-			}
-			prevbot = e;
-			currentbots = currentbots + 1;
-		}
-		e = e.chain;
-	}
-	dprint(strcat("relink: ", ftos(currentbots), " bots seen.\n"));
-	bot_strategytoken = bot_list;
-	bot_strategytoken_taken = TRUE;
-};
-
-void() havocbot_setupbot;
-float JoinBestTeam(entity pl, float only_return_best, float forcebestteam);
-
-void bot_clientdisconnect()
-{
-	if (clienttype(self) != CLIENTTYPE_BOT)
-		return;
-	if(self.netname_freeme)
-		strunzone(self.netname_freeme);
-	if(self.playermodel_freeme)
-		strunzone(self.playermodel_freeme);
-	if(self.playerskin_freeme)
-		strunzone(self.playerskin_freeme);
-	self.netname_freeme = string_null;
-	self.playermodel_freeme = string_null;
-	self.playerskin_freeme = string_null;
-}
-
-void bot_clientconnect()
-{
-	if (clienttype(self) != CLIENTTYPE_BOT)
-		return;
-	self.bot_preferredcolors = self.clientcolors;
-	self.bot_nextthink = time - random();
-	self.lag_func = bot_lagfunc;
-	self.isbot = TRUE;
-	self.createdtime = self.nextthink;
-
-	if(!self.bot_config_loaded) // This is needed so team overrider doesn't break between matches
-		bot_setnameandstuff();
-
-	if(self.bot_forced_team==1)
-		self.team = COLOR_TEAM1;
-	else if(self.bot_forced_team==2)
-		self.team = COLOR_TEAM2;
-	else if(self.bot_forced_team==3)
-		self.team = COLOR_TEAM3;
-	else if(self.bot_forced_team==4)
-		self.team = COLOR_TEAM4;
-	else
-		JoinBestTeam(self, FALSE, TRUE);
-
-	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()
-{
-	local entity oldself, bot;
-	bot = spawnclient();
-	if (bot)
-	{
-		currentbots = currentbots + 1;
-		oldself = self;
-		self = bot;
-		bot_setnameandstuff();
-		ClientConnect();
-		PutClientInServer();
-		self = oldself;
-	}
-	return bot;
-};
-
-void CheckAllowedTeams(entity for_whom); void GetTeamCounts(entity other); float c1, c2, c3, c4;
-void bot_removefromlargestteam()
-{
-	local float besttime, bestcount, thiscount;
-	local entity best, head;
-	CheckAllowedTeams(world);
-	GetTeamCounts(world);
-	head = findchainfloat(isbot, TRUE);
-	if (!head)
-		return;
-	best = head;
-	besttime = head.createdtime;
-	bestcount = 0;
-	while (head)
-	{
-		if(head.team == COLOR_TEAM1)
-			thiscount = c1;
-		else if(head.team == COLOR_TEAM2)
-			thiscount = c2;
-		else if(head.team == COLOR_TEAM3)
-			thiscount = c3;
-		else if(head.team == COLOR_TEAM4)
-			thiscount = c4;
-		else
-			thiscount = 0;
-		if (thiscount > bestcount)
-		{
-			bestcount = thiscount;
-			besttime = head.createdtime;
-			best = head;
-		}
-		else if (thiscount == bestcount && besttime < head.createdtime)
-		{
-			besttime = head.createdtime;
-			best = head;
-		}
-		head = head.chain;
-	}
-	currentbots = currentbots - 1;
-	dropclient(best);
-};
-
-void bot_removenewest()
-{
-	local float besttime;
-	local entity best, head;
-
-	if(teams_matter)
-	{
-		bot_removefromlargestteam();
-		return;
-	}
-
-	head = findchainfloat(isbot, TRUE);
-	if (!head)
-		return;
-	best = head;
-	besttime = head.createdtime;
-	while (head)
-	{
-		if (besttime < head.createdtime)
-		{
-			besttime = head.createdtime;
-			best = head;
-		}
-		head = head.chain;
-	}
-	currentbots = currentbots - 1;
-	dropclient(best);
-};
-
-float botframe_waypointeditorlightningtime;
-void botframe_showwaypointlinks()
-{
-	local entity player, head, w;
-	if (time < botframe_waypointeditorlightningtime)
-		return;
-	botframe_waypointeditorlightningtime = time + 0.5;
-	player = find(world, classname, "player");
-	while (player)
-	{
-		if (!player.isbot)
-		if (player.flags & FL_ONGROUND || player.waterlevel > WATERLEVEL_NONE)
-		{
-			//navigation_testtracewalk = TRUE;
-			head = navigation_findnearestwaypoint(player, FALSE);
-		//	print("currently selected WP is ", etos(head), "\n");
-			//navigation_testtracewalk = FALSE;
-			if (head)
-			{
-				w = head     ;if (w) te_lightning2(world, w.origin, player.origin);
-				w = head.wp00;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp01;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp02;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp03;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp04;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp05;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp06;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp07;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp08;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp09;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp10;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp11;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp12;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp13;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp14;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp15;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp16;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp17;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp18;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp19;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp20;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp21;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp22;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp23;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp24;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp25;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp26;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp27;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp28;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp29;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp30;if (w) te_lightning2(world, w.origin, head.origin);
-				w = head.wp31;if (w) te_lightning2(world, w.origin, head.origin);
-			}
-		}
-		player = find(player, classname, "player");
-	}
-};
-
-entity botframe_dangerwaypoint;
-void botframe_updatedangerousobjects(float maxupdate)
-{
-	local entity head, bot_dodgelist;
-	local vector m1, m2, v;
-	local float c, d, danger;
-	c = 0;
-	bot_dodgelist = findchainfloat(bot_dodge, TRUE);
-	botframe_dangerwaypoint = find(botframe_dangerwaypoint, classname, "waypoint");
-	while (botframe_dangerwaypoint != world)
-	{
-		danger = 0;
-		m1 = botframe_dangerwaypoint.mins;
-		m2 = botframe_dangerwaypoint.maxs;
-		head = bot_dodgelist;
-		while (head)
-		{
-			v = head.origin;
-			v_x = bound(m1_x, v_x, m2_x);
-			v_y = bound(m1_y, v_y, m2_y);
-			v_z = bound(m1_z, v_z, m2_z);
-			d = head.bot_dodgerating - vlen(head.origin - v);
-			if (d > 0)
-			{
-				traceline(head.origin, v, TRUE, world);
-				if (trace_fraction == 1)
-					danger = danger + d;
-			}
-			head = head.chain;
-		}
-		botframe_dangerwaypoint.dmg = danger;
-		c = c + 1;
-		if (c >= maxupdate)
-			break;
-		botframe_dangerwaypoint = find(botframe_dangerwaypoint, classname, "waypoint");
-	}
-};
-
-
-float botframe_spawnedwaypoints;
-float botframe_nextthink;
-float botframe_nextdangertime;
-
-float autoskill_nextthink;
-.float totalfrags_lastcheck;
-void autoskill(float factor)
-{
-	float bestbot;
-	float bestplayer;
-	entity head;
-
-	bestbot = -1;
-	bestplayer = -1;
-	FOR_EACH_PLAYER(head)
-	{
-		if(clienttype(head) == CLIENTTYPE_REAL)
-			bestplayer = max(bestplayer, head.totalfrags - head.totalfrags_lastcheck);
-		else
-			bestbot = max(bestbot, head.totalfrags - head.totalfrags_lastcheck);
-	}
-
-	dprint("autoskill: best player got ", ftos(bestplayer), ", ");
-	dprint("best bot got ", ftos(bestbot), "; ");
-	if(bestbot < 0 || bestplayer < 0)
-	{
-		dprint("not doing anything\n");
-		// don't return, let it reset all counters below
-	}
-	else if(bestbot <= bestplayer * factor - 2)
-	{
-		if(cvar("skill") < 17)
-		{
-			dprint("2 frags difference, increasing skill\n");
-			cvar_set("skill", ftos(cvar("skill") + 1));
-			bprint("^2SKILL UP!^7 Now at level ", ftos(cvar("skill")), "\n");
-		}
-	}
-	else if(bestbot >= bestplayer * factor + 2)
-	{
-		if(cvar("skill") > 0)
-		{
-			dprint("2 frags difference, decreasing skill\n");
-			cvar_set("skill", ftos(cvar("skill") - 1));
-			bprint("^1SKILL DOWN!^7 Now at level ", ftos(cvar("skill")), "\n");
-		}
-	}
-	else
-	{
-		dprint("not doing anything\n");
-		return;
-		// don't reset counters, wait for them to accumulate
-	}
-
-	FOR_EACH_PLAYER(head)
-		head.totalfrags_lastcheck = head.totalfrags;
-}
-
-float bot_cvar_nextthink;
-void bot_serverframe()
-{
-	float realplayers, bots, activerealplayers;
-	entity head;
-
-	if (intermission_running)
-		return;
-
-	if (time < 2)
-		return;
-
-	stepheightvec = cvar("sv_stepheight") * '0 0 1';
-	bot_navigation_movemode = ((cvar("bot_navigation_ignoreplayers")) ? MOVE_NOMONSTERS : MOVE_NORMAL);
-
-	if(time > autoskill_nextthink)
-	{
-		float a;
-		a = cvar("skill_auto");
-		if(a)
-			autoskill(a);
-		autoskill_nextthink = time + 5;
-	}
-
-	activerealplayers = 0;
-	realplayers = 0;
-
-	FOR_EACH_REALCLIENT(head)
-	{
-		if(head.classname == "player" || g_lms || g_arena)
-			++activerealplayers;
-		++realplayers;
-	}
-
-	// add/remove bots if needed to make sure there are at least
-	// minplayers+bot_number, or remove all bots if no one is playing
-	// But don't remove bots immediately on level change, as the real players
-	// usually haven't rejoined yet
-	bots_would_leave = FALSE;
-	if ((realplayers || cvar("bot_join_empty") || (currentbots > 0 && time < 5)))
-	{
-		float realminplayers, minplayers;
-		realminplayers = cvar("minplayers");
-		minplayers = max(0, floor(realminplayers));
-
-		float realminbots, minbots;
-		if(teamplay && cvar("bot_vs_human"))
-			realminbots = ceil(fabs(cvar("bot_vs_human")) * activerealplayers);
-		else
-			realminbots = cvar("bot_number");
-		minbots = max(0, floor(realminbots));
-
-		bots = min(max(minbots, minplayers - activerealplayers), maxclients - realplayers);
-		if(bots > minbots)
-			bots_would_leave = TRUE;
-	}
-	else
-	{
-		// if there are no players, remove bots
-		bots = 0;
-	}
-
-	bot_ignore_bots = cvar("bot_ignore_bots");
-
-	// only add one bot per frame to avoid utter chaos
-	if(time > botframe_nextthink)
-	{
-		//dprint(ftos(bots), " ? ", ftos(currentbots), "\n");
-		while (currentbots < bots)
-		{
-			if (bot_spawn() == world)
-			{
-				bprint("Can not add bot, server full.\n");
-				botframe_nextthink = time + 10;
-				break;
-			}
-		}
-		while (currentbots > bots)
-			bot_removenewest();
-	}
-
-	if(botframe_spawnedwaypoints)
-	{
-		if(cvar("waypoint_benchmark"))
-			localcmd("quit\n");
-	}
-
-	if (currentbots > 0 || cvar("g_waypointeditor"))
-	if (botframe_spawnedwaypoints)
-	{
-		if(botframe_cachedwaypointlinks)
-		{
-			if(!botframe_loadedforcedlinks)
-				waypoint_load_links_hardwired();
-		}
-		else
-		{
-			// TODO: Make this check cleaner
-			local entity wp = findchain(classname, "waypoint");
-			if(time - wp.nextthink > 10)
-				waypoint_save_links();
-		}
-	}
-	else
-	{
-		botframe_spawnedwaypoints = TRUE;
-		waypoint_loadall();
-		if(!waypoint_load_links())
-			waypoint_schedulerelinkall();
-	}
-
-	if (bot_list)
-	{
-		// cycle the goal token from one bot to the next each frame
-		// (this prevents them from all doing spawnfunc_waypoint searches on the same
-		//  frame, which causes choppy framerates)
-		if (bot_strategytoken_taken)
-		{
-			bot_strategytoken_taken = FALSE;
-			if (bot_strategytoken)
-				bot_strategytoken = bot_strategytoken.nextbot;
-			if (!bot_strategytoken)
-				bot_strategytoken = bot_list;
-		}
-
-		if (botframe_nextdangertime < time)
-		{
-			local float interval;
-			interval = cvar("bot_ai_dangerdetectioninterval");
-			if (botframe_nextdangertime < time - interval * 1.5)
-				botframe_nextdangertime = time;
-			botframe_nextdangertime = botframe_nextdangertime + interval;
-			botframe_updatedangerousobjects(cvar("bot_ai_dangerdetectionupdates"));
-		}
-	}
-
-	if (cvar("g_waypointeditor"))
-		botframe_showwaypointlinks();
-
-	if(time > bot_cvar_nextthink)
-	{
-		if(currentbots>0)
-			bot_custom_weapon_priority_setup();
-		bot_cvar_nextthink = time + 5;
-	}
-};
-
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(lag_time);
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(lag_float1);
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(lag_float2);
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(lag_vec1);
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(lag_vec2);
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(lag_vec3);
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(lag_vec4);
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(lag_entity1);

Deleted: branches/nexuiz-2.0/data/qcsrc/server/bots_scripting.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/bots_scripting.qc	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/bots_scripting.qc	2009-09-23 10:28:19 UTC (rev 7880)
@@ -1,1306 +0,0 @@
-.float bot_cmdqueuebuf_allocated;
-.float bot_cmdqueuebuf;
-.float bot_cmdqueuebuf_start;
-.float bot_cmdqueuebuf_end;
-
-void bot_clearqueue(entity bot)
-{
-	if(!bot.bot_cmdqueuebuf_allocated)
-		error("clearqueue but no queue allocated");
-	buf_del(bot.bot_cmdqueuebuf);
-	bot.bot_cmdqueuebuf_allocated = FALSE;
-	dprint("bot ", bot.netname, " queue cleared\n");
-}
-
-void bot_queuecommand(entity bot, string cmdstring)
-{
-	if(!bot.bot_cmdqueuebuf_allocated)
-	{
-		bot.bot_cmdqueuebuf = buf_create();
-		bot.bot_cmdqueuebuf_allocated = TRUE;
-	}
-
-	bufstr_set(bot.bot_cmdqueuebuf, bot.bot_cmdqueuebuf_end, cmdstring);
-	bot.bot_cmdqueuebuf_end += 1;
-}
-
-void bot_dequeuecommand(entity bot, float idx)
-{
-	if(!bot.bot_cmdqueuebuf_allocated)
-		error("dequeuecommand but no queue allocated");
-	if(idx < bot.bot_cmdqueuebuf_start)
-		error("dequeueing a command in the past");
-	if(idx >= bot.bot_cmdqueuebuf_end)
-		error("dequeueing a command in the future");
-	bufstr_set(bot.bot_cmdqueuebuf, idx, "");
-	if(idx == bot.bot_cmdqueuebuf_start)
-		bot.bot_cmdqueuebuf_start += 1;
-	if(bot.bot_cmdqueuebuf_start >= bot.bot_cmdqueuebuf_end)
-		bot_clearqueue(bot);
-}
-
-string bot_readcommand(entity bot, float idx)
-{
-	if(!bot.bot_cmdqueuebuf_allocated)
-		error("readcommand but no queue allocated");
-	if(idx < bot.bot_cmdqueuebuf_start)
-		error("reading a command in the past");
-	if(idx >= bot.bot_cmdqueuebuf_end)
-		error("reading a command in the future");
-	return bufstr_get(bot.bot_cmdqueuebuf, idx);
-}
-
-float bot_havecommand(entity bot, float idx)
-{
-	if(!bot.bot_cmdqueuebuf_allocated)
-		return 0;
-	if(idx < bot.bot_cmdqueuebuf_start)
-		return 0;
-	if(idx >= bot.bot_cmdqueuebuf_end)
-		return 0;
-	return 1;
-}
-
-#define MAX_BOT_PLACES 4
-.float bot_places_count;
-.entity bot_places[MAX_BOT_PLACES]; FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(bot_places);
-.string bot_placenames[MAX_BOT_PLACES]; FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(bot_placenames);
-entity bot_getplace(string placename)
-{
-	entity e;
-	if(substring(placename, 0, 1) == "@")
-	{
-		float i, p;
-		placename = substring(placename, 1, -1);
-		string s, s2;
-		for(i = 0; i < self.bot_places_count; ++i)
-			if(self.(bot_placenames[i]) == placename)
-				return self.(bot_places[i]);
-		// now: i == self.bot_places_count
-		s = s2 = cvar_string(placename);
-		p = strstrofs(s2, " ", 0);
-		if(p >= 0)
-		{
-			s = substring(s2, 0, p);
-			//print("places: ", placename, " -> ", cvar_string(placename), "\n");
-			cvar_set(placename, strcat(substring(s2, p+1, -1), " ", s));
-			//print("places: ", placename, " := ", cvar_string(placename), "\n");
-		}
-		e = find(world, targetname, s);
-		if(!e)
-			print("invalid place ", s, "\n");
-		if(i < MAX_BOT_PLACES)
-		{
-			self.(bot_placenames[i]) = strzone(placename);
-			self.(bot_places[i]) = e;
-			self.bot_places_count += 1;
-		}
-		return e;
-	}
-	else
-	{
-		e = find(world, targetname, placename);
-		if(!e)
-			print("invalid place ", s, "\n");
-		return e;
-	}
-}
-
-
-// NOTE: New commands should be added here. Do not forget to update BOT_CMD_COUNTER
-#define BOT_CMD_NULL			0
-#define BOT_CMD_PAUSE			1
-#define BOT_CMD_CONTINUE		2
-#define BOT_CMD_WAIT			3
-#define BOT_CMD_TURN			4
-#define BOT_CMD_MOVETO			5
-#define BOT_CMD_RESETGOAL		6	// Not implemented yet
-#define BOT_CMD_CC			7
-#define BOT_CMD_IF      		8
-#define BOT_CMD_ELSE    		9
-#define BOT_CMD_FI      		10
-#define BOT_CMD_RESETAIM   		11
-#define BOT_CMD_AIM			12
-#define BOT_CMD_PRESSKEY		13
-#define BOT_CMD_RELEASEKEY		14
-#define BOT_CMD_SELECTWEAPON		15
-#define BOT_CMD_IMPULSE			16
-#define BOT_CMD_WAIT_UNTIL		17
-#define BOT_CMD_MOVETOTARGET    18
-#define BOT_CMD_AIMTARGET       19
-#define BOT_CMD_BARRIER         20
-#define BOT_CMD_CONSOLE			21
-#define BOT_CMD_SOUND			22
-#define BOT_CMD_WHILE			23	// TODO: Not implemented yet
-#define BOT_CMD_WEND			24	// TODO: Not implemented yet
-#define BOT_CMD_CHASE			25	// TODO: Not implemented yet
-
-#define BOT_CMD_COUNTER			23	// Update this value if you add/remove a command
-
-// NOTE: Following commands should be implemented on the bot ai
-//		 If a new command should be handled by the target ai(s) please declare it here
-.float(vector) cmd_moveto;
-.float() cmd_resetgoal;
-
-//
-#define BOT_CMD_PARAMETER_NONE		0
-#define BOT_CMD_PARAMETER_FLOAT		1
-#define BOT_CMD_PARAMETER_STRING	2
-#define BOT_CMD_PARAMETER_VECTOR	3
-
-float bot_cmds_initialized;
-float bot_cmd_parm_type[BOT_CMD_COUNTER];
-string bot_cmd_string[BOT_CMD_COUNTER];
-
-// Bots command queue
-entity bot_cmd;	// global current command
-.entity bot_cmd_current; // current command of this bot
-
-.float is_bot_cmd;			// Tells if the entity is a bot command
-.float bot_cmd_index;			// Position of the command in the queue
-.float bot_cmd_type;			// If of command (see the BOT_CMD_* defines)
-.float bot_cmd_parm_float;		// Field to store a float parameter
-.string bot_cmd_parm_string;		// Field to store a string parameter
-.vector bot_cmd_parm_vector;		// Field to store a vector parameter
-
-float bot_barriertime;
-.float bot_barrier;
-
-.float bot_cmd_execution_index;		// Position in the queue of the command to be executed
-
-// Initialize global commands list
-// NOTE: New commands should be initialized here
-void bot_commands_init()
-{
-	bot_cmd_string[BOT_CMD_NULL] = "";
-	bot_cmd_parm_type[BOT_CMD_NULL] = BOT_CMD_PARAMETER_NONE;
-
-	bot_cmd_string[BOT_CMD_PAUSE] = "pause";
-	bot_cmd_parm_type[BOT_CMD_PAUSE] = BOT_CMD_PARAMETER_NONE;
-
-	bot_cmd_string[BOT_CMD_CONTINUE] = "continue";
-	bot_cmd_parm_type[BOT_CMD_CONTINUE] = BOT_CMD_PARAMETER_NONE;
-
-	bot_cmd_string[BOT_CMD_WAIT] = "wait";
-	bot_cmd_parm_type[BOT_CMD_WAIT] = BOT_CMD_PARAMETER_FLOAT;
-
-	bot_cmd_string[BOT_CMD_TURN] = "turn";
-	bot_cmd_parm_type[BOT_CMD_TURN] = BOT_CMD_PARAMETER_FLOAT;
-
-	bot_cmd_string[BOT_CMD_MOVETO] = "moveto";
-	bot_cmd_parm_type[BOT_CMD_MOVETO] = BOT_CMD_PARAMETER_VECTOR;
-
-	bot_cmd_string[BOT_CMD_MOVETOTARGET] = "movetotarget";
-	bot_cmd_parm_type[BOT_CMD_MOVETOTARGET] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmd_string[BOT_CMD_RESETGOAL] = "resetgoal";
-	bot_cmd_parm_type[BOT_CMD_RESETGOAL] = BOT_CMD_PARAMETER_NONE;
-
-	bot_cmd_string[BOT_CMD_CC] = "cc";
-	bot_cmd_parm_type[BOT_CMD_CC] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmd_string[BOT_CMD_IF] = "if";
-	bot_cmd_parm_type[BOT_CMD_IF] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmd_string[BOT_CMD_ELSE] = "else";
-	bot_cmd_parm_type[BOT_CMD_ELSE] = BOT_CMD_PARAMETER_NONE;
-
-	bot_cmd_string[BOT_CMD_FI] = "fi";
-	bot_cmd_parm_type[BOT_CMD_FI] = BOT_CMD_PARAMETER_NONE;
-
-	bot_cmd_string[BOT_CMD_RESETAIM] = "resetaim";
-	bot_cmd_parm_type[BOT_CMD_RESETAIM] = BOT_CMD_PARAMETER_NONE;
-
-	bot_cmd_string[BOT_CMD_AIM] = "aim";
-	bot_cmd_parm_type[BOT_CMD_AIM] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmd_string[BOT_CMD_AIMTARGET] = "aimtarget";
-	bot_cmd_parm_type[BOT_CMD_AIMTARGET] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmd_string[BOT_CMD_PRESSKEY] = "presskey";
-	bot_cmd_parm_type[BOT_CMD_PRESSKEY] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmd_string[BOT_CMD_RELEASEKEY] = "releasekey";
-	bot_cmd_parm_type[BOT_CMD_RELEASEKEY] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmd_string[BOT_CMD_SELECTWEAPON] = "selectweapon";
-	bot_cmd_parm_type[BOT_CMD_SELECTWEAPON] = BOT_CMD_PARAMETER_FLOAT;
-
-	bot_cmd_string[BOT_CMD_IMPULSE] = "impulse";
-	bot_cmd_parm_type[BOT_CMD_IMPULSE] = BOT_CMD_PARAMETER_FLOAT;
-
-	bot_cmd_string[BOT_CMD_WAIT_UNTIL] = "wait_until";
-	bot_cmd_parm_type[BOT_CMD_WAIT_UNTIL] = BOT_CMD_PARAMETER_FLOAT;
-
-	bot_cmd_string[BOT_CMD_BARRIER] = "barrier";
-	bot_cmd_parm_type[BOT_CMD_BARRIER] = BOT_CMD_PARAMETER_NONE;
-
-	bot_cmd_string[BOT_CMD_CONSOLE] = "console";
-	bot_cmd_parm_type[BOT_CMD_CONSOLE] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmd_string[BOT_CMD_SOUND] = "sound";
-	bot_cmd_parm_type[BOT_CMD_SOUND] = BOT_CMD_PARAMETER_STRING;
-
-	bot_cmds_initialized = TRUE;
-}
-
-// Returns first bot with matching name
-entity find_bot_by_name(string name)
-{
-	local entity bot;
-
-	bot = findchainflags(flags, FL_CLIENT);
-	while (bot)
-	{
-		if(clienttype(bot) == CLIENTTYPE_BOT)
-		if(bot.netname==name)
-			return bot;
-
-		bot = bot.chain;
-	}
-
-	return world;
-}
-
-// Returns a bot by number on list
-entity find_bot_by_number(float number)
-{
-	local entity bot;
-	local float c;
-
-	if(!number)
-		return world;
-
-	bot = findchainflags(flags, FL_CLIENT);
-	while (bot)
-	{
-		if(clienttype(bot) == CLIENTTYPE_BOT)
-		{
-			if(++c==number)
-				return bot;
-		}
-		bot = bot.chain;
-	}
-
-	return world;
-}
-
-float bot_decodecommand(string cmdstring)
-{
-	local float cmd_parm_type, i;
-	float sp;
-	string parm;
-
-	sp = strstrofs(cmdstring, " ", 0);
-	if(sp < 0)
-	{
-		parm = "";
-	}
-	else
-	{
-		parm = substring(cmdstring, sp + 1, -1);
-		cmdstring = substring(cmdstring, 0, sp);
-	}
-
-	if(!bot_cmds_initialized)
-		bot_commands_init();
-
-	for(i=1;i<BOT_CMD_COUNTER;++i)
-	{
-		if(bot_cmd_string[i]!=cmdstring)
-			continue;
-
-		cmd_parm_type = bot_cmd_parm_type[i];
-
-		if(cmd_parm_type!=BOT_CMD_PARAMETER_NONE&&parm=="")
-		{
-			print("ERROR: A parameter is required for this command\n");
-			return 0;
-		}
-
-		// Load command into queue
-		bot_cmd.bot_cmd_type = i;
-
-		// Attach parameter
-		switch(cmd_parm_type)
-		{
-			case BOT_CMD_PARAMETER_FLOAT:
-				bot_cmd.bot_cmd_parm_float = stof(parm);
-				break;
-			case BOT_CMD_PARAMETER_STRING:
-				if(bot_cmd.bot_cmd_parm_string)
-					strunzone(bot_cmd.bot_cmd_parm_string);
-				bot_cmd.bot_cmd_parm_string = strzone(parm);
-				break;
-			case BOT_CMD_PARAMETER_VECTOR:
-				bot_cmd.bot_cmd_parm_vector = stov(parm);
-				break;
-			default:
-				break;
-		}
-		return 1;
-	}
-	print("ERROR: No such command '", cmdstring, "'\n");
-	return 0;
-}
-
-void bot_cmdhelp(string scmd)
-{
-	local float i, ntype;
-	local string stype;
-
-	if(!bot_cmds_initialized)
-		bot_commands_init();
-
-	for(i=1;i<BOT_CMD_COUNTER;++i)
-	{
-		if(bot_cmd_string[i]!=scmd)
-			continue;
-
-		ntype = bot_cmd_parm_type[i];
-
-		switch(ntype)
-		{
-			case BOT_CMD_PARAMETER_FLOAT:
-				stype = "float number";
-				break;
-			case BOT_CMD_PARAMETER_STRING:
-				stype = "string";
-				break;
-			case BOT_CMD_PARAMETER_VECTOR:
-				stype = "vector";
-				break;
-			default:
-				stype = "none";
-				break;
-		}
-
-		print(strcat("Command: ",bot_cmd_string[i],"\nParameter: <",stype,"> \n"));
-
-		print("Description: ");
-		switch(i)
-		{
-			case BOT_CMD_PAUSE:
-				print("Stops the bot completely. Any command other than 'continue' will be ignored.");
-				break;
-			case BOT_CMD_CONTINUE:
-				print("Disable paused status");
-				break;
-			case BOT_CMD_WAIT:
-				print("Pause command parsing and bot ai for N seconds. Pressed key will remain pressed");
-				break;
-			case BOT_CMD_WAIT_UNTIL:
-				print("Pause command parsing and bot ai until time is N from the last barrier. Pressed key will remain pressed");
-				break;
-			case BOT_CMD_BARRIER:
-				print("Waits till all bots that have a command queue reach this command. Pressed key will remain pressed");
-				break;
-			case BOT_CMD_TURN:
-				print("Look to the right or left N degrees. For turning to the left use positive numbers.");
-				break;
-			case BOT_CMD_MOVETO:
-				print("Walk to an specific coordinate on the map. Usage: moveto \"x y z\"");
-				break;
-			case BOT_CMD_MOVETOTARGET:
-				print("Walk to the specific target on the map");
-				break;
-			case BOT_CMD_RESETGOAL:
-				print("Resets the goal stack");
-				break;
-			case BOT_CMD_CC:
-				print("Execute client command. Examples: cc \"say something\"; cc god; cc \"name newnickname\"; cc kill;");
-				break;
-			case BOT_CMD_IF:
-				print("Perform simple conditional execution.\n");
-				print("Syntax: \n");
-				print("        sv_cmd .. if \"condition\"\n");
-				print("        sv_cmd .. 	<instruction if true>\n");
-				print("        sv_cmd .. 	<instruction if true>\n");
-				print("        sv_cmd .. else\n");
-				print("        sv_cmd .. 	<instruction if false>\n");
-				print("        sv_cmd .. 	<instruction if false>\n");
-				print("        sv_cmd .. fi\n");
-				print("Conditions: a=b, a>b, a<b, a\t\t(spaces not allowed)\n");
-				print("            Values in conditions can be numbers, cvars in the form cvar.cvar_string or special fields\n");
-				print("Fields: health, speed, flagcarrier\n");
-				print("Examples: if health>50; if health>cvar.g_balance_laser_primary_damage; if flagcarrier;");
-				break;
-			case BOT_CMD_RESETAIM:
-				print("Points the aim to the coordinates x,y 0,0");
-				break;
-			case BOT_CMD_AIM:
-				print("Move the aim x/y (horizontal/vertical) degrees relatives to the bot\n");
-				print("There is a 3rd optional parameter telling in how many seconds the aim has to reach the new position\n");
-				print("Examples: aim \"90 0\"	// Turn 90 degrees inmediately (positive numbers move to the left/up)\n");
-				print("          aim \"0 90 2\"	// Will gradually look to the sky in the next two seconds");
-				break;
-			case BOT_CMD_AIMTARGET:
-				print("Points the aim to given target");
-				break;
-			case BOT_CMD_PRESSKEY:
-				print("Press one of the following keys: forward, backward, left, right, jump, crouch, attack1, attack2, use\n");
-				print("Multiple keys can be pressed at time (with many presskey calls) and it will remain pressed until the command \"releasekey\" is called");
-				print("Note: The script will not return the control to the bot ai until all keys are released");
-				break;
-			case BOT_CMD_RELEASEKEY:
-				print("Release previoulsy used keys. Use the parameter \"all\" to release all keys");
-				break;
-			case BOT_CMD_SOUND:
-				print("play sound file at bot location");
-				break;
-			default:
-				print("This command has no description yet.");
-				break;
-		}
-		print("\n");
-	}
-}
-
-void bot_list_commands()
-{
-	local float i;
-	local string ptype;
-
-	if(!bot_cmds_initialized)
-		bot_commands_init();
-
-	print("List of all available commands:\n");
-	print(" Command\t\t\t\tParameter Type\n");
-
-	for(i=1;i<BOT_CMD_COUNTER;++i)
-	{
-		switch(bot_cmd_parm_type[i])
-		{
-			case BOT_CMD_PARAMETER_FLOAT:
-				ptype = "float number";
-				break;
-			case BOT_CMD_PARAMETER_STRING:
-				ptype = "string";
-				break;
-			case BOT_CMD_PARAMETER_VECTOR:
-				ptype = "vector";
-				break;
-			default:
-				ptype = "none";
-				break;
-		}
-		print(strcat(" ",bot_cmd_string[i],"\t\t\t\t<",ptype,"> \n"));
-	}
-}
-
-// Commands code
-.float bot_exec_status;
-
-#define BOT_EXEC_STATUS_IDLE	0
-#define BOT_EXEC_STATUS_PAUSED	1
-#define BOT_EXEC_STATUS_WAITING	2
-
-#define CMD_STATUS_EXECUTING	0
-#define CMD_STATUS_FINISHED	1
-#define CMD_STATUS_ERROR	2
-
-void SV_ParseClientCommand(string s);
-float bot_cmd_cc()
-{
-	SV_ParseClientCommand(bot_cmd.bot_cmd_parm_string);
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_impulse()
-{
-	self.impulse = bot_cmd.bot_cmd_parm_float;
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_continue()
-{
-	self.bot_exec_status &~= BOT_EXEC_STATUS_PAUSED;
-	return CMD_STATUS_FINISHED;
-}
-
-.float bot_cmd_wait_time;
-float bot_cmd_wait()
-{
-	if(self.bot_exec_status & BOT_EXEC_STATUS_WAITING)
-	{
-		if(time>=self.bot_cmd_wait_time)
-		{
-			self.bot_exec_status &~= BOT_EXEC_STATUS_WAITING;
-			return CMD_STATUS_FINISHED;
-		}
-		else
-			return CMD_STATUS_EXECUTING;
-	}
-
-	self.bot_cmd_wait_time = time + bot_cmd.bot_cmd_parm_float;
-	self.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
-	return CMD_STATUS_EXECUTING;
-}
-
-float bot_cmd_wait_until()
-{
-	if(time < bot_cmd.bot_cmd_parm_float + bot_barriertime)
-	{
-		self.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
-		return CMD_STATUS_EXECUTING;
-	}
-	self.bot_exec_status &~= BOT_EXEC_STATUS_WAITING;
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_barrier()
-{
-	entity cl;
-
-	// 0 = no barrier, 1 = waiting, 2 = waiting finished
-
-	if(self.bot_barrier == 0) // initialization
-	{
-		self.bot_barrier = 1;
-
-		//self.colormod = '4 4 0';
-	}
-
-	if(self.bot_barrier == 1) // find other bots
-	{
-		FOR_EACH_CLIENT(cl) if(cl.isbot)
-		{
-			if(cl.bot_cmdqueuebuf_allocated)
-				if(cl.bot_barrier != 1)
-					return CMD_STATUS_EXECUTING; // not all are at the barrier yet
-		}
-
-		// all bots hit the barrier!
-		FOR_EACH_CLIENT(cl) if(cl.isbot)
-		{
-			cl.bot_barrier = 2; // acknowledge barrier
-		}
-
-		bot_barriertime = time;
-	}
-
-	// if we get here, the barrier is finished
-	// so end it...
-	self.bot_barrier = 0;
-	//self.colormod = '0 0 0';
-
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_turn()
-{
-	self.v_angle_y = self.v_angle_y + bot_cmd.bot_cmd_parm_float;
-	self.v_angle_y = self.v_angle_y - floor(self.v_angle_y / 360) * 360;
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_select_weapon()
-{
-	local float id;
-
-	id = bot_cmd.bot_cmd_parm_float;
-
-	if(id < WEP_FIRST || id > WEP_LAST)
-		return CMD_STATUS_ERROR;
-
-	if(client_hasweapon(self, id, TRUE, FALSE))
-		self.switchweapon = id;
-	else
-		return CMD_STATUS_ERROR;
-
-	return CMD_STATUS_FINISHED;
-}
-
-.float bot_cmd_condition_status;
-
-#define CMD_CONDITION_NONE		0
-#define CMD_CONDITION_TRUE		1
-#define CMD_CONDITION_FALSE		2
-#define CMD_CONDITION_TRUE_BLOCK	4
-#define CMD_CONDITION_FALSE_BLOCK	8
-
-float bot_cmd_eval(string expr)
-{
-	// Search for numbers
-	if(strstrofs("0123456789", substring(expr, 0, 1), 0) >= 0)
-	{
-		return stof(expr);
-	}
-
-	// Search for cvars
-	if(substring(expr, 0, 5)=="cvar.")
-	{
-		return cvar(substring(expr, 5, strlen(expr)));
-	}
-
-	// Search for fields
-	switch(expr)
-	{
-		case "health":
-			return self.health;
-		case "speed":
-			return vlen(self.velocity);
-		case "flagcarrier":
-			return ((self.flagcarried!=world));
-	}
-
-	print(strcat("ERROR: Unable to convert the expression '",expr,"' into a numeric value\n"));
-	return 0;
-}
-
-float bot_cmd_if()
-{
-	local string expr, val_a, val_b;
-	local float cmpofs;
-
-	if(self.bot_cmd_condition_status != CMD_CONDITION_NONE)
-	{
-		// Only one "if" block is allowed at time
-		print("ERROR: Only one conditional block can be processed at time");
-		bot_clearqueue(self);
-		return CMD_STATUS_ERROR;
-	}
-
-	self.bot_cmd_condition_status |= CMD_CONDITION_TRUE_BLOCK;
-
-	// search for operators
-	expr = bot_cmd.bot_cmd_parm_string;
-
-	cmpofs = strstrofs(expr,"=",0);
-
-	if(cmpofs>0)
-	{
-		val_a = substring(expr,0,cmpofs);
-		val_b = substring(expr,cmpofs+1,strlen(expr));
-
-		if(bot_cmd_eval(val_a)==bot_cmd_eval(val_b))
-			self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
-		else
-			self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
-
-  		return CMD_STATUS_FINISHED;
-	}
-
-	cmpofs = strstrofs(expr,">",0);
-
-	if(cmpofs>0)
-	{
-		val_a = substring(expr,0,cmpofs);
-		val_b = substring(expr,cmpofs+1,strlen(expr));
-
-		if(bot_cmd_eval(val_a)>bot_cmd_eval(val_b))
-			self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
-		else
-			self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
-
-		return CMD_STATUS_FINISHED;
-	}
-
-	cmpofs = strstrofs(expr,"<",0);
-
-	if(cmpofs>0)
-	{
-		val_a = substring(expr,0,cmpofs);
-		val_b = substring(expr,cmpofs+1,strlen(expr));
-
-		if(bot_cmd_eval(val_a)<bot_cmd_eval(val_b))
-			self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
-		else
-			self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
-
-  		return CMD_STATUS_FINISHED;
-	}
-
-	if(bot_cmd_eval(expr))
-		self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
-	else
-		self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
-
-  	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_else()
-{
-	self.bot_cmd_condition_status &~= CMD_CONDITION_TRUE_BLOCK;
-	self.bot_cmd_condition_status |= CMD_CONDITION_FALSE_BLOCK;
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_fi()
-{
-	self.bot_cmd_condition_status = CMD_CONDITION_NONE;
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_resetaim()
-{
-	self.v_angle = '0 0 0';
-	return CMD_STATUS_FINISHED;
-}
-
-.float bot_cmd_aim_begintime;
-.float bot_cmd_aim_endtime;
-.vector bot_cmd_aim_begin;
-.vector bot_cmd_aim_end;
-
-float bot_cmd_aim()
-{
-	// Current direction
-	if(self.bot_cmd_aim_endtime)
-	{
-		local float progress;
-
-		progress = min(1 - (self.bot_cmd_aim_endtime - time) / (self.bot_cmd_aim_endtime - self.bot_cmd_aim_begintime),1);
-		self.v_angle = self.bot_cmd_aim_begin + ((self.bot_cmd_aim_end - self.bot_cmd_aim_begin) * progress);
-
-		if(time>=self.bot_cmd_aim_endtime)
-		{
-			self.bot_cmd_aim_endtime = 0;
-			return CMD_STATUS_FINISHED;
-		}
-		else
-			return CMD_STATUS_EXECUTING;
-	}
-
-	// New aiming direction
-	local string parms;
-	local float tokens, step;
-
-	parms = bot_cmd.bot_cmd_parm_string;
-
-	tokens = tokenizebyseparator(parms, " ");
-
-	if(tokens==2)
-	{
-		self.v_angle_x -= stof(argv(1));
-		self.v_angle_y += stof(argv(0));
-		return CMD_STATUS_FINISHED;
-	}
-
-	if(tokens<2||tokens>3)
-		return CMD_STATUS_ERROR;
-
-	step = stof(argv(2));
-
-	self.bot_cmd_aim_begin = self.v_angle;
-
-	self.bot_cmd_aim_end_x = self.v_angle_x - stof(argv(1));
-	self.bot_cmd_aim_end_y = self.v_angle_y + stof(argv(0));
-	self.bot_cmd_aim_end_z = 0;
-
-	self.bot_cmd_aim_begintime = time;
-	self.bot_cmd_aim_endtime = time + step;
-
-	return CMD_STATUS_EXECUTING;
-}
-
-float bot_cmd_aimtarget()
-{
-	if(self.bot_cmd_aim_endtime)
-	{
-		return bot_cmd_aim();
-	}
-
-	local entity e;
-	local string parms;
-	local vector v;
-	local float tokens, step;
-
-	parms = bot_cmd.bot_cmd_parm_string;
-
-	tokens = tokenizebyseparator(parms, " ");
-
-	e = bot_getplace(argv(0));
-	if(!e)
-		return CMD_STATUS_ERROR;
-
-	v = e.origin + (e.mins + e.maxs) * 0.5;
-
-	if(tokens==1)
-	{
-		self.v_angle = vectoangles(v - (self.origin + self.view_ofs));
-		self.v_angle_x = -self.v_angle_x;
-		return CMD_STATUS_FINISHED;
-	}
-
-	if(tokens<1||tokens>2)
-		return CMD_STATUS_ERROR;
-
-	step = stof(argv(1));
-
-	self.bot_cmd_aim_begin = self.v_angle;
-	self.bot_cmd_aim_end = vectoangles(v - (self.origin + self.view_ofs));
-	self.bot_cmd_aim_end_x = -self.bot_cmd_aim_end_x;
-
-	self.bot_cmd_aim_begintime = time;
-	self.bot_cmd_aim_endtime = time + step;
-
-	return CMD_STATUS_EXECUTING;
-}
-
-.float bot_cmd_keys;
-
-#define BOT_CMD_KEY_NONE	0
-#define BOT_CMD_KEY_FORWARD 	1
-#define BOT_CMD_KEY_BACKWARD	2
-#define BOT_CMD_KEY_RIGHT	4
-#define BOT_CMD_KEY_LEFT	8
-#define BOT_CMD_KEY_JUMP	16
-#define BOT_CMD_KEY_ATTACK1 	32
-#define BOT_CMD_KEY_ATTACK2 	64
-#define BOT_CMD_KEY_USE		128
-#define BOT_CMD_KEY_HOOK	256
-#define BOT_CMD_KEY_CROUCH	512
-#define BOT_CMD_KEY_CHAT	1024
-
-float bot_presskeys()
-{
-	self.movement = '0 0 0';
-
-	if(self.bot_cmd_keys == BOT_CMD_KEY_NONE)
-		return FALSE;
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_FORWARD)
-		self.movement_x = cvar("sv_maxspeed");
-	else if(self.bot_cmd_keys & BOT_CMD_KEY_BACKWARD)
-		self.movement_x = -cvar("sv_maxspeed");
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_RIGHT)
-		self.movement_y = cvar("sv_maxspeed");
-	else if(self.bot_cmd_keys & BOT_CMD_KEY_LEFT)
-		self.movement_y = -cvar("sv_maxspeed");
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_JUMP)
-		self.BUTTON_JUMP = TRUE;
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_CROUCH)
-		self.BUTTON_CROUCH = TRUE;
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_ATTACK1)
-		self.BUTTON_ATCK = TRUE;
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_ATTACK2)
-		self.BUTTON_ATCK2 = TRUE;
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_USE)
-		self.BUTTON_USE = TRUE;
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_HOOK)
-		self.BUTTON_HOOK = TRUE;
-
-	if(self.bot_cmd_keys & BOT_CMD_KEY_CHAT)
-		self.BUTTON_CHAT = TRUE;
-
-	return TRUE;
-}
-
-
-float bot_cmd_keypress_handler(string key, float enabled)
-{
-	switch(key)
-	{
-		case "all":
-			if(enabled)
-				self.bot_cmd_keys = power2of(20) - 1; // >:)
-			else
-				self.bot_cmd_keys = BOT_CMD_KEY_NONE;
-		case "forward":
-			if(enabled)
-			{
-				self.bot_cmd_keys |= BOT_CMD_KEY_FORWARD;
-				self.bot_cmd_keys &~= BOT_CMD_KEY_BACKWARD;
-			}
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_FORWARD;
-			break;
-		case "backward":
-			if(enabled)
-			{
-				self.bot_cmd_keys |= BOT_CMD_KEY_BACKWARD;
-				self.bot_cmd_keys &~= BOT_CMD_KEY_FORWARD;
-			}
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_BACKWARD;
-			break;
-		case "left":
-			if(enabled)
-			{
-				self.bot_cmd_keys |= BOT_CMD_KEY_LEFT;
-				self.bot_cmd_keys &~= BOT_CMD_KEY_RIGHT;
-			}
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_LEFT;
-			break;
-		case "right":
-			if(enabled)
-			{
-				self.bot_cmd_keys |= BOT_CMD_KEY_RIGHT;
-				self.bot_cmd_keys &~= BOT_CMD_KEY_LEFT;
-			}
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_RIGHT;
-			break;
-		case "jump":
-			if(enabled)
-				self.bot_cmd_keys |= BOT_CMD_KEY_JUMP;
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_JUMP;
-			break;
-		case "crouch":
-			if(enabled)
-				self.bot_cmd_keys |= BOT_CMD_KEY_CROUCH;
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_CROUCH;
-			break;
-		case "attack1":
-			if(enabled)
-				self.bot_cmd_keys |= BOT_CMD_KEY_ATTACK1;
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_ATTACK1;
-			break;
-		case "attack2":
-			if(enabled)
-				self.bot_cmd_keys |= BOT_CMD_KEY_ATTACK2;
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_ATTACK2;
-			break;
-		case "use":
-			if(enabled)
-				self.bot_cmd_keys |= BOT_CMD_KEY_USE;
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_USE;
-			break;
-		case "hook":
-			if(enabled)
-				self.bot_cmd_keys |= BOT_CMD_KEY_HOOK;
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_HOOK;
-			break;
-		case "chat":
-			if(enabled)
-				self.bot_cmd_keys |= BOT_CMD_KEY_CHAT;
-			else
-				self.bot_cmd_keys &~= BOT_CMD_KEY_CHAT;
-			break;
-		default:
-			break;
-	}
-
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_presskey()
-{
-	local string key;
-
-	key = bot_cmd.bot_cmd_parm_string;
-
-	bot_cmd_keypress_handler(key,TRUE);
-
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_releasekey()
-{
-	local string key;
-
-	key = bot_cmd.bot_cmd_parm_string;
-
-	return bot_cmd_keypress_handler(key,FALSE);
-}
-
-float bot_cmd_pause()
-{
-	self.button1        = 0;
-	self.button8        = 0;
-	self.BUTTON_USE     = 0;
-	self.BUTTON_ATCK    = 0;
-	self.BUTTON_JUMP    = 0;
-	self.BUTTON_HOOK    = 0;
-	self.BUTTON_CHAT    = 0;
-	self.BUTTON_ATCK2   = 0;
-	self.BUTTON_CROUCH  = 0;
-
-	self.movement = '0 0 0';
-	self.bot_cmd_keys = BOT_CMD_KEY_NONE;
-
-	self.bot_exec_status |= BOT_EXEC_STATUS_PAUSED;
-	return CMD_STATUS_FINISHED;
-}
-
-float bot_cmd_moveto()
-{
-	return self.cmd_moveto(bot_cmd.bot_cmd_parm_vector);
-}
-
-float bot_cmd_movetotarget()
-{
-	entity e;
-	e = bot_getplace(bot_cmd.bot_cmd_parm_string);
-	if(!e)
-		return CMD_STATUS_ERROR;
-	return self.cmd_moveto(e.origin + (e.mins + e.maxs) * 0.5);
-}
-
-float bot_cmd_resetgoal()
-{
-	return self.cmd_resetgoal();
-}
-
-
-float bot_cmd_sound()
-{
-	string f;
-	f = bot_cmd.bot_cmd_parm_string;
-
-	precache_sound(f);
-	sound(self, CHAN_WEAPON2, f, VOL_BASE, ATTN_MIN);
-
-	return CMD_STATUS_FINISHED;
-}
-
-//
-
-void bot_command_executed(float rm)
-{
-	entity cmd;
-
-	cmd = bot_cmd;
-
-	if(rm)
-		bot_dequeuecommand(self, self.bot_cmd_execution_index);
-
-	self.bot_cmd_execution_index++;
-}
-
-void bot_setcurrentcommand()
-{
-	bot_cmd = world;
-
-	if(!self.bot_cmd_current)
-	{
-		self.bot_cmd_current = spawn();
-		self.bot_cmd_current.classname = "bot_cmd";
-		self.bot_cmd_current.is_bot_cmd = 1;
-	}
-
-	bot_cmd = self.bot_cmd_current;
-	if(bot_cmd.bot_cmd_index != self.bot_cmd_execution_index || self.bot_cmd_execution_index == 0)
-	{
-		if(bot_havecommand(self, self.bot_cmd_execution_index))
-		{
-			string cmdstring;
-			cmdstring = bot_readcommand(self, self.bot_cmd_execution_index);
-			if(bot_decodecommand(cmdstring))
-			{
-				bot_cmd.owner = self;
-				bot_cmd.bot_cmd_index = self.bot_cmd_execution_index;
-			}
-			else
-			{
-				// Invalid command, remove from queue
-				bot_cmd = world;
-				bot_dequeuecommand(self, self.bot_cmd_execution_index);
-				self.bot_cmd_execution_index++;
-			}
-		}
-		else
-			bot_cmd = world;
-	}
-}
-
-void bot_resetqueues()
-{
-	entity cl;
-	float i;
-
-	FOR_EACH_CLIENT(cl) if(cl.isbot)
-	{
-		if(cl.bot_cmdqueuebuf_allocated)
-			bot_clearqueue(cl);
-		// also, cancel all barriers
-		cl.bot_barrier = 0;
-		for(i = 0; i < cl.bot_places_count; ++i)
-		{
-			strunzone(cl.(bot_placenames[i]));
-			cl.(bot_placenames[i]) = string_null;
-		}
-		cl.bot_places_count = 0;
-	}
-
-	bot_barriertime = time;
-}
-
-// Here we map commands to functions and deal with complex interactions between commands and execution states
-// NOTE: Of course you need to include your commands here too :)
-float bot_execute_commands_once()
-{
-	local float status, ispressingkey;
-
-	if(self.deadflag!=DEAD_NO)
-		return 0;
-
-	// Find command
-	bot_setcurrentcommand();
-
-	// Ignore all commands except continue when the bot is paused
-	if(self.bot_exec_status & BOT_EXEC_STATUS_PAUSED)
-	if(bot_cmd.bot_cmd_type!=BOT_CMD_CONTINUE)
-	{
-		if(bot_cmd.bot_cmd_type!=BOT_CMD_NULL)
-		{
-			bot_command_executed(TRUE);
-			print( "WARNING: Commands are ignored while the bot is paused. Use the command 'continue' instead.\n");
-		}
-		return 1;
-	}
-
-	// Keep pressing keys raised by the "presskey" command
-	ispressingkey = !!bot_presskeys();
-
-	if(bot_cmd==world)
-		return ispressingkey;
-
-	// Handle conditions
-	if not(bot_cmd.bot_cmd_type==BOT_CMD_FI||bot_cmd.bot_cmd_type==BOT_CMD_ELSE)
-	if(self.bot_cmd_condition_status & CMD_CONDITION_TRUE && self.bot_cmd_condition_status & CMD_CONDITION_FALSE_BLOCK)
-	{
-		bot_command_executed(TRUE);
-		return -1;
-	}
-	else if(self.bot_cmd_condition_status & CMD_CONDITION_FALSE && self.bot_cmd_condition_status & CMD_CONDITION_TRUE_BLOCK)
-	{
-		bot_command_executed(TRUE);
-		return -1;
-	}
-
-	// Map commands to functions
-	switch(bot_cmd.bot_cmd_type)
-	{
-		case BOT_CMD_NULL:
-			return ispressingkey;
-			//break;
-		case BOT_CMD_PAUSE:
-			status = bot_cmd_pause();
-			break;
-		case BOT_CMD_CONTINUE:
-			status = bot_cmd_continue();
-			break;
-		case BOT_CMD_WAIT:
-			status = bot_cmd_wait();
-			break;
-		case BOT_CMD_WAIT_UNTIL:
-			status = bot_cmd_wait_until();
-			break;
-		case BOT_CMD_TURN:
-			status = bot_cmd_turn();
-			break;
-		case BOT_CMD_MOVETO:
-			status = bot_cmd_moveto();
-			break;
-		case BOT_CMD_MOVETOTARGET:
-			status = bot_cmd_movetotarget();
-			break;
-		case BOT_CMD_RESETGOAL:
-			status = bot_cmd_resetgoal();
-			break;
-		case BOT_CMD_CC:
-			status = bot_cmd_cc();
-			break;
-		case BOT_CMD_IF:
-			status = bot_cmd_if();
-			break;
-		case BOT_CMD_ELSE:
-			status = bot_cmd_else();
-			break;
-		case BOT_CMD_FI:
-			status = bot_cmd_fi();
-			break;
-		case BOT_CMD_RESETAIM:
-			status = bot_cmd_resetaim();
-			break;
-		case BOT_CMD_AIM:
-			status = bot_cmd_aim();
-			break;
-		case BOT_CMD_AIMTARGET:
-			status = bot_cmd_aimtarget();
-			break;
-		case BOT_CMD_PRESSKEY:
-			status = bot_cmd_presskey();
-			break;
-		case BOT_CMD_RELEASEKEY:
-			status = bot_cmd_releasekey();
-			break;
-		case BOT_CMD_SELECTWEAPON:
-			status = bot_cmd_select_weapon();
-			break;
-		case BOT_CMD_IMPULSE:
-			status = bot_cmd_impulse();
-			break;
-		case BOT_CMD_BARRIER:
-			status = bot_cmd_barrier();
-			break;
-		case BOT_CMD_CONSOLE:
-			localcmd(strcat(bot_cmd.bot_cmd_parm_string, "\n"));
-			status = CMD_STATUS_FINISHED;
-			break;
-		case BOT_CMD_SOUND:
-			status = bot_cmd_sound();
-			break;
-		default:
-			print(strcat("ERROR: Invalid command on queue with id '",ftos(bot_cmd.bot_cmd_type),"'\n"));
-			return 0;
-	}
-
-	if (status==CMD_STATUS_ERROR)
-		print(strcat("ERROR: The command '",bot_cmd_string[bot_cmd.bot_cmd_type],"' returned an error status\n"));
-
-	// Move execution pointer
-	if(status==CMD_STATUS_EXECUTING)
-	{
-		return 1;
-	}
-	else
-	{
-		if(cvar("g_debug_bot_commands"))
-		{
-			local string parms;
-
-			switch(bot_cmd_parm_type[bot_cmd.bot_cmd_type])
-			{
-				case BOT_CMD_PARAMETER_FLOAT:
-					parms = ftos(bot_cmd.bot_cmd_parm_float);
-					break;
-				case BOT_CMD_PARAMETER_STRING:
-					parms = bot_cmd.bot_cmd_parm_string;
-					break;
-				case BOT_CMD_PARAMETER_VECTOR:
-					parms = vtos(bot_cmd.bot_cmd_parm_vector);
-					break;
-				default:
-					parms = "";
-					break;
-			}
-			clientcommand(self,strcat("say ^7", bot_cmd_string[bot_cmd.bot_cmd_type]," ",parms,"\n"));
-		}
-
-		bot_command_executed(TRUE);
-	}
-
-	if(status == CMD_STATUS_FINISHED)
-		return -1;
-
-	return CMD_STATUS_ERROR;
-}
-
-// This function should be (the only) called directly from the bot ai loop
-float bot_execute_commands()
-{
-	float f;
-	do
-	{
-		f = bot_execute_commands_once();
-	}
-	while(f < 0);
-	return f;
-}

Deleted: branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc	2009-09-23 10:28:19 UTC (rev 7880)
@@ -1,1443 +0,0 @@
-.void() havocbot_role;
-void() havocbot_chooserole;
-.float havocbot_keyboardskill;
-.float facingwalltime, ignoregoaltime;
-.entity ignoregoal;
-.float lastfiredweapon;
-.float lastcombotime;
-.float havocbot_blockhead;
-
-#ifdef DEBUG_BOT_GOALSTACK
-void debuggoalstack();
-#endif
-
-vector havocbot_dodge()
-{
-	// LordHavoc: disabled because this is too expensive
-	return '0 0 0';
-	/*
-	local entity head;
-	local vector dodge, v, n;
-	local float danger, bestdanger, vl, d;
-	dodge = '0 0 0';
-	bestdanger = -20;
-	// check for dangerous objects near bot or approaching bot
-	head = findchainfloat(bot_dodge, TRUE);
-	while(head)
-	{
-		if (head.owner != self)
-		{
-			vl = vlen(head.velocity);
-			if (vl > sv_maxspeed * 0.3)
-			{
-				n = normalize(head.velocity);
-				v = self.origin - head.origin;
-				d = v * n;
-				if (d > (0 - head.bot_dodgerating))
-				if (d < (vl * 0.2 + head.bot_dodgerating))
-				{
-					// calculate direction and distance from the flight path, by removing the forward axis
-					v = v - (n * (v * n));
-					danger = head.bot_dodgerating - vlen(v);
-					if (bestdanger < danger)
-					{
-						bestdanger = danger;
-						// dodge to the side of the object
-						dodge = normalize(v);
-					}
-				}
-			}
-			else
-			{
-				danger = head.bot_dodgerating - vlen(head.origin - self.origin);
-				if (bestdanger < danger)
-				{
-					bestdanger = danger;
-					dodge = normalize(self.origin - head.origin);
-				}
-			}
-		}
-		head = head.chain;
-	}
-	return dodge;
-	*/
-};
-
-.float havocbot_keyboardtime;
-.float havocbot_ducktime;
-.vector havocbot_keyboard;
-void havocbot_keyboard_movement(vector destorg)
-{
-	local vector keyboard;
-	local float blend, maxspeed;
-
-	maxspeed = cvar("sv_maxspeed");
-
-	if (time < self.havocbot_keyboardtime)
-		return;
-
-	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 = self.movement * (1.0 / maxspeed);
-
-	local float trigger, trigger1;
-	blend = bound(0,skill*0.1,1);
-	trigger = cvar("bot_ai_keyboard_treshold");
-	trigger1 = 0 - trigger;
-
-	// categorize forward movement
-	// at skill < 1.5 only forward
-	// at skill < 2.5 only individual directions
-	// at skill < 4.5 only individual directions, and forward diagonals
-	// at skill >= 4.5, all cases allowed
-	if (keyboard_x > trigger)
-	{
-		keyboard_x = 1;
-		if (skill < 2.5)
-			keyboard_y = 0;
-	}
-	else if (keyboard_x < trigger1 && skill > 1.5)
-	{
-		keyboard_x = -1;
-		if (skill < 4.5)
-			keyboard_y = 0;
-	}
-	else
-	{
-		keyboard_x = 0;
-		if (skill < 1.5)
-			keyboard_y = 0;
-	}
-	if (skill < 4.5)
-		keyboard_z = 0;
-
-	if (keyboard_y > trigger)
-		keyboard_y = 1;
-	else if (keyboard_y < trigger1)
-		keyboard_y = -1;
-	else
-		keyboard_y = 0;
-
-	if (keyboard_z > trigger)
-		keyboard_z = 1;
-	else if (keyboard_z < trigger1)
-		keyboard_z = -1;
-	else
-		keyboard_z = 0;
-
-	self.havocbot_keyboard = keyboard * maxspeed;
-	if (self.havocbot_ducktime>time) self.BUTTON_CROUCH=TRUE;
-
-	keyboard = self.havocbot_keyboard;
-	blend = bound(0,vlen(destorg-self.origin)/cvar("bot_ai_keyboard_distance"),1); // When getting close move with 360 degree
-	//dprint("movement ", vtos(self.movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
-	self.movement = self.movement + (keyboard - self.movement) * blend;
-};
-
-.entity bot_lastseengoal;
-.float bot_timelastseengoal;
-.float bot_canruntogoal;
-void havocbot_bunnyhop(vector dir)
-{
-	local float bunnyhopdistance;
-	local vector deviation;
-	local float maxspeed;
-
-	if(cvar("g_midair"))
-		return;
-
-	// Don't jump when using some weapons
-	if(self.aistatus & AI_STATUS_ATTACKING)
-	if(self.weapon & WEP_CAMPINGRIFLE)
-		return;
-
-	if(self.goalcurrent.classname == "player")
-		return;
-
-	maxspeed = cvar("sv_maxspeed");
-
-	if(self.aistatus & AI_STATUS_DANGER_AHEAD)
-	{
-		self.aistatus &~= AI_STATUS_RUNNING;
-		self.BUTTON_JUMP = FALSE;
-		self.bot_canruntogoal = 0;
-		self.bot_timelastseengoal = 0;
-		return;
-	}
-
-	if(self.waterlevel > WATERLEVEL_WETFEET)
-	{
-		self.aistatus &~= AI_STATUS_RUNNING;
-		return;
-	}
-
-	if(self.bot_lastseengoal != self.goalcurrent && !(self.aistatus & AI_STATUS_RUNNING))
-	{
-		self.bot_canruntogoal = 0;
-		self.bot_timelastseengoal = 0;
-	}
-
-	bunnyhopdistance = vlen(self.origin - self.goalcurrent.origin);
-
-	// Run only to visible goals
-	if(self.flags & FL_ONGROUND)
-	if(self.speed==maxspeed)
-	if(checkpvs(self.origin + self.view_ofs, self.goalcurrent))
-	{
-			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(bunnyhopdistance > 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 not(self.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL)
-					if(fabs(self.goalcurrent.origin_z - self.origin_z) < self.maxs_z - self.mins_z)
-					if(self.goalstack01!=world)
-					{
-						deviation = vectoangles(self.goalstack01.origin - self.origin) - vectoangles(self.goalcurrent.origin - self.origin);
-						while (deviation_y < -180) deviation_y = deviation_y + 360;
-						while (deviation_y > 180) deviation_y = deviation_y - 360;
-
-						if(fabs(deviation_y) < 20)
-						if(bunnyhopdistance < vlen(self.origin - self.goalstack01.origin))
-						if(fabs(self.goalstack01.origin_z - self.goalcurrent.origin_z) < self.maxs_z - self.mins_z)
-						{
-							if(vlen(self.goalcurrent.origin - self.goalstack01.origin) > cvar("bot_ai_bunnyhop_startdistance"))
-							if(checkpvs(self.origin + self.view_ofs, self.goalstack01))
-							{
-								checkdistance = FALSE;
-							}
-						}
-					}
-
-					if(checkdistance)
-					{
-						self.aistatus &~= AI_STATUS_RUNNING;
-						if(bunnyhopdistance > 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 || vlen(self.velocity)<maxspeed)
-			self.BUTTON_JUMP = FALSE;
-
-		// Strafe
-		if(self.aistatus & AI_STATUS_RUNNING)
-		if(vlen(self.velocity)>maxspeed)
-		{
-			deviation = vectoangles(dir) - vectoangles(self.velocity);
-			while (deviation_y < -180) deviation_y = deviation_y + 360;
-			while (deviation_y > 180) deviation_y = deviation_y - 360;
-
-			if(fabs(deviation_y)>10)
-				self.movement_x = 0;
-
-			if(deviation_y>10)
-				self.movement_y = maxspeed * -1;
-			else if(deviation_y<10)
-				self.movement_y = maxspeed;
-
-		}
-	}
-};
-
-//.float havocbotignoretime;
-//.vector bot_dodgevector;
-//.float bot_dodgevector_time;
-//.float bot_dodgevector_jumpbutton;
-.float ladder_time;
-.entity ladder_entity;
-.float rocketjumptime;
-void havocbot_movetogoal()
-{
-	local vector destorg;
-	local vector diff;
-	local vector dir;
-	local vector flatdir;
-	local vector m1;
-	local vector m2;
-	local vector evadeobstacle;
-	local vector evadelava;
-	local float s;
-	local float maxspeed;
-	//local float dist;
-	local vector dodge;
-	//if (self.goalentity)
-	//	te_lightning2(self, self.origin, (self.goalentity.absmin + self.goalentity.absmax) * 0.5);
-	self.movement = '0 0 0';
-	maxspeed = cvar("sv_maxspeed");
-
-	// 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)
-		{
-			// Calculate brake distance in xy
-			float db, v, d;
-			vector dxy;
-
-			dxy = self.origin - self.goalcurrent.origin; dxy_z = 0;
-			d = vlen(dxy);
-			v = vlen(self.velocity -  self.velocity_z * '0 0 1');
-			db = (pow(v,2) / (cvar("g_jetpack_acceleration_side") * 2)) + 100;
-		//	dprint("distance ", ftos(ceil(d)), " velocity ", ftos(ceil(v)), " brake at ", ftos(ceil(db)), "\n");
-			if(d < db || d < 500)
-			{
-				// Brake
-				if(fabs(self.velocity_x)>maxspeed*0.3)
-				{
-					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;
-	}
-
-	// Handling of jump pads
-	if(self.jumppadcount)
-	{
-		if(self.flags & FL_ONGROUND)
-		{
-			self.jumppadcount = FALSE;
-			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_OUT_JUMPPAD)
-		{
-			if(fabs(self.velocity_z)<50)
-			{
-				local entity head, newgoal;
-				local float distance, bestdistance;
-
-				for (head = findchainfloat(bot_pickup, TRUE); head; head = head.chain)
-				{
-					if(head.classname=="worldspawn")
-						continue;
-
-					distance = vlen(head.origin - self.origin);
-					if(distance>1000)
-						continue;
-
-					traceline(self.origin + self.view_ofs , head.origin, TRUE, world);
-
-					if(trace_fraction<1)
-						continue;
-
-					if(distance>bestdistance)
-					{
-						newgoal = head;
-						bestdistance = distance;
-					}
-				}
-
-				if(newgoal)
-				{
-					self.ignoregoal = self.goalcurrent;
-					self.ignoregoaltime = time + cvar("bot_ai_ignoregoal_timeout");
-					navigation_clearroute();
-					navigation_routetogoal(newgoal, self.origin);
-					self.aistatus &~= AI_STATUS_OUT_JUMPPAD;
-				}
-			}
-			else
-				return;
-		}
-		else
-		{
-			if(self.velocity_z>0)
-			{
-				local float threshold;
-				threshold = maxspeed * 0.2;
-				if(fabs(self.velocity_x) < threshold  &&  fabs(self.velocity_y) < threshold)
-					self.aistatus |= AI_STATUS_OUT_JUMPPAD;
-				return;
-			}
-		}
-	}
-
-	// If there is a trigger_hurt right below try to use the jetpack or make a rocketjump
-	if(skill>6)
-	if not(self.flags & FL_ONGROUND)
-	{
-		tracebox(self.origin, self.mins, self.maxs, self.origin + '0 0 -65536', MOVE_NOMONSTERS, self);
-		if(tracebox_hits_trigger_hurt(self.origin, self.mins, self.maxs, trace_endpos ))
-		if(self.items & IT_JETPACK)
-		{
-			tracebox(self.origin, self.mins, self.maxs, self.origin + '0 0 65536', MOVE_NOMONSTERS, self);
-			if(tracebox_hits_trigger_hurt(self.origin, self.mins, self.maxs, trace_endpos + '0 0 1' ))
-			{
-				if(self.velocity_z<0)
-				{
-					self.BUTTON_HOOK = TRUE;
-				}
-			}
-			else
-				self.BUTTON_HOOK = TRUE;
-
-			// If there is no goal try to move forward
-
-			if(self.goalcurrent==world)
-				dir = v_forward;
-			else
-				dir = normalize(self.goalcurrent.origin - self.origin);
-
-			local vector xyvelocity = self.velocity; xyvelocity_z = 0;
-			local float xyspeed = xyvelocity * dir;
-
-			if(xyspeed < (maxspeed / 2))
-			{
-				makevectors(self.v_angle_y * '0 1 0');
-				tracebox(self.origin, self.mins, self.maxs, self.origin + (dir * maxspeed * 3), MOVE_NOMONSTERS, self);
-				if(trace_fraction==1)
-				{
-					self.movement_x = dir * v_forward * maxspeed;
-					self.movement_y = dir * v_right * maxspeed;
-					if (skill < 10)
-						havocbot_keyboard_movement(self.origin + dir * 100);
-				}
-			}
-
-			self.havocbot_blockhead = TRUE;
-
-			return;
-		}
-		else if(self.health>cvar("g_balance_rocketlauncher_damage")*0.5)
-		{
-			if(self.velocity_z < 0)
-			if(client_hasweapon(self, WEP_ROCKET_LAUNCHER, TRUE, FALSE))
-			{
-				self.movement_x = maxspeed;
-
-				if(self.rocketjumptime)
-				{
-					if(time > self.rocketjumptime)
-					{
-						self.BUTTON_ATCK2 = TRUE;
-						self.rocketjumptime = 0;
-					}
-					return;
-				}
-
-				self.switchweapon = WEP_ROCKET_LAUNCHER;
-				self.v_angle_x = 90;
-				self.BUTTON_ATCK = TRUE;
-				self.rocketjumptime = time + cvar("g_balance_rocketlauncher_detonatedelay");
-				return;
-			}
-		}
-		else
-		{
-			// If there is no goal try to move forward
-			if(self.goalcurrent==world)
-				self.movement_x = maxspeed;
-		}
-	}
-
-	// If we are under water with no goals, swim up
-	if(self.waterlevel)
-	if(self.goalcurrent==world)
-	{
-		dir = '0 0 0';
-		if(self.waterlevel>WATERLEVEL_SWIMMING)
-			dir_z = 1;
-		else if(self.velocity_z >= 0 && !(self.waterlevel == WATERLEVEL_WETFEET && 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;
-
-	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)
-	{
-		self.bot_strategytime = 0;
-		return;
-	}
-
-#ifdef DEBUG_BOT_GOALSTACK
-	debuggoalstack();
-#endif
-
-	m1 = self.goalcurrent.origin + self.goalcurrent.mins;
-	m2 = self.goalcurrent.origin + self.goalcurrent.maxs;
-	destorg = self.origin;
-	destorg_x = bound(m1_x, destorg_x, m2_x);
-	destorg_y = bound(m1_y, destorg_y, m2_y);
-	destorg_z = bound(m1_z, destorg_z, m2_z);
-	diff = destorg - self.origin;
-	//dist = vlen(diff);
-	dir = normalize(diff);
-	flatdir = diff;flatdir_z = 0;
-	flatdir = normalize(flatdir);
-
-	//if (self.bot_dodgevector_time < time)
-	{
-	//	self.bot_dodgevector_time = time + cvar("bot_ai_dodgeupdateinterval");
-	//	self.bot_dodgevector_jumpbutton = 1;
-		evadeobstacle = '0 0 0';
-		evadelava = '0 0 0';
-
-		if (self.waterlevel)
-		{
-			if(self.waterlevel>WATERLEVEL_SWIMMING)
-			{
-			//	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 == WATERLEVEL_WETFEET && 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);
-			if (trace_fraction < 1)
-			if (trace_plane_normal_z < 0.7)
-			{
-				s = trace_fraction;
-				tracebox(self.origin + '0 0 16', self.mins, self.maxs, self.origin + self.velocity * 0.2 + '0 0 16', FALSE, self);
-				if (trace_fraction < s + 0.01)
-				if (trace_plane_normal_z < 0.7)
-				{
-					s = trace_fraction;
-					tracebox(self.origin + '0 0 48', self.mins, self.maxs, self.origin + self.velocity * 0.2 + '0 0 48', FALSE, self);
-					if (trace_fraction > s)
-						self.BUTTON_JUMP = 1;
-				}
-			}
-
-			// avoiding dangers and obstacles
-			local vector dst_ahead, dst_down;
-			makevectors(self.v_angle_y * '0 1 0');
-			dst_ahead = self.origin + self.view_ofs + (self.velocity * 0.4) + (v_forward * 32 * 3);
-			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) < 25 && !(self.aistatus & AI_STATUS_OUT_WATER))
-			{
-				self.BUTTON_JUMP = TRUE;
-				if(self.facingwalltime && time > self.facingwalltime)
-				{
-					self.ignoregoal = self.goalcurrent;
-					self.ignoregoaltime = time + cvar("bot_ai_ignoregoal_timeout");
-					self.bot_strategytime = 0;
-					return;
-				}
-				else
-				{
-					self.facingwalltime = time + 0.05;
-				}
-			}
-			else
-			{
-				self.facingwalltime = 0;
-
-				if(self.ignoregoal != world && time > self.ignoregoaltime)
-				{
-					self.ignoregoal = world;
-					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;
-
-			if(trace_fraction == 1)
-			if(self.flags & FL_ONGROUND || self.aistatus & AI_STATUS_RUNNING || self.BUTTON_JUMP == TRUE)
-			{
-				// Look downwards
-				traceline(dst_ahead , dst_down, TRUE, world);
-			//	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)
-				{
-					s = pointcontents(trace_endpos + '0 0 1');
-					if (s != CONTENT_SOLID)
-					if (s == CONTENT_LAVA || s == CONTENT_SLIME)
-						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,
-								self.goalcurrent.absmin, self.goalcurrent.absmax))
-					{
-						// if ain't a safe goal with "holes" (like the jumpad on soylent)
-						// and there is a trigger_hurt below
-						if(tracebox_hits_trigger_hurt(dst_ahead, self.mins, self.maxs, trace_endpos))
-						{
-							// Remove dangerous dynamic goals from stack
-							if (self.goalcurrent.classname == "player" || self.goalcurrent.classname == "droppedweapon")
-								navigation_poproute();
-							// try to stop
-							flatdir = '0 0 0';
-							evadeobstacle = normalize(self.velocity) * -1;
-						}
-					}
-				}
-			}
-
-			dir = flatdir;
-			evadeobstacle_z = 0;
-			evadelava_z = 0;
-			makevectors(self.v_angle_y * '0 1 0');
-
-			if(evadeobstacle!='0 0 0'||evadelava!='0 0 0')
-				self.aistatus |= AI_STATUS_DANGER_AHEAD;
-		}
-
-		dodge = havocbot_dodge();
-		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);
-	//	self.bot_dodgevector = dir;
-	//	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_z = 1;
-		}
-		else
-		{
-			if(self.origin_z + self.mins_z  > self.ladder_entity.origin_z + self.ladder_entity.mins_z)
-				dir_z = -1;
-		}
-	}
-
-	//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;
-
-	// Emulate keyboard interface
-	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);
-};
-
-.float havocbot_chooseenemy_finished;
-.float havocbot_stickenemy;
-void havocbot_chooseenemy()
-{
-	local entity head, best, head2;
-	local float rating, bestrating, i, f;
-	local vector eye, v;
-	if (cvar("bot_nofire") || IS_INDEPENDENT_PLAYER(self))
-	{
-		self.enemy = world;
-		return;
-	}
-	if (self.enemy)
-	{
-		if (!bot_shouldattack(self.enemy))
-		{
-			// enemy died or something, find a new target
-			self.enemy = world;
-			self.havocbot_chooseenemy_finished = time;
-		}
-		else if (self.havocbot_stickenemy)
-		{
-			// tracking last chosen enemy
-			// if enemy is visible
-			// and not really really far away
-			// and we're not severely injured
-			// then keep tracking for a half second into the future
-			traceline(self.origin+self.view_ofs, self.enemy.origin+self.enemy.view_ofs*0.5,FALSE,world);
-			if (trace_ent == self.enemy || trace_fraction == 1)
-			if (vlen(self.enemy.origin - self.origin) < 1000)
-			if (self.health > 30)
-			{
-				// remain tracking him for a shot while (case he went after a small corner or pilar
-				self.havocbot_chooseenemy_finished = time + cvar("bot_ai_enemydetectioninterval");
-				return;
-			}
-			// enemy isn't visible, or is far away, or we're injured severely
-			// so stop preferring this enemy
-			// (it will still take a half second until a new one is chosen)
-			self.havocbot_stickenemy = 0;
-		}
-	}
-	if (time < self.havocbot_chooseenemy_finished)
-		return;
-	self.havocbot_chooseenemy_finished = time + cvar("bot_ai_enemydetectioninterval");
-	eye = self.origin + self.view_ofs;
-	best = world;
-	bestrating = 100000000;
-	head = head2 = findchainfloat(bot_attack, TRUE);
-
-	// Search for enemies, if no enemy can be seen directly try to look through transparent objects
-	for(;;)
-	{
-		while (head)
-		{
-			v = (head.absmin + head.absmax) * 0.5;
-			rating = vlen(v - eye);
-			if (rating<cvar("bot_ai_enemydetectionradius"))
-			if (bestrating > rating)
-			if (bot_shouldattack(head))
-			{
-				traceline(eye, v, TRUE, self);
-				if (trace_ent == head || trace_fraction >= 1)
-				{
-					best = head;
-					bestrating = rating;
-				}
-			}
-			head = head.chain;
-		}
-
-		// I want to do a second scan if no enemy was found or I don't have weapons
-		// TODO: Perform the scan when using the rifle (requires changes on the rifle code)
-		if(best || self.weapons) // || self.weapon == WEP_CAMPINGRIFLE
-			break;
-		if(i)
-			break;
-
-		// Set flags to see through transparent objects
-		f = self.dphitcontentsmask;
-		self.dphitcontentsmask = DPCONTENTS_OPAQUE;
-
-		head = head2;
-		++i;
-	}
-
-	// Restore hit flags if needed
-	if(i)
-		self.dphitcontentsmask = f;
-
-	self.enemy = best;
-	self.havocbot_stickenemy = TRUE;
-};
-
-.float bot_chooseweapontime;
-float(entity e) w_getbestweapon;
-void havocbot_chooseweapon()
-{
-	local float i;
-
-	// ;)
-	if(g_weaponarena == WEPBIT_TUBA)
-	{
-		self.switchweapon = WEP_TUBA;
-		return;
-	}
-
-	// TODO: clean this up by moving it to weapon code
-	if(self.enemy==world)
-	{
-		// If no weapon was chosen get the first available weapon
-		if(self.weapon==0)
-		for(i=WEP_LASER + 1; i < WEP_COUNT ; ++i)
-		{
-			if(client_hasweapon(self, i, TRUE, FALSE))
-			{
-				self.switchweapon = i;
-				return;
-			}
-		}
-		return;
-	}
-
-	// Do not change weapon during the next second after a combo
-	i = time - self.lastcombotime;
-	if(i < 1)
-		return;
-
-	// Workaround for rifle reloading (..)
-	if(self.weapon == WEP_CAMPINGRIFLE)
-	if(i < cvar("g_balance_campingrifle_reloadtime") + 1)
-		return;
-
-	local float w;
-	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 campingrifle ; campingrifle  =-1000;
-	local float laser   ; laser    =-1000;
-	local float minstanex ; minstanex =-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;
-
-	// Should it do a weapon combo?
-	local float af, ct, combo_time, combo;
-
-	af = ATTACK_FINISHED(self);
-	ct = cvar("bot_ai_weapon_combo_threshold");
-
-	// Bots with no skill will be 4 times more slower than "godlike" bots when doing weapon combos
-	// Ideally this 4 should be calculated as longest_weapon_refire / bot_ai_weapon_combo_threshold
-	combo_time = time + ct + (ct * ((-0.3*skill)+3));
-
-	combo = FALSE;
-
-	if(cvar("bot_ai_weapon_combo"))
-	if(self.weapon == self.lastfiredweapon)
-	if(af > combo_time)
-	{
-		combo = TRUE;
-		self.lastcombotime = time;
-	}
-
-	// Custom weapon list based on distance to the enemy
-	if(bot_custom_weapon){
-
-		// Choose weapons for far distance
-		if ( distance > bot_distance_far ) {
-			for(i=0; i < WEP_COUNT && bot_weapons_far[i] != -1 ; ++i){
-				w = bot_weapons_far[i];
-				if ( client_hasweapon(self, w, TRUE, FALSE) ){
-					if ( self.weapon == w && combo)
-						continue;
-					self.switchweapon = w;
-					return;
-				}
-			}
-		}
-
-		// Choose weapons for mid distance
-		if ( distance > bot_distance_close ) {
-			for(i=0; i < WEP_COUNT && bot_weapons_mid[i] != -1 ; ++i){
-				w = bot_weapons_mid[i];
-				if ( client_hasweapon(self, w, TRUE, FALSE) ){
-					if ( self.weapon == w && combo)
-						continue;
-					self.switchweapon = w;
-					return;
-				}
-			}
-		}
-
-		// Choose weapons for close distance
-		for(i=0; i < WEP_COUNT && bot_weapons_close[i] != -1 ; ++i){
-			w = bot_weapons_close[i];
-			if ( client_hasweapon(self, w, TRUE, FALSE) ){
-				if ( self.weapon == w && combo)
-					continue;
-				self.switchweapon = w;
-				return;
-			}
-		}
-	}
-
-#ifdef 0
-	// TODO: This disabled code is not working well and got replaced by custom weapon priorities.
-	// However, this logic should be refactored and moved to weapons code so each new weapon can be
-	// evaluated dynamically by bots without updating the "ai" or config files.	--mand1nga
-	float s, distancefromfloor, currentscore;
-
-
-	// 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)
-	// %weaponaddpoint
-
-	traceline(self.enemy.origin,self.enemy.origin-'0 0 1000',TRUE,world);
-	distancefromfloor = self.enemy.origin_z - trace_endpos_z;
-
-	if (client_hasweapon(self, WEP_MINSTANEX, TRUE, FALSE))
-		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 &&
-			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 &&
-			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) ) // &&
-	//	!( 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 &&
-			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 &&
-			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) ) // &&
-	//	!( 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) ) // &&
-	//	!( 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 &&
-			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 &&
-			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));
-		electro = electro * (1.5-bound(0,distancefromfloor/cvar("g_balance_electro_primary_radius"        ),0.95));
-		laser = laser     * (1.5-bound(0,distancefromfloor/cvar("g_balance_laser_primary_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");
-	*/
-	currentscore = -1;
-	w = WEP_MINSTANEX        ;s = minstanex;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_ROCKET_LAUNCHER  ;s = rocket   ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_NEX              ;s = nex      ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_HAGAR            ;s = hagar    ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_GRENADE_LAUNCHER ;s = grenade  ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_ELECTRO          ;s = electro  ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_CRYLINK          ;s = crylink  ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_UZI              ;s = uzi      ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_SHOTGUN          ;s = shotgun  ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-	w = WEP_LASER            ;s = laser    ;if (s > bestscore){bestscore = s;bestweapon = w;} if (self.switchweapon == w) currentscore = s;
-
-	// 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"));
-	}
-#endif
-};
-
-.float nextaim;
-void havocbot_aim()
-{
-	local vector selfvel, enemyvel;
-//	if(self.flags & FL_INWATER)
-//		return;
-	if (time < self.nextaim)
-		return;
-	self.nextaim = time + 0.1;
-	selfvel = self.velocity;
-	if (!self.waterlevel)
-		selfvel_z = 0;
-	if (self.enemy)
-	{
-		enemyvel = self.enemy.velocity;
-		if (!self.enemy.waterlevel)
-			enemyvel_z = 0;
-		lag_additem(time + self.ping, 0, 0, self.enemy, self.origin, selfvel, self.enemy.origin, enemyvel);
-	}
-	else
-		lag_additem(time + self.ping, 0, 0, world, self.origin, selfvel, self.goalcurrent.origin, '0 0 0');
-};
-
-.entity draggedby;
-void havocbot_ai()
-{
-	if(self.draggedby)
-		return;
-
-	if(bot_execute_commands())
-		return;
-
-	if (bot_strategytoken == self)
-	if (!bot_strategytoken_taken)
-	{
-		if(self.havocbot_blockhead)
-		{
-			self.havocbot_blockhead = FALSE;
-		}
-		else
-		{
-			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.deadflag != DEAD_NO)
-		if(self.goalcurrent==world)
-		if(self.waterlevel==WATERLEVEL_SWIMMING || 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 != DEAD_NO)
-		return;
-
-	havocbot_chooseenemy();
-	if (self.bot_chooseweapontime < time )
-	{
-		self.bot_chooseweapontime = time + cvar("bot_ai_chooseweaponinterval");
-		havocbot_chooseweapon();
-	}
-	havocbot_aim();
-	lag_update();
-	if (self.bot_aimtarg)
-	{
-		self.aistatus |= AI_STATUS_ATTACKING;
-		self.aistatus &~= AI_STATUS_ROAMING;
-
-		if(self.weapons)
-		{
-			weapon_action(self.weapon, WR_AIM);
-			if (cvar("bot_nofire") || IS_INDEPENDENT_PLAYER(self))
-			{
-				self.BUTTON_ATCK = FALSE;
-				self.BUTTON_ATCK2 = FALSE;
-			}
-			else
-			{
-				if(self.BUTTON_ATCK||self.BUTTON_ATCK2)
-					self.lastfiredweapon = self.weapon;
-			}
-		}
-		else
-		{
-			if(self.bot_aimtarg.classname=="player")
-				bot_aimdir(self.bot_aimtarg.origin + self.bot_aimtarg.view_ofs - self.origin - self.view_ofs , -1);
-		}
-	}
-	else if (self.goalcurrent)
-	{
-		self.aistatus |= AI_STATUS_ROAMING;
-		self.aistatus &~= AI_STATUS_ATTACKING;
-
-		local vector now,v,next;//,heading;
-		local float aimdistance,skillblend,distanceblend,blend;
-		next = now = self.goalcurrent.origin - (self.origin + self.view_ofs);
-		aimdistance = vlen(now);
-		//heading = self.velocity;
-		//dprint(self.goalstack01.classname,etos(self.goalstack01),"\n");
-		if(
-			self.goalstack01 != self && self.goalstack01 != world && self.aistatus & AI_STATUS_RUNNING == 0 &&
-			!(self.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT)
-		)
-			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,aimdistance/cvar("bot_ai_keyboard_distance"),1);
-		blend = skillblend * (1-distanceblend);
-		//v = (now * (distanceblend) + next * (1-distanceblend)) * (skillblend) + now * (1-skillblend);
-		//v = now * (distanceblend) * (skillblend) + next * (1-distanceblend) * (skillblend) + now * (1-skillblend);
-		//v = now * ((1-skillblend) + (distanceblend) * (skillblend)) + next * (1-distanceblend) * (skillblend);
-		v = now + blend * (next - now);
-		//dprint(etos(self), " ");
-		//dprint(vtos(now), ":", vtos(next), "=", vtos(v), " (blend ", ftos(blend), ")\n");
-		//v = now * (distanceblend) + next * (1-distanceblend);
-		if (self.waterlevel < WATERLEVEL_SWIMMING)
-			v_z = 0;
-		//dprint("walk at:", vtos(v), "\n");
-		//te_lightning2(world, self.origin, self.goalcurrent.origin);
-		bot_aimdir(v, -1);
-	}
-	havocbot_movetogoal();
-};
-
-.entity havocbot_personal_waypoint;
-.float havocbot_personal_waypoint_searchtime;
-float havocbot_moveto_refresh_route()
-{
-	// Refresh path to goal if necessary
-	entity wp;
-	wp = self.havocbot_personal_waypoint;
-	navigation_goalrating_start();
-	navigation_routerating(wp, 10000, 10000);
-	navigation_goalrating_end();
-	return self.navigation_hasgoals;
-}
-
-.float havocbot_personal_waypoint_failcounter;
-float havocbot_moveto(vector pos)
-{
-	local entity wp;
-
-	if(self.aistatus & AI_STATUS_WAYPOINT_PERSONAL_GOING)
-	{
-		// Step 4: Move to waypoint
-		if(self.havocbot_personal_waypoint==world)
-		{
-			dprint("Error: ", self.netname, " trying to walk to a non existent personal waypoint\n");
-			self.aistatus &~= AI_STATUS_WAYPOINT_PERSONAL_GOING;
-			return CMD_STATUS_ERROR;
-		}
-
-		if (!bot_strategytoken_taken)
-		if(self.havocbot_personal_waypoint_searchtime<time)
-		{
-			bot_strategytoken_taken = TRUE;
-			if(havocbot_moveto_refresh_route())
-			{
-				dprint(self.netname, " walking to its personal waypoint (after ", ftos(self.havocbot_personal_waypoint_failcounter), " failed attempts)\n");
-				self.havocbot_personal_waypoint_searchtime = time + 10;
-				self.havocbot_personal_waypoint_failcounter = 0;
-			}
-			else
-			{
-				self.havocbot_personal_waypoint_failcounter += 1;
-				self.havocbot_personal_waypoint_searchtime = time + 2;
-				if(self.havocbot_personal_waypoint_failcounter >= 30)
-				{
-					dprint("Warning: can't walk to the personal waypoint located at ", vtos(self.havocbot_personal_waypoint.origin),"\n");
-					self.aistatus &~= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
-					remove(self.havocbot_personal_waypoint);
-					return CMD_STATUS_ERROR;
-				}
-				else
-					dprint(self.netname, " can't walk to its personal waypoint (after ", ftos(self.havocbot_personal_waypoint_failcounter), " failed attempts), trying later\n");
-			}
-		}
-
-		#ifdef DEBUG_BOT_GOALSTACK
-			debuggoalstack();
-		#endif
-
-		// Heading
-		local vector dir = self.goalcurrent.origin - (self.origin + self.view_ofs);
-		dir_z = 0;
-		bot_aimdir(dir, -1);
-
-		// Go!
-		havocbot_movetogoal();
-
-		if(self.aistatus & AI_STATUS_WAYPOINT_PERSONAL_REACHED)
-		{
-			// Step 5: Waypoint reached
-			dprint(self.netname, "'s personal waypoint reached\n");
-			remove(self.havocbot_personal_waypoint);
-			self.aistatus &~= AI_STATUS_WAYPOINT_PERSONAL_REACHED;
-			return CMD_STATUS_FINISHED;
-		}
-
-		return CMD_STATUS_EXECUTING;
-	}
-
-	// Step 2: Linking waypoint
-	if(self.aistatus & AI_STATUS_WAYPOINT_PERSONAL_LINKING)
-	{
-		// Wait until it is linked
-		if(!self.havocbot_personal_waypoint.wplinked)
-		{
-			dprint(self.netname, " waiting for personal waypoint to be linked\n");
-			return CMD_STATUS_EXECUTING;
-		}
-
-		self.havocbot_personal_waypoint_searchtime = time; // so we set the route next frame
-		self.aistatus &~= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
-		self.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_GOING;
-
-		// Step 3: Route to waypoint
-		dprint(self.netname, " walking to its personal waypoint\n");
-
-		return CMD_STATUS_EXECUTING;
-	}
-
-	// Step 1: Spawning waypoint
-	wp = waypoint_spawnpersonal(pos);
-	if(wp==world)
-	{
-		dprint("Error: Can't spawn personal waypoint at ",vtos(pos),"\n");
-		return CMD_STATUS_ERROR;
-	}
-
-	self.havocbot_personal_waypoint = wp;
-	self.havocbot_personal_waypoint_failcounter = 0;
-	self.aistatus |= AI_STATUS_WAYPOINT_PERSONAL_LINKING;
-
-	return CMD_STATUS_EXECUTING;
-}
-
-float havocbot_resetgoal()
-{
-	navigation_clearroute();
-	return CMD_STATUS_FINISHED;
-}
-
-void havocbot_setupbot()
-{
-	self.bot_ai = havocbot_ai;
-	self.cmd_moveto = havocbot_moveto;
-	self.cmd_resetgoal = havocbot_resetgoal;
-
-	// will be updated by think code
-	//Generate some random skill levels
-	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

Deleted: branches/nexuiz-2.0/data/qcsrc/server/havocbot_ctf.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot_ctf.qc	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot_ctf.qc	2009-09-23 10:28:19 UTC (rev 7880)
@@ -1,680 +0,0 @@
-#define HAVOCBOT_CTF_ROLE_NONE 		0
-#define HAVOCBOT_CTF_ROLE_DEFENSE	2
-#define HAVOCBOT_CTF_ROLE_MIDDLE	4
-#define HAVOCBOT_CTF_ROLE_OFFENSE	8
-#define HAVOCBOT_CTF_ROLE_CARRIER	16
-#define HAVOCBOT_CTF_ROLE_RETRIEVER	32
-#define HAVOCBOT_CTF_ROLE_ESCORT	64
-
-.void() havocbot_role;
-.void() havocbot_previous_role;
-
-void() havocbot_role_ctf_middle;
-void() havocbot_role_ctf_defense;
-void() havocbot_role_ctf_offense;
-void() havocbot_role_ctf_carrier;
-void() havocbot_role_ctf_retriever;
-void() havocbot_role_ctf_escort;
-
-void(entity bot) havocbot_ctf_reset_role;
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
-
-.float havocbot_cantfindflag;
-.float havocbot_role_timeout;
-.entity ctf_worldflagnext;
-.entity basewaypoint;
-
-vector havocbot_ctf_middlepoint;
-float havocbot_ctf_middlepoint_radius;
-entity ctf_worldflaglist;
-
-entity havocbot_ctf_find_flag(entity bot)
-{
-	entity f;
-	f = ctf_worldflaglist;
-	while (f)
-	{
-		if (bot.team == f.team)
-			return f;
-		f = f.ctf_worldflagnext;
-	}
-	return world;
-};
-
-entity havocbot_ctf_find_enemy_flag(entity bot)
-{
-	entity f;
-	f = ctf_worldflaglist;
-	while (f)
-	{
-		if (bot.team != f.team)
-			return f;
-		f = f.ctf_worldflagnext;
-	}
-	return world;
-};
-
-float havocbot_ctf_teamcount(entity bot, vector org, float radius)
-{
-	if not(teams_matter)
-		return 0;
-
-	float c;
-	entity head;
-
-	FOR_EACH_PLAYER(head)
-	{
-		if(head.team!=bot.team || head.deadflag != DEAD_NO || head == bot)
-			continue;
-
-		if(vlen(head.origin - org) < radius)
-			++c;
-	}
-
-	return c;
-};
-
-void havocbot_goalrating_ctf_ourflag(float ratingscale)
-{
-	local entity head;
-	head = ctf_worldflaglist;
-	while (head)
-	{
-		if (self.team == head.team)
-			break;
-		head = head.ctf_worldflagnext;
-	}
-	if (head)
-		navigation_routerating(head, ratingscale, 10000);
-};
-
-void havocbot_goalrating_ctf_ourbase(float ratingscale)
-{
-	local entity head;
-	head = ctf_worldflaglist;
-	while (head)
-	{
-		if (self.team == head.team)
-			break;
-		head = head.ctf_worldflagnext;
-	}
-	if not(head)
-		return;
-
-	navigation_routerating(head.basewaypoint, ratingscale, 10000);
-};
-
-void havocbot_goalrating_ctf_enemyflag(float ratingscale)
-{
-	local entity head;
-	head = ctf_worldflaglist;
-	while (head)
-	{
-		if (self.team != head.team)
-			break;
-		head = head.ctf_worldflagnext;
-	}
-	if (head)
-		navigation_routerating(head, ratingscale, 10000);
-};
-
-void havocbot_goalrating_ctf_enemybase(float ratingscale)
-{
-	if not(bot_waypoints_for_items)
-	{
-		havocbot_goalrating_ctf_enemyflag(ratingscale);
-		return;
-	}
-
-	local entity head;
-
-	head = havocbot_ctf_find_enemy_flag(self);
-
-	if not(head)
-		return;
-
-	navigation_routerating(head.basewaypoint, ratingscale, 10000);
-};
-
-void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
-{
-	local entity mf;
-
-	mf = havocbot_ctf_find_flag(self);
-
-	if(mf.cnt == FLAG_BASE)
-		return;
-
-	navigation_routerating(mf, ratingscale, 10000);
-};
-
-void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float radius)
-{
-	local entity head;
-	head = ctf_worldflaglist;
-	while (head)
-	{
-		// flag is out in the field
-		if(head.cnt != FLAG_BASE)
-		if(head.tag_entity==world)	// dropped
-		{
-			if(radius)
-			{
-				if(vlen(org-head.origin)<radius)
-					navigation_routerating(head, ratingscale, 10000);
-			}
-			else
-				navigation_routerating(head, ratingscale, 10000);
-		}
-
-		head = head.ctf_worldflagnext;
-	}
-};
-
-void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
-{
-	local entity head;
-	local float t;
-	head = findchainfloat(bot_pickup, TRUE);
-	while (head)
-	{
-		// gather health and armor only
-		if (head.solid)
-		if (head.health || head.armorvalue)
-		if (vlen(head.origin - org) < sradius)
-		{
-			// get the value of the item
-			t = head.bot_pickupevalfunc(self, head) * 0.0001;
-			if (t > 0)
-				navigation_routerating(head, t * ratingscale, 500);
-		}
-		head = head.chain;
-	}
-};
-
-void havocbot_role_ctf_setrole(entity bot, float role)
-{
-	dprint(strcat(bot.netname," switched to "));
-	switch(role)
-	{
-		case HAVOCBOT_CTF_ROLE_CARRIER:
-			dprint("carrier");
-			bot.havocbot_role = havocbot_role_ctf_carrier;
-			bot.havocbot_role_timeout = 0;
-			bot.havocbot_cantfindflag = time + 10;
-			break;
-		case HAVOCBOT_CTF_ROLE_DEFENSE:
-			dprint("defense");
-			bot.havocbot_role = havocbot_role_ctf_defense;
-			bot.havocbot_role_timeout = 0;
-			break;
-		case HAVOCBOT_CTF_ROLE_MIDDLE:
-			dprint("middle");
-			bot.havocbot_role = havocbot_role_ctf_middle;
-			bot.havocbot_role_timeout = 0;
-			break;
-		case HAVOCBOT_CTF_ROLE_OFFENSE:
-			dprint("offense");
-			bot.havocbot_role = havocbot_role_ctf_offense;
-			bot.havocbot_role_timeout = 0;
-			break;
-		case HAVOCBOT_CTF_ROLE_RETRIEVER:
-			dprint("retriever");
-			bot.havocbot_previous_role = bot.havocbot_role;
-			bot.havocbot_role = havocbot_role_ctf_retriever;
-			bot.havocbot_role_timeout = time + 10;
-			break;
-		case HAVOCBOT_CTF_ROLE_ESCORT:
-			dprint("escort");
-			bot.havocbot_previous_role = bot.havocbot_role;
-			bot.havocbot_role = havocbot_role_ctf_escort;
-			bot.havocbot_role_timeout = time + 30;
-			break;
-	}
-	dprint("\n");
-};
-
-void havocbot_role_ctf_carrier()
-{
-	if(self.deadflag != DEAD_NO)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.flagcarried == world)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.bot_strategytime < time)
-	{
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-
-		navigation_goalrating_start();
-		havocbot_goalrating_ctf_ourbase(50000);
-
-		if(self.health<100)
-			havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
-
-		navigation_goalrating_end();
-
-		if (self.navigation_hasgoals)
-			self.havocbot_cantfindflag = time + 10;
-		else if (time > self.havocbot_cantfindflag)
-		{
-			// Can't navigate to my own base, suicide!
-			// TODO: drop it and wander around
-			Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
-			return;
-		}
-	}
-};
-
-void havocbot_role_ctf_escort()
-{
-	local entity mf, ef;
-
-	if(self.deadflag != DEAD_NO)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.flagcarried)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
-		return;
-	}
-
-	// If enemy flag is back on the base switch to previous role
-	ef = havocbot_ctf_find_enemy_flag(self);
-	if(ef.cnt==FLAG_BASE)
-	{
-		self.havocbot_role = self.havocbot_previous_role;
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	// If the flag carrier reached the base switch to defense
-	mf = havocbot_ctf_find_flag(self);
-	if(mf.cnt!=FLAG_BASE)
-	if(vlen(ef.origin - mf.dropped_origin) < 300)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_DEFENSE);
-		return;
-	}
-
-	// Set the role timeout if necessary
-	if (!self.havocbot_role_timeout)
-	{
-		self.havocbot_role_timeout = time + random() * 30 + 60;
-	}
-
-	// If nothing happened just switch to previous role
-	if (time > self.havocbot_role_timeout)
-	{
-		self.havocbot_role = self.havocbot_previous_role;
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	// Chase the flag carrier
-	if (self.bot_strategytime < time)
-	{
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-		havocbot_goalrating_ctf_enemyflag(30000);
-		havocbot_goalrating_ctf_ourstolenflag(40000);
-		havocbot_goalrating_items(10000, self.origin, 10000);
-		navigation_goalrating_end();
-	}
-};
-
-void havocbot_role_ctf_offense()
-{
-	local entity mf, ef;
-	local vector pos;
-
-	if(self.deadflag != DEAD_NO)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.flagcarried)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
-		return;
-	}
-
-	// Check flags
-	mf = havocbot_ctf_find_flag(self);
-	ef = havocbot_ctf_find_enemy_flag(self);
-
-	// Own flag stolen
-	if(mf.cnt!=FLAG_BASE)
-	{
-		if(mf.tag_entity)
-			pos = mf.tag_entity.origin;
-		else
-			pos = mf.origin;
-
-		// Try to get it if closer than the enemy base
-		if(vlen(self.origin-ef.dropped_origin)>vlen(self.origin-pos))
-		{
-			havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
-			return;
-		}
-	}
-
-	// Escort flag carrier
-	if(ef.cnt!=FLAG_BASE)
-	{
-		if(ef.tag_entity)
-			pos = ef.tag_entity.origin;
-		else
-			pos = ef.origin;
-
-		if(vlen(pos-mf.dropped_origin)>700)
-		{
-			havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_ESCORT);
-			return;
-		}
-	}
-
-	// About to fail, switch to middlefield
-	if(self.health<50)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_MIDDLE);
-		return;
-	}
-
-	// Set the role timeout if necessary
-	if (!self.havocbot_role_timeout)
-		self.havocbot_role_timeout = time + 120;
-
-	if (time > self.havocbot_role_timeout)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.bot_strategytime < time)
-	{
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-		havocbot_goalrating_ctf_ourstolenflag(50000);
-		havocbot_goalrating_ctf_enemybase(20000);
-		havocbot_goalrating_items(5000, self.origin, 1000);
-		havocbot_goalrating_items(1000, self.origin, 10000);
-		navigation_goalrating_end();
-	}
-};
-
-// Retriever (temporary role):
-void havocbot_role_ctf_retriever()
-{
-	local entity mf;
-
-	if(self.deadflag != DEAD_NO)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.flagcarried)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
-		return;
-	}
-
-	// If flag is back on the base switch to previous role
-	mf = havocbot_ctf_find_flag(self);
-	if(mf.cnt==FLAG_BASE)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (!self.havocbot_role_timeout)
-		self.havocbot_role_timeout = time + 20;
-
-	if (time > self.havocbot_role_timeout)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.bot_strategytime < time)
-	{
-		local float radius;
-		radius = 10000;
-
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-		havocbot_goalrating_ctf_ourstolenflag(50000);
-		havocbot_goalrating_ctf_droppedflags(40000, self.origin, radius);
-		havocbot_goalrating_ctf_enemybase(30000);
-		havocbot_goalrating_items(500, self.origin, radius);
-		navigation_goalrating_end();
-	}
-};
-
-void havocbot_role_ctf_middle()
-{
-	local entity mf;
-
-	if(self.deadflag != DEAD_NO)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.flagcarried)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
-		return;
-	}
-
-	mf = havocbot_ctf_find_flag(self);
-	if(mf.cnt!=FLAG_BASE)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
-		return;
-	}
-
-	if (!self.havocbot_role_timeout)
-		self.havocbot_role_timeout = time + 10;
-
-	if (time > self.havocbot_role_timeout)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.bot_strategytime < time)
-	{
-		local vector org;
-
-		org = havocbot_ctf_middlepoint;
-		org_z = self.origin_z;
-
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-		havocbot_goalrating_ctf_ourstolenflag(50000);
-		havocbot_goalrating_ctf_droppedflags(30000, self.origin, 10000);
-		havocbot_goalrating_enemyplayers(10000, org, havocbot_ctf_middlepoint_radius * 0.5);
-		havocbot_goalrating_items(5000, org, havocbot_ctf_middlepoint_radius * 0.5);
-		havocbot_goalrating_items(2500, self.origin, 10000);
-		havocbot_goalrating_ctf_enemybase(2500);
-		navigation_goalrating_end();
-	}
-};
-
-void havocbot_role_ctf_defense()
-{
-	local entity mf;
-
-	if(self.deadflag != DEAD_NO)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-
-	if (self.flagcarried)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
-		return;
-	}
-
-	// If own flag was captured
-	mf = havocbot_ctf_find_flag(self);
-	if(mf.cnt!=FLAG_BASE)
-	{
-		havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
-		return;
-	}
-
-	if (!self.havocbot_role_timeout)
-		self.havocbot_role_timeout = time + 30;
-
-	if (time > self.havocbot_role_timeout)
-	{
-		havocbot_ctf_reset_role(self);
-		return;
-	}
-	if (self.bot_strategytime < time)
-	{
-		local float radius;
-		local vector org;
-
-		org = mf.dropped_origin;
-		radius = havocbot_ctf_middlepoint_radius;
-
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-
-		// if enemies are closer to our base, go there
-		local entity head, closestplayer;
-		local float distance, bestdistance;
-		distance = 10000;
-		FOR_EACH_PLAYER(head)
-		{
-			if(head.deadflag!=DEAD_NO)
-				continue;
-
-			distance = vlen(org - head.origin);
-			if(distance<bestdistance)
-			{
-				closestplayer = head;
-				bestdistance = distance;
-			}
-		}
-
-		if(closestplayer)
-		if(closestplayer.team!=self.team)
-		if(vlen(org - self.origin)>1000)
-		if(checkpvs(self.origin,closestplayer)||random()<0.5)
-			havocbot_goalrating_ctf_ourbase(30000);
-
-		havocbot_goalrating_ctf_ourstolenflag(20000);
-		havocbot_goalrating_ctf_droppedflags(20000, org, radius);
-		havocbot_goalrating_enemyplayers(15000, org, radius);
-		havocbot_goalrating_items(10000, org, radius);
-		havocbot_goalrating_items(5000, self.origin, 10000);
-		navigation_goalrating_end();
-	}
-};
-
-void havocbot_calculate_middlepoint()
-{
-	entity f;
-	vector p1, p2;
-
-	f = ctf_worldflaglist;
-	while (f)
-	{
-		if(p1)
-			p2 = f.origin;
-		else
-			p1 = f.origin;
-
-		f = f.ctf_worldflagnext;
-	}
-	havocbot_ctf_middlepoint = p1 + ((p2-p1) * 0.5);
-	havocbot_ctf_middlepoint_radius	 = vlen(p2-p1) * 0.5;
-};
-
-void havocbot_ctf_reset_role(entity bot)
-{
-	local float cdefense, cmiddle, coffense;
-	local entity mf, ef, head;
-	local float c;
-
-	if(bot.deadflag != DEAD_NO)
-		return;
-
-	if(vlen(havocbot_ctf_middlepoint)==0)
-		havocbot_calculate_middlepoint();
-
-	// Check ctf flags
-	if (bot.flagcarried)
-	{
-		havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_CARRIER);
-		return;
-	}
-
-	mf = havocbot_ctf_find_flag(bot);
-	ef = havocbot_ctf_find_enemy_flag(bot);
-
-	// Retrieve stolen flag
-	if(mf.cnt!=FLAG_BASE)
-	{
-		havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_RETRIEVER);
-		return;
-	}
-
-	// If enemy flag is taken go to the middle to intercept pursuers
-	if(ef.cnt!=FLAG_BASE)
-	{
-		havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
-		return;
-	}
-
-	// if there is only me on the team switch to offense
-	c = 0;
-	FOR_EACH_PLAYER(head)
-	if(head.team==bot.team)
-		++c;
-
-	if(c==1)
-	{
-		havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
-		return;
-	}
-
-	// Evaluate best position to take
-	// Count mates on middle position
-	cmiddle = havocbot_ctf_teamcount(bot, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
-
-	// Count mates on defense position
-	cdefense = havocbot_ctf_teamcount(bot, mf.dropped_origin, havocbot_ctf_middlepoint_radius * 0.5);
-
-	// Count mates on offense position
-	coffense = havocbot_ctf_teamcount(bot, ef.dropped_origin, havocbot_ctf_middlepoint_radius);
-
-	if(cdefense<=coffense)
-		havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_DEFENSE);
-	else if(coffense<=cmiddle)
-		havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
-	else
-		havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
-};
-
-void havocbot_chooserole_ctf()
-{
-	havocbot_ctf_reset_role(self);
-};

Deleted: branches/nexuiz-2.0/data/qcsrc/server/havocbot_ons.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot_ons.qc	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot_ons.qc	2009-09-23 10:28:19 UTC (rev 7880)
@@ -1,366 +0,0 @@
-#define HAVOCBOT_ONS_ROLE_NONE 		0
-#define HAVOCBOT_ONS_ROLE_DEFENSE	2
-#define HAVOCBOT_ONS_ROLE_ASSISTANT	4
-#define HAVOCBOT_ONS_ROLE_OFFENSE	8
-
-.float havocbot_role_flags;
-.float havocbot_attack_time;
-
-.void() havocbot_role;
-.void() havocbot_previous_role;
-
-void() havocbot_role_ons_defense;
-void() havocbot_role_ons_offense;
-void() havocbot_role_ons_assistant;
-
-void(entity bot) havocbot_ons_reset_role;
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
-void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
-
-.float isshielded;
-.float iscaptured;
-.float islinked;
-.float isgenneighbor_blue, iscpneighbor_blue;
-.float isgenneighbor_red, iscpneighbor_red;
-
-.entity havocbot_ons_target;
-
-void havocbot_goalrating_ons_offenseitems(float ratingscale, vector org, float sradius)
-{
-	local entity head;
-	local float t, i, c, needarmor, needweapons;
-
-	// Needs armor/health?
-	if(self.health<100)
-		needarmor = TRUE;
-
-	// Needs weapons?
-	for(i = WEP_FIRST; i < WEP_LAST ; ++i)
-	{
-		// Find weapon
-		if((get_weaponinfo(i)).weapons & self.weapons)
-		if(++c>=4)
-			break;
-	}
-
-	if(c<4)
-		needweapons = TRUE;
-
-	if(!needweapons && !needarmor)
-		return;
-
-//	dprint(self.netname, " needs weapons ", ftos(needweapons) , "\n");
-//	dprint(self.netname, " needs armor ", ftos(needarmor) , "\n");
-
-	// See what is around
-	head = findchainfloat(bot_pickup, TRUE);
-	while (head)
-	{
-		// gather health and armor only
-		if (head.solid)
-		if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
-		if (vlen(head.origin - org) < sradius)
-		{
-			t = head.bot_pickupevalfunc(self, head);
-			if (t > 0)
-				navigation_routerating(head, t * ratingscale, 500);
-		}
-		head = head.chain;
-	}
-};
-
-void havocbot_role_ons_setrole(entity bot, float role)
-{
-	dprint(strcat(bot.netname," switched to "));
-	switch(role)
-	{
-		case HAVOCBOT_ONS_ROLE_DEFENSE:
-			dprint("defense");
-			bot.havocbot_role = havocbot_role_ons_defense;
-			bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
-			bot.havocbot_role_timeout = 0;
-			break;
-		case HAVOCBOT_ONS_ROLE_ASSISTANT:
-			dprint("assistant");
-			bot.havocbot_role = havocbot_role_ons_assistant;
-			bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
-			bot.havocbot_role_timeout = 0;
-			break;
-		case HAVOCBOT_ONS_ROLE_OFFENSE:
-			dprint("offense");
-			bot.havocbot_role = havocbot_role_ons_offense;
-			bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
-			bot.havocbot_role_timeout = 0;
-			break;
-	}
-	dprint("\n");
-};
-
-float havocbot_ons_teamcount(entity bot, float role)
-{
-	local float c;
-	local entity head;
-
-	FOR_EACH_PLAYER(head)
-	if(head.team==self.team)
-	if(head.havocbot_role_flags & role)
-		++c;
-
-	return c;
-};
-
-void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
-{
-	entity cp, cp1, cp2, best, pl, wp;
-	float radius, found, bestvalue, c;
-
-	cp1 = cp2 = findchain(classname, "onslaught_controlpoint");
-
-	// Filter control points
-	for (; cp2; cp2 = cp2.chain)
-	{
-		cp2.wpcost = c = 0;
-		cp2.wpconsidered = FALSE;
-
-		if(cp2.isshielded)
-			continue;
-
-		// Ignore owned controlpoints
-		if(self.team == COLOR_TEAM1)
-		{
-			if( (cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) && !(cp2.isgenneighbor_red || cp2.iscpneighbor_red) )
-				continue;
-		}
-		else if(self.team == COLOR_TEAM2)
-		{
-			if( (cp2.isgenneighbor_red || cp2.iscpneighbor_red) && !(cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) )
-				continue;
-		}
-
-		// Count team mates interested in this control point
-		// (easier and cleaner than keeping counters per cp and teams)
-		FOR_EACH_PLAYER(pl)
-		if(pl.team==self.team)
-		if(pl.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
-		if(pl.havocbot_ons_target==cp2)
-			++c;
-
-		// NOTE: probably decrease the cost of attackable control points
-		cp2.wpcost = c;
-		cp2.wpconsidered = TRUE;
-	}
-
-	// We'll consider only the best case
-	bestvalue = 99999999999;
-	for (; cp1; cp1 = cp1.chain)
-	{
-		if not(cp1.wpconsidered)
-			continue;
-
-		if(cp1.wpcost<bestvalue)
-		{
-			bestvalue = cp1.wpcost;
-			cp = cp1;
-			self.havocbot_ons_target = cp1;
-		}
-	}
-
-	if not(cp)
-		return;
-
-//	dprint(self.netname, " chose cp ranked ", ftos(bestvalue), "\n");
-
-	if(cp.goalentity)
-	{
-		// Should be attacked
-		// Rate waypoints near it
-		found = FALSE;
-		best = world;
-		bestvalue = 99999999999;
-		for(radius=0; radius<1000 && !found; radius+=500)
-		{
-			for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
-			{
-				if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
-				if(wp.classname=="waypoint")
-				if(checkpvs(wp.origin,cp))
-				{
-					found = TRUE;
-					if(wp.cnt<bestvalue)
-					{
-						best = wp;
-						bestvalue = wp.cnt;
-					}
-				}
-			}
-		}
-
-		if(best)
-		{
-			navigation_routerating(best, ratingscale, 10000);
-			best.cnt += 1;
-
-			self.havocbot_attack_time = 0;
-			if(checkpvs(self.view_ofs,cp))
-			if(checkpvs(self.view_ofs,best))
-				self.havocbot_attack_time = time + 2;
-		}
-		else
-		{
-			navigation_routerating(cp, ratingscale, 10000);
-		}
-	//	dprint(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n");
-	}
-	else
-	{
-		// Should be touched
-		// dprint(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n");
-
-		// Look for auto generated waypoint
-		if not(bot_waypoints_for_items)
-		for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
-		{
-			if(wp.classname=="waypoint")
-			{
-				navigation_routerating(wp, ratingscale, 10000);
-				found = TRUE;
-			}
-		}
-
-		// Nothing found, rate the controlpoint itself
-		if not(found)
-			navigation_routerating(cp, ratingscale, 10000);
-	}
-};
-
-float havocbot_goalrating_ons_generator_attack(float ratingscale)
-{
-	local entity g, wp, bestwp;
-	local float found, best;
-
-	for (g = findchain(classname, "onslaught_generator"); g; g = g.chain)
-	{
-		if(g.team == self.team || g.isshielded)
-			continue;
-
-		// Should be attacked
-		// Rate waypoints near it
-		found = FALSE;
-		bestwp = world;
-		best = 99999999999;
-
-		for(wp=findradius(g.origin,400); wp; wp=wp.chain)
-		{
-			if(wp.classname=="waypoint")
-			if(checkpvs(wp.origin,g))
-			{
-				found = TRUE;
-				if(wp.cnt<best)
-				{
-					bestwp = wp;
-					best = wp.cnt;
-				}
-			}
-		}
-
-		if(bestwp)
-		{
-		//	dprint("waypoints found around generator\n");
-			navigation_routerating(bestwp, ratingscale, 10000);
-			bestwp.cnt += 1;
-
-			self.havocbot_attack_time = 0;
-			if(checkpvs(self.view_ofs,g))
-			if(checkpvs(self.view_ofs,bestwp))
-				self.havocbot_attack_time = time + 5;
-
-			return TRUE;
-		}
-		else
-		{
-		//	dprint("generator found without waypoints around\n");
-			// if there aren't waypoints near the generator go straight to it
-			navigation_routerating(g, ratingscale, 10000);
-			self.havocbot_attack_time = 0;
-			return TRUE;
-		}
-	}
-	return FALSE;
-};
-
-void havocbot_role_ons_offense()
-{
-	if(self.deadflag != DEAD_NO)
-	{
-		self.havocbot_attack_time = 0;
-		havocbot_ons_reset_role(self);
-		return;
-	}
-
-	// Set the role timeout if necessary
-	if (!self.havocbot_role_timeout)
-		self.havocbot_role_timeout = time + 120;
-
-	if (time > self.havocbot_role_timeout)
-	{
-		havocbot_ons_reset_role(self);
-		return;
-	}
-
-	if(self.havocbot_attack_time>time)
-		return;
-
-	if (self.bot_strategytime < time)
-	{
-		navigation_goalrating_start();
-		havocbot_goalrating_enemyplayers(20000, self.origin, 650);
-		if(!havocbot_goalrating_ons_generator_attack(20000))
-			havocbot_goalrating_ons_controlpoints_attack(20000);
-		havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
-		navigation_goalrating_end();
-
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-	}
-};
-
-void havocbot_role_ons_assistant()
-{
-	havocbot_ons_reset_role(self);
-};
-
-void havocbot_role_ons_defense()
-{
-	havocbot_ons_reset_role(self);
-};
-
-void havocbot_ons_reset_role(entity bot)
-{
-	local entity head;
-	local float c;
-
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	bot.havocbot_ons_target = world;
-
-	// TODO: Defend control points or generator if necessary
-
-	// if there is only me on the team switch to offense
-	c = 0;
-	FOR_EACH_PLAYER(head)
-	if(head.team==self.team)
-		++c;
-
-	if(c==1)
-	{
-		havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
-		return;
-	}
-
-	havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
-};
-
-void havocbot_chooserole_ons()
-{
-	havocbot_ons_reset_role(self);
-};

Deleted: branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc	2009-09-23 10:28:19 UTC (rev 7880)
@@ -1,544 +0,0 @@
-
-.float havocbot_role_timeout;
-.void() havocbot_previous_role;
-.void() havocbot_role;
-float bot_ignore_bots;
-
-.float max_armorvalue;
-
-void havocbot_goalrating_items(float ratingscale, vector org, float sradius)
-{
-	local entity head;
-	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;
-		}
-
-		// Check if the item can be picked up safely
-		if(head.classname == "droppedweapon")
-		{
-			traceline(head.origin, head.origin + '0 0 -1500', TRUE, world);
-
-			d = pointcontents(trace_endpos + '0 0 1');
-			if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
-			{
-				head = head.chain;
-				continue;
-			}
-			if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
-			{
-				head = head.chain;
-				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)
-			{
-
-				if ( self == player || player.deadflag )
-					continue;
-
-				d = vlen(player.origin - head.origin); // distance between player and item
-
-				if ( player.team == self.team )
-				{
-					if ( clienttype(player) != CLIENTTYPE_REAL || discard )
-						continue;
-
-					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;
-
-					if (head.ammo_shells && player.ammo_shells > self.ammo_shells)
-						continue;
-
-					if (head.ammo_nails && player.ammo_nails > self.ammo_nails)
-						continue;
-
-					if (head.ammo_rockets && player.ammo_rockets > self.ammo_rockets)
-						continue;
-
-					if (head.ammo_cells && player.ammo_cells > self.ammo_cells )
-						continue;
-
-					discard = FALSE;
-				}
-				else
-				{
-					// If enemy only track distances
-					// TODO: track only if visible ?
-					if( d < enemy_distance )
-						enemy_distance = d;
-				}
-			}
-
-			// Rate the item only if no one needs it, or if an enemy is closer to it
-			if ( (enemy_distance < friend_distance && distance < enemy_distance) ||
-				(friend_distance > cvar("bot_ai_friends_aware_pickup_radius") ) || !discard )
-				rating = head.bot_pickupevalfunc(self, head);
-
-		}
-		else
-			rating = head.bot_pickupevalfunc(self, head);
-
-		if(rating > 0)
-			navigation_routerating(head, rating * ratingscale, 2000);
-		head = head.chain;
-	}
-};
-
-void havocbot_goalrating_controlpoints(float ratingscale, vector org, float sradius)
-{
-	local entity head;
-	head = findchain(classname, "dom_controlpoint");
-	while (head)
-	{
-		if (vlen(head.origin - org) < sradius)
-		{
-			if(head.cnt > -1) // this is just being fought for
-				navigation_routerating(head, ratingscale, 5000);
-			else if(head.goalentity.cnt == 0) // unclaimed point
-				navigation_routerating(head, ratingscale * 0.5, 5000);
-			else if(head.goalentity.team != self.team) // other team's point
-				navigation_routerating(head, ratingscale * 0.2, 5000);
-		}
-		head = head.chain;
-	}
-};
-
-/*
-// LordHavoc: this function was already unused, but for waypoints to be a
-// useful goal the bots would have to seek out the least-recently-visited
-// ones, not the closest
-void havocbot_goalrating_waypoints(float ratingscale, vector org, float sradius)
-{
-	local entity head;
-	head = findchain(classname, "waypoint");
-	while (head)
-	{
-		if (vlen(head.origin - org) < sradius && vlen(head.origin - org) > 100)
-			navigation_routerating(head, ratingscale, 2000);
-		head = head.chain;
-	}
-};
-*/
-
-void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius)
-{
-	local entity head;
-	local float t, noteam, distance;
-	noteam = ((self.team == 0) || !teams_matter); // fteqcc sucks
-
-	if (cvar("bot_nofire"))
-		return;
-
-	// don't chase players if we're under water
-	if(self.waterlevel>WATERLEVEL_WETFEET)
-		return;
-
-	FOR_EACH_PLAYER(head)
-	{
-		// TODO: Merge this logic with the bot_shouldattack function
-		if (self != head)
-		if (head.health > 0)
-		if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
-		{
-			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)
-			{
-				traceline(head.origin, head.origin + '0 0 -1500', TRUE, world);
-				t = pointcontents(trace_endpos + '0 0 1');
-				if( t != CONTENT_SOLID )
-				if(t & CONTENT_WATER || t & CONTENT_SLIME || t & CONTENT_LAVA)
-					continue;
-				if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
-					continue;
-			}
-
-			t = (self.health + self.armorvalue ) / (head.health + head.armorvalue );
-			navigation_routerating(head, t * ratingscale, 2000);
-		}
-	}
-};
-
-// choose a role according to the situation
-void() havocbot_role_dm;
-
-//DOM:
-//go to best items, or control points you don't own
-void havocbot_role_dom()
-{
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	if (self.bot_strategytime < time)
-	{
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-		havocbot_goalrating_controlpoints(10000, self.origin, 15000);
-		havocbot_goalrating_items(8000, self.origin, 8000);
-		//havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
-		//havocbot_goalrating_waypoints(1, self.origin, 1000);
-		navigation_goalrating_end();
-	}
-};
-
-//DM:
-//go to best items
-void havocbot_role_dm()
-{
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	if (self.bot_strategytime < time)
-	{
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-		havocbot_goalrating_items(10000, self.origin, 10000);
-		havocbot_goalrating_enemyplayers(20000, self.origin, 10000);
-		//havocbot_goalrating_waypoints(1, self.origin, 1000);
-		navigation_goalrating_end();
-	}
-};
-
-//Race:
-//go to next checkpoint, and annoy enemies
-.float race_checkpoint;
-void havocbot_role_race()
-{
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	entity e;
-	if (self.bot_strategytime < time)
-	{
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-		/*
-		havocbot_goalrating_items(100, self.origin, 10000);
-		havocbot_goalrating_enemyplayers(500, self.origin, 20000);
-		*/
-
-		for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; )
-		{
-			if(e.cnt == self.race_checkpoint)
-			{
-				navigation_routerating(e, 1000000, 5000);
-			}
-			else if(self.race_checkpoint == -1)
-			{
-				navigation_routerating(e, 1000000, 5000);
-			}
-		}
-
-		navigation_goalrating_end();
-	}
-};
-
-void havocbot_chooserole_dm()
-{
-	self.havocbot_role = havocbot_role_dm;
-};
-
-void havocbot_chooserole_race()
-{
-	self.havocbot_role = havocbot_role_race;
-};
-
-void havocbot_chooserole_dom()
-{
-	self.havocbot_role = havocbot_role_dom;
-};
-
-
-
-
-
-
-entity kh_worldkeylist;
-.entity kh_worldkeynext;
-void havocbot_goalrating_kh(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
-{
-	local entity head;
-	for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
-	{
-		if(head.owner == self)
-			continue;
-		if(!kh_tracking_enabled)
-		{
-			// if it's carried by our team we know about it
-			// otherwise we have to see it to know about it
-			if(!head.owner || head.team != self.team)
-			{
-				traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
-				if (trace_fraction < 1 && trace_ent != head)
-					continue; // skip what I can't see
-			}
-		}
-		if(!head.owner)
-			navigation_routerating(head, ratingscale_dropped * BOT_PICKUP_RATING_HIGH, 100000);
-		else if(head.team == self.team)
-			navigation_routerating(head.owner, ratingscale_team * BOT_PICKUP_RATING_HIGH, 100000);
-		else
-			navigation_routerating(head.owner, ratingscale_enemy * BOT_PICKUP_RATING_HIGH, 100000);
-	}
-
-	havocbot_goalrating_items(1, self.origin, 10000);
-};
-
-void() havocbot_role_kh_carrier;
-void() havocbot_role_kh_defense;
-void() havocbot_role_kh_offense;
-void() havocbot_role_kh_freelancer;
-void havocbot_role_kh_carrier()
-{
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	if (!(self.kh_next))
-	{
-		dprint("changing role to freelancer\n");
-		self.havocbot_role = havocbot_role_kh_freelancer;
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	if (self.bot_strategytime < time)
-	{
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-
-		if(kh_Key_AllOwnedByWhichTeam() == self.team)
-			havocbot_goalrating_kh(10, 0.1, 0.1); // bring home
-		else
-			havocbot_goalrating_kh(4, 4, 1); // play defensively
-
-		navigation_goalrating_end();
-	}
-}
-
-void havocbot_role_kh_defense()
-{
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	if (self.kh_next)
-	{
-		dprint("changing role to carrier\n");
-		self.havocbot_role = havocbot_role_kh_carrier;
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	if (!self.havocbot_role_timeout)
-		self.havocbot_role_timeout = time + random() * 10 + 20;
-	if (time > self.havocbot_role_timeout)
-	{
-		dprint("changing role to freelancer\n");
-		self.havocbot_role = havocbot_role_kh_freelancer;
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	if (self.bot_strategytime < time)
-	{
-		float key_owner_team;
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-
-		key_owner_team = kh_Key_AllOwnedByWhichTeam();
-		if(key_owner_team == self.team)
-			havocbot_goalrating_kh(10, 0.1, 0.1); // defend key carriers
-		else if(key_owner_team == -1)
-			havocbot_goalrating_kh(4, 1, 0.1); // play defensively
-		else
-			havocbot_goalrating_kh(0.1, 0.1, 10); // ATTACK ANYWAY
-
-		navigation_goalrating_end();
-	}
-};
-
-void havocbot_role_kh_offense()
-{
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	if (self.kh_next)
-	{
-		dprint("changing role to carrier\n");
-		self.havocbot_role = havocbot_role_kh_carrier;
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	if (!self.havocbot_role_timeout)
-		self.havocbot_role_timeout = time + random() * 10 + 20;
-	if (time > self.havocbot_role_timeout)
-	{
-		dprint("changing role to freelancer\n");
-		self.havocbot_role = havocbot_role_kh_freelancer;
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	if (self.bot_strategytime < time)
-	{
-		float key_owner_team;
-
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-
-		key_owner_team = kh_Key_AllOwnedByWhichTeam();
-		if(key_owner_team == self.team)
-			havocbot_goalrating_kh(10, 0.1, 0.1); // defend anyway
-		else if(key_owner_team == -1)
-			havocbot_goalrating_kh(0.1, 1, 4); // play offensively
-		else
-			havocbot_goalrating_kh(0.1, 0.1, 10); // ATTACK! EMERGENCY!
-
-		navigation_goalrating_end();
-	}
-};
-
-void havocbot_role_kh_freelancer()
-{
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	if (self.kh_next)
-	{
-		dprint("changing role to carrier\n");
-		self.havocbot_role = havocbot_role_kh_carrier;
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	if (!self.havocbot_role_timeout)
-		self.havocbot_role_timeout = time + random() * 10 + 10;
-	if (time > self.havocbot_role_timeout)
-	{
-		if (random() < 0.5)
-		{
-			dprint("changing role to offense\n");
-			self.havocbot_role = havocbot_role_kh_offense;
-		}
-		else
-		{
-			dprint("changing role to defense\n");
-			self.havocbot_role = havocbot_role_kh_defense;
-		}
-		self.havocbot_role_timeout = 0;
-		return;
-	}
-
-	if (self.bot_strategytime < time)
-	{
-		float key_owner_team;
-
-		self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
-		navigation_goalrating_start();
-
-		key_owner_team = kh_Key_AllOwnedByWhichTeam();
-		if(key_owner_team == self.team)
-			havocbot_goalrating_kh(10, 0.1, 0.1); // defend anyway
-		else if(key_owner_team == -1)
-			havocbot_goalrating_kh(1, 10, 4); // prefer dropped keys
-		else
-			havocbot_goalrating_kh(0.1, 0.1, 10); // ATTACK ANYWAY
-
-		navigation_goalrating_end();
-	}
-};
-
-void havocbot_chooserole_kh()
-{
-	local float r;
-
-	if(self.deadflag != DEAD_NO)
-		return;
-
-	r = random() * 3;
-	if (r < 1)
-		self.havocbot_role = havocbot_role_kh_offense;
-	else if (r < 2)
-		self.havocbot_role = havocbot_role_kh_defense;
-	else
-		self.havocbot_role = havocbot_role_kh_freelancer;
-};
-
-void havocbot_chooserole()
-{
-	dprint("choosing a role...\n");
-	navigation_clearroute();
-	self.bot_strategytime = 0;
-	if (g_ctf)
-		havocbot_chooserole_ctf();
-	else if (g_domination)
-		havocbot_chooserole_dom();
-	else if (g_keyhunt)
-		havocbot_chooserole_kh();
-	else if (g_race || g_cts)
-		havocbot_chooserole_race();
-	else if (g_onslaught)
-		havocbot_chooserole_ons();
-	else // assume anything else is deathmatch
-		havocbot_chooserole_dm();
-};
-

Modified: branches/nexuiz-2.0/data/qcsrc/server/progs.src
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/progs.src	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/progs.src	2009-09-23 10:28:19 UTC (rev 7880)
@@ -46,17 +46,8 @@
 
 waypointsprites.qc
 
+bot/bot.qc
 
-// general bot utility functions and management
-bots.qc
-bots_scripting.qc
-
-// LordHavoc's bots
-havocbot.qc
-havocbot_ctf.qc
-havocbot_ons.qc
-havocbot_roles.qc
-
 g_subs.qc
 
 g_tetris.qc

Modified: branches/nexuiz-2.0/data/qcsrc/server/w_electro.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/w_electro.qc	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/w_electro.qc	2009-09-23 10:28:19 UTC (rev 7880)
@@ -63,7 +63,10 @@
 			self.nextthink = time + vlen(self.origin - inflictor.origin) / cvar("g_balance_electro_combo_speed"); // delay combo chains, looks cooler
 		}
 		else
-			self.think = W_Plasma_Explode;
+		{
+			self.use = W_Plasma_Explode;
+			self.think = adaptor_think2use;
+		}
 	}
 }
 

Modified: branches/nexuiz-2.0/data/qcsrc/server/w_rocketlauncher.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/w_rocketlauncher.qc	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/qcsrc/server/w_rocketlauncher.qc	2009-09-23 10:28:19 UTC (rev 7880)
@@ -456,7 +456,7 @@
 		{
 			if (self.BUTTON_ATCK)
 			{
-				if(self.rl_release)
+				if(self.rl_release || cvar("g_balance_rocketlauncher_guidestop"))
 				if(weapon_prepareattack(0, cvar("g_balance_rocketlauncher_refire")))
 				{
 					W_Rocket_Attack();

Modified: branches/nexuiz-2.0/data/weapons.cfg
===================================================================
--- branches/nexuiz-2.0/data/weapons.cfg	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/weapons.cfg	2009-09-23 10:28:19 UTC (rev 7880)
@@ -271,6 +271,7 @@
 set g_balance_rocketlauncher_guiderate 90 // max degrees per second
 set g_balance_rocketlauncher_guidegoal 512 // goal distance for (non-laser) guiding (higher = less control, lower = erratic)
 set g_balance_rocketlauncher_guidedelay 0.15 // delay before guiding kicks in
+set g_balance_rocketlauncher_guidestop 0 // stop guiding when firing again
 set g_balance_rocketlauncher_laserguided_speed 1000  //650
 set g_balance_rocketlauncher_laserguided_speedaccel 0
 set g_balance_rocketlauncher_laserguided_speedstart 1000

Modified: branches/nexuiz-2.0/data/weaponsHavoc.cfg
===================================================================
--- branches/nexuiz-2.0/data/weaponsHavoc.cfg	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/data/weaponsHavoc.cfg	2009-09-23 10:28:19 UTC (rev 7880)
@@ -266,6 +266,7 @@
 set g_balance_rocketlauncher_guiderate 360 // max degrees per second
 set g_balance_rocketlauncher_guidegoal 512 // goal distance for (non-laser) guiding (higher = less control, lower = erratic)
 set g_balance_rocketlauncher_guidedelay 0.15 // delay before guiding kicks in
+set g_balance_rocketlauncher_guidestop 0 // stop guiding when firing again
 set g_balance_rocketlauncher_laserguided_speed 1000  //650
 set g_balance_rocketlauncher_laserguided_speedaccel 0
 set g_balance_rocketlauncher_laserguided_speedstart 1000

Modified: branches/nexuiz-2.0/server/rcon2irc/rcon2irc.pl
===================================================================
--- branches/nexuiz-2.0/server/rcon2irc/rcon2irc.pl	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/server/rcon2irc/rcon2irc.pl	2009-09-23 10:28:19 UTC (rev 7880)
@@ -201,10 +201,10 @@
 			my $oldcolor = $color;
 			$color = $color_dp2irc_table[$data];
 
-			$color == $oldcolor ? '' :
-			$color < 0          ? "\017" :
-			$next eq ','        ? "\003$color\002\002" :
-			                      sprintf "\003%02d", $color;
+			$color == $oldcolor        ? '' :
+			$color < 0                 ? "\017" :
+			index '0123456789,', $next ? "\003$color\002\002" :
+			                             "\003$color";
 		} :
 			die "Invalid type";
 	}
@@ -1538,7 +1538,7 @@
 				my $sep = ' ';
 				for(@t)
 				{
-					$scores_string .= $sep . sprintf "\003%02d\%d\017", $color_team2irc_table{$_->{team}}, $_->{score};
+					$scores_string .= $sep . "\003" . $color_team2irc_table{$_->{team}}. "\002\002" . $_->{score} . "\017";
 					$sep = ':';
 				}
 			}

Modified: branches/nexuiz-2.0/server/server.cfg
===================================================================
--- branches/nexuiz-2.0/server/server.cfg	2009-09-23 10:25:17 UTC (rev 7879)
+++ branches/nexuiz-2.0/server/server.cfg	2009-09-23 10:28:19 UTC (rev 7880)
@@ -118,3 +118,6 @@
 
 //g_balance_teams 1	// 0 will show players the team selection menu after joining instead of automaticly putting them on the smaller team
 //g_balance_teams_force 0	// 1 to automaticly balance teams even during a game
+
+//set g_ban_sync_uri "http://94.23.21.40/~nexuiz/bans/" // sync bans using this ban list provider (disabled by default, uncomment this line to enable)
+//set g_ban_sync_trusted_servers "" // accept bans that were initially set on the server IPs listed here (if not set, your bans are just sent to the sync URIs, but no bans are retrieved from there)



More information about the nexuiz-commits mailing list