r5918 - in trunk/data: . qcsrc/server
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Sat Feb 21 17:55:27 EST 2009
Author: mand1nga
Date: 2009-02-21 17:55:27 -0500 (Sat, 21 Feb 2009)
New Revision: 5918
Modified:
trunk/data/defaultNexuiz.cfg
trunk/data/qcsrc/server/bots.qc
trunk/data/qcsrc/server/havocbot.qc
trunk/data/qcsrc/server/havocbot_roles.qc
Log:
Bots: Added bunny-hopping support :)
Added function to debug the goal stack visually
Added .aistatus field
Lowered ammo/health eagerness a bit
Lowered enemy rating radius from 20000 to 10000
Modified: trunk/data/defaultNexuiz.cfg
===================================================================
--- trunk/data/defaultNexuiz.cfg 2009-02-20 18:28:59 UTC (rev 5917)
+++ trunk/data/defaultNexuiz.cfg 2009-02-21 22:55:27 UTC (rev 5918)
@@ -340,7 +340,7 @@
seta skill_auto 0 "when 1, \"skill\" gets adjusted to match the best player on the map"
// general bot AI cvars
set bot_ai_thinkinterval 0.05
-set bot_ai_strategyinterval 2
+set bot_ai_strategyinterval 5
set bot_ai_enemydetectioninterval 0.5
set bot_ai_dodgeupdateinterval 0.1
set bot_ai_chooseweaponinterval 0.3
@@ -364,6 +364,10 @@
set bot_ai_weapon_combo_threshold 0.3 "Try to make a combo N seconds after the last attack"
set bot_ai_friends_aware_pickup_radius "500" "Bots will not pickup items if a team mate is this distance near the item"
set bot_ai_ignoregoal_timeout 3 "Ignore goals making bots to get stuck in front of a wall for N seconds"
+set bot_ai_bunnyhop_skilloffset 7 "Bots with skill equal or greater than this value will perform the \"bunnyhop\" technique"
+set bot_ai_bunnyhop_startdistance 250 "Run to goals located further than this distance"
+set bot_ai_bunnyhop_stopdistance 200 "Stop jumping after reaching this distance to the goal"
+set bot_ai_bunnyhop_firstjumpdelay 0.5 "Start running to the goal only if it was seen for more than N seconds"
// Better don't touch these, there are hard to tweak!
set bot_ai_aimskill_order_mix_1st 0.01
set bot_ai_aimskill_order_mix_2nd 0.1
Modified: trunk/data/qcsrc/server/bots.qc
===================================================================
--- trunk/data/qcsrc/server/bots.qc 2009-02-20 18:28:59 UTC (rev 5917)
+++ trunk/data/qcsrc/server/bots.qc 2009-02-21 22:55:27 UTC (rev 5918)
@@ -1,8 +1,13 @@
+.float aistatus;
+float AI_STATUS_ROAMING = 1;
+float AI_STATUS_ATTACKING = 2;
+float AI_STATUS_RUNNING = 4;
+
+.string netname_freeme;
+
// rough simulation of walking from one point to another to test if a path
// can be traveled, used by havocbot
-.string netname_freeme;
-
vector stepheightvec;
float navigation_testtracewalk;
float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float movemode)
@@ -1310,6 +1315,21 @@
org = self.origin;// + self.velocity * 0.1;
m1 = org + self.mins;
m2 = org + self.maxs;
+
+ // Loose goal touching check for running state
+ if(self.aistatus & AI_STATUS_RUNNING)
+ if(self.goalcurrent.classname=="waypoint")
+ {
+ if(vlen(self.origin - self.goalcurrent.origin)<150)
+ {
+ traceline(self.origin + self.view_ofs , self.goalcurrent.origin, TRUE, world);
+ if(trace_fraction==1)
+ {
+ navigation_poproute();
+ }
+ }
+ }
+
while (self.goalcurrent && boxesoverlap(m1, m2, self.goalcurrent.absmin, self.goalcurrent.absmax))
navigation_poproute();
}
Modified: trunk/data/qcsrc/server/havocbot.qc
===================================================================
--- trunk/data/qcsrc/server/havocbot.qc 2009-02-20 18:28:59 UTC (rev 5917)
+++ trunk/data/qcsrc/server/havocbot.qc 2009-02-21 22:55:27 UTC (rev 5918)
@@ -1,10 +1,13 @@
-
.void() havocbot_role;
void() havocbot_chooserole;
.float havocbot_keyboardskill;
.float facingwalltime, ignoregoaltime;
.entity ignoregoal;
+#ifdef DEBUG_BOT_GOALSTACK
+void debuggoalstack();
+#endif
+
vector havocbot_dodge()
{
// LordHavoc: disabled because this is too expensive
@@ -132,6 +135,123 @@
self.movement = self.movement + (keyboard - self.movement) * blend;
};
+.entity bot_lastseengoal;
+.float bot_timelastseengoal;
+.float bot_canruntogoal;
+void havocbot_bunnyhop(vector dir)
+{
+ local float distance;
+ local vector deviation;
+
+ if(self.goalcurrent.classname == "player")
+ return;
+
+ if(self.bot_lastseengoal != self.goalcurrent && !(self.aistatus & AI_STATUS_RUNNING))
+ {
+ self.bot_canruntogoal = 0;
+ self.bot_timelastseengoal = 0;
+ }
+
+ distance = vlen(self.origin - self.goalcurrent.origin);
+
+ // Run only to visible goals
+ traceline(self.origin + self.view_ofs , self.goalcurrent.origin, TRUE, world);
+ if(self.flags & FL_ONGROUND)
+ if(trace_fraction == 1)
+ {
+ self.bot_lastseengoal = self.goalcurrent;
+
+ // seen it before
+ if(self.bot_timelastseengoal)
+ {
+ // for a period of time
+ if(time - self.bot_timelastseengoal > cvar("bot_ai_bunnyhop_firstjumpdelay"))
+ {
+ local float checkdistance;
+ checkdistance = TRUE;
+
+ // don't run if it is too close
+ if(self.bot_canruntogoal==0)
+ {
+ if(distance > cvar("bot_ai_bunnyhop_startdistance"))
+ self.bot_canruntogoal = 1;
+ else
+ self.bot_canruntogoal = -1;
+ }
+
+ if(self.bot_canruntogoal != 1)
+ return;
+
+ if(self.aistatus & AI_STATUS_ROAMING)
+ if(self.goalcurrent.classname=="waypoint")
+ if(fabs(self.goalcurrent.origin_z - self.origin_z) < self.maxs_z - self.mins_z)
+ if(self.goalstack01!=world)
+ {
+ deviation = self.goalstack01.origin - (self.origin + self.view_ofs);
+ deviation = vectoangles(deviation) - self.v_angle;
+ while (deviation_y < -180) deviation_y = deviation_y + 360;
+ while (deviation_y > 180) deviation_y = deviation_y - 360;
+
+ if(deviation_y < 20 && deviation_y > -20)
+ if(distance < vlen(self.origin - self.goalstack01.origin))
+ if(fabs(self.goalstack01.origin_z - self.goalcurrent.origin_z) < self.maxs_z - self.mins_z)
+ {
+ traceline(self.origin + self.view_ofs , self.goalstack01.origin, TRUE, world);
+ if(trace_fraction==1)
+ {
+ checkdistance = FALSE;
+ }
+ }
+ }
+
+ if(checkdistance)
+ {
+ self.aistatus &~= AI_STATUS_RUNNING;
+ if(distance > cvar("bot_ai_bunnyhop_stopdistance"))
+ self.BUTTON_JUMP = TRUE;
+ }
+ else
+ {
+ self.aistatus |= AI_STATUS_RUNNING;
+ self.BUTTON_JUMP = TRUE;
+ }
+ }
+ }
+ else
+ {
+ self.bot_timelastseengoal = time;
+ }
+ }
+ else
+ {
+ self.bot_timelastseengoal = 0;
+ }
+
+ // Release jump button
+ if(self.flags & FL_ONGROUND == 0)
+ {
+ if(self.velocity_z < 0)
+ self.BUTTON_JUMP = FALSE;
+
+ // Strafe
+ local float maxspeed;
+ maxspeed = cvar("sv_maxspeed");
+
+ if(self.aistatus & AI_STATUS_RUNNING)
+ if(vlen(self.velocity)>maxspeed)
+ {
+ deviation = vectoangles(dir) - self.v_angle;
+ while (deviation_y < -180) deviation_y = deviation_y + 360;
+ while (deviation_y > 180) deviation_y = deviation_y - 360;
+
+ if ( deviation_y > 2 )
+ self.movement_y = maxspeed;
+ if ( deviation_y < -2 )
+ self.movement_y = maxspeed * -1;
+ }
+ }
+};
+
//.float havocbotignoretime;
//.vector bot_dodgevector;
//.float bot_dodgevector_time;
@@ -182,8 +302,10 @@
return;
}
-// te_wizspike(self.goalcurrent.origin);
-// te_lightning2(world, self.origin, self.goalcurrent.origin);
+#ifdef DEBUG_BOT_GOALSTACK
+ debuggoalstack();
+#endif
+// te_lightning2(world, self.goalcurrent.origin + self.goalcurrent.mins, self.goalcurrent.origin + self.goalcurrent.maxs);
m1 = self.goalcurrent.origin + self.goalcurrent.mins;
m2 = self.goalcurrent.origin + self.goalcurrent.maxs;
@@ -313,7 +435,6 @@
//dir = self.bot_dodgevector;
//if (self.bot_dodgevector_jumpbutton)
// self.BUTTON_JUMP = 1;
-
self.movement_x = dir * v_forward * maxspeed;
self.movement_y = dir * v_right * maxspeed;
self.movement_z = dir * v_up * maxspeed;
@@ -322,6 +443,11 @@
if (skill < 10)
havocbot_keyboard_movement(destorg);
+ // Bunnyhop!
+// if(self.aistatus & AI_STATUS_ROAMING)
+ if(skill >= cvar("bot_ai_bunnyhop_skilloffset"))
+ havocbot_bunnyhop(dir);
+
if ((dir * v_up) >= cvar("sv_jumpvelocity")*0.5 && (self.flags & FL_ONGROUND)) self.BUTTON_JUMP=1;
if (((dodge * v_up) > 0) && random()*frametime >= 0.2*bound(0,(10-skill)*0.1,1)) self.BUTTON_JUMP=TRUE;
if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill)*0.1,1)) self.havocbot_ducktime=time+0.3/bound(0.1,skill,10);
@@ -650,6 +776,9 @@
lag_update();
if (self.bot_aimtarg)
{
+ self.aistatus |= AI_STATUS_ATTACKING;
+ self.aistatus &~= AI_STATUS_ROAMING;
+
weapon_action(self.weapon, WR_AIM);
if (cvar("bot_nofire") || IS_INDEPENDENT_PLAYER(self))
{
@@ -659,13 +788,16 @@
}
else if (self.goalcurrent)
{
+ self.aistatus |= AI_STATUS_ROAMING;
+ self.aistatus &~= AI_STATUS_ATTACKING;
+
local vector now,v,next;//,heading;
local float distance,skillblend,distanceblend,blend;
next = now = self.goalcurrent.origin - (self.origin + self.view_ofs);
distance = vlen(now);
//heading = self.velocity;
//dprint(self.goalstack01.classname,etos(self.goalstack01),"\n");
- if(self.goalstack01 != self && self.goalstack01 != world)
+ if(self.goalstack01 != self && self.goalstack01 != world && self.aistatus & AI_STATUS_RUNNING == 0)
next = self.goalstack01.origin - (self.origin + self.view_ofs);
skillblend=bound(0,(skill-2.5)*0.5,1); //lower skill player can't preturn
distanceblend=bound(0,distance/cvar("bot_ai_keyboard_distance"),1);
@@ -694,3 +826,69 @@
self.havocbot_keyboardskill=random()-0.5;
havocbot_chooserole();
}
+
+
+#ifdef DEBUG_BOT_GOALSTACK
+
+.float goalcounter;
+.vector lastposition;
+
+// Debug the goal stack visually
+void debuggoalstack()
+{
+ local entity target;
+ local vector org;
+
+ if(self.goalcounter==0)target=self.goalcurrent;
+ else if(self.goalcounter==1)target=self.goalstack01;
+ else if(self.goalcounter==2)target=self.goalstack02;
+ else if(self.goalcounter==3)target=self.goalstack03;
+ else if(self.goalcounter==4)target=self.goalstack04;
+ else if(self.goalcounter==5)target=self.goalstack05;
+ else if(self.goalcounter==6)target=self.goalstack06;
+ else if(self.goalcounter==7)target=self.goalstack07;
+ else if(self.goalcounter==8)target=self.goalstack08;
+ else if(self.goalcounter==9)target=self.goalstack09;
+ else if(self.goalcounter==10)target=self.goalstack10;
+ else if(self.goalcounter==11)target=self.goalstack11;
+ else if(self.goalcounter==12)target=self.goalstack12;
+ else if(self.goalcounter==13)target=self.goalstack13;
+ else if(self.goalcounter==14)target=self.goalstack14;
+ else if(self.goalcounter==15)target=self.goalstack15;
+ else if(self.goalcounter==16)target=self.goalstack16;
+ else if(self.goalcounter==17)target=self.goalstack17;
+ else if(self.goalcounter==18)target=self.goalstack18;
+ else if(self.goalcounter==19)target=self.goalstack19;
+ else if(self.goalcounter==20)target=self.goalstack20;
+ else if(self.goalcounter==21)target=self.goalstack21;
+ else if(self.goalcounter==22)target=self.goalstack22;
+ else if(self.goalcounter==23)target=self.goalstack23;
+ else if(self.goalcounter==24)target=self.goalstack24;
+ else if(self.goalcounter==25)target=self.goalstack25;
+ else if(self.goalcounter==26)target=self.goalstack26;
+ else if(self.goalcounter==27)target=self.goalstack27;
+ else if(self.goalcounter==28)target=self.goalstack28;
+ else if(self.goalcounter==29)target=self.goalstack29;
+ else if(self.goalcounter==30)target=self.goalstack30;
+ else if(self.goalcounter==31)target=self.goalstack31;
+
+ if(target==world)
+ {
+ self.goalcounter = 0;
+ self.lastposition='0 0 0';
+ return;
+ }
+
+ if(self.lastposition=='0 0 0')
+ org = self.origin;
+ else
+ org = self.lastposition;
+
+
+ te_lightning2(world, org, target.origin);
+ self.lastposition = target.origin;
+
+ self.goalcounter++;
+}
+
+#endif
\ No newline at end of file
Modified: trunk/data/qcsrc/server/havocbot_roles.qc
===================================================================
--- trunk/data/qcsrc/server/havocbot_roles.qc 2009-02-20 18:28:59 UTC (rev 5917)
+++ trunk/data/qcsrc/server/havocbot_roles.qc 2009-02-21 22:55:27 UTC (rev 5918)
@@ -76,12 +76,14 @@
rating = rating + max(0, 1 - self.ammo_cells / g_pickup_cells_max);
if (item.armorvalue)
- if (self.armorvalue < item.max_armorvalue)
- rating = rating + max(0, 1 - self.armorvalue / item.max_armorvalue);
+ if (self.armorvalue < item.max_armorvalue * 0.5)
+ rating = rating + max(0, 1 - self.armorvalue / (item.max_armorvalue * 0.5));
if (item.health)
- if (self.health < item.max_health)
- rating = rating + max(0, 1 - self.health / item.max_health);
+ if (self.health < item.max_health * 0.5)
+ {
+ rating = rating + max(0, 1 - self.health / (item.max_health * 0.5));
+ }
// TODO: if the item is not recognized then default to item.bot_pickupevalfunc(self, item);
@@ -199,7 +201,7 @@
if(rating > 0)
navigation_routerating(head, rating * ratingscale, 2000);
-
+
head = head.chain;
}
};
@@ -714,7 +716,7 @@
self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
navigation_goalrating_start();
havocbot_goalrating_items(10000, self.origin, 10000);
- havocbot_goalrating_enemyplayers(5000, self.origin, 20000);
+ havocbot_goalrating_enemyplayers(5000, self.origin, 10000);
//havocbot_goalrating_waypoints(1, self.origin, 1000);
navigation_goalrating_end();
}
More information about the nexuiz-commits
mailing list