X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fbot%2Fhavocbot%2Fhavocbot.qc;h=79f305a2673af51b9cfe7cfe6326ebe2035d683d;hb=5d2f4a6d42d25232423fa1add7461a8f477abe0f;hp=5ed78628a8889b6577153625ba6dbad6008be991;hpb=411fb987cf22de8cd739ea2b8513ce1cecd6898e;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/bot/havocbot/havocbot.qc b/qcsrc/server/bot/havocbot/havocbot.qc index 5ed78628a..79f305a26 100644 --- a/qcsrc/server/bot/havocbot/havocbot.qc +++ b/qcsrc/server/bot/havocbot/havocbot.qc @@ -2,6 +2,9 @@ #include "role_ctf.qc" #include "role_onslaught.qc" #include "role_keyhunt.qc" +#include "role_freezetag.qc" +#include "role_keepaway.qc" +#include "role_assault.qc" #include "roles.qc" void havocbot_ai() @@ -21,7 +24,8 @@ void havocbot_ai() } else { - self.havocbot_role(); + if not(self.jumppadcount) + self.havocbot_role(); } // TODO: tracewalk() should take care of this job (better path finding under water) @@ -80,7 +84,7 @@ void havocbot_ai() havocbot_chooseenemy(); if (self.bot_chooseweapontime < time ) { - self.bot_chooseweapontime = time + cvar("bot_ai_chooseweaponinterval"); + self.bot_chooseweapontime = time + autocvar_bot_ai_chooseweaponinterval; havocbot_chooseweapon(); } havocbot_aim(); @@ -93,7 +97,7 @@ void havocbot_ai() if(self.weapons) { weapon_action(self.weapon, WR_AIM); - if (cvar("bot_nofire") || IS_INDEPENDENT_PLAYER(self)) + if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(self)) { self.BUTTON_ATCK = FALSE; self.BUTTON_ATCK2 = FALSE; @@ -117,7 +121,7 @@ void havocbot_ai() local vector now,v,next;//,heading; local float aimdistance,skillblend,distanceblend,blend; - next = now = self.goalcurrent.origin - (self.origin + self.view_ofs); + next = now = ( (self.goalcurrent.absmin + self.goalcurrent.absmax) * 0.5) - (self.origin + self.view_ofs); aimdistance = vlen(now); //heading = self.velocity; //dprint(self.goalstack01.classname,etos(self.goalstack01),"\n"); @@ -125,10 +129,10 @@ void havocbot_ai() 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); + next = ((self.goalstack01.absmin + self.goalstack01.absmax) * 0.5) - (self.origin + self.view_ofs); skillblend=bound(0,(skill+self.bot_moveskill-2.5)*0.5,1); //lower skill player can't preturn - distanceblend=bound(0,aimdistance/cvar("bot_ai_keyboard_distance"),1); + distanceblend=bound(0,aimdistance/autocvar_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); @@ -144,6 +148,31 @@ void havocbot_ai() bot_aimdir(v, -1); } havocbot_movetogoal(); + + // if the bot is not attacking, consider reloading weapons + if not(self.aistatus & AI_STATUS_ATTACKING) + { + float i; + entity e; + + // we are currently holding a weapon that's not fully loaded, reload it + if(skill >= 2) // bots can only reload the held weapon on purpose past this skill + if(self.clip_load < self.clip_size) + self.impulse = 20; // "press" the reload button, not sure if this is done right + + // if we're not reloading a weapon, switch to any weapon in our invnetory that's not fully loaded to reload it next + // the code above executes next frame, starting the reloading then + if(skill >= 5) // bots can only look for unloaded weapons past this skill + if(self.clip_load >= 0) // only if we're not reloading a weapon already + { + for(i = WEP_FIRST; i <= WEP_LAST; ++i) + { + e = get_weaponinfo(i); + if ((e.spawnflags & WEP_FLAG_RELOADABLE) && (self.weapon_load[i] < cvar(strcat("g_balance_", e.netname, "_reload_ammo")))) + self.switchweapon = i; + } + } + } }; void havocbot_keyboard_movement(vector destorg) @@ -154,7 +183,7 @@ void havocbot_keyboard_movement(vector destorg) sk = skill + self.bot_moveskill; - maxspeed = cvar("sv_maxspeed"); + maxspeed = autocvar_sv_maxspeed; if (time < self.havocbot_keyboardtime) return; @@ -169,7 +198,7 @@ void havocbot_keyboard_movement(vector destorg) local float trigger, trigger1; blend = bound(0,sk*0.1,1); - trigger = cvar("bot_ai_keyboard_treshold"); + trigger = autocvar_bot_ai_keyboard_threshold; trigger1 = 0 - trigger; // categorize forward movement @@ -216,7 +245,7 @@ void havocbot_keyboard_movement(vector destorg) 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 + blend = bound(0,vlen(destorg-self.origin)/autocvar_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; }; @@ -226,19 +255,22 @@ void havocbot_bunnyhop(vector dir) local float bunnyhopdistance; local vector deviation; local float maxspeed; + vector gco, gno; - if(cvar("g_midair")) + if(autocvar_g_midair) return; // Don't jump when using some weapons + /* if(self.aistatus & AI_STATUS_ATTACKING) - if(self.weapon & WEP_CAMPINGRIFLE) + if(self.weapon == WEP_RIFLE) return; if(self.goalcurrent.classname == "player") return; + */ - maxspeed = cvar("sv_maxspeed"); + maxspeed = autocvar_sv_maxspeed; if(self.aistatus & AI_STATUS_DANGER_AHEAD) { @@ -261,7 +293,8 @@ void havocbot_bunnyhop(vector dir) self.bot_timelastseengoal = 0; } - bunnyhopdistance = vlen(self.origin - self.goalcurrent.origin); + gco = (self.goalcurrent.absmin + self.goalcurrent.absmax) * 0.5; + bunnyhopdistance = vlen(self.origin - gco); // Run only to visible goals if(self.flags & FL_ONGROUND) @@ -274,7 +307,7 @@ void havocbot_bunnyhop(vector dir) if(self.bot_timelastseengoal) { // for a period of time - if(time - self.bot_timelastseengoal > cvar("bot_ai_bunnyhop_firstjumpdelay")) + if(time - self.bot_timelastseengoal > autocvar_bot_ai_bunnyhop_firstjumpdelay) { local float checkdistance; checkdistance = TRUE; @@ -282,7 +315,7 @@ void havocbot_bunnyhop(vector dir) // don't run if it is too close if(self.bot_canruntogoal==0) { - if(bunnyhopdistance > cvar("bot_ai_bunnyhop_startdistance")) + if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_startdistance) self.bot_canruntogoal = 1; else self.bot_canruntogoal = -1; @@ -294,18 +327,19 @@ void havocbot_bunnyhop(vector dir) 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(fabs(gco_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); + gno = (self.goalstack01.absmin + self.goalstack01.absmax) * 0.5; + deviation = vectoangles(gno - self.origin) - vectoangles(gco - 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(bunnyhopdistance < vlen(self.origin - gno)) + if(fabs(gno_z - gco_z) < self.maxs_z - self.mins_z) { - if(vlen(self.goalcurrent.origin - self.goalstack01.origin) > cvar("bot_ai_bunnyhop_startdistance")) + if(vlen(gco - gno) > autocvar_bot_ai_bunnyhop_startdistance) if(checkpvs(self.origin + self.view_ofs, self.goalstack01)) { checkdistance = FALSE; @@ -316,7 +350,7 @@ void havocbot_bunnyhop(vector dir) if(checkdistance) { self.aistatus &~= AI_STATUS_RUNNING; - if(bunnyhopdistance > cvar("bot_ai_bunnyhop_stopdistance")) + if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_stopdistance) self.BUTTON_JUMP = TRUE; } else @@ -337,6 +371,7 @@ void havocbot_bunnyhop(vector dir) } // Release jump button + if(!cvar("sv_pogostick")) if(self.flags & FL_ONGROUND == 0) { if(self.velocity_z < 0 || vlen(self.velocity)1000) continue; - traceline(self.origin + self.view_ofs , head.origin, TRUE, world); + traceline(self.origin + self.view_ofs , ( ( head.absmin + head.absmax ) * 0.5 ), TRUE, world); if(trace_fraction<1) continue; @@ -491,7 +521,7 @@ void havocbot_movetogoal() if(newgoal) { self.ignoregoal = self.goalcurrent; - self.ignoregoaltime = time + cvar("bot_ai_ignoregoal_timeout"); + self.ignoregoaltime = time + autocvar_bot_ai_ignoregoal_timeout; navigation_clearroute(); navigation_routetogoal(newgoal, self.origin); self.aistatus &~= AI_STATUS_OUT_JUMPPAD; @@ -507,11 +537,20 @@ void havocbot_movetogoal() local float threshold; threshold = maxspeed * 0.2; if(fabs(self.velocity_x) < threshold && fabs(self.velocity_y) < threshold) + { + dprint("Warning: ", self.netname, " got stuck on a jumppad, trying to get out of it now\n"); self.aistatus |= AI_STATUS_OUT_JUMPPAD; + } return; } + + // Don't chase players while using a jump pad + if(self.goalcurrent.classname=="player" || self.goalstack01.classname=="player") + return; } } + else if(self.aistatus & AI_STATUS_OUT_JUMPPAD) + self.aistatus &~= AI_STATUS_OUT_JUMPPAD; // If there is a trigger_hurt right below try to use the jetpack or make a rocketjump if(skill>6) @@ -537,7 +576,7 @@ void havocbot_movetogoal() if(self.goalcurrent==world) dir = v_forward; else - dir = normalize(self.goalcurrent.origin - self.origin); + dir = normalize(( ( self.goalcurrent.absmin + self.goalcurrent.absmax ) * 0.5 ) - self.origin); local vector xyvelocity = self.velocity; xyvelocity_z = 0; local float xyspeed = xyvelocity * dir; @@ -559,7 +598,7 @@ void havocbot_movetogoal() return; } - else if(self.health>cvar("g_balance_rocketlauncher_damage")*0.5) + else if(self.health>autocvar_g_balance_rocketlauncher_damage*0.5) { if(self.velocity_z < 0) if(client_hasweapon(self, WEP_ROCKET_LAUNCHER, TRUE, FALSE)) @@ -579,7 +618,7 @@ void havocbot_movetogoal() self.switchweapon = WEP_ROCKET_LAUNCHER; self.v_angle_x = 90; self.BUTTON_ATCK = TRUE; - self.rocketjumptime = time + cvar("g_balance_rocketlauncher_detonatedelay"); + self.rocketjumptime = time + autocvar_g_balance_rocketlauncher_detonatedelay; return; } } @@ -622,9 +661,9 @@ void havocbot_movetogoal() return; } -#ifdef DEBUG_BOT_GOALSTACK - debuggoalstack(); -#endif + + if(autocvar_bot_debug_goalstack) + debuggoalstack(); m1 = self.goalcurrent.origin + self.goalcurrent.mins; m2 = self.goalcurrent.origin + self.goalcurrent.maxs; @@ -637,6 +676,7 @@ void havocbot_movetogoal() dir = normalize(diff); flatdir = diff;flatdir_z = 0; flatdir = normalize(flatdir); + gco = (self.goalcurrent.absmin + self.goalcurrent.absmax) * 0.5; //if (self.bot_dodgevector_time < time) { @@ -654,7 +694,7 @@ void havocbot_movetogoal() } else { - if(self.velocity_z >= 0 && !(self.watertype == CONTENT_WATER && self.goalcurrent.origin_z < self.origin_z) && + if(self.velocity_z >= 0 && !(self.watertype == CONTENT_WATER && gco_z < self.origin_z) && ( !(self.waterlevel == WATERLEVEL_WETFEET && self.watertype == CONTENT_WATER) || self.aistatus & AI_STATUS_OUT_WATER)) self.BUTTON_JUMP = TRUE; else @@ -675,12 +715,12 @@ void havocbot_movetogoal() 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); + tracebox(self.origin + stepheightvec, self.mins, self.maxs, self.origin + self.velocity * 0.2 + stepheightvec, 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); + tracebox(self.origin + jumpstepheightvec, self.mins, self.maxs, self.origin + self.velocity * 0.2 + jumpstepheightvec, FALSE, self); if (trace_fraction > s) self.BUTTON_JUMP = 1; } @@ -702,7 +742,7 @@ void havocbot_movetogoal() if(self.facingwalltime && time > self.facingwalltime) { self.ignoregoal = self.goalcurrent; - self.ignoregoaltime = time + cvar("bot_ai_ignoregoal_timeout"); + self.ignoregoaltime = time + autocvar_bot_ai_ignoregoal_timeout; self.bot_strategytime = 0; return; } @@ -726,7 +766,7 @@ void havocbot_movetogoal() // (only when the bot is on the ground or jumping intentionally) self.aistatus &~= AI_STATUS_DANGER_AHEAD; - if(trace_fraction == 1) + if(trace_fraction == 1 && self.jumppadcount == 0) if(self.flags & FL_ONGROUND || self.aistatus & AI_STATUS_RUNNING || self.BUTTON_JUMP == TRUE) { // Look downwards @@ -750,7 +790,11 @@ void havocbot_movetogoal() { // Remove dangerous dynamic goals from stack if (self.goalcurrent.classname == "player" || self.goalcurrent.classname == "droppedweapon") + { navigation_poproute(); + if(self.goalcurrent) + gco = (self.goalcurrent.absmin + self.goalcurrent.absmax) * 0.5; + } // try to stop flatdir = '0 0 0'; evadeobstacle = normalize(self.velocity) * -1; @@ -771,7 +815,7 @@ void havocbot_movetogoal() dodge = havocbot_dodge(); dodge = dodge * bound(0,0.5+(skill+self.bot_dodgeskill)*0.1,1); evadelava = evadelava * bound(1,3-(skill+self.bot_dodgeskill),3); //Noobs fear lava a lot and take more distance from it - traceline(self.origin, self.enemy.origin, TRUE, world); + traceline(self.origin, ( ( self.enemy.absmin + self.enemy.absmax ) * 0.5 ), TRUE, world); if(trace_ent.classname == "player") dir = dir * bound(0,(skill+self.bot_dodgeskill)/7,1); @@ -808,10 +852,10 @@ void havocbot_movetogoal() // Bunnyhop! // if(self.aistatus & AI_STATUS_ROAMING) if(self.goalcurrent) - if(skill+self.bot_moveskill >= cvar("bot_ai_bunnyhop_skilloffset")) + if(skill+self.bot_moveskill >= autocvar_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 ((dir * v_up) >= autocvar_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-self.bot_dodgeskill)*0.1,1)) self.BUTTON_JUMP=TRUE; if (((dodge * v_up) < 0) && random()*frametime >= 0.5*bound(0,(10-skill-self.bot_dodgeskill)*0.1,1)) self.havocbot_ducktime=time+0.3/bound(0.1,skill+self.bot_dodgeskill,10); }; @@ -821,7 +865,7 @@ 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)) + if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(self)) { self.enemy = world; return; @@ -841,13 +885,13 @@ void havocbot_chooseenemy() // 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); + traceline(self.origin+self.view_ofs, ( self.enemy.absmin + self.enemy.absmax ) * 0.5,FALSE,world); if (trace_ent == self.enemy || trace_fraction == 1) - if (vlen(self.enemy.origin - self.origin) < 1000) + if (vlen((( self.enemy.absmin + self.enemy.absmax ) * 0.5) - 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"); + self.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval; return; } // enemy isn't visible, or is far away, or we're injured severely @@ -858,7 +902,7 @@ void havocbot_chooseenemy() } if (time < self.havocbot_chooseenemy_finished) return; - self.havocbot_chooseenemy_finished = time + cvar("bot_ai_enemydetectioninterval"); + self.havocbot_chooseenemy_finished = time + autocvar_bot_ai_enemydetectioninterval; eye = self.origin + self.view_ofs; best = world; bestrating = 100000000; @@ -871,7 +915,7 @@ void havocbot_chooseenemy() { v = (head.absmin + head.absmax) * 0.5; rating = vlen(v - eye); - if (rating rating) if (bot_shouldattack(head)) { @@ -887,7 +931,7 @@ void havocbot_chooseenemy() // 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 + if(best || self.weapons) // || self.weapon == WEP_RIFLE break; if(i) break; @@ -908,6 +952,31 @@ void havocbot_chooseenemy() self.havocbot_stickenemy = TRUE; }; +float havocbot_chooseweapon_checkreload(float new_weapon) +{ + // bots under this skill cannot find unloaded weapons to reload idly when not in combat, + // so skip this for them, or they'll never get to reload their weapons at all. + // this also allows bots under this skill to be more stupid, and reload more often during combat :) + if(skill < 5) + return FALSE; + + // if this weapon is scheduled for reloading, don't switch to it during combat + if (self.weapon_load[new_weapon] < 0) + { + local float i, other_weapon_available; + for(i = WEP_FIRST; i <= WEP_LAST; ++i) + { + // if we are out of ammo for all other weapons, it's an emergency to switch to anything else + if (weapon_action(i, WR_CHECKAMMO1) + weapon_action(i, WR_CHECKAMMO2)) + other_weapon_available = TRUE; + } + if(other_weapon_available) + return TRUE; + } + + return FALSE; +} + void havocbot_chooseweapon() { local float i; @@ -940,35 +1009,14 @@ void havocbot_chooseweapon() 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 mine ; mine =-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"); + ct = autocvar_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 @@ -976,7 +1024,7 @@ void havocbot_chooseweapon() combo = FALSE; - if(cvar("bot_ai_weapon_combo")) + if(autocvar_bot_ai_weapon_combo) if(self.weapon == self.lastfiredweapon) if(af > combo_time) { @@ -993,8 +1041,9 @@ void havocbot_chooseweapon() 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) + if ( client_hasweapon(self, w, TRUE, FALSE) ) + { + if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w)) continue; self.switchweapon = w; return; @@ -1006,8 +1055,9 @@ void havocbot_chooseweapon() 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) + if ( client_hasweapon(self, w, TRUE, FALSE) ) + { + if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w)) continue; self.switchweapon = w; return; @@ -1018,8 +1068,9 @@ void havocbot_chooseweapon() // 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) + if ( client_hasweapon(self, w, TRUE, FALSE) ) + { + if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w)) continue; self.switchweapon = w; return; @@ -1044,10 +1095,10 @@ void havocbot_aim() 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); + lag_additem(time + self.ping, 0, 0, self.enemy, self.origin, selfvel, (self.enemy.absmin + self.enemy.absmax) * 0.5, enemyvel); } else - lag_additem(time + self.ping, 0, 0, world, self.origin, selfvel, self.goalcurrent.origin, '0 0 0'); + lag_additem(time + self.ping, 0, 0, world, self.origin, selfvel, ( self.goalcurrent.absmin + self.goalcurrent.absmax ) * 0.5, '0 0 0'); }; float havocbot_moveto_refresh_route() @@ -1101,12 +1152,11 @@ float havocbot_moveto(vector pos) } } - #ifdef DEBUG_BOT_GOALSTACK + if(autocvar_bot_debug_goalstack) debuggoalstack(); - #endif // Heading - local vector dir = self.goalcurrent.origin - (self.origin + self.view_ofs); + local vector dir = ( ( self.goalcurrent.absmin + self.goalcurrent.absmax ) * 0.5 ) - (self.origin + self.view_ofs); dir_z = 0; bot_aimdir(dir, -1); @@ -1197,7 +1247,7 @@ vector havocbot_dodge() { // LordHavoc: disabled because this is too expensive return '0 0 0'; - /* +#if 0 local entity head; local vector dodge, v, n; local float danger, bestdanger, vl, d; @@ -1242,5 +1292,5 @@ vector havocbot_dodge() head = head.chain; } return dodge; - */ +#endif };