64 this.havocbot_role(
this);
69 if(!(
IS_DEAD(
this) || STAT(FROZEN,
this)))
77 if(it.origin.z < this.origin.z)
80 if(it.origin.z - this.origin.z - this.view_ofs.z > 100)
83 if (pointcontents(it.origin + it.maxs +
'0 0 1') != CONTENT_EMPTY)
86 traceline(this.origin + this.view_ofs, ((it.absmin + it.absmax) * 0.5), true, this);
88 if(trace_fraction < 1)
91 if(!newgoal || vlen2(it.origin - this.origin) < vlen2(newgoal.origin - this.origin))
113 if(
IS_DEAD(
this) || STAT(FROZEN,
this))
127 if(this.(weaponentity).m_weapon != WEP_Null || slot == 0)
142 if(STAT(WEAPONS,
this))
154 Weapon w = this.(weaponentity).m_weapon;
155 if(w == WEP_Null && slot != 0)
157 w.wr_aim(w,
this, weaponentity);
159 this.(weaponentity).
lastfiredweapon = this.(weaponentity).m_weapon.m_id;
166 bot_aimdir(
this, this.
bot_aimtarg.origin +
this.bot_aimtarg.view_ofs -
this.origin -
this.view_ofs, 0);
192 if(this.(weaponentity).m_weapon == WEP_Null && slot != 0)
198 CS(
this).impulse = IMP_weapon_reload.impulse;
205 FOREACH(Weapons, it != WEP_Null, {
206 if((STAT(WEAPONS,
this) & (it.m_wepset)) && (it.spawnflags &
WEP_FLAG_RELOADABLE) && (
this.(weaponentity).weapon_load[it.m_id] < it.reloading_ammo))
208 this.(weaponentity).m_switchweapon = it;
219 bool can_run =
false;
227 while (deviation.y < -180) deviation.y = deviation.y + 360;
228 while (deviation.y > 180) deviation.y = deviation.y - 360;
235 float jump_distance = 52.661 + 0.606 * vel;
236 jump_distance += this.
origin.z - gco.z;
247 while (deviation.y < -180) deviation.y = deviation.y + 360;
248 while (deviation.y > 180) deviation.y = deviation.y - 360;
286 vector keyboard =
CS(
this).movement / autocvar_sv_maxspeed;
295 if (keyboard.x > trigger)
301 else if (keyboard.x < -trigger && sk > 1.5)
316 if (keyboard.y > trigger)
318 else if (keyboard.y < -trigger)
323 if (keyboard.z > trigger)
325 else if (keyboard.z < -trigger)
331 if (keyboard ==
'0 0 0')
341 CS(
this).movement =
CS(
this).movement + (keyboard -
CS(
this).movement) * blend;
352 if(distance_time < 0)
353 distance_time = -distance_time;
358 else if (
time - distance_time > 0.5)
374 float selected_dist2 = 0;
378 float dist2 = vlen2(this.origin - it.origin);
379 if (dist2 < 600 ** 2 && dist2 > selected_dist2)
382 selected_dist2 = vlen2(this.origin - selected.origin);
390 if (!
tracewalk(
this, this.
origin, STAT(PL_MIN,
this), STAT(PL_MAX,
this),
404 float dodge_enemy_factor = 1;
410 CS(
this).movement =
'0 0 0';
411 maxspeed = autocvar_sv_maxspeed;
445 float db = (vel2 / (autocvar_g_jetpack_acceleration_side * 2)) + 100;
447 if(d < db || d < 500)
450 if (vel2 > (maxspeed * 0.3) ** 2)
457 this.
aistatus &= ~AI_STATUS_JETPACK_LANDING;
458 this.
aistatus &= ~AI_STATUS_JETPACK_FLYING;
465 this.
aistatus &= ~AI_STATUS_JETPACK_FLYING;
475 CS(
this).movement_y = dir *
v_right * maxspeed;
498 if(it.wpflags & WAYPOINTFLAG_TELEPORT)
499 if(it.origin.z < this.origin.z - 100 && vdist(vec2(it.origin - this.origin), <, 100))
502 traceline(this.origin + this.view_ofs, ((it.absmin + it.absmax) * 0.5), true, this);
504 if(trace_fraction < 1)
507 if(!newgoal || ((random() < 0.8) && vlen2(it.origin - this.origin) > vlen2(newgoal.origin - this.origin)))
519 this.
aistatus &= ~AI_STATUS_OUT_JUMPPAD;
538 this.
aistatus &= ~AI_STATUS_OUT_JUMPPAD;
551 if(this.
velocity.z > 0 &&
this.origin.z -
this.lastteleport_origin.z > (
this.maxs.z -
this.mins.z) * 0.5)
554 if(
vdist(velxy, <, autocvar_sv_maxspeed * 0.2))
556 LOG_TRACE(
"Warning: ", this.
netname,
" got stuck on a jumppad (velocity in xy is ",
vtos(velxy),
"), trying to get out of it now");
568 this.
aistatus &= ~AI_STATUS_OUT_JUMPPAD;
573 #define ROCKETJUMP_DAMAGE() WEP_CVAR(devastator, damage) * 0.8 \ 574 * ((StatusEffects_active(STATUSEFFECT_Strength, this)) ? autocvar_g_balance_powerup_strength_selfdamage : 1) \ 575 * ((StatusEffects_active(STATUSEFFECT_Shield, this)) ? autocvar_g_balance_powerup_invincible_takedamage : 1) 579 int action_for_trigger_hurt = 0;
580 if (this.
items & IT_JETPACK)
581 action_for_trigger_hurt = 1;
586 action_for_trigger_hurt = 2;
589 action_for_trigger_hurt = 3;
591 if (action_for_trigger_hurt)
595 action_for_trigger_hurt = 0;
598 if(action_for_trigger_hurt == 1)
617 float xyspeed = xyvelocity *
dir;
619 if(xyspeed < (maxspeed / 2))
626 CS(
this).movement_y = dir *
v_right * maxspeed;
636 else if(action_for_trigger_hurt == 2)
644 if(this.(weaponentity).m_weapon == WEP_Null && slot != 0)
649 CS(
this).movement_x = maxspeed;
661 this.(weaponentity).m_switchweapon = WEP_DEVASTATOR;
670 else if(action_for_trigger_hurt == 3)
673 CS(
this).movement_x = maxspeed;
689 CS(
this).movement.z = v *
v_up;
697 bool locked_goal =
false;
714 this.
goalentity.bot_pickup_respawning =
false;
719 this.
goalentity.bot_pickup_respawning =
false;
747 bool goalcurrent_can_be_removed =
false;
753 goalcurrent_can_be_removed =
true;
761 if (
vdist(it.origin -
this.goalcurrent.death_origin, <, 50))
763 navigation_clearroute(this);
764 navigation_pushroute(this, it);
767 navigation_goalrating_timeout_expire(this, 1);
801 if (goalcurrent_can_be_removed)
813 if (old_goal.item_group &&
this.item_group != old_goal.item_group)
839 bool bunnyhop_forbidden =
false;
851 || (
this.absmin.z > destorg.z && destorg.x ==
this.origin.x && destorg.y ==
this.origin.y))
853 bunnyhop_forbidden =
true;
855 if(destorg.z >
this.origin.z)
860 diff = destorg - this.
origin;
867 diff = dir =
'0 0 0';
871 if (
vdist(diff, <, 80))
875 diff = dir =
'0 0 0';
882 destorg -= dir * PL_MAX_CONST.x *
M_SQRT2;
883 diff = destorg - this.
origin;
890 bool danger_detected =
false;
891 vector do_break =
'0 0 0';
906 else if(destorg.z >
this.origin.z)
919 if (destorg.z >
this.origin.z)
929 this.
aistatus &= ~AI_STATUS_OUT_WATER;
933 vector deviation =
'0 0 0';
935 if (current_speed < maxspeed * 0.2)
936 current_speed = maxspeed * 0.2;
940 while (deviation.y < -180) deviation.y += 360;
941 while (deviation.y > 180) deviation.y -= 360;
943 float turning =
false;
945 offset =
max(32, current_speed *
cos(deviation.y *
DEG2RAD) * 0.3) * flatdir;
946 vector actual_destorg = this.origin + offset;
950 &&
fabs(deviation.y) > 20 && current_speed > maxspeed * 0.4
955 if (current_speed > autocvar_sv_maxspeed * 0.9
976 actual_destorg.x = destorg.x;
977 actual_destorg.y = destorg.y;
981 else if (
vdist(flat_diff, <, 32) && diff.z < -16)
983 actual_destorg.x = destorg.x;
984 actual_destorg.y = destorg.y;
990 float dist =
vlen(
vec2(this.origin + offset - destorg));
993 if (dist ** 2 >
vlen2(
vec2(next_goal_org - destorg)))
994 actual_destorg = next_goal_org;
996 actual_destorg =
vec2(destorg) + dist * next_dir;
997 actual_destorg.z = this.origin.z;
1001 LABEL(jumpobstacle_check);
1002 dir = flatdir =
normalize(actual_destorg - this.origin);
1004 bool jump_forbidden =
false;
1005 if (!turning &&
fabs(deviation.y) > 50)
1006 jump_forbidden =
true;
1009 tracebox(this.origin, PL_MIN_CONST, PL_MAX_CONST, this.origin,
false,
this);
1011 jump_forbidden =
true;
1014 if (!jump_forbidden)
1016 tracebox(this.origin, this.
mins, this.
maxs, actual_destorg,
false,
this);
1024 if (turning &&
fabs(deviation.y) > 5)
1027 actual_destorg = destorg;
1030 goto jumpobstacle_check;
1036 tracebox(this.origin + jump_height, this.
mins, this.
maxs, actual_destorg + jump_height,
false,
this);
1045 tracebox(this.origin + jump_height, this.
mins, this.
maxs, actual_destorg + jump_height,
false,
this);
1085 && current_speed > maxspeed * 0.9 &&
fabs(deviation.y) > 70)
1095 vector dst_down = dst_ahead -
'0 0 3000';
1096 traceline(this.origin + this.
view_ofs, dst_ahead,
true,
NULL);
1098 bool unreachable =
false;
1106 traceline(dst_ahead , dst_down,
true,
NULL);
1112 danger_detected =
true;
1113 else if (
trace_endpos.z <
min(this.origin.z +
this.mins.z,
this.goalcurrent.origin.z) - 100)
1114 danger_detected =
true;
1121 danger_detected =
true;
1126 tracebox(dst_ahead, this.
mins, this.
maxs, dst_down,
true,
this);
1135 danger_detected =
true;
1155 &&
vdist(flat_diff, <, 250) && this.origin.z - destorg.z > 120
1159 traceline(this.origin, this.origin -
'0 0 200',
true,
this);
1178 traceline(this.origin, (this.
enemy.absmin +
this.enemy.absmax) * 0.5,
true,
NULL);
1186 float ladder_zdir = 0;
1189 if(this.
goalcurrent.origin.z +
this.goalcurrent.mins.z >
this.origin.z +
this.mins.z)
1191 if(this.origin.z +
this.mins.z <
this.ladder_entity.origin.z +
this.ladder_entity.maxs.z)
1196 if(this.origin.z +
this.mins.z >
this.ladder_entity.origin.z +
this.ladder_entity.mins.z)
1202 dir.z = ladder_zdir * 4;
1204 dir.z = ladder_zdir * 2;
1228 vector evadedanger =
'0 0 0';
1231 dir *= dodge_enemy_factor;
1238 if (
vdist(evadedanger, >, 20))
1240 if (
vdist(evadedanger, >, 40))
1246 evadedanger =
'0 0 0';
1248 dir =
normalize(dir + dodge + do_break + evadedanger);
1256 CS(
this).movement_y = dir *
v_right * maxspeed;
1257 CS(
this).movement_z = dir *
v_up * maxspeed;
1267 if (dir *
v_up >= autocvar_sv_jumpvelocity * 0.5 &&
IS_ONGROUND(
this))
1282 IL_EACH(
g_bot_targets,
boolean((secondary) ? it.classname ==
"misc_breakablemodel" : it.classname !=
"misc_breakablemodel"),
1284 vector v = CENTER_OR_VIEWOFS(it);
1285 if(vdist(v - eye, <, autocvar_bot_ai_enemydetectionradius))
1286 if(!best || vlen2(CENTER_OR_VIEWOFS(best) - eye) > vlen2(v - eye))
1287 if(bot_shouldattack(this, it))
1289 traceline(eye, v, true, this);
1290 if (trace_ent == it || trace_fraction >= 1)
1345 bool scan_transparent =
false;
1346 bool scan_secondary_targets =
false;
1347 bool have_secondary_targets =
false;
1350 scan_secondary_targets =
false;
1354 if(!scan_secondary_targets)
1356 if(it.classname ==
"misc_breakablemodel")
1358 have_secondary_targets = true;
1362 else if(it.classname !=
"misc_breakablemodel")
1365 vector v = (it.absmin + it.absmax) * 0.5;
1366 float rating =
vlen2(
v - eye);
1369 traceline(eye,
v,
true,
this);
1373 bestrating = rating;
1378 if(!best && have_secondary_targets && !scan_secondary_targets)
1380 scan_secondary_targets =
true;
1388 if(best || STAT(WEAPONS,
this))
1390 if(scan_transparent)
1396 scan_transparent =
true;
1404 if(
best &&
best.classname ==
"misc_breakablemodel")
1417 if (this.(weaponentity).
weapon_load[new_weapon] < 0)
1419 FOREACH(Weapons, it != WEP_Null, {
1420 if(it.wr_checkammo1(it,
this, weaponentity) + it.wr_checkammo2(it,
this, weaponentity))
1435 this.(weaponentity).m_switchweapon = WEP_TUBA;
1443 if(this.(weaponentity).m_weapon==WEP_Null)
1444 FOREACH(Weapons, it != WEP_Null, {
1447 this.(weaponentity).m_switchweapon = it;
1463 float af, ct, combo_time, combo;
1475 if(this.(weaponentity).m_weapon.m_id ==
this.(weaponentity).lastfiredweapon)
1479 this.lastcombotime =
time;
1495 this.(weaponentity).m_switchweapon =
REGISTRY_GET(Weapons, w);
1509 this.(weaponentity).m_switchweapon =
REGISTRY_GET(Weapons, w);
1522 this.(weaponentity).m_switchweapon =
REGISTRY_GET(Weapons, w);
1538 else if (this.
enemy)
1541 if (!this.
enemy.waterlevel)
1569 LOG_TRACE(
"Error: ", this.
netname,
" trying to walk to a non existent personal waypoint");
1570 this.
aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_GOING;
1621 this.
aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_REACHED;
1639 this.
aistatus &= ~AI_STATUS_WAYPOINT_PERSONAL_LINKING;
1652 LOG_TRACE(
"Error: Can't spawn personal waypoint at ",
vtos(pos));
1700 float danger, bestdanger, vl, d;
1707 if (head.owner !=
this)
1709 vl =
vlen(head.velocity);
1710 if (vl > autocvar_sv_maxspeed * 0.3)
1713 v = this.
origin - head.origin;
1715 if (d > (0 - head.bot_dodgerating))
1716 if (d < (vl * 0.2 + head.bot_dodgerating))
1719 v = v - (n * (v * n));
1720 danger = head.bot_dodgerating -
vlen(v);
1721 if (bestdanger < danger)
1723 bestdanger = danger;
1731 danger = head.bot_dodgerating -
vlen(head.origin -
this.origin);
1732 if (bestdanger < danger)
1734 bestdanger = danger;
#define PHYS_INPUT_BUTTON_ATCK2(s)
float havocbot_stickenemy_time
#define PHYS_INPUT_BUTTON_JUMP(s)
const int WAYPOINTFLAG_CROUCH
#define IL_EACH(this, cond, body)
float autocvar_bot_ai_bunnyhop_turn_angle_min
#define PHYS_INPUT_BUTTON_CROUCH(s)
float havocbot_moveto(entity this, vector pos)
float weapon_load[REGISTRY_MAX(Weapons)]
void navigation_goalrating_start(entity this)
const int WEP_FLAG_RELOADABLE
bool autocvar_bot_ai_weapon_combo
void waypoint_remove(entity wp)
void navigation_clearroute(entity this)
void havocbot_chooserole(entity this)
float autocvar_bot_ai_enemydetectionradius
float trace_dphitq3surfaceflags
void navigation_goalrating_end(entity this)
float havocbot_resetgoal(entity this)
vector get_closer_dest(entity ent, vector org)
#define IS_INDEPENDENT_PLAYER(e)
int bot_execute_commands(entity this)
IntrusiveList g_teleporters
const int AI_STATUS_ROAMING
entity havocbot_gettarget(entity this, bool secondary)
const int WAYPOINTFLAG_LADDER
float goalentity_lock_timeout
#define REGISTRY_GET(id, i)
float autocvar_bot_ai_bunnyhop_turn_angle_max
float autocvar_bot_ai_ignoregoal_timeout
ClientState CS(Client this)
void bot_aimdir(entity this, vector v, float maxfiredeviation)
float autocvar_bot_ai_keyboard_threshold
const int WAYPOINTFLAG_JUMP
float autocvar_bot_ai_enemydetectioninterval_stickingtoenemy
const float CONTENT_SOLID
const int AI_STATUS_JETPACK_LANDING
#define ROCKETJUMP_DAMAGE()
float checkpvs(vector viewpos, entity viewee)
#define WEP_CVAR(wepname, name)
float bot_weapons_close[REGISTRY_MAX(Weapons)]
const int AI_STATUS_WAYPOINT_PERSONAL_GOING
const int AI_STATUS_OUT_JUMPPAD
void havocbot_aim(entity this)
bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
float bot_stop_moving_timeout
void navigation_goalrating_timeout_force(entity this)
ERASEABLE vector point_line_vec(vector p, vector l0, vector ldir)
float autocvar_bot_ai_chooseweaponinterval
void navigation_routerating(entity this, entity e, float f, float rangebias)
IntrusiveList g_bot_targets
float bot_chooseweapontime
float autocvar_bot_ai_bunnyhop_skilloffset
float autocvar_bot_ai_bunnyhop_dir_deviation_max
#define REGISTRY_COUNT(id)
const int AI_STATUS_WAYPOINT_PERSONAL_LINKING
#define CMD_STATUS_FINISHED
float havocbot_chooseenemy_finished
float goalcurrent_distance_z
bool navigation_goalrating_timeout_can_be_anticipated(entity this)
float bot_rangepreference
bool navigation_shortenpath(entity this)
const float MOVE_NOMONSTERS
void lag_update(entity this)
const float CONTENT_SLIME
const int WAYPOINTFLAG_TELEPORT
void havocbot_keyboard_movement(entity this, vector destorg)
ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4)
requires that m2>m1 in all coordinates, and that m4>m3
const int MAX_WEAPONSLOTS
float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
const float CONTENT_WATER
vector navigation_jetpack_point
entity havocbot_personal_waypoint
int navigation_poptouchedgoals(entity this)
#define CMD_STATUS_EXECUTING
float goalcurrent_distance_time
void havocbot_chooseenemy(entity this)
float goalcurrent_distance_2d
#define PHYS_INPUT_BUTTON_ATCK(s)
float autocvar_bot_ai_bunnyhop_downward_pitch_max
const int AI_STATUS_WAYPOINT_PERSONAL_REACHED
float tracewalk_dest_height
float autocvar_bot_ai_bunnyhop_turn_angle_reduction
const int WATERLEVEL_WETFEET
void havocbot_movetogoal(entity this)
float bot_weapons_far[REGISTRY_MAX(Weapons)]
IntrusiveList g_waypoints
entity waypoint_spawnpersonal(entity this, vector position)
void navigation_goalrating_timeout_expire(entity this, float seconds)
const int AI_STATUS_OUT_WATER
#define CENTER_OR_VIEWOFS(ent)
vector(float skel, float bonenum) _skel_get_boneabs_hidden
void havocbot_bunnyhop(entity this, vector dir)
bool navigation_routetogoal(entity this, entity e, vector startposition)
float bot_navigation_movemode
float autocvar_bot_ai_weapon_combo_threshold
const int AI_STATUS_DANGER_AHEAD
void navigation_pushroute(entity this, entity e)
entity navigation_jetpack_goal
void set_tracewalk_dest(entity ent, vector org, bool fix_player_dest)
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
void havocbot_chooseweapon(entity this,.entity weaponentity)
vector havocbot_dodge(entity this)
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
void havocbot_ai(entity this)
void debuggoalstack(entity this)
bool waypoint_is_hardwiredlink(entity wp_from, entity wp_to)
#define PHYS_INPUT_BUTTON_JETPACK(s)
float havocbot_chooseweapon_checkreload(entity this,.entity weaponentity, int new_weapon)
void havocbot_setupbot(entity this)
float autocvar_bot_ai_enemydetectioninterval
float autocvar_bot_ai_keyboard_distance
bool autocvar_bot_debug_goalstack
float havocbot_personal_waypoint_failcounter
const int WATERLEVEL_SWIMMING
bool havocbot_checkgoaldistance(entity this, vector gco)
#define MUTATOR_CALLHOOK(id,...)
entity weaponentities[MAX_WEAPONSLOTS]
bool bot_shouldattack(entity this, entity e)
bool Item_IsLoot(entity item)
Returns whether the item is loot.
entity havocbot_select_an_item_of_group(entity this, int gr)
float havocbot_keyboardskill
float bot_weapons_mid[REGISTRY_MAX(Weapons)]
vector trace_plane_normal
#define ATTACK_FINISHED(ent, w)
float havocbot_personal_waypoint_searchtime
bool bot_ispaused(entity this)
float havocbot_keyboardtime
const int AI_STATUS_ATTACKING
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
bool client_hasweapon(entity this, Weapon wpn,.entity weaponentity, float andammo, bool complain)
const int AI_STATUS_JETPACK_FLYING
float lag_additem(entity this, float t, float f1, float f2, entity e1, vector v1, vector v2, vector v3, vector v4)
#define FOREACH(list, cond, body)
const int AI_STATUS_RUNNING
bool goalentity_shouldbefrozen
WepSet g_weaponarena_weapons
bool havocbot_moveto_refresh_route(entity this)
float bot_strategytoken_taken