From 41615bd24934d601cb97d59c3a3217ceb623c661 Mon Sep 17 00:00:00 2001 From: mand1nga Date: Thu, 12 Mar 2009 03:56:37 +0000 Subject: [PATCH] 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 git-svn-id: svn://svn.icculus.org/nexuiz/trunk@6107 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/qcsrc/server/bots.qc | 48 +++++-- data/qcsrc/server/havocbot.qc | 209 ++++++++++++++++++++-------- data/qcsrc/server/havocbot_roles.qc | 55 +++++--- 3 files changed, 220 insertions(+), 92 deletions(-) diff --git a/data/qcsrc/server/bots.qc b/data/qcsrc/server/bots.qc index 54f0311ed..2c1955779 100644 --- a/data/qcsrc/server/bots.qc +++ b/data/qcsrc/server/bots.qc @@ -3,7 +3,8 @@ float AI_STATUS_ROAMING = 1; // Bot is just crawling the map. No enemies at si 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 @@ float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float //particle(org, move * 64, 104, 4); te_gunshot(org); } - // failed return 0; } org = trace_endpos; @@ -115,8 +115,10 @@ float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float { 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 @@ float tracewalk(entity e, vector start, vector m1, vector m2, vector end, float { 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 @@ float navigation_markroutes_nearestwaypoints(entity waylist, float maxdist) local entity head; local vector v, m1, m2, diff; local float c; - //navigation_testtracewalk = TRUE; +// navigation_testtracewalk = TRUE; c = 0; head = waylist; while (head) @@ -1175,7 +1195,7 @@ void navigation_markroutes() } // 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, 500)) if (!navigation_markroutes_nearestwaypoints(waylist, 1000)) navigation_markroutes_nearestwaypoints(waylist, 1000000); searching = TRUE; @@ -1553,10 +1573,10 @@ void bot_custom_weapon_priority_setup() 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 +1999,10 @@ void bot_think() { 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(); }; diff --git a/data/qcsrc/server/havocbot.qc b/data/qcsrc/server/havocbot.qc index ab37c74b2..f5596ade2 100644 --- a/data/qcsrc/server/havocbot.qc +++ b/data/qcsrc/server/havocbot.qc @@ -68,7 +68,7 @@ void havocbot_keyboard_movement(vector destorg) 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 @@ void havocbot_bunnyhop(vector dir) 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 @@ void havocbot_bunnyhop(vector dir) { if(distance > cvar("bot_ai_bunnyhop_startdistance")) self.bot_canruntogoal = 1; - else + else self.bot_canruntogoal = -1; } @@ -240,7 +246,7 @@ void havocbot_bunnyhop(vector dir) if(self.velocity_z < 0) self.BUTTON_JUMP = FALSE; - // Strafe + // Strafe local float maxspeed; maxspeed = cvar("sv_maxspeed"); @@ -287,12 +293,12 @@ void havocbot_movetogoal() 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 +331,7 @@ void havocbot_movetogoal() 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 +342,59 @@ void havocbot_movetogoal() 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 - navigation_findnearestwaypoint(self.alternativegoal, TRUE); - navigation_routetogoal(self.alternativegoal); - self.alternativegoal = world; + + // use the alternative goal + if (bot_strategytoken == self) + if (!bot_strategytoken_taken) + { + navigation_findnearestwaypoint(self.alternativegoal, TRUE); + navigation_routetogoal(self.alternativegoal); + self.alternativegoal = world; + bot_strategytoken_taken = TRUE; + } + return; } @@ -387,14 +420,30 @@ void havocbot_movetogoal() // 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 +465,13 @@ void havocbot_movetogoal() // 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 +494,7 @@ void havocbot_movetogoal() 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 +504,7 @@ void havocbot_movetogoal() { // 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 +514,7 @@ void havocbot_movetogoal() 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) @@ -601,7 +650,9 @@ void havocbot_chooseweapon() // 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 +680,7 @@ void havocbot_chooseweapon() 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 +750,70 @@ void havocbot_chooseweapon() 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 +847,7 @@ void havocbot_chooseweapon() // 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 +858,8 @@ void havocbot_chooseweapon() 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 +883,56 @@ void havocbot_ai() 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) + { + // TODO: Make the bots detect and handle ladders and/or platforms + // 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= 0 ) + if (position >= 0 ) { position = WEP_LAST - position; // item.bot_pickupbasevalue is overwritten here @@ -86,28 +86,28 @@ float havocbot_pickupevalfunc(entity item) } // 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 @@ void havocbot_goalrating_items(float ratingscale, vector org, float sradius) 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 @@ void havocbot_goalrating_items(float ratingscale, vector org, float sradius) 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 @@ void havocbot_goalrating_items(float ratingscale, vector org, float sradius) 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 @@ void havocbot_goalrating_items(float ratingscale, vector org, float sradius) { // rating = head.bot_pickupevalfunc(self, head); rating = havocbot_pickupevalfunc(head); - } + } } else { @@ -201,7 +211,6 @@ void havocbot_goalrating_items(float ratingscale, vector org, float sradius) if(rating > 0) navigation_routerating(head, rating * ratingscale, 2000); - head = head.chain; } }; @@ -248,6 +257,10 @@ void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradi local float t, noteam; 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 @@ -261,17 +274,17 @@ void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradi 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 +734,7 @@ void havocbot_role_dm() 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 +766,7 @@ void havocbot_role_race() navigation_routerating(e, 1000000, 5000); } } - + navigation_goalrating_end(); } }; -- 2.39.2