[nexuiz-commits] r6221 - in branches/nexuiz-2.0: . data data/qcsrc/server
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Thu Mar 19 08:23:00 EDT 2009
Author: div0
Date: 2009-03-19 08:23:00 -0400 (Thu, 19 Mar 2009)
New Revision: 6221
Modified:
branches/nexuiz-2.0/.patchsets
branches/nexuiz-2.0/data/defaultNexuiz.cfg
branches/nexuiz-2.0/data/qcsrc/server/bots.qc
branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc
branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc
Log:
r6107 | mand1nga | 2009-03-12 04:56:37 +0100 (Thu, 12 Mar 2009) | 9 lines
Bots: Swimming support (only to get out of water)
Avoid evaluation of pick-ups under water
Adjusted detection of vertical jumpads
If there is no enemy at sight wear the laser instead of no weapon
Doors recognition (tested only with accident_v3)
Avoid another strategy think if an alternative goal was chosen on the same frame
Fixed some indents and trailing whitespaces (done automatically by codeblocks, sorry)
Other minor fixes/changes
r6126 | mand1nga | 2009-03-12 15:02:10 +0100 (Thu, 12 Mar 2009) | 2 lines
More bots related cvars descriptions
r6127 | mand1nga | 2009-03-12 16:42:05 +0100 (Thu, 12 Mar 2009) | 2 lines
Basic ladder handling for bots
r6128 | mand1nga | 2009-03-13 01:32:14 +0100 (Fri, 13 Mar 2009) | 1 line
Fixed addvote alias
r6159 | mand1nga | 2009-03-14 22:53:42 +0100 (Sat, 14 Mar 2009) | 1 line
Search for nearest waypoints more progressively. This reduces greatly the server load on some maps (mentalspace, reservoir)
r6161 | mand1nga | 2009-03-14 23:09:56 +0100 (Sat, 14 Mar 2009) | 1 line
Fixed typo in last commit
r6170 | mand1nga | 2009-03-15 02:01:55 +0100 (Sun, 15 Mar 2009) | 2 lines
Fixed bug in the routing to alternative goals. Don't rate enemies as goals when they're too close.
r6182 | mand1nga | 2009-03-15 21:41:24 +0100 (Sun, 15 Mar 2009) | 1 line
Narrow the search for nearest waypoints to no more than 1500 qu when the bot is not on the ground
Modified: branches/nexuiz-2.0/.patchsets
===================================================================
--- branches/nexuiz-2.0/.patchsets 2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/.patchsets 2009-03-19 12:23:00 UTC (rev 6221)
@@ -1,2 +1,2 @@
master = svn://svn.icculus.org/nexuiz/trunk
-revisions_applied = 1-6039,6044-6106,6108-6125,6129-6158,6160-6160,6162-6169,6171-6181,6183-6208
+revisions_applied = 1-6039,6044-6208
Modified: branches/nexuiz-2.0/data/defaultNexuiz.cfg
===================================================================
--- branches/nexuiz-2.0/data/defaultNexuiz.cfg 2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/data/defaultNexuiz.cfg 2009-03-19 12:23:00 UTC (rev 6221)
@@ -340,11 +340,11 @@
set bot_ai_thinkinterval 0.05
set bot_ai_strategyinterval 2 "How often a new objective is chosen"
set bot_ai_enemydetectioninterval 0.5 "How often bots pick a new target"
-set bot_ai_dodgeupdateinterval 0.1
-set bot_ai_chooseweaponinterval 0.3 "How often the weapon selection will be evaluated"
-set bot_ai_dangerdetectioninterval 0.1
-set bot_ai_dangerdetectionupdates 64
-set bot_ai_aimskill_blendrate 2 "How much correction is made to aim at the target"
+set bot_ai_dodgeupdateinterval 0.1 "How often scan for items to dodge. Currently not in use."
+set bot_ai_chooseweaponinterval 0.3 "How often the best weapon according to the situation will be chosen"
+set bot_ai_dangerdetectioninterval 0.1 "How often scan for waypoints with dangers near"
+set bot_ai_dangerdetectionupdates 64 "How many waypoints will be considered for danger detection"
+set bot_ai_aimskill_blendrate 2 "How much correction will be applied to the aiming angle"
set bot_ai_aimskill_fixedrate 15
set bot_ai_aimskill_firetolerance_distdegrees 180
set bot_ai_aimskill_firetolerance_mindegrees 2 "Minimum angle tolerance. Used on large distances"
@@ -1054,7 +1054,7 @@
alias gametype "sv_cmd gametype $*"
alias addfav "qc_cmd addtolist net_slist_favorites $*"
-alias addvote "qc_cmd addvote sv_vote_commands $*"
+alias addvote "qc_cmd addtolist sv_vote_commands $*"
// key hunt
set g_keyhunt 0
Modified: branches/nexuiz-2.0/data/qcsrc/server/bots.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/bots.qc 2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/data/qcsrc/server/bots.qc 2009-03-19 12:23:00 UTC (rev 6221)
@@ -3,7 +3,8 @@
float AI_STATUS_ATTACKING = 2; // There are enemies at sight
float AI_STATUS_RUNNING = 4; // Bot is bunny hopping
float AI_STATUS_DANGER_AHEAD = 8; // There is lava/slime/abism ahead
-float AI_STATUS_BAD_JUMPPAD = 16; // Trying to get out of a "vertical" jump pad
+float AI_STATUS_OUT_JUMPPAD = 16; // Trying to get out of a "vertical" jump pad
+float AI_STATUS_OUT_WATER = 32; // Trying to get out of water
.string netname_freeme;
// rough simulation of walking from one point to another to test if a path
@@ -106,7 +107,6 @@
//particle(org, move * 64, 104, 4);
te_gunshot(org);
}
- // failed
return 0;
}
org = trace_endpos;
@@ -115,8 +115,10 @@
{
move = dir * stepdist + org;
tracebox(org, m1, m2, move, movemode, e);
+ // hit something
if (trace_fraction < 1)
{
+ // check if we can walk over this obstacle
tracebox(org + stepheightvec, m1, m2, move + stepheightvec, movemode, e);
if (trace_fraction < 1 || trace_startsolid)
{
@@ -124,15 +126,33 @@
{
if (navigation_testtracewalk > 1)
dprint("hit-something\n");
- //move = normalize(end - org);
- //particle(org, move * 64, 104, 4);
- te_gunshot(org);
+ // move = normalize(end - org);
+ // particle(org, move * 64, 104, 4);
+ // te_gunshot(org);
}
- // failed
- return 0;
+
+ // check for doors
+ traceline( org, move, movemode, e);
+ if ( trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
+ {
+ local vector nextmove;
+ move = trace_endpos;
+ while(trace_ent.classname == "door_rotating" || trace_ent.classname == "door")
+ {
+ nextmove = move + (dir * stepdist);
+ traceline( move, nextmove, movemode, e);
+ move = nextmove;
+ }
+ }
+ else
+ return 0; // failed
}
+ else
+ move = trace_endpos;
}
- move = trace_endpos;
+ else
+ move = trace_endpos;
+
// trace down from stepheight as far as possible and move there,
// if this starts in solid we try again without the stepup, and
// if that also fails we assume it is a wall
@@ -1092,7 +1112,7 @@
local entity head;
local vector v, m1, m2, diff;
local float c;
- //navigation_testtracewalk = TRUE;
+// navigation_testtracewalk = TRUE;
c = 0;
head = waylist;
while (head)
@@ -1173,11 +1193,17 @@
w.enemy = world;
w = w.chain;
}
- // try a short range search for the nearest waypoints, and expand the
- // search repeatedly if none are found
- if (!navigation_markroutes_nearestwaypoints(waylist, 250))
- if (!navigation_markroutes_nearestwaypoints(waylist, 1000))
- navigation_markroutes_nearestwaypoints(waylist, 1000000);
+
+ // try a short range search for the nearest waypoints, and expand thesearch repeatedly if none are found
+ local float i, increment, maxdistance;
+ increment = 500;
+ if(self.flags & FL_ONGROUND)
+ maxdistance = 50000;
+ else
+ maxdistance = 1500;
+
+ for(i=increment;!navigation_markroutes_nearestwaypoints(waylist, i)&&i<maxdistance;i+=increment);
+
searching = TRUE;
while (searching)
{
@@ -1553,10 +1579,10 @@
bot_distance_far = stof(argv(0));
bot_distance_close = stof(argv(1));
-
+
if(bot_distance_far < bot_distance_close){
bot_distance_far = stof(argv(1));
- bot_distance_close = stof(argv(0));
+ bot_distance_close = stof(argv(0));
}
// Initialize list of weapons
@@ -1979,10 +2005,10 @@
{
self.BUTTON_JUMP = 1; // press jump to respawn
self.bot_strategytime = 0;
- return;
}
+ return;
}
-
+
// now call the current bot AI (havocbot for example)
self.bot_ai();
};
Modified: branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc 2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot.qc 2009-03-19 12:23:00 UTC (rev 6221)
@@ -68,7 +68,7 @@
local vector keyboard;
local float blend, maxspeed;
- maxspeed = cvar("sv_maxspeed");
+ maxspeed = cvar("sv_maxspeed");
if (time < self.havocbot_keyboardtime)
return;
@@ -153,6 +153,12 @@
return;
}
+ if(self.waterlevel > 1)
+ {
+ self.aistatus &~= AI_STATUS_RUNNING;
+ return;
+ }
+
if(self.bot_lastseengoal != self.goalcurrent && !(self.aistatus & AI_STATUS_RUNNING))
{
self.bot_canruntogoal = 0;
@@ -182,7 +188,7 @@
{
if(bunnyhopdistance > cvar("bot_ai_bunnyhop_startdistance"))
self.bot_canruntogoal = 1;
- else
+ else
self.bot_canruntogoal = -1;
}
@@ -240,7 +246,7 @@
if(self.velocity_z < 0)
self.BUTTON_JUMP = FALSE;
- // Strafe
+ // Strafe
local float maxspeed;
maxspeed = cvar("sv_maxspeed");
@@ -263,6 +269,8 @@
//.vector bot_dodgevector;
//.float bot_dodgevector_time;
//.float bot_dodgevector_jumpbutton;
+.float ladder_time;
+.entity ladder_entity;
void havocbot_movetogoal()
{
local vector destorg;
@@ -287,12 +295,12 @@
if(self.flags & FL_ONGROUND)
{
self.jumppadcount = FALSE;
- if(self.aistatus & AI_STATUS_BAD_JUMPPAD)
- self.aistatus &~= AI_STATUS_BAD_JUMPPAD;
+ if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
+ self.aistatus &~= AI_STATUS_OUT_JUMPPAD;
}
// If got stuck on the jump pad try to reach the farther visible item
- if(self.aistatus & AI_STATUS_BAD_JUMPPAD)
+ if(self.aistatus & AI_STATUS_OUT_JUMPPAD)
{
if(fabs(self.velocity_z)<50)
{
@@ -325,7 +333,7 @@
self.ignoregoal = self.goalcurrent;
self.ignoregoaltime = time + cvar("bot_ai_ignoregoal_timeout");
navigation_routetogoal(newgoal);
- self.aistatus &~= AI_STATUS_BAD_JUMPPAD;
+ self.aistatus &~= AI_STATUS_OUT_JUMPPAD;
}
}
else
@@ -336,32 +344,55 @@
if(self.velocity_z>0)
{
local float threshold;
- threshold = maxspeed * 0.3;
+ threshold = maxspeed * 0.2;
if(fabs(self.velocity_x) < threshold && fabs(self.velocity_y) < threshold)
- self.aistatus |= AI_STATUS_BAD_JUMPPAD;
+ self.aistatus |= AI_STATUS_OUT_JUMPPAD;
return;
}
}
}
+ // If we are under water with no goals, swim up
+ if(self.waterlevel)
+ if(self.goalcurrent==world)
+ {
+ dir = '0 0 0';
+ if(self.waterlevel>2)
+ dir_z = 1;
+ else if(self.velocity_z >= 0 && !(self.waterlevel == 1 && self.watertype == CONTENT_WATER))
+ self.BUTTON_JUMP = TRUE;
+ else
+ self.BUTTON_JUMP = FALSE;
+ makevectors(self.v_angle_y * '0 1 0');
+ self.movement_x = dir * v_forward * maxspeed;
+ self.movement_y = dir * v_right * maxspeed;
+ self.movement_z = dir * v_up * maxspeed;
+ }
+
+ // if there is nowhere to go, exit
if (self.goalcurrent == world)
return;
- navigation_poptouchedgoals();
+ if (self.goalcurrent)
+ navigation_poptouchedgoals();
+ // if ran out of goals try to use an alternative goal or get a new strategy asap
if(self.goalcurrent == world)
if(self.flags & FL_ONGROUND || self.aistatus & AI_STATUS_RUNNING || self.BUTTON_JUMP == TRUE)
{
if(self.alternativegoal==world)
{
- // ran out of goals, rethink strategy as soon as possible
+ // ran out of goals
self.bot_strategytime = 0;
return;
}
- // try to use the alternative goal
+
+ // use the alternative goal
navigation_findnearestwaypoint(self.alternativegoal, TRUE);
navigation_routetogoal(self.alternativegoal);
self.alternativegoal = world;
+ bot_strategytoken_taken = TRUE;
+
return;
}
@@ -387,14 +418,30 @@
// self.bot_dodgevector_jumpbutton = 1;
evadeobstacle = '0 0 0';
evadelava = '0 0 0';
+
if (self.waterlevel)
{
- makevectors(self.v_angle);
- self.BUTTON_JUMP = TRUE;
- evadelava_z = 1;
+ if(self.waterlevel>2)
+ {
+ // flatdir_z = 1;
+ self.aistatus |= AI_STATUS_OUT_WATER;
+ }
+ else
+ {
+ if(self.velocity_z >= 0 && !(self.watertype == CONTENT_WATER && self.goalcurrent.origin_z < self.origin_z) &&
+ ( !(self.waterlevel == 1 && self.watertype == CONTENT_WATER) || self.aistatus & AI_STATUS_OUT_WATER))
+ self.BUTTON_JUMP = TRUE;
+ else
+ self.BUTTON_JUMP = FALSE;
+ }
+ dir = normalize(flatdir);
+ makevectors(self.v_angle_y * '0 1 0');
}
else
{
+ if(self.aistatus & AI_STATUS_OUT_WATER)
+ self.aistatus &~= AI_STATUS_OUT_WATER;
+
// jump if going toward an obstacle that doesn't look like stairs we
// can walk up directly
tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 0.2, FALSE, self);
@@ -416,13 +463,13 @@
// avoiding dangers and obstacles
local vector dst_ahead, dst_down;
dst_ahead = self.origin + self.view_ofs + (self.velocity * 0.32);
- dst_down = dst_ahead + '0 0 -1500';
-
+ dst_down = dst_ahead + '0 0 -1500';
+
// Look ahead
traceline(self.origin + self.view_ofs , dst_ahead, TRUE, world);
// Check head-banging against walls
- if(vlen(self.origin + self.view_ofs - trace_endpos) < 2)
+ if(vlen(self.origin + self.view_ofs - trace_endpos) < 2 && !(self.aistatus & AI_STATUS_OUT_WATER))
{
if(self.facingwalltime && time > self.facingwalltime)
{
@@ -445,7 +492,7 @@
self.ignoregoaltime = 0;
}
}
-
+
// Check for water/slime/lava and dangerous edges
// (only when the bot is on the ground or jumping intentionally)
self.aistatus &~= AI_STATUS_DANGER_AHEAD;
@@ -455,7 +502,7 @@
{
// Look downwards
traceline(dst_ahead , dst_down, TRUE, world);
- // te_lightning2(world, self.origin, dst_ahead); // Draw "ahead" look
+ // te_lightning2(world, self.origin, dst_ahead); // Draw "ahead" look
// te_lightning2(world, dst_ahead, dst_down); // Draw "downwards" look
if(trace_endpos_z < self.origin_z + self.mins_z)
{
@@ -465,7 +512,7 @@
evadelava = normalize(self.velocity) * -1;
else if (s == CONTENT_SKY)
evadeobstacle = normalize(self.velocity) * -1;
- else if (!boxesoverlap(dst_ahead - self.view_ofs + self.mins, dst_ahead - self.view_ofs + self.maxs,
+ else if (!boxesoverlap(dst_ahead - self.view_ofs + self.mins, dst_ahead - self.view_ofs + self.maxs,
self.goalcurrent.absmin, self.goalcurrent.absmax))
{
// if ain't a safe goal with "holes" (like the jumpad on soylent)
@@ -504,6 +551,20 @@
// self.bot_dodgevector_jumpbutton = self.BUTTON_JUMP;
}
+ if(time < self.ladder_time)
+ {
+ if(self.goalcurrent.origin_z + self.goalcurrent.mins_z > self.origin_z + self.mins_z)
+ {
+ if(self.origin_z + self.mins_z < self.ladder_entity.origin_z + self.ladder_entity.maxs_z)
+ dir = '0 0 1';
+ }
+ else
+ {
+ if(self.origin_z + self.mins_z > self.ladder_entity.origin_z + self.ladder_entity.mins_z)
+ dir = '0 0 -1';
+ }
+ }
+
//dir = self.bot_dodgevector;
//if (self.bot_dodgevector_jumpbutton)
// self.BUTTON_JUMP = 1;
@@ -601,7 +662,9 @@
// TODO: clean this up by moving it to weapon code
if(self.enemy.classname!="player")
{
- self.switchweapon = w_getbestweapon(self);
+ // self.switchweapon = w_getbestweapon(self);
+ if(client_hasweapon(self, WEP_LASER, TRUE, FALSE))
+ self.switchweapon = WEP_LASER;
return;
}
@@ -629,7 +692,7 @@
traceline(self.enemy.origin,self.enemy.origin-'0 0 1000',TRUE,world);
distancefromfloor = self.enemy.origin_z - trace_endpos_z;
-
+
af = ATTACK_FINISHED(self);
ct = cvar("bot_ai_weapon_combo_threshold");
@@ -699,70 +762,70 @@
minstanex = (1000/cvar("g_balance_minstanex_refire")*1.0)
* (0.5);
- if (client_hasweapon(self, WEP_ROCKET_LAUNCHER, TRUE, FALSE) &&
- !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_ROCKET_LAUNCHER &&
+ if (client_hasweapon(self, WEP_ROCKET_LAUNCHER, TRUE, FALSE) &&
+ !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_ROCKET_LAUNCHER &&
af > combo_time
)
)
rocket = (cvar("g_balance_rocketlauncher_damage")/cvar("g_balance_rocketlauncher_refire")*0.75)
* bound(0,(cvar("g_balance_rocketlauncher_speed")/distance*maxdelaytime),1)*1.5;
-
- if (client_hasweapon(self, WEP_NEX, TRUE, FALSE) &&
- !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_NEX &&
+
+ if (client_hasweapon(self, WEP_NEX, TRUE, FALSE) &&
+ !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_NEX &&
af > combo_time
)
)
nex = (cvar("g_balance_nex_damage")/cvar("g_balance_nex_refire")*1.0)
* (0.5);
-
- if (client_hasweapon(self, WEP_HAGAR, TRUE, FALSE) ) // &&
+
+ if (client_hasweapon(self, WEP_HAGAR, TRUE, FALSE) ) // &&
// !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_HAGAR && time < self.bot_lastshot + cvar("g_balance_hagar_primary_refire") ))
hagar = (cvar("g_balance_hagar_primary_damage")/cvar("g_balance_hagar_primary_refire")*1.0)
* bound(0,(cvar("g_balance_hagar_primary_speed")/distance*maxdelaytime),1)*0.2;
-
- if (client_hasweapon(self, WEP_GRENADE_LAUNCHER, TRUE, FALSE) &&
- !(
- cvar("bot_ai_weapon_combo") && self.weapon == WEP_GRENADE_LAUNCHER &&
+
+ if (client_hasweapon(self, WEP_GRENADE_LAUNCHER, TRUE, FALSE) &&
+ !(
+ cvar("bot_ai_weapon_combo") && self.weapon == WEP_GRENADE_LAUNCHER &&
af > combo_time
)
)
grenade = (cvar("g_balance_grenadelauncher_primary_damage")/cvar("g_balance_grenadelauncher_primary_refire")*1.0)
* bound(0,(cvar("g_balance_grenadelauncher_primary_speed")/distance*maxdelaytime),1)*1.1;
-
- if (client_hasweapon(self, WEP_ELECTRO, TRUE, FALSE) &&
- !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_ELECTRO &&
+
+ if (client_hasweapon(self, WEP_ELECTRO, TRUE, FALSE) &&
+ !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_ELECTRO &&
af > combo_time
)
)
electro = (cvar("g_balance_electro_primary_damage")/cvar("g_balance_electro_primary_refire")*0.75)
* bound(0,(cvar("g_balance_electro_primary_speed")/distance*maxdelaytime),1)*1.0;
-
- if (client_hasweapon(self, WEP_CRYLINK, TRUE, FALSE) ) // &&
+
+ if (client_hasweapon(self, WEP_CRYLINK, TRUE, FALSE) ) // &&
// !( self.weapon == WEP_CRYLINK && time < self.bot_lastshot + cvar("g_balance_crylink_primary_refire") ))
crylink = (cvar("g_balance_crylink_primary_damage")/cvar("g_balance_crylink_primary_refire")*1.0)
* bound(0,(cvar("g_balance_crylink_primary_speed")/distance*maxdelaytime),1)*(64/(32+cvar("g_balance_crylink_primary_spread")*distance))*1.0;
-
- if (client_hasweapon(self, WEP_UZI, TRUE, FALSE) ) // &&
+
+ if (client_hasweapon(self, WEP_UZI, TRUE, FALSE) ) // &&
// !( self.weapon == WEP_UZI && time < self.bot_lastshot + cvar("g_balance_uzi_sustained_refire") ))
uzi = (cvar("g_balance_uzi_sustained_damage")/cvar("g_balance_uzi_sustained_refire")*1.0)
* bound(0,32/(32+cvar("g_balance_uzi_sustained_spread")*distance),1);
-
- if (client_hasweapon(self, WEP_SHOTGUN, TRUE, FALSE) &&
- !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_SHOTGUN &&
+
+ if (client_hasweapon(self, WEP_SHOTGUN, TRUE, FALSE) &&
+ !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_SHOTGUN &&
af > combo_time
)
)
shotgun = (cvar("g_balance_shotgun_primary_damage")*cvar("g_balance_shotgun_primary_bullets")/cvar("g_balance_shotgun_primary_refire")*1.0)
* bound(0,32/(32+cvar("g_balance_shotgun_primary_spread")*distance),1);
-
- if (client_hasweapon(self, WEP_LASER, FALSE, FALSE) &&
- !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_LASER &&
+
+ if (client_hasweapon(self, WEP_LASER, FALSE, FALSE) &&
+ !( cvar("bot_ai_weapon_combo") && self.weapon == WEP_LASER &&
af > combo_time
)
)
laser = (cvar("g_balance_laser_primary_damage")/cvar("g_balance_laser_primary_refire")*1.0)
* bound(0,cvar("g_balance_laser_primary_speed")/distance*maxdelaytime,1);
-
+
if((self.enemy.flags & FL_ONGROUND)==FALSE){
rocket = rocket * (1.5-bound(0, distancefromfloor/cvar("g_balance_rocketlauncher_radius" ),0.9)); //slight bigger change
grenade = grenade * (1.5-bound(0,distancefromfloor/cvar("g_balance_grenadelauncher_primary_radius"),0.95));
@@ -796,7 +859,7 @@
// switch if the best weapon would provide a significant damage increase
if (bestscore > currentscore*1.5){
self.switchweapon = bestweapon;
-
+
// buys time for detonating the rocket. not tested yet
if ( cvar("bot_ai_weapon_combo") && bestweapon == WEP_ROCKET_LAUNCHER )
self.bot_chooseweapontime += (distance / cvar("g_balance_rocketlauncher_speed"));
@@ -807,8 +870,8 @@
void havocbot_aim()
{
local vector selfvel, enemyvel;
- if(self.flags & FL_INWATER)
- return;
+// if(self.flags & FL_INWATER)
+// return;
if (time < self.nextaim)
return;
self.nextaim = time + 0.1;
@@ -832,12 +895,55 @@
if (!bot_strategytoken_taken)
{
self.havocbot_role();
+
+ // TODO: tracewalk() should take care of this job (better path finding under water)
+ // if we don't have a goal and we're under water look for a waypoint near the "shore" and push it
+ if(self.goalcurrent==world)
+ if(self.waterlevel==2 || self.aistatus & AI_STATUS_OUT_WATER)
+ {
+ // Look for the closest waypoint out of water
+ local entity newgoal, head;
+ local float bestdistance, distance;
+
+ newgoal = world;
+ bestdistance = 10000;
+ for (head = findchain(classname, "waypoint"); head; head = head.chain)
+ {
+ distance = vlen(head.origin - self.origin);
+ if(distance>10000)
+ continue;
+
+ if(head.origin_z < self.origin_z)
+ continue;
+
+ if(head.origin_z - self.origin_z - self.view_ofs_z > 100)
+ continue;
+
+ if (pointcontents(head.origin + head.maxs + '0 0 1') != CONTENT_EMPTY)
+ continue;
+
+ traceline(self.origin + self.view_ofs , head.origin, TRUE, head);
+
+ if(trace_fraction<1)
+ continue;
+
+ if(distance<bestdistance)
+ {
+ newgoal = head;
+ bestdistance = distance;
+ }
+ }
+
+ if(newgoal)
+ {
+ // te_wizspike(newgoal.origin);
+ navigation_pushroute(newgoal);
+ }
+ }
+
// token has been used this frame
bot_strategytoken_taken = TRUE;
}
- if(self.deadflag)
- return;
-
havocbot_chooseenemy();
if (self.bot_chooseweapontime < time )
{
Modified: branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc
===================================================================
--- branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc 2009-03-19 12:14:30 UTC (rev 6220)
+++ branches/nexuiz-2.0/data/qcsrc/server/havocbot_roles.qc 2009-03-19 12:23:00 UTC (rev 6221)
@@ -28,10 +28,10 @@
rating = 0.5 + bound(0, skill / 20, 0.5);
else
rating = 1;
-
+
if( bot_custom_weapon )
{
- for(i = WEP_FIRST; i < WEP_LAST ; ++i){
+ for(i = WEP_FIRST; i < WEP_LAST ; ++i){
if( power2of(i-1) & item.weapons != item.weapons )
continue;
@@ -48,7 +48,7 @@
}
}
- if (position >= 0 )
+ if (position >= 0 )
{
position = WEP_LAST - position;
// item.bot_pickupbasevalue is overwritten here
@@ -86,28 +86,28 @@
}
// TODO: if the item is not recognized then default to item.bot_pickupevalfunc(self, item);
-
+
return base * rating;
};
void havocbot_goalrating_items(float ratingscale, vector org, float sradius)
{
local entity head;
- local entity player;
+ local entity player;
local float rating, d, discard, distance, friend_distance, enemy_distance;
ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
head = findchainfloat(bot_pickup, TRUE);
-
+
while (head)
{
distance = vlen(head.origin - org);
friend_distance = 10000; enemy_distance = 10000;
rating = 0;
-
+
if(!head.solid || distance > sradius || (head == self.ignoregoal && time < self.ignoregoaltime) )
{
head = head.chain;
- continue;
+ continue;
}
// Check if the item can be picked up safely
@@ -119,7 +119,7 @@
if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
{
head = head.chain;
- continue;
+ continue;
}
if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
{
@@ -127,11 +127,21 @@
continue;
}
}
-
+ else
+ {
+ // Ignore items under water
+ traceline(head.origin + head.maxs, head.origin + head.maxs, MOVE_NORMAL, head);
+ if(trace_dpstartcontents & DPCONTENTS_LIQUIDSMASK)
+ {
+ head = head.chain;
+ continue;
+ }
+ }
+
if(teams_matter)
{
discard = FALSE;
-
+
FOR_EACH_PLAYER(player)
{
@@ -147,17 +157,17 @@
if( d > friend_distance)
continue;
-
+
friend_distance = d;
discard = TRUE;
-
+
if( head.health && player.health > self.health )
continue;
if( head.armorvalue && player.armorvalue > self.armorvalue)
continue;
-
+
if( head.weapons )
if( (player.weapons & head.weapons) != head.weapons)
continue;
@@ -191,7 +201,7 @@
{
// rating = head.bot_pickupevalfunc(self, head);
rating = havocbot_pickupevalfunc(head);
- }
+ }
}
else
{
@@ -201,7 +211,6 @@
if(rating > 0)
navigation_routerating(head, rating * ratingscale, 2000);
-
head = head.chain;
}
};
@@ -245,9 +254,13 @@
void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius)
{
local entity head;
- local float t, noteam;
+ local float t, noteam, distance;
noteam = ((self.team == 0) || !teams_matter); // fteqcc sucks
+ // don't chase players if we're under water
+ if(self.waterlevel>1)
+ return;
+
FOR_EACH_PLAYER(head)
{
// TODO: Merge this logic with the bot_shouldattack function
@@ -255,23 +268,24 @@
if (head.health > 0)
if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
{
- if (vlen(head.origin - org) > sradius)
+ distance = vlen(head.origin - org);
+ if (distance < 100 || distance > sradius)
continue;
if(g_minstagib)
if(head.items & IT_STRENGTH)
continue;
-
+
// rate only visible enemies
/*
traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
if (trace_fraction < 1 || trace_ent != head)
continue;
*/
-
+
if(head.flags & FL_INWATER || head.flags & FL_PARTIALGROUND)
continue;
-
+
// not falling
if(head.flags & FL_ONGROUND == 0)
{
@@ -721,7 +735,7 @@
self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
navigation_goalrating_start();
havocbot_goalrating_items(10000, self.origin, 10000);
- havocbot_goalrating_enemyplayers(20000, self.origin, 20000);
+ havocbot_goalrating_enemyplayers(20000, self.origin, 10000);
//havocbot_goalrating_waypoints(1, self.origin, 1000);
navigation_goalrating_end();
}
@@ -753,7 +767,7 @@
navigation_routerating(e, 1000000, 5000);
}
}
-
+
navigation_goalrating_end();
}
};
More information about the nexuiz-commits
mailing list