From 3b7669dbd04b0ade07c5c946c81783381e64fd20 Mon Sep 17 00:00:00 2001 From: ineedbots Date: Wed, 26 May 2021 10:47:29 -0600 Subject: [PATCH] Greatly reduce var usage --- main_shared/maps/mp/bots/_bot.gsc | 535 ++-- main_shared/maps/mp/bots/_bot_internal.gsc | 1343 +++++---- main_shared/maps/mp/bots/_bot_script.gsc | 3173 +++++++++++--------- 3 files changed, 2656 insertions(+), 2395 deletions(-) diff --git a/main_shared/maps/mp/bots/_bot.gsc b/main_shared/maps/mp/bots/_bot.gsc index f7dcc7f..4088c7e 100644 --- a/main_shared/maps/mp/bots/_bot.gsc +++ b/main_shared/maps/mp/bots/_bot.gsc @@ -367,6 +367,82 @@ add_bot() } } +/* + A server thread for monitoring all bot's difficulty levels for custom server settings. +*/ +diffBots_loop() +{ + var_allies_hard = getDVarInt("bots_skill_allies_hard"); + var_allies_med = getDVarInt("bots_skill_allies_med"); + var_axis_hard = getDVarInt("bots_skill_axis_hard"); + var_axis_med = getDVarInt("bots_skill_axis_med"); + var_skill = getDvarInt("bots_skill"); + + allies_hard = 0; + allies_med = 0; + axis_hard = 0; + axis_med = 0; + + if(var_skill == 8) + { + playercount = level.players.size; + for(i = 0; i < playercount; i++) + { + player = level.players[i]; + + if(!isDefined(player.pers["team"])) + continue; + + if(!player is_bot()) + continue; + + if(player.pers["team"] == "axis") + { + if(axis_hard < var_axis_hard) + { + axis_hard++; + player.pers["bots"]["skill"]["base"] = 7; + } + else if(axis_med < var_axis_med) + { + axis_med++; + player.pers["bots"]["skill"]["base"] = 4; + } + else + player.pers["bots"]["skill"]["base"] = 1; + } + else if(player.pers["team"] == "allies") + { + if(allies_hard < var_allies_hard) + { + allies_hard++; + player.pers["bots"]["skill"]["base"] = 7; + } + else if(allies_med < var_allies_med) + { + allies_med++; + player.pers["bots"]["skill"]["base"] = 4; + } + else + player.pers["bots"]["skill"]["base"] = 1; + } + } + } + else if (var_skill != 0 && var_skill != 9) + { + playercount = level.players.size; + for(i = 0; i < playercount; i++) + { + player = level.players[i]; + + if(!player is_bot()) + continue; + + player.pers["bots"]["skill"]["base"] = var_skill; + } + } +} + /* A server thread for monitoring all bot's difficulty levels for custom server settings. */ @@ -375,74 +451,131 @@ diffBots() for(;;) { wait 1.5; + + diffBots_loop(); + } +} + +/* + A server thread for monitoring all bot's teams for custom server settings. +*/ +teamBots_loop() +{ + teamAmount = getDvarInt("bots_team_amount"); + toTeam = getDvar("bots_team"); + + alliesbots = 0; + alliesplayers = 0; + axisbots = 0; + axisplayers = 0; + + playercount = level.players.size; + for(i = 0; i < playercount; i++) + { + player = level.players[i]; - var_allies_hard = getDVarInt("bots_skill_allies_hard"); - var_allies_med = getDVarInt("bots_skill_allies_med"); - var_axis_hard = getDVarInt("bots_skill_axis_hard"); - var_axis_med = getDVarInt("bots_skill_axis_med"); - var_skill = getDvarInt("bots_skill"); + if(!isDefined(player.pers["team"])) + continue; - allies_hard = 0; - allies_med = 0; - axis_hard = 0; - axis_med = 0; - - if(var_skill == 8) + if(player is_bot()) { - playercount = level.players.size; - for(i = 0; i < playercount; i++) + if(player.pers["team"] == "allies") + alliesbots++; + else if(player.pers["team"] == "axis") + axisbots++; + } + else + { + if(player.pers["team"] == "allies") + alliesplayers++; + else if(player.pers["team"] == "axis") + axisplayers++; + } + } + + allies = alliesbots; + axis = axisbots; + + if(!getDvarInt("bots_team_mode")) + { + allies += alliesplayers; + axis += axisplayers; + } + + if(toTeam != "custom") + { + if(getDvarInt("bots_team_force")) + { + if(toTeam == "autoassign") { - player = level.players[i]; - - if(!isDefined(player.pers["team"])) - continue; - - if(!player is_bot()) - continue; - - if(player.pers["team"] == "axis") + if(abs(axis - allies) > 1) { - if(axis_hard < var_axis_hard) - { - axis_hard++; - player.pers["bots"]["skill"]["base"] = 7; - } - else if(axis_med < var_axis_med) - { - axis_med++; - player.pers["bots"]["skill"]["base"] = 4; - } - else - player.pers["bots"]["skill"]["base"] = 1; + toTeam = "axis"; + if(axis > allies) + toTeam = "allies"; } - else if(player.pers["team"] == "allies") + } + + if(toTeam != "autoassign") + { + playercount = level.players.size; + for(i = 0; i < playercount; i++) { - if(allies_hard < var_allies_hard) - { - allies_hard++; - player.pers["bots"]["skill"]["base"] = 7; - } - else if(allies_med < var_allies_med) - { - allies_med++; - player.pers["bots"]["skill"]["base"] = 4; - } + player = level.players[i]; + + if(!isDefined(player.pers["team"])) + continue; + + if(!player is_bot()) + continue; + + if(player.pers["team"] == toTeam) + continue; + + if (toTeam == "allies") + player thread [[level.allies]](); + else if (toTeam == "axis") + player thread [[level.axis]](); else - player.pers["bots"]["skill"]["base"] = 1; + player thread [[level.spectator]](); + break; } } } - else if (var_skill != 0 && var_skill != 9) + } + else + { + playercount = level.players.size; + for(i = 0; i < playercount; i++) { - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; + player = level.players[i]; + + if(!isDefined(player.pers["team"])) + continue; + + if(!player is_bot()) + continue; - if(!player is_bot()) - continue; - - player.pers["bots"]["skill"]["base"] = var_skill; + if(player.pers["team"] == "axis") + { + if(axis > teamAmount) + { + player thread [[level.allies]](); + break; + } + } + else + { + if(axis < teamAmount) + { + player thread [[level.axis]](); + break; + } + else if(player.pers["team"] != "allies") + { + player thread [[level.allies]](); + break; + } } } } @@ -456,124 +589,112 @@ teamBots() for(;;) { wait 1.5; - teamAmount = getDvarInt("bots_team_amount"); - toTeam = getDvar("bots_team"); + + teamBots_loop(); + } +} + +/* + A server thread for monitoring all bot's in game. Will add and kick bots according to server settings. +*/ +addBots_loop() +{ + botsToAdd = GetDvarInt("bots_manage_add"); + + if(botsToAdd > 0) + { + SetDvar("bots_manage_add", 0); - alliesbots = 0; - alliesplayers = 0; - axisbots = 0; + if(botsToAdd > 64) + botsToAdd = 64; + + for(; botsToAdd > 0; botsToAdd--) + { + level add_bot(); + wait 0.25; + } + } + + fillMode = getDVarInt("bots_manage_fill_mode"); + + if(fillMode == 2 || fillMode == 3) + setDvar("bots_manage_fill", getGoodMapAmount()); + + fillAmount = getDvarInt("bots_manage_fill"); + + players = 0; + bots = 0; + spec = 0; + + playercount = level.players.size; + for(i = 0; i < playercount; i++) + { + player = level.players[i]; + + if(player is_bot()) + bots++; + else if(!isDefined(player.pers["team"]) || (player.pers["team"] != "axis" && player.pers["team"] != "allies")) + spec++; + else + players++; + } + + if (!randomInt(999)) + { + setDvar("testclients_doreload", true); + wait 0.1; + setDvar("testclients_doreload", false); + doExtraCheck(); + } + + if(fillMode == 4) + { axisplayers = 0; + alliesplayers = 0; playercount = level.players.size; for(i = 0; i < playercount; i++) { player = level.players[i]; + if(player is_bot()) + continue; + if(!isDefined(player.pers["team"])) continue; - if(player is_bot()) - { - if(player.pers["team"] == "allies") - alliesbots++; - else if(player.pers["team"] == "axis") - axisbots++; - } + if(player.pers["team"] == "axis") + axisplayers++; + else if(player.pers["team"] == "allies") + alliesplayers++; + } + + result = fillAmount - abs(axisplayers - alliesplayers) + bots; + + if (players == 0) + { + if(bots < fillAmount) + result = fillAmount-1; + else if (bots > fillAmount) + result = fillAmount+1; else - { - if(player.pers["team"] == "allies") - alliesplayers++; - else if(player.pers["team"] == "axis") - axisplayers++; - } + result = fillAmount; } - allies = alliesbots; - axis = axisbots; + bots = result; + } + + amount = bots; + if(fillMode == 0 || fillMode == 2) + amount += players; + if(getDVarInt("bots_manage_fill_spec")) + amount += spec; - if(!getDvarInt("bots_team_mode")) - { - allies += alliesplayers; - axis += axisplayers; - } - - if(toTeam != "custom") - { - if(getDvarInt("bots_team_force")) - { - if(toTeam == "autoassign") - { - if(abs(axis - allies) > 1) - { - toTeam = "axis"; - if(axis > allies) - toTeam = "allies"; - } - } - - if(toTeam != "autoassign") - { - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; - - if(!isDefined(player.pers["team"])) - continue; - - if(!player is_bot()) - continue; - - if(player.pers["team"] == toTeam) - continue; - - if (toTeam == "allies") - player thread [[level.allies]](); - else if (toTeam == "axis") - player thread [[level.axis]](); - else - player thread [[level.spectator]](); - break; - } - } - } - } - else - { - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; - - if(!isDefined(player.pers["team"])) - continue; - - if(!player is_bot()) - continue; - - if(player.pers["team"] == "axis") - { - if(axis > teamAmount) - { - player thread [[level.allies]](); - break; - } - } - else - { - if(axis < teamAmount) - { - player thread [[level.axis]](); - break; - } - else if(player.pers["team"] != "allies") - { - player thread [[level.allies]](); - break; - } - } - } - } + if(amount < fillAmount) + setDvar("bots_manage_add", 1); + else if(amount > fillAmount && getDvarInt("bots_manage_fill_kick")) + { + RemoveTestClient(); //cod4x } } @@ -590,103 +711,7 @@ addBots() { wait 1.5; - botsToAdd = GetDvarInt("bots_manage_add"); - - if(botsToAdd > 0) - { - SetDvar("bots_manage_add", 0); - - if(botsToAdd > 64) - botsToAdd = 64; - - for(; botsToAdd > 0; botsToAdd--) - { - level add_bot(); - wait 0.25; - } - } - - fillMode = getDVarInt("bots_manage_fill_mode"); - - if(fillMode == 2 || fillMode == 3) - setDvar("bots_manage_fill", getGoodMapAmount()); - - fillAmount = getDvarInt("bots_manage_fill"); - - players = 0; - bots = 0; - spec = 0; - - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; - - if(player is_bot()) - bots++; - else if(!isDefined(player.pers["team"]) || (player.pers["team"] != "axis" && player.pers["team"] != "allies")) - spec++; - else - players++; - } - - if (!randomInt(999)) - { - setDvar("testclients_doreload", true); - wait 0.1; - setDvar("testclients_doreload", false); - doExtraCheck(); - } - - if(fillMode == 4) - { - axisplayers = 0; - alliesplayers = 0; - - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; - - if(player is_bot()) - continue; - - if(!isDefined(player.pers["team"])) - continue; - - if(player.pers["team"] == "axis") - axisplayers++; - else if(player.pers["team"] == "allies") - alliesplayers++; - } - - result = fillAmount - abs(axisplayers - alliesplayers) + bots; - - if (players == 0) - { - if(bots < fillAmount) - result = fillAmount-1; - else if (bots > fillAmount) - result = fillAmount+1; - else - result = fillAmount; - } - - bots = result; - } - - amount = bots; - if(fillMode == 0 || fillMode == 2) - amount += players; - if(getDVarInt("bots_manage_fill_spec")) - amount += spec; - - if(amount < fillAmount) - setDvar("bots_manage_add", 1); - else if(amount > fillAmount && getDvarInt("bots_manage_fill_kick")) - { - RemoveTestClient(); //cod4x - } + addBots_loop(); } } diff --git a/main_shared/maps/mp/bots/_bot_internal.gsc b/main_shared/maps/mp/bots/_bot_internal.gsc index 4e1f336..d2dff74 100644 --- a/main_shared/maps/mp/bots/_bot_internal.gsc +++ b/main_shared/maps/mp/bots/_bot_internal.gsc @@ -287,13 +287,62 @@ watchC4Thrown(c4) break; } - weap = self getCurrentWeapon(); - if ( weap != "c4_mp" ) + if ( self getCurrentWeapon() != "c4_mp" ) self notify( "alt_detonate" ); else self thread pressFire(); } +/* + Bot moves towards the point +*/ +doBotMovement_loop(data) +{ + angles = self GetPlayerAngles(); + + // climb through windows + if (self isMantling()) + { + data.wasMantling = true; + self crouch(); + } + else if (data.wasMantling) + { + data.wasMantling = false; + self stand(); + } + + startPos = self.origin + (0, 0, 50); + startPosForward = startPos + anglesToForward((0, angles[1], 0)) * 25; + bt = bulletTrace(startPos, startPosForward, false, self); + if (bt["fraction"] >= 1) + { + // check if need to jump + bt = bulletTrace(startPosForward, startPosForward - (0, 0, 40), false, self); + + if (bt["fraction"] < 1 && bt["normal"][2] > 0.9 && data.i > 1.5 && !self isOnLadder()) + { + data.i = 0; + self thread jump(); + } + } + // check if need to knife glass + else if (bt["surfacetype"] == "glass") + { + if (data.i > 1.5) + { + data.i = 0; + self thread knife(); + } + } + else + { + // check if need to crouch + if (bulletTracePassed(startPos - (0, 0, 25), startPosForward - (0, 0, 25), false, self) && !self.bot.climbing) + self crouch(); + } +} + /* Bot moves towards the point */ @@ -302,56 +351,14 @@ doBotMovement() self endon("disconnect"); self endon("death"); - FORWARDAMOUNT = 25; - wasMantling = false; + data = spawnStruct(); + data.wasMantling = false; - for (i = 0;;i+=0.05) + for (data.i = 0; true; data.i += 0.05) { wait 0.05; - angles = self GetPlayerAngles(); - - // climb through windows - if (self isMantling()) - { - wasMantling = true; - self crouch(); - } - else if (wasMantling) - { - wasMantling = false; - self stand(); - } - - startPos = self.origin + (0, 0, 50); - startPosForward = startPos + anglesToForward((0, angles[1], 0)) * FORWARDAMOUNT; - bt = bulletTrace(startPos, startPosForward, false, self); - if (bt["fraction"] >= 1) - { - // check if need to jump - bt = bulletTrace(startPosForward, startPosForward - (0, 0, 40), false, self); - - if (bt["fraction"] < 1 && bt["normal"][2] > 0.9 && i > 1.5 && !self isOnLadder()) - { - i = 0; - self thread jump(); - } - } - // check if need to knife glass - else if (bt["surfacetype"] == "glass") - { - if (i > 1.5) - { - i = 0; - self thread knife(); - } - } - else - { - // check if need to crouch - if (bulletTracePassed(startPos - (0, 0, 25), startPosForward - (0, 0, 25), false, self) && !self.bot.climbing) - self crouch(); - } + self doBotMovement_loop(data); } } @@ -409,6 +416,33 @@ watchHoldBreath() } } +/* + When the bot enters laststand, we fix the weapons +*/ +onLastStand_loop() +{ + while (!self inLastStand()) + wait 0.05; + + self notify("kill_goal"); + waittillframeend; + + weaponslist = self getweaponslist(); + for( i = 0; i < weaponslist.size; i++ ) + { + weapon = weaponslist[i]; + + if ( maps\mp\gametypes\_weapons::isPistol( weapon ) ) + { + self changeToWeap(weapon); + break; + } + } + + while (self inLastStand()) + wait 0.05; +} + /* When the bot enters laststand, we fix the weapons */ @@ -419,26 +453,7 @@ onLastStand() while (true) { - while (!self inLastStand()) - wait 0.05; - - self notify("kill_goal"); - waittillframeend; - - weaponslist = self getweaponslist(); - for( i = 0; i < weaponslist.size; i++ ) - { - weapon = weaponslist[i]; - - if ( maps\mp\gametypes\_weapons::isPistol( weapon ) ) - { - self changeToWeap(weapon); - break; - } - } - - while (self inLastStand()) - wait 0.05; + self onLastStand_loop(); } } @@ -491,6 +506,31 @@ sprint_watch() } } +/* + Update's the bot if it is reloading. +*/ +reload_watch_loop() +{ + self.bot.isreloading = true; + + while(true) + { + ret = self waittill_any_timeout(7.5, "reload"); + + if (ret == "timeout") + break; + + weap = self GetCurrentWeapon(); + + if (weap == "none") + break; + + if (self GetWeaponAmmoClip(weap) >= WeaponClipSize(weap)) + break; + } + self.bot.isreloading = false; +} + /* Update's the bot if it is reloading. */ @@ -502,23 +542,75 @@ reload_watch() for(;;) { self waittill("reload_start"); - self.bot.isreloading = true; - while(true) - { - ret = self waittill_any_timeout(7.5, "reload"); - - if (ret == "timeout") - break; - - weap = self GetCurrentWeapon(); - if (self GetWeaponAmmoClip(weap) >= WeaponClipSize(weap)) - break; - } - self.bot.isreloading = false; + self reload_watch_loop(); } } +/* + Bots will update its needed stance according to the nodes on the level. Will also allow the bot to sprint when it can. +*/ +stance_loop() +{ + self.bot.climbing = false; + + if(self.bot.isfrozen) + return; + + toStance = "stand"; + if(self.bot.next_wp != -1) + toStance = level.waypoints[self.bot.next_wp].type; + + if (!isDefined(toStance)) + toStance = "crouch"; + + if(toStance == "stand" && randomInt(100) <= self.pers["bots"]["behavior"]["crouch"]) + toStance = "crouch"; + + if(toStance == "climb") + { + self.bot.climbing = true; + toStance = "stand"; + } + + if(toStance != "stand" && toStance != "crouch" && toStance != "prone") + toStance = "crouch"; + + if(toStance == "stand") + self stand(); + else if(toStance == "crouch") + self crouch(); + else + self prone(); + + curweap = self getCurrentWeapon(); + time = getTime(); + chance = self.pers["bots"]["behavior"]["sprint"]; + + if (time - self.lastSpawnTime < 5000) + chance *= 2; + + if(isDefined(self.bot.script_goal) && DistanceSquared(self.origin, self.bot.script_goal) > 256*256) + chance *= 2; + + if(toStance != "stand" || self.bot.isreloading || self.bot.issprinting || self.bot.isfraggingafter || self.bot.issmokingafter) + return; + + if(randomInt(100) > chance) + return; + + if(isDefined(self.bot.target) && self canFire(curweap) && self isInRange(self.bot.target.dist, curweap)) + return; + + if(self.bot.sprintendtime != -1 && time - self.bot.sprintendtime < 2000) + return; + + if(!isDefined(self.bot.towards_goal) || DistanceSquared(self.origin, self.bot.towards_goal) < level.bots_minSprintDistance || getConeDot(self.bot.towards_goal, self.origin, self GetPlayerAngles()) < 0.75) + return; + + self thread sprint(); +} + /* Bots will update its needed stance according to the nodes on the level. Will also allow the bot to sprint when it can. */ @@ -531,63 +623,7 @@ stance() { self waittill_either("finished_static_waypoints", "new_static_waypoint"); - self.bot.climbing = false; - - if(self.bot.isfrozen) - continue; - - toStance = "stand"; - if(self.bot.next_wp != -1) - toStance = level.waypoints[self.bot.next_wp].type; - - if (!isDefined(toStance)) - toStance = "crouch"; - - if(toStance == "stand" && randomInt(100) <= self.pers["bots"]["behavior"]["crouch"]) - toStance = "crouch"; - - if(toStance == "climb") - { - self.bot.climbing = true; - toStance = "stand"; - } - - if(toStance != "stand" && toStance != "crouch" && toStance != "prone") - toStance = "crouch"; - - if(toStance == "stand") - self stand(); - else if(toStance == "crouch") - self crouch(); - else - self prone(); - - curweap = self getCurrentWeapon(); - time = getTime(); - chance = self.pers["bots"]["behavior"]["sprint"]; - - if (time - self.lastSpawnTime < 5000) - chance *= 2; - - if(isDefined(self.bot.script_goal) && DistanceSquared(self.origin, self.bot.script_goal) > 256*256) - chance *= 2; - - if(toStance != "stand" || self.bot.isreloading || self.bot.issprinting || self.bot.isfraggingafter || self.bot.issmokingafter) - continue; - - if(randomInt(100) > chance) - continue; - - if(isDefined(self.bot.target) && self canFire(curweap) && self isInRange(self.bot.target.dist, curweap)) - continue; - - if(self.bot.sprintendtime != -1 && time - self.bot.sprintendtime < 2000) - continue; - - if(!isDefined(self.bot.towards_goal) || DistanceSquared(self.origin, self.bot.towards_goal) < level.bots_minSprintDistance || getConeDot(self.bot.towards_goal, self.origin, self GetPlayerAngles()) < 0.75) - continue; - - self thread sprint(); + self stance_loop(); } } @@ -812,6 +848,196 @@ targetObjUpdateNoTrace(obj) obj.didlook = false; } +/* + The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. +*/ +target_loop() +{ + myEye = self GetEyePos(); + theTime = getTime(); + myAngles = self GetPlayerAngles(); + myFov = self.pers["bots"]["skill"]["fov"]; + bestTargets = []; + bestTime = 2147483647; + rememberTime = self.pers["bots"]["skill"]["remember_time"]; + initReactTime = self.pers["bots"]["skill"]["init_react_time"]; + hasTarget = isDefined(self.bot.target); + adsAmount = self PlayerADS(); + adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"]; + + // reduce fov if ads'ing + if (adsAmount > 0) + { + myFov *= 1 - adsFovFact * adsAmount; + } + + if(hasTarget && !isDefined(self.bot.target.entity)) + { + self.bot.target = undefined; + hasTarget = false; + } + + playercount = level.players.size; + for(i = -1; i < playercount; i++) + { + obj = undefined; + + if (i == -1) + { + if(!isDefined(self.bot.script_target)) + continue; + + ent = self.bot.script_target; + key = ent getEntityNumber()+""; + daDist = distanceSquared(self.origin, ent.origin); + obj = self.bot.targets[key]; + isObjDef = isDefined(obj); + entOrigin = ent.origin; + if (isDefined(self.bot.script_target_offset)) + entOrigin += self.bot.script_target_offset; + + if(SmokeTrace(myEye, entOrigin, level.smokeRadius) && bulletTracePassed(myEye, entOrigin, false, ent)) + { + if(!isObjDef) + { + obj = self createTargetObj(ent, theTime); + obj.offset = self.bot.script_target_offset; + + self.bot.targets[key] = obj; + } + + self targetObjUpdateTraced(obj, daDist, ent, theTime, true); + } + else + { + if(!isObjDef) + continue; + + self targetObjUpdateNoTrace(obj); + + if(obj.no_trace_time > rememberTime) + { + self.bot.targets[key] = undefined; + continue; + } + } + } + else + { + player = level.players[i]; + + if(!player IsPlayerModelOK()) + continue; + if(player == self) + continue; + + key = player getEntityNumber()+""; + obj = self.bot.targets[key]; + daDist = distanceSquared(self.origin, player.origin); + isObjDef = isDefined(obj); + if((level.teamBased && self.team == player.team) || player.sessionstate != "playing" || !isAlive(player)) + { + if(isObjDef) + self.bot.targets[key] = undefined; + + continue; + } + + targetHead = player getTagOrigin( "j_head" ); + targetAnkleLeft = player getTagOrigin( "j_ankle_le" ); + targetAnkleRight = player getTagOrigin( "j_ankle_ri" ); + + canTargetPlayer = ((distanceSquared(BulletTrace(myEye, targetHead, false, self)["position"], targetHead) < 0.05 || + distanceSquared(BulletTrace(myEye, targetAnkleLeft, false, self)["position"], targetAnkleLeft) < 0.05 || + distanceSquared(BulletTrace(myEye, targetAnkleRight, false, self)["position"], targetAnkleRight) < 0.05) + + && (SmokeTrace(myEye, player.origin, level.smokeRadius) || + daDist < level.bots_maxKnifeDistance*4) + + && (getConeDot(player.origin, self.origin, myAngles) >= myFov || + (isObjDef && obj.trace_time))); + + if (isDefined(self.bot.target_this_frame) && self.bot.target_this_frame == player) + { + self.bot.target_this_frame = undefined; + + canTargetPlayer = true; + } + + if(canTargetPlayer) + { + if(!isObjDef) + { + obj = self createTargetObj(player, theTime); + + self.bot.targets[key] = obj; + } + + self targetObjUpdateTraced(obj, daDist, player, theTime, false); + } + else + { + if(!isObjDef) + continue; + + self targetObjUpdateNoTrace(obj); + + if(obj.no_trace_time > rememberTime) + { + self.bot.targets[key] = undefined; + continue; + } + } + } + + if (!isdefined(obj)) + continue; + + if(theTime - obj.time < initReactTime) + continue; + + timeDiff = theTime - obj.trace_time_time; + if(timeDiff < bestTime) + { + bestTargets = []; + bestTime = timeDiff; + } + + if(timeDiff == bestTime) + bestTargets[key] = obj; + } + + if(hasTarget && isDefined(bestTargets[self.bot.target.entity getEntityNumber()+""])) + return; + + closest = 2147483647; + toBeTarget = undefined; + + bestKeys = getArrayKeys(bestTargets); + for(i = bestKeys.size - 1; i >= 0; i--) + { + theDist = bestTargets[bestKeys[i]].dist; + if(theDist > closest) + continue; + + closest = theDist; + toBeTarget = bestTargets[bestKeys[i]]; + } + + beforeTargetID = -1; + newTargetID = -1; + if(hasTarget && isDefined(self.bot.target.entity)) + beforeTargetID = self.bot.target.entity getEntityNumber(); + if(isDefined(toBeTarget) && isDefined(toBeTarget.entity)) + newTargetID = toBeTarget.entity getEntityNumber(); + + if(beforeTargetID != newTargetID) + { + self.bot.target = toBeTarget; + self notify("new_enemy"); + } +} + /* The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. */ @@ -827,189 +1053,7 @@ target() if(self maps\mp\_flashgrenades::isFlashbanged()) continue; - myEye = self GetEyePos(); - theTime = getTime(); - myAngles = self GetPlayerAngles(); - myFov = self.pers["bots"]["skill"]["fov"]; - bestTargets = []; - bestTime = 2147483647; - rememberTime = self.pers["bots"]["skill"]["remember_time"]; - initReactTime = self.pers["bots"]["skill"]["init_react_time"]; - hasTarget = isDefined(self.bot.target); - adsAmount = self PlayerADS(); - adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"]; - - // reduce fov if ads'ing - if (adsAmount > 0) - { - myFov *= 1 - adsFovFact * adsAmount; - } - - if(hasTarget && !isDefined(self.bot.target.entity)) - { - self.bot.target = undefined; - hasTarget = false; - } - - playercount = level.players.size; - for(i = -1; i < playercount; i++) - { - obj = undefined; - - if (i == -1) - { - if(!isDefined(self.bot.script_target)) - continue; - - ent = self.bot.script_target; - key = ent getEntityNumber()+""; - daDist = distanceSquared(self.origin, ent.origin); - obj = self.bot.targets[key]; - isObjDef = isDefined(obj); - entOrigin = ent.origin; - if (isDefined(self.bot.script_target_offset)) - entOrigin += self.bot.script_target_offset; - - if(SmokeTrace(myEye, entOrigin, level.smokeRadius) && bulletTracePassed(myEye, entOrigin, false, ent)) - { - if(!isObjDef) - { - obj = self createTargetObj(ent, theTime); - obj.offset = self.bot.script_target_offset; - - self.bot.targets[key] = obj; - } - - self targetObjUpdateTraced(obj, daDist, ent, theTime, true); - } - else - { - if(!isObjDef) - continue; - - self targetObjUpdateNoTrace(obj); - - if(obj.no_trace_time > rememberTime) - { - self.bot.targets[key] = undefined; - continue; - } - } - } - else - { - player = level.players[i]; - - if(!player IsPlayerModelOK()) - continue; - if(player == self) - continue; - - key = player getEntityNumber()+""; - obj = self.bot.targets[key]; - daDist = distanceSquared(self.origin, player.origin); - isObjDef = isDefined(obj); - if((level.teamBased && self.team == player.team) || player.sessionstate != "playing" || !isAlive(player)) - { - if(isObjDef) - self.bot.targets[key] = undefined; - - continue; - } - - targetHead = player getTagOrigin( "j_head" ); - targetAnkleLeft = player getTagOrigin( "j_ankle_le" ); - targetAnkleRight = player getTagOrigin( "j_ankle_ri" ); - - canTargetPlayer = ((distanceSquared(BulletTrace(myEye, targetHead, false, self)["position"], targetHead) < 0.05 || - distanceSquared(BulletTrace(myEye, targetAnkleLeft, false, self)["position"], targetAnkleLeft) < 0.05 || - distanceSquared(BulletTrace(myEye, targetAnkleRight, false, self)["position"], targetAnkleRight) < 0.05) - - && (SmokeTrace(myEye, player.origin, level.smokeRadius) || - daDist < level.bots_maxKnifeDistance*4) - - && (getConeDot(player.origin, self.origin, myAngles) >= myFov || - (isObjDef && obj.trace_time))); - - if (isDefined(self.bot.target_this_frame) && self.bot.target_this_frame == player) - { - self.bot.target_this_frame = undefined; - - canTargetPlayer = true; - } - - if(canTargetPlayer) - { - if(!isObjDef) - { - obj = self createTargetObj(player, theTime); - - self.bot.targets[key] = obj; - } - - self targetObjUpdateTraced(obj, daDist, player, theTime, false); - } - else - { - if(!isObjDef) - continue; - - self targetObjUpdateNoTrace(obj); - - if(obj.no_trace_time > rememberTime) - { - self.bot.targets[key] = undefined; - continue; - } - } - } - - if (!isdefined(obj)) - continue; - - if(theTime - obj.time < initReactTime) - continue; - - timeDiff = theTime - obj.trace_time_time; - if(timeDiff < bestTime) - { - bestTargets = []; - bestTime = timeDiff; - } - - if(timeDiff == bestTime) - bestTargets[key] = obj; - } - - if(hasTarget && isDefined(bestTargets[self.bot.target.entity getEntityNumber()+""])) - continue; - - closest = 2147483647; - toBeTarget = undefined; - - bestKeys = getArrayKeys(bestTargets); - for(i = bestKeys.size - 1; i >= 0; i--) - { - theDist = bestTargets[bestKeys[i]].dist; - if(theDist > closest) - continue; - - closest = theDist; - toBeTarget = bestTargets[bestKeys[i]]; - } - - beforeTargetID = -1; - newTargetID = -1; - if(hasTarget && isDefined(self.bot.target.entity)) - beforeTargetID = self.bot.target.entity getEntityNumber(); - if(isDefined(toBeTarget) && isDefined(toBeTarget.entity)) - newTargetID = toBeTarget.entity getEntityNumber(); - - if(beforeTargetID != newTargetID) - { - self.bot.target = toBeTarget; - self notify("new_enemy"); - } + self target_loop(); } } @@ -1069,11 +1113,10 @@ watchToLook() if(self.bot.target.dist <= level.bots_maxKnifeDistance) continue; - curweap = self getCurrentWEapon(); - if(!self canFire(curweap)) + if(!self canFire(self getCurrentWEapon())) continue; - if(!self isInRange(self.bot.target.dist, curweap)) + if(!self isInRange(self.bot.target.dist, self getCurrentWEapon())) continue; if (self.bot.is_cur_sniper) @@ -1085,8 +1128,7 @@ watchToLook() if (!getDvarInt("bots_play_jumpdrop")) continue; - thetime = getTime(); - if(isDefined(self.bot.jump_time) && thetime - self.bot.jump_time <= 5000) + if(isDefined(self.bot.jump_time) && getTime() - self.bot.jump_time <= 5000) continue; if(self.bot.target.rand <= self.pers["bots"]["behavior"]["strafe"]) @@ -1094,7 +1136,7 @@ watchToLook() if(self getStance() != "stand") continue; - self.bot.jump_time = thetime; + self.bot.jump_time = getTime(); self jump(); } else @@ -1102,7 +1144,7 @@ watchToLook() if(getConeDot(self.bot.target.last_seen_pos, self.origin, self getPlayerAngles()) < 0.8 || self.bot.target.dist <= level.bots_noADSDistance) continue; - self.bot.jump_time = thetime; + self.bot.jump_time = getTime(); self prone(); self notify("kill_goal"); wait 2.5; @@ -1111,7 +1153,6 @@ watchToLook() } } - /* Assigns the bot's after target (bot will keep firing at a target after no sight or death) */ @@ -1140,6 +1181,239 @@ clear_bot_after_target() self notify("kill_after_target"); } +/* + This is the bot's main aimming thread. The bot will aim at its targets or a node its going towards. Bots will aim, fire, ads, grenade. +*/ +aim_loop() +{ + aimspeed = self.pers["bots"]["skill"]["aim_time"]; + + if(self IsStunned() || self isArtShocked()) + aimspeed = 1; + + eyePos = self getEyePos(); + curweap = self getCurrentWeapon(); + angles = self GetPlayerAngles(); + adsAmount = self PlayerADS(); + adsAimSpeedFact = self.pers["bots"]["skill"]["ads_aimspeed_multi"]; + + // reduce aimspeed if ads'ing + if (adsAmount > 0) + { + aimspeed *= 1 + adsAimSpeedFact * adsAmount; + } + + if(isDefined(self.bot.target) && isDefined(self.bot.target.entity)) + { + no_trace_time = self.bot.target.no_trace_time; + no_trace_look_time = self.pers["bots"]["skill"]["no_trace_look_time"]; + + if (no_trace_time <= no_trace_look_time) + { + trace_time = self.bot.target.trace_time; + last_pos = self.bot.target.last_seen_pos; + target = self.bot.target.entity; + conedot = 0; + isplay = self.bot.target.isplay; + + offset = self.bot.target.offset; + if (!isDefined(offset)) + offset = (0, 0, 0); + + aimoffset = self.bot.target.aim_offset; + if (!isDefined(aimoffset)) + aimoffset = (0, 0, 0); + + dist = self.bot.target.dist; + rand = self.bot.target.rand; + no_trace_ads_time = self.pers["bots"]["skill"]["no_trace_ads_time"]; + reaction_time = self.pers["bots"]["skill"]["reaction_time"]; + nadeAimOffset = 0; + + bone = self.bot.target.bone; + if (!isDefined(bone)) + bone = "j_spineupper"; + + if(self.bot.isfraggingafter || self.bot.issmokingafter) + nadeAimOffset = dist/3000; + else if(curweap != "none" && weaponClass(curweap) == "grenade") + nadeAimOffset = dist/16000; + + if(no_trace_time && (!isDefined(self.bot.after_target) || self.bot.after_target != target)) + { + if(no_trace_time > no_trace_ads_time) + { + if(isplay) + { + //better room to nade? cook time function with dist? + if(!self.bot.isfraggingafter && !self.bot.issmokingafter) + { + nade = self getValidGrenade(); + if(isDefined(nade) && rand <= self.pers["bots"]["behavior"]["nade"] && bulletTracePassed(eyePos, eyePos + (0, 0, 75), false, self) && bulletTracePassed(last_pos, last_pos + (0, 0, 100), false, target) && dist > level.bots_minGrenadeDistance && dist < level.bots_maxGrenadeDistance && getDvarInt("bots_play_nade")) + { + if(nade == "frag_grenade_mp") + self thread frag(2.5); + else + self thread smoke(0.5); + + self notify("kill_goal"); + } + } + } + } + else + { + if (self canAds(dist, curweap)) + { + if (!self.bot.is_cur_sniper || !self.pers["bots"]["behavior"]["quickscope"]) + self thread pressAds(); + } + } + + self botLookAt(last_pos + (0, 0, self getEyeHeight() + nadeAimOffset), aimspeed); + return; + } + + if (trace_time) + { + if(isplay) + { + if (!target IsPlayerModelOK()) + return; + + aimpos = target getTagOrigin( bone ); + + if (!isDefined(aimpos)) + return; + + aimpos += offset; + aimpos += aimoffset; + aimpos += (0, 0, nadeAimOffset); + + conedot = getConeDot(aimpos, eyePos, angles); + + if(!nadeAimOffset && conedot > 0.999 && lengthsquared(aimoffset) < 0.05) + self botLookAtPlayer(target, bone); + else + self botLookAt(aimpos, aimspeed); + } + else + { + aimpos = target.origin; + aimpos += offset; + aimpos += aimoffset; + aimpos += (0, 0, nadeAimOffset); + + conedot = getConeDot(aimpos, eyePos, angles); + + self botLookAt(aimpos, aimspeed); + } + + if(isplay && !self.bot.isknifingafter && conedot > 0.9 && dist < level.bots_maxKnifeDistance && trace_time > reaction_time && getDvarInt("bots_play_knife")) + { + self clear_bot_after_target(); + self thread knife(); + return; + } + + if(!self canFire(curweap) || !self isInRange(dist, curweap)) + return; + + canADS = (self canAds(dist, curweap) && conedot > 0.75); + if (canADS) + { + stopAdsOverride = false; + if (self.bot.is_cur_sniper) + { + if (self.pers["bots"]["behavior"]["quickscope"] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000) + stopAdsOverride = true; + else + self notify("kill_goal"); + } + + if (!stopAdsOverride) + self thread pressAds(); + } + + if (trace_time > reaction_time) + { + if((!canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone") && (conedot > 0.99 || dist < level.bots_maxKnifeDistance) && getDvarInt("bots_play_fire")) + self botFire(); + + if (isplay) + self thread start_bot_after_target(target); + } + + return; + } + } + } + + if (isDefined(self.bot.after_target)) + { + nadeAimOffset = 0; + last_pos = self.bot.after_target_pos; + dist = DistanceSquared(self.origin, last_pos); + + if(self.bot.isfraggingafter || self.bot.issmokingafter) + nadeAimOffset = dist/3000; + else if(curweap != "none" && weaponClass(curweap) == "grenade") + nadeAimOffset = dist/16000; + + aimpos = last_pos + (0, 0, self getEyeHeight() + nadeAimOffset); + conedot = getConeDot(aimpos, eyePos, angles); + + self botLookAt(aimpos, aimspeed); + + if(!self canFire(curweap) || !self isInRange(dist, curweap)) + return; + + canADS = (self canAds(dist, curweap) && conedot > 0.75); + if (canADS) + { + stopAdsOverride = false; + if (self.bot.is_cur_sniper) + { + if (self.pers["bots"]["behavior"]["quickscope"] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000) + stopAdsOverride = true; + else + self notify("kill_goal"); + } + + if (!stopAdsOverride) + self thread pressAds(); + } + + if((!canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone") && (conedot > 0.95 || dist < level.bots_maxKnifeDistance) && getDvarInt("bots_play_fire")) + self botFire(); + + return; + } + + if (self.bot.next_wp != -1 && isDefined(level.waypoints[self.bot.next_wp].angles) && false) + { + forwardPos = anglesToForward(level.waypoints[self.bot.next_wp].angles) * 1024; + + self botLookAt(eyePos + forwardPos, aimspeed); + } + else if (isDefined(self.bot.script_aimpos)) + { + self botLookAt(self.bot.script_aimpos, aimspeed); + } + else + { + lookat = undefined; + + if(self.bot.second_next_wp != -1 && !self.bot.issprinting && !self.bot.climbing) + lookat = level.waypoints[self.bot.second_next_wp].origin; + else if(isDefined(self.bot.towards_goal)) + lookat = self.bot.towards_goal; + + if(isDefined(lookat)) + self botLookAt(lookat + (0, 0, self getEyeHeight()), aimspeed); + } +} + /* This is the bot's main aimming thread. The bot will aim at its targets or a node its going towards. Bots will aim, fire, ads, grenade. */ @@ -1155,232 +1429,7 @@ aim() if(level.inPrematchPeriod || level.gameEnded || self.bot.isfrozen || self maps\mp\_flashgrenades::isFlashbanged()) continue; - aimspeed = self.pers["bots"]["skill"]["aim_time"]; - - if(self IsStunned() || self isArtShocked()) - aimspeed = 1; - - eyePos = self getEyePos(); - curweap = self getCurrentWeapon(); - angles = self GetPlayerAngles(); - adsAmount = self PlayerADS(); - adsAimSpeedFact = self.pers["bots"]["skill"]["ads_aimspeed_multi"]; - - // reduce aimspeed if ads'ing - if (adsAmount > 0) - { - aimspeed *= 1 + adsAimSpeedFact * adsAmount; - } - - if(isDefined(self.bot.target) && isDefined(self.bot.target.entity)) - { - no_trace_time = self.bot.target.no_trace_time; - no_trace_look_time = self.pers["bots"]["skill"]["no_trace_look_time"]; - - if (no_trace_time <= no_trace_look_time) - { - trace_time = self.bot.target.trace_time; - last_pos = self.bot.target.last_seen_pos; - target = self.bot.target.entity; - conedot = 0; - isplay = self.bot.target.isplay; - - offset = self.bot.target.offset; - if (!isDefined(offset)) - offset = (0, 0, 0); - - aimoffset = self.bot.target.aim_offset; - if (!isDefined(aimoffset)) - aimoffset = (0, 0, 0); - - dist = self.bot.target.dist; - rand = self.bot.target.rand; - no_trace_ads_time = self.pers["bots"]["skill"]["no_trace_ads_time"]; - reaction_time = self.pers["bots"]["skill"]["reaction_time"]; - nadeAimOffset = 0; - - bone = self.bot.target.bone; - if (!isDefined(bone)) - bone = "j_spineupper"; - - if(self.bot.isfraggingafter || self.bot.issmokingafter) - nadeAimOffset = dist/3000; - else if(curweap != "none" && weaponClass(curweap) == "grenade") - nadeAimOffset = dist/16000; - - if(no_trace_time && (!isDefined(self.bot.after_target) || self.bot.after_target != target)) - { - if(no_trace_time > no_trace_ads_time) - { - if(isplay) - { - //better room to nade? cook time function with dist? - if(!self.bot.isfraggingafter && !self.bot.issmokingafter) - { - nade = self getValidGrenade(); - if(isDefined(nade) && rand <= self.pers["bots"]["behavior"]["nade"] && bulletTracePassed(eyePos, eyePos + (0, 0, 75), false, self) && bulletTracePassed(last_pos, last_pos + (0, 0, 100), false, target) && dist > level.bots_minGrenadeDistance && dist < level.bots_maxGrenadeDistance && getDvarInt("bots_play_nade")) - { - if(nade == "frag_grenade_mp") - self thread frag(2.5); - else - self thread smoke(0.5); - - self notify("kill_goal"); - } - } - } - } - else - { - if (self canAds(dist, curweap)) - { - if (!self.bot.is_cur_sniper || !self.pers["bots"]["behavior"]["quickscope"]) - self thread pressAds(); - } - } - - self botLookAt(last_pos + (0, 0, self getEyeHeight() + nadeAimOffset), aimspeed); - continue; - } - - if (trace_time) - { - if(isplay) - { - if (!target IsPlayerModelOK()) - continue; - - aimpos = target getTagOrigin( bone ); - - if (!isDefined(aimpos)) - continue; - - aimpos += offset; - aimpos += aimoffset; - aimpos += (0, 0, nadeAimOffset); - - conedot = getConeDot(aimpos, eyePos, angles); - - if(!nadeAimOffset && conedot > 0.999 && lengthsquared(aimoffset) < 0.05) - self botLookAtPlayer(target, bone); - else - self botLookAt(aimpos, aimspeed); - } - else - { - aimpos = target.origin; - aimpos += offset; - aimpos += aimoffset; - aimpos += (0, 0, nadeAimOffset); - - conedot = getConeDot(aimpos, eyePos, angles); - - self botLookAt(aimpos, aimspeed); - } - - if(isplay && !self.bot.isknifingafter && conedot > 0.9 && dist < level.bots_maxKnifeDistance && trace_time > reaction_time && getDvarInt("bots_play_knife")) - { - self clear_bot_after_target(); - self thread knife(); - continue; - } - - if(!self canFire(curweap) || !self isInRange(dist, curweap)) - continue; - - canADS = (self canAds(dist, curweap) && conedot > 0.75); - if (canADS) - { - stopAdsOverride = false; - if (self.bot.is_cur_sniper) - { - if (self.pers["bots"]["behavior"]["quickscope"] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000) - stopAdsOverride = true; - else - self notify("kill_goal"); - } - - if (!stopAdsOverride) - self thread pressAds(); - } - - if (trace_time > reaction_time) - { - if((!canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone") && (conedot > 0.99 || dist < level.bots_maxKnifeDistance) && getDvarInt("bots_play_fire")) - self botFire(); - - if (isplay) - self thread start_bot_after_target(target); - } - - continue; - } - } - } - - if (isDefined(self.bot.after_target)) - { - nadeAimOffset = 0; - last_pos = self.bot.after_target_pos; - dist = DistanceSquared(self.origin, last_pos); - - if(self.bot.isfraggingafter || self.bot.issmokingafter) - nadeAimOffset = dist/3000; - else if(curweap != "none" && weaponClass(curweap) == "grenade") - nadeAimOffset = dist/16000; - - aimpos = last_pos + (0, 0, self getEyeHeight() + nadeAimOffset); - conedot = getConeDot(aimpos, eyePos, angles); - - self botLookAt(aimpos, aimspeed); - - if(!self canFire(curweap) || !self isInRange(dist, curweap)) - continue; - - canADS = (self canAds(dist, curweap) && conedot > 0.75); - if (canADS) - { - stopAdsOverride = false; - if (self.bot.is_cur_sniper) - { - if (self.pers["bots"]["behavior"]["quickscope"] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000) - stopAdsOverride = true; - else - self notify("kill_goal"); - } - - if (!stopAdsOverride) - self thread pressAds(); - } - - if((!canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone") && (conedot > 0.95 || dist < level.bots_maxKnifeDistance) && getDvarInt("bots_play_fire")) - self botFire(); - - continue; - } - - if (self.bot.next_wp != -1 && isDefined(level.waypoints[self.bot.next_wp].angles) && false) - { - forwardPos = anglesToForward(level.waypoints[self.bot.next_wp].angles) * 1024; - - self botLookAt(eyePos + forwardPos, aimspeed); - } - else if (isDefined(self.bot.script_aimpos)) - { - self botLookAt(self.bot.script_aimpos, aimspeed); - } - else - { - lookat = undefined; - - if(self.bot.second_next_wp != -1 && !self.bot.issprinting && !self.bot.climbing) - lookat = level.waypoints[self.bot.second_next_wp].origin; - else if(isDefined(self.bot.towards_goal)) - lookat = self.bot.towards_goal; - - if(isDefined(lookat)) - self botLookAt(lookat + (0, 0, self getEyeHeight()), aimspeed); - } + self aim_loop(); } } @@ -1483,6 +1532,95 @@ killWalkCauseNoWaypoints() self notify("kill_goal"); } +/* + This is the main walking logic for the bot. +*/ +walk_loop() +{ + hasTarget = isDefined(self.bot.target) && isDefined(self.bot.target.entity); + if(hasTarget) + { + curweap = self getCurrentWeapon(); + + if(self.bot.target.entity.classname == "script_vehicle" || self.bot.isfraggingafter || self.bot.issmokingafter) + { + return; + } + + if(self.bot.target.isplay && self.bot.target.trace_time && self canFire(curweap) && self isInRange(self.bot.target.dist, curweap)) + { + if (self InLastStand() || self GetStance() == "prone" || (self.bot.is_cur_sniper && self PlayerADS() > 0)) + return; + + if(self.bot.target.rand <= self.pers["bots"]["behavior"]["strafe"]) + self strafe(self.bot.target.entity); + return; + } + } + + dist = 16; + if(level.waypointCount) + goal = level.waypoints[randomInt(level.waypointCount)].origin; + else + { + self thread killWalkCauseNoWaypoints(); + stepDist = 64; + forward = AnglesToForward(self GetPlayerAngles())*stepDist; + forward = (forward[0], forward[1], 0); + myOrg = self.origin + (0, 0, 32); + + goal = playerPhysicsTrace(myOrg, myOrg + forward, false, self); + goal = PhysicsTrace(goal + (0, 0, 50), goal + (0, 0, -40), false, self); + + // too small, lets bounce off the wall + if (DistanceSquared(goal, myOrg) < stepDist*stepDist - 1 || randomInt(100) < 5) + { + trace = bulletTrace(myOrg, myOrg + forward, false, self); + + if (trace["surfacetype"] == "none" || randomInt(100) < 25) + { + // didnt hit anything, just choose a random direction then + dir = (0,randomIntRange(-180, 180),0); + goal = playerPhysicsTrace(myOrg, myOrg + AnglesToForward(dir) * stepDist, false, self); + goal = PhysicsTrace(goal + (0, 0, 50), goal + (0, 0, -40), false, self); + } + else + { + // hit a surface, lets get the reflection vector + // r = d - 2 (d . n) n + d = VectorNormalize(trace["position"] - myOrg); + n = trace["normal"]; + + r = d - 2 * (VectorDot(d, n)) * n; + + goal = playerPhysicsTrace(myOrg, myOrg + (r[0], r[1], 0) * stepDist, false, self); + goal = PhysicsTrace(goal + (0, 0, 50), goal + (0, 0, -40), false, self); + } + } + } + + isScriptGoal = false; + if(isDefined(self.bot.script_goal) && !hasTarget) + { + goal = self.bot.script_goal; + dist = self.bot.script_goal_dist; + + isScriptGoal = true; + } + else + { + if(hasTarget) + goal = self.bot.target.last_seen_pos; + + self notify("new_goal_internal"); + } + + self doWalk(goal, dist, isScriptGoal); + self.bot.towards_goal = undefined; + self.bot.next_wp = -1; + self.bot.second_next_wp = -1; +} + /* This is the main walking logic for the bot. */ @@ -1511,88 +1649,7 @@ walk() continue; } - hasTarget = isDefined(self.bot.target) && isDefined(self.bot.target.entity); - if(hasTarget) - { - curweap = self getCurrentWeapon(); - - if(self.bot.target.entity.classname == "script_vehicle" || self.bot.isfraggingafter || self.bot.issmokingafter) - { - continue; - } - - if(self.bot.target.isplay && self.bot.target.trace_time && self canFire(curweap) && self isInRange(self.bot.target.dist, curweap)) - { - if (self InLastStand() || self GetStance() == "prone" || (self.bot.is_cur_sniper && self PlayerADS() > 0)) - continue; - - if(self.bot.target.rand <= self.pers["bots"]["behavior"]["strafe"]) - self strafe(self.bot.target.entity); - continue; - } - } - - dist = 16; - if(level.waypointCount) - goal = level.waypoints[randomInt(level.waypointCount)].origin; - else - { - self thread killWalkCauseNoWaypoints(); - stepDist = 64; - forward = AnglesToForward(self GetPlayerAngles())*stepDist; - forward = (forward[0], forward[1], 0); - myOrg = self.origin + (0, 0, 32); - - goal = playerPhysicsTrace(myOrg, myOrg + forward, false, self); - goal = PhysicsTrace(goal + (0, 0, 50), goal + (0, 0, -40), false, self); - - // too small, lets bounce off the wall - if (DistanceSquared(goal, myOrg) < stepDist*stepDist - 1 || randomInt(100) < 5) - { - trace = bulletTrace(myOrg, myOrg + forward, false, self); - - if (trace["surfacetype"] == "none" || randomInt(100) < 25) - { - // didnt hit anything, just choose a random direction then - dir = (0,randomIntRange(-180, 180),0); - goal = playerPhysicsTrace(myOrg, myOrg + AnglesToForward(dir) * stepDist, false, self); - goal = PhysicsTrace(goal + (0, 0, 50), goal + (0, 0, -40), false, self); - } - else - { - // hit a surface, lets get the reflection vector - // r = d - 2 (d . n) n - d = VectorNormalize(trace["position"] - myOrg); - n = trace["normal"]; - - r = d - 2 * (VectorDot(d, n)) * n; - - goal = playerPhysicsTrace(myOrg, myOrg + (r[0], r[1], 0) * stepDist, false, self); - goal = PhysicsTrace(goal + (0, 0, 50), goal + (0, 0, -40), false, self); - } - } - } - - isScriptGoal = false; - if(isDefined(self.bot.script_goal) && !hasTarget) - { - goal = self.bot.script_goal; - dist = self.bot.script_goal_dist; - - isScriptGoal = true; - } - else - { - if(hasTarget) - goal = self.bot.target.last_seen_pos; - - self notify("new_goal_internal"); - } - - self doWalk(goal, dist, isScriptGoal); - self.bot.towards_goal = undefined; - self.bot.next_wp = -1; - self.bot.second_next_wp = -1; + self walk_loop(); } } @@ -1724,12 +1781,12 @@ doWalk(goal, dist, isScriptGoal) self endon("kill_goal"); self endon("goal_internal");//so that the watchOnGoal notify can happen same frame, not a frame later - distsq = dist*dist; + dist *= dist; if (isScriptGoal) self thread doWalkScriptNotify(); self thread killWalkOnEvents(); - self thread watchOnGoal(goal, distsq); + self thread watchOnGoal(goal, dist); current = self initAStar(goal); // skip waypoints we already completed to prevent rubber banding @@ -1739,9 +1796,7 @@ doWalk(goal, dist, isScriptGoal) if (current >= 0) { // check if a waypoint is closer than the goal - wpOrg = level.waypoints[self.bot.astar[current]].origin; - ppt = PlayerPhysicsTrace(self.origin + (0,0,32), wpOrg, false, self); - if (DistanceSquared(self.origin, wpOrg) < DistanceSquared(self.origin, goal) || DistanceSquared(wpOrg, ppt) > 1.0) + if (DistanceSquared(self.origin, level.waypoints[self.bot.astar[current]].origin) < DistanceSquared(self.origin, goal) || DistanceSquared(level.waypoints[self.bot.astar[current]].origin, PlayerPhysicsTrace(self.origin + (0,0,32), level.waypoints[self.bot.astar[current]].origin, false, self)) > 1.0) { while(current >= 0) { @@ -1765,7 +1820,7 @@ doWalk(goal, dist, isScriptGoal) self.bot.second_next_wp = -1; self notify("finished_static_waypoints"); - if(DistanceSquared(self.origin, goal) > distsq) + if(DistanceSquared(self.origin, goal) > dist) { self.bot.last_next_wp = -1; self.bot.last_second_next_wp = -1; @@ -1775,7 +1830,7 @@ doWalk(goal, dist, isScriptGoal) self notify("finished_goal"); wait 1; - if(DistanceSquared(self.origin, goal) > distsq) + if(DistanceSquared(self.origin, goal) > dist) self notify("bad_path_internal"); } diff --git a/main_shared/maps/mp/bots/_bot_script.gsc b/main_shared/maps/mp/bots/_bot_script.gsc index 502c6e0..20705a7 100644 --- a/main_shared/maps/mp/bots/_bot_script.gsc +++ b/main_shared/maps/mp/bots/_bot_script.gsc @@ -180,6 +180,47 @@ bot_cry_for_help( attacker ) } } +/* + Chooses a random class +*/ +chooseRandomClass() +{ + class = ""; + rank = self maps\mp\gametypes\_rank::getRankForXp( self getStat( int(tableLookup( "mp/playerStatsTable.csv", 1, "rankxp", 0 )) ) ) + 1; + if(rank < 4 || randomInt(100) < 2) + { + while(class == "") + { + switch(randomInt(5)) + { + case 0: + class = "assault_mp"; + break; + case 1: + class = "specops_mp"; + break; + case 2: + class = "heavygunner_mp"; + break; + case 3: + if(rank >= 2) + class = "demolitions_mp"; + break; + case 4: + if(rank >= 3) + class = "sniper_mp"; + break; + } + } + } + else + { + class = "custom"+(randomInt(5)+1); + } + + return class; +} + /* Selects a class for the bot. */ @@ -193,40 +234,9 @@ classWatch() wait .05; wait 0.5; - class = ""; - rank = self maps\mp\gametypes\_rank::getRankForXp( self getStat( int(tableLookup( "mp/playerStatsTable.csv", 1, "rankxp", 0 )) ) ) + 1; - if(rank < 4 || randomInt(100) < 2) - { - while(class == "") - { - switch(randomInt(5)) - { - case 0: - class = "assault_mp"; - break; - case 1: - class = "specops_mp"; - break; - case 2: - class = "heavygunner_mp"; - break; - case 3: - if(rank >= 2) - class = "demolitions_mp"; - break; - case 4: - if(rank >= 3) - class = "sniper_mp"; - break; - } - } - } - else - { - class = "custom"+(randomInt(5)+1); - } - self notify("menuresponse", game["menu_changeclass"], class); + + self notify("menuresponse", game["menu_changeclass"], self chooseRandomClass()); self.bot_change_class = true; while(isdefined(self.pers["team"]) && isdefined(self.pers["class"]) && isDefined(self.bot_change_class)) @@ -263,9 +273,7 @@ difficulty() for(;;) { - rankVar = GetDvarInt("bots_skill"); - - if(rankVar != 9) + if(GetDvarInt("bots_skill") != 9) { switch(self.pers["bots"]["skill"]["base"]) { @@ -1387,6 +1395,30 @@ stop_go_target_on_death(tar) self ClearScriptGoal(); } +/* + Bot logic for bot determining to camp. +*/ +bot_think_camp_loop() +{ + campSpot = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("camp"), 1024))); + + if (!isDefined(campSpot)) + return; + + self SetScriptGoal(campSpot.origin, 16); + + ret = self waittill_any_return("new_goal", "goal", "bad_path"); + + if (ret != "new_goal") + self ClearScriptGoal(); + + if (ret != "goal") + return; + + self thread killCampAfterTime(randomIntRange(10,20)); + self CampAtSpot(campSpot.origin, campSpot.origin + AnglesToForward(campSpot.angles) * 2048); +} + /* Bot logic for bot determining to camp. */ @@ -1405,23 +1437,7 @@ bot_think_camp() if(randomInt(100) > self.pers["bots"]["behavior"]["camp"]) continue; - campSpot = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("camp"), 1024))); - - if (!isDefined(campSpot)) - continue; - - self SetScriptGoal(campSpot.origin, 16); - - ret = self waittill_any_return("new_goal", "goal", "bad_path"); - - if (ret != "new_goal") - self ClearScriptGoal(); - - if (ret != "goal") - continue; - - self thread killCampAfterTime(randomIntRange(10,20)); - self CampAtSpot(campSpot.origin, campSpot.origin + AnglesToForward(campSpot.angles) * 2048); + self bot_think_camp_loop(); } } @@ -1483,6 +1499,43 @@ CampAtSpot(origin, anglePos) self notify("kill_camp_bot"); } +/* + Bot logic for bot determining to follow another player. +*/ +bot_think_follow_loop() +{ + follows = []; + distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; + for (i = level.players.size - 1; i >= 0; i--) + { + player = level.players[i]; + + if(!player IsPlayerModelOK()) + continue; + + if (player == self) + continue; + + if(!isAlive(player)) + continue; + + if (player.team != self.team) + continue; + + if (DistanceSquared(player.origin, self.origin) > distSq) + continue; + + follows[follows.size] = player; + } + toFollow = random(follows); + + if (!isDefined(toFollow)) + return; + + self thread killFollowAfterTime(randomIntRange(10,20)); + self followPlayer(toFollow); +} + /* Bot logic for bot determining to follow another player. */ @@ -1504,36 +1557,7 @@ bot_think_follow() if (!level.teamBased) continue; - follows = []; - distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; - for (i = level.players.size - 1; i >= 0; i--) - { - player = level.players[i]; - - if(!player IsPlayerModelOK()) - continue; - - if (player == self) - continue; - - if(!isAlive(player)) - continue; - - if (player.team != self.team) - continue; - - if (DistanceSquared(player.origin, self.origin) > distSq) - continue; - - follows[follows.size] = player; - } - toFollow = random(follows); - - if (!isDefined(toFollow)) - continue; - - self thread killFollowAfterTime(randomIntRange(10,20)); - self followPlayer(toFollow); + self bot_think_follow_loop(); } } @@ -1610,6 +1634,108 @@ followPlayer(who) self notify("kill_follow_bot"); } +/* + Bots thinking of using a noobtube +*/ +bot_use_tube_think_loop(data) +{ + if (data.doFastContinue) + data.doFastContinue = false; + else + { + wait randomintRange(3, 7); + + chance = self.pers["bots"]["behavior"]["nade"] / 2; + if (chance > 20) + chance = 20; + + if (randomInt(100) > chance) + return; + } + + tube = self getValidTube(); + if (!isDefined(tube)) + return; + + if (self HasThreat() || self HasScriptAimPos()) + return; + + if(self BotIsFrozen()) + return; + + if (self IsBotFragging() || self IsBotSmoking()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self InLastStand()) + return; + + loc = undefined; + + if (!self nearAnyOfWaypoints(128, getWaypointsOfType("tube"))) + { + tubeWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("tube"), 1024))); + + myEye = self GetEye(); + if (!isDefined(tubeWp) || self HasScriptGoal() || self.bot_lock_goal) + { + traceForward = BulletTrace(myEye, myEye + AnglesToForward(self GetPlayerAngles()) * 900 * 5, false, self); + + loc = traceForward["position"]; + dist = DistanceSquared(self.origin, loc); + if (dist < level.bots_minGrenadeDistance || dist > level.bots_maxGrenadeDistance * 5) + return; + + if (!bulletTracePassed(self.origin + (0, 0, 5), self.origin + (0, 0, 2048), false, self)) + return; + + if (!bulletTracePassed(loc + (0, 0, 5), loc + (0, 0, 2048), false, self)) + return; + + loc += (0, 0, dist/16000); + } + else + { + self SetScriptGoal(tubeWp.origin, 16); + + ret = self waittill_any_return("new_goal", "goal", "bad_path"); + + if (ret != "new_goal") + self ClearScriptGoal(); + + if (ret != "goal") + return; + + data.doFastContinue = true; + return; + } + } + else + { + tubeWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("tube"))); + loc = tubeWp.origin + AnglesToForward(tubeWp.angles) * 2048; + } + + if (!isDefined(loc)) + return; + + self SetScriptAimPos(loc); + self BotStopMoving(true); + wait 1; + + if (self changeToWeapon(tube)) + { + self thread fire_current_weapon(); + self waittill_any_timeout(5, "missile_fire", "weapon_change"); + self notify("stop_firing_weapon"); + } + + self ClearScriptAimPos(); + self BotStopMoving(false); +} + /* Bots thinking of using a noobtube */ @@ -1619,108 +1745,120 @@ bot_use_tube_think() self endon("death"); level endon("game_ended"); - doFastContinue = false; + data = spawnStruct(); + data.doFastContinue = false; for (;;) { - if (doFastContinue) - doFastContinue = false; - else - { - wait randomintRange(3, 7); - - chance = self.pers["bots"]["behavior"]["nade"] / 2; - if (chance > 20) - chance = 20; - - if (randomInt(100) > chance) - continue; - } - - tube = self getValidTube(); - if (!isDefined(tube)) - continue; - - if (self HasThreat() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if (self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self InLastStand()) - continue; - - loc = undefined; - - if (!self nearAnyOfWaypoints(128, getWaypointsOfType("tube"))) - { - tubeWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("tube"), 1024))); - - myEye = self GetEye(); - if (!isDefined(tubeWp) || self HasScriptGoal() || self.bot_lock_goal) - { - traceForward = BulletTrace(myEye, myEye + AnglesToForward(self GetPlayerAngles()) * 900 * 5, false, self); - - loc = traceForward["position"]; - dist = DistanceSquared(self.origin, loc); - if (dist < level.bots_minGrenadeDistance || dist > level.bots_maxGrenadeDistance * 5) - continue; - - if (!bulletTracePassed(self.origin + (0, 0, 5), self.origin + (0, 0, 2048), false, self)) - continue; - - if (!bulletTracePassed(loc + (0, 0, 5), loc + (0, 0, 2048), false, self)) - continue; - - loc += (0, 0, dist/16000); - } - else - { - self SetScriptGoal(tubeWp.origin, 16); - - ret = self waittill_any_return("new_goal", "goal", "bad_path"); - - if (ret != "new_goal") - self ClearScriptGoal(); - - if (ret != "goal") - continue; - - doFastContinue = true; - continue; - } - } - else - { - tubeWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("tube"))); - loc = tubeWp.origin + AnglesToForward(tubeWp.angles) * 2048; - } - - if (!isDefined(loc)) - continue; - - self SetScriptAimPos(loc); - self BotStopMoving(true); - wait 1; - - if (self changeToWeapon(tube)) - { - self thread fire_current_weapon(); - self waittill_any_timeout(5, "missile_fire", "weapon_change"); - self notify("stop_firing_weapon"); - } - - self ClearScriptAimPos(); - self BotStopMoving(false); + self bot_use_tube_think_loop(data); } } +/* + Bots thinking of using claymores +*/ +bot_use_equipment_think_loop(data) +{ + if (data.doFastContinue) + data.doFastContinue = false; + else + { + wait randomintRange(2, 4); + + chance = self.pers["bots"]["behavior"]["nade"] / 2; + if (chance > 20) + chance = 20; + + if (randomInt(100) > chance) + return; + } + + nade = undefined; + if (self GetAmmoCount("claymore_mp")) + nade = "claymore_mp"; + if (self GetAmmoCount("c4_mp")) + nade = "c4_mp"; + + if (!isDefined(nade)) + return; + + if (self HasThreat() || self HasScriptAimPos()) + return; + + if(self BotIsFrozen()) + return; + + if(self IsBotFragging() || self IsBotSmoking()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self inLastStand()) + return; + + curWeap = self GetCurrentWeapon(); + if (curWeap == "none" || !isWeaponDroppable(curWeap)) + curWeap = self.lastDroppableWeapon; + + loc = undefined; + + if (!self nearAnyOfWaypoints(128, getWaypointsOfType("claymore"))) + { + clayWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("claymore"), 1024))); + + if (!isDefined(clayWp) || self HasScriptGoal() || self.bot_lock_goal) + { + myEye = self GetEye(); + loc = myEye + AnglesToForward(self GetPlayerAngles()) * 256; + + if (!bulletTracePassed(myEye, loc, false, self)) + return; + } + else + { + self SetScriptGoal(clayWp.origin, 16); + + ret = self waittill_any_return("new_goal", "goal", "bad_path"); + + if (ret != "new_goal") + self ClearScriptGoal(); + + if (ret != "goal") + return; + + data.doFastContinue = true; + return; + } + } + else + { + clayWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("claymore"))); + loc = clayWp.origin + AnglesToForward(clayWp.angles) * 2048; + } + + if (!isDefined(loc)) + return; + + self SetScriptAimPos(loc); + self BotStopMoving(true); + wait 1; + + if (self changeToWeapon(nade)) + { + if (nade != "c4_mp") + self thread fire_current_weapon(); + else + self thread fire_c4(); + self waittill_any_timeout(5, "grenade_fire", "weapon_change"); + self notify("stop_firing_weapon"); + } + + self thread changeToWeapon(curWeap); + self ClearScriptAimPos(); + self BotStopMoving(false); +} + /* Bots thinking of using claymores */ @@ -1730,111 +1868,115 @@ bot_use_equipment_think() self endon("death"); level endon("game_ended"); - doFastContinue = false; + data = spawnStruct(); + data.doFastContinue = false; for (;;) { - if (doFastContinue) - doFastContinue = false; - else - { - wait randomintRange(2, 4); - - chance = self.pers["bots"]["behavior"]["nade"] / 2; - if (chance > 20) - chance = 20; - - if (randomInt(100) > chance) - continue; - } - - nade = undefined; - if (self GetAmmoCount("claymore_mp")) - nade = "claymore_mp"; - if (self GetAmmoCount("c4_mp")) - nade = "c4_mp"; - - if (!isDefined(nade)) - continue; - - if (self HasThreat() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if(self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self inLastStand()) - continue; - - curWeap = self GetCurrentWeapon(); - if (curWeap == "none" || !isWeaponDroppable(curWeap)) - curWeap = self.lastDroppableWeapon; - - loc = undefined; - - if (!self nearAnyOfWaypoints(128, getWaypointsOfType("claymore"))) - { - clayWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("claymore"), 1024))); - - if (!isDefined(clayWp) || self HasScriptGoal() || self.bot_lock_goal) - { - myEye = self GetEye(); - loc = myEye + AnglesToForward(self GetPlayerAngles()) * 256; - - if (!bulletTracePassed(myEye, loc, false, self)) - continue; - } - else - { - self SetScriptGoal(clayWp.origin, 16); - - ret = self waittill_any_return("new_goal", "goal", "bad_path"); - - if (ret != "new_goal") - self ClearScriptGoal(); - - if (ret != "goal") - continue; - - doFastContinue = true; - continue; - } - } - else - { - clayWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("claymore"))); - loc = clayWp.origin + AnglesToForward(clayWp.angles) * 2048; - } - - if (!isDefined(loc)) - continue; - - self SetScriptAimPos(loc); - self BotStopMoving(true); - wait 1; - - if (self changeToWeapon(nade)) - { - if (nade != "c4_mp") - self thread fire_current_weapon(); - else - self thread fire_c4(); - self waittill_any_timeout(5, "grenade_fire", "weapon_change"); - self notify("stop_firing_weapon"); - } - - self thread changeToWeapon(curWeap); - self ClearScriptAimPos(); - self BotStopMoving(false); + self bot_use_equipment_think_loop(data); } } +/* + Bots thinking of using grenades +*/ +bot_use_grenade_think_loop(data) +{ + if (data.doFastContinue) + data.doFastContinue = false; + else + { + wait randomintRange(4, 7); + + chance = self.pers["bots"]["behavior"]["nade"] / 2; + if (chance > 20) + chance = 20; + + if (randomInt(100) > chance) + return; + } + + nade = self getValidGrenade(); + if (!isDefined(nade)) + return; + + if (self HasThreat() || self HasScriptAimPos()) + return; + + if(self BotIsFrozen()) + return; + + if(self IsBotFragging() || self IsBotSmoking()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self inLastStand()) + return; + + loc = undefined; + + if (!self nearAnyOfWaypoints(128, getWaypointsOfType("grenade"))) + { + nadeWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("grenade"), 1024))); + + myEye = self GetEye(); + if (!isDefined(nadeWp) || self HasScriptGoal() || self.bot_lock_goal) + { + traceForward = BulletTrace(myEye, myEye + AnglesToForward(self GetPlayerAngles()) * 900, false, self); + + loc = traceForward["position"]; + dist = DistanceSquared(self.origin, loc); + if (dist < level.bots_minGrenadeDistance || dist > level.bots_maxGrenadeDistance) + return; + + if (!bulletTracePassed(self.origin + (0, 0, 5), self.origin + (0, 0, 2048), false, self)) + return; + + if (!bulletTracePassed(loc + (0, 0, 5), loc + (0, 0, 2048), false, self)) + return; + + loc += (0, 0, dist/3000); + } + else + { + self SetScriptGoal(nadeWp.origin, 16); + + ret = self waittill_any_return("new_goal", "goal", "bad_path"); + + if (ret != "new_goal") + self ClearScriptGoal(); + + if (ret != "goal") + return; + + data.doFastContinue = true; + return; + } + } + else + { + nadeWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("grenade"))); + loc = nadeWp.origin + AnglesToForward(nadeWp.angles) * 2048; + } + + if (!isDefined(loc)) + return; + + self SetScriptAimPos(loc); + self BotStopMoving(true); + wait 1; + + time = 0.5; + if (nade == "frag_grenade_mp") + time = 2; + self botThrowGrenade(nade, time); + + self ClearScriptAimPos(); + self BotStopMoving(false); +} + /* Bots thinking of using grenades */ @@ -1844,106 +1986,35 @@ bot_use_grenade_think() self endon("death"); level endon("game_ended"); - doFastContinue = false; + data = spawnStruct(); + data.doFastContinue = false; for (;;) { - if (doFastContinue) - doFastContinue = false; - else - { - wait randomintRange(4, 7); - - chance = self.pers["bots"]["behavior"]["nade"] / 2; - if (chance > 20) - chance = 20; - - if (randomInt(100) > chance) - continue; - } - - nade = self getValidGrenade(); - if (!isDefined(nade)) - continue; - - if (self HasThreat() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if(self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self inLastStand()) - continue; - - loc = undefined; - - if (!self nearAnyOfWaypoints(128, getWaypointsOfType("grenade"))) - { - nadeWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("grenade"), 1024))); - - myEye = self GetEye(); - if (!isDefined(nadeWp) || self HasScriptGoal() || self.bot_lock_goal) - { - traceForward = BulletTrace(myEye, myEye + AnglesToForward(self GetPlayerAngles()) * 900, false, self); - - loc = traceForward["position"]; - dist = DistanceSquared(self.origin, loc); - if (dist < level.bots_minGrenadeDistance || dist > level.bots_maxGrenadeDistance) - continue; - - if (!bulletTracePassed(self.origin + (0, 0, 5), self.origin + (0, 0, 2048), false, self)) - continue; - - if (!bulletTracePassed(loc + (0, 0, 5), loc + (0, 0, 2048), false, self)) - continue; - - loc += (0, 0, dist/3000); - } - else - { - self SetScriptGoal(nadeWp.origin, 16); - - ret = self waittill_any_return("new_goal", "goal", "bad_path"); - - if (ret != "new_goal") - self ClearScriptGoal(); - - if (ret != "goal") - continue; - - doFastContinue = true; - continue; - } - } - else - { - nadeWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("grenade"))); - loc = nadeWp.origin + AnglesToForward(nadeWp.angles) * 2048; - } - - if (!isDefined(loc)) - continue; - - self SetScriptAimPos(loc); - self BotStopMoving(true); - wait 1; - - time = 0.5; - if (nade == "frag_grenade_mp") - time = 2; - self botThrowGrenade(nade, time); - - self ClearScriptAimPos(); - self BotStopMoving(false); + self bot_use_grenade_think_loop(data); } } +/* + Goes to the target's location if it had one +*/ +follow_target_loop() +{ + threat = self GetThreat(); + + if (!isPlayer(threat)) + return; + + if(randomInt(100) > self.pers["bots"]["behavior"]["follow"]*5) + return; + + self thread stop_go_target_on_death(threat); + + self SetScriptGoal(threat.origin, 64); + if (self waittill_any_return("new_goal", "goal", "bad_path") != "new_goal") + self ClearScriptGoal(); +} + /* Goes to the target's location if it had one */ @@ -1962,22 +2033,68 @@ follow_target() if ( !self HasThreat() ) continue; - threat = self GetThreat(); - - if (!isPlayer(threat)) - continue; - - if(randomInt(100) > self.pers["bots"]["behavior"]["follow"]*5) - continue; - - self thread stop_go_target_on_death(threat); - - self SetScriptGoal(threat.origin, 64); - if (self waittill_any_return("new_goal", "goal", "bad_path") != "new_goal") - self ClearScriptGoal(); + self follow_target_loop(); } } +/* + Bot logic for detecting nearby players. +*/ +bot_listen_to_steps_loop() +{ + dist = level.bots_listenDist; + if(self hasPerk("specialty_parabolic")) + dist *= 1.4; + + dist *= dist; + + heard = undefined; + for(i = level.players.size-1 ; i >= 0; i--) + { + player = level.players[i]; + + if(!player IsPlayerModelOK()) + continue; + + if(player == self) + continue; + if(level.teamBased && self.team == player.team) + continue; + if(player.sessionstate != "playing") + continue; + if(!isAlive(player)) + continue; + if(player hasPerk("specialty_quieter")) + continue; + + if(lengthsquared( player getVelocity() ) < 20000) + continue; + + if(distanceSquared(player.origin, self.origin) > dist) + continue; + + heard = player; + break; + } + + if(!IsDefined(heard)) + return; + + if(bulletTracePassed(self getEyePos(), heard getTagOrigin( "j_spineupper" ), false, heard)) + { + self setAttacker(heard); + return; + } + + if(self HasScriptGoal() || self.bot_lock_goal) + return; + + self SetScriptGoal( heard.origin, 64 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); +} + /* Bot logic for detecting nearby players. */ @@ -1993,57 +2110,7 @@ bot_listen_to_steps() if(self.pers["bots"]["skill"]["base"] < 3) continue; - dist = level.bots_listenDist; - if(self hasPerk("specialty_parabolic")) - dist *= 1.4; - - dist *= dist; - - heard = undefined; - for(i = level.players.size-1 ; i >= 0; i--) - { - player = level.players[i]; - - if(!player IsPlayerModelOK()) - continue; - - if(player == self) - continue; - if(level.teamBased && self.team == player.team) - continue; - if(player.sessionstate != "playing") - continue; - if(!isAlive(player)) - continue; - if(player hasPerk("specialty_quieter")) - continue; - - if(lengthsquared( player getVelocity() ) < 20000) - continue; - - if(distanceSquared(player.origin, self.origin) > dist) - continue; - - heard = player; - break; - } - - if(!IsDefined(heard)) - continue; - - if(bulletTracePassed(self getEyePos(), heard getTagOrigin( "j_spineupper" ), false, heard)) - { - self setAttacker(heard); - continue; - } - - if(self HasScriptGoal() || self.bot_lock_goal) - continue; - - self SetScriptGoal( heard.origin, 64 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); + self bot_listen_to_steps_loop(); } } @@ -2088,6 +2155,67 @@ bot_revenge_think() } } +/* + Reload cancels +*/ +doReloadCancel_loop() +{ + ret = self waittill_any_return("reload", "weapon_change"); + + if(self BotIsFrozen()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self InLastStand()) + return; + + curWeap = self GetCurrentWeapon(); + + if (!maps\mp\gametypes\_weapons::isSideArm( curWeap ) && !maps\mp\gametypes\_weapons::isPrimaryWeapon( curWeap )) + return; + + if (ret == "reload") + { + // check single reloads + if (self GetWeaponAmmoClip(curWeap) < WeaponClipSize(curWeap)) + return; + } + + // check difficulty + if (self.pers["bots"]["skill"]["base"] <= 3) + return; + + // check if got another weapon + weaponslist = self GetWeaponsListPrimaries(); + weap = ""; + while(weaponslist.size) + { + weapon = weaponslist[randomInt(weaponslist.size)]; + weaponslist = array_remove(weaponslist, weapon); + + if (!maps\mp\gametypes\_weapons::isSideArm( weapon ) && !maps\mp\gametypes\_weapons::isPrimaryWeapon( weapon )) + continue; + + if(curWeap == weapon || weapon == "none" || weapon == "") + continue; + + weap = weapon; + break; + } + + if(weap == "") + return; + + // do the cancel + wait 0.1; + self BotChangeToWeapon(weap); + wait 0.25; + self BotChangeToWeapon(curWeap); + wait 2; +} + /* Reload cancels */ @@ -2098,61 +2226,84 @@ doReloadCancel() for (;;) { - ret = self waittill_any_return("reload", "weapon_change"); + self doReloadCancel_loop(); + } +} - if(self BotIsFrozen()) +/* + Bot logic for switching weapons. +*/ +bot_weapon_think_loop(data) +{ + self waittill_any_timeout(randomIntRange(2, 4), "bot_force_check_switch"); + + if(self BotIsFrozen()) + return; + + if(self isDefusing() || self isPlanting() || self InLastStand()) + return; + + hasTarget = self hasThreat(); + curWeap = self GetCurrentWeapon(); + + if(hasTarget) + { + threat = self getThreat(); + + if(threat.classname == "script_vehicle" && self getAmmoCount("rpg_mp")) + { + if (curWeap != "rpg_mp") + self thread ChangeToWeapon("rpg_mp"); + return; + } + } + + if (data.first) + { + data.first = false; + + if(randomInt(100) > self.pers["bots"]["behavior"]["initswitch"]) + return; + } + else + { + if(curWeap != "none" && self getAmmoCount(curWeap)) + { + if(randomInt(100) > self.pers["bots"]["behavior"]["switch"]) + return; + + if(hasTarget) + return; + } + } + + weaponslist = self getweaponslist(); + weap = ""; + while(weaponslist.size) + { + weapon = weaponslist[randomInt(weaponslist.size)]; + weaponslist = array_remove(weaponslist, weapon); + + if(!self getAmmoCount(weapon)) + continue; + + if (maps\mp\gametypes\_weapons::isHackWeapon( weapon )) continue; - if(self isDefusing() || self isPlanting()) + if (maps\mp\gametypes\_weapons::isGrenade( weapon )) continue; - - if (self InLastStand()) + + if(curWeap == weapon || weapon == "c4_mp" || weapon == "none" || weapon == "claymore_mp" || weapon == "") continue; - - curWeap = self GetCurrentWeapon(); - - if (!maps\mp\gametypes\_weapons::isSideArm( curWeap ) && !maps\mp\gametypes\_weapons::isPrimaryWeapon( curWeap )) - continue; - - if (ret == "reload") - { - // check single reloads - if (self GetWeaponAmmoClip(curWeap) < WeaponClipSize(curWeap)) - continue; - } - - // check difficulty - if (self.pers["bots"]["skill"]["base"] <= 3) - continue; - - // check if got another weapon - weaponslist = self GetWeaponsListPrimaries(); - weap = ""; - while(weaponslist.size) - { - weapon = weaponslist[randomInt(weaponslist.size)]; - weaponslist = array_remove(weaponslist, weapon); - - if (!maps\mp\gametypes\_weapons::isSideArm( weapon ) && !maps\mp\gametypes\_weapons::isPrimaryWeapon( weapon )) - continue; - - if(curWeap == weapon || weapon == "none" || weapon == "") - continue; - - weap = weapon; - break; - } - - if(weap == "") - continue; - - // do the cancel - wait 0.1; - self BotChangeToWeapon(weap); - wait 0.25; - self BotChangeToWeapon(curWeap); - wait 2; + + weap = weapon; + break; } + + if(weap == "") + return; + + self thread ChangeToWeapon(weap); } /* @@ -2164,82 +2315,40 @@ bot_weapon_think() self endon("disconnect"); level endon("game_ended"); - first = true; + data = spawnStruct(); + data.first = true; for(;;) { - self waittill_any_timeout(randomIntRange(2, 4), "bot_force_check_switch"); - - if(self BotIsFrozen()) - continue; - - if(self isDefusing() || self isPlanting() || self InLastStand()) - continue; - - hasTarget = self hasThreat(); - curWeap = self GetCurrentWeapon(); - - if(hasTarget) - { - threat = self getThreat(); - - if(threat.classname == "script_vehicle" && self getAmmoCount("rpg_mp")) - { - if (curWeap != "rpg_mp") - self thread ChangeToWeapon("rpg_mp"); - continue; - } - } - - if (first) - { - first = false; - - if(randomInt(100) > self.pers["bots"]["behavior"]["initswitch"]) - continue; - } - else - { - if(curWeap != "none" && self getAmmoCount(curWeap)) - { - if(randomInt(100) > self.pers["bots"]["behavior"]["switch"]) - continue; - - if(hasTarget) - continue; - } - } - - weaponslist = self getweaponslist(); - weap = ""; - while(weaponslist.size) - { - weapon = weaponslist[randomInt(weaponslist.size)]; - weaponslist = array_remove(weaponslist, weapon); - - if(!self getAmmoCount(weapon)) - continue; - - if (maps\mp\gametypes\_weapons::isHackWeapon( weapon )) - continue; - - if (maps\mp\gametypes\_weapons::isGrenade( weapon )) - continue; - - if(curWeap == weapon || weapon == "c4_mp" || weapon == "none" || weapon == "claymore_mp" || weapon == "") - continue; - - weap = weapon; - break; - } - - if(weap == "") - continue; - - self thread ChangeToWeapon(weap); + self bot_weapon_think_loop(data); } } +/* + Bots play mw2 +*/ +bot_watch_think_mw2_loop() +{ + tube = self getValidTube(); + if (!isDefined(tube)) + { + if (self GetAmmoCount("rpg_mp")) + tube = "rpg_mp"; + else + return; + } + + if (self GetCurrentWeapon() == tube) + return; + + chance = self.pers["bots"]["behavior"]["nade"]; + + if (randomInt(100) > chance) + return; + + self ChangeToWeapon(tube); +} + /* Bots play mw2 */ @@ -2265,25 +2374,107 @@ bot_watch_think_mw2() if (self HasThreat()) continue; - tube = self getValidTube(); - if (!isDefined(tube)) + self bot_watch_think_mw2_loop(); + } +} + +/* + Bot logic for killstreaks. +*/ +bot_killstreak_think_loop() +{ + curWeap = self GetCurrentWeapon(); + if (curWeap == "none" || !isWeaponDroppable(curWeap)) + curWeap = self.lastDroppableWeapon; + + targetPos = undefined; + switch(self.pers["hardPointItem"]) + { + case "radar_mp": + if(self.bot_radar && self.pers["bots"]["skill"]["base"] > 3) + return; + break; + + case "helicopter_mp": + chopper = level.chopper; + + if (isDefined(chopper) && level.teamBased && getDvarInt("doubleHeli")) + chopper = level.chopper[self.team]; + + if (isDefined(chopper)) + return; + + if (isDefined( level.mannedchopper )) + return; + + break; + + case "airstrike_mp": + if(isDefined( level.airstrikeInProgress )) + return; + + players = []; + for(i = level.players.size - 1; i >= 0; i--) + { + player = level.players[i]; + + if(!player IsPlayerModelOK()) + continue; + + if(player == self) + continue; + if(!isDefined(player.team)) + continue; + if(level.teamBased && self.team == player.team) + continue; + if(player.sessionstate != "playing") + continue; + if(!isAlive(player)) + continue; + if(player hasPerk("specialty_gpsjammer")) + continue; + if(!bulletTracePassed(player.origin, player.origin+(0,0,512), false, player) && self.pers["bots"]["skill"]["base"] > 3) + continue; + + players[players.size] = player; + } + + target = random(players); + + if(isDefined(target)) + targetPos = target.origin + (randomIntRange((8-self.pers["bots"]["skill"]["base"])*-75, (8-self.pers["bots"]["skill"]["base"])*75), randomIntRange((8-self.pers["bots"]["skill"]["base"])*-75, (8-self.pers["bots"]["skill"]["base"])*75), 0); + else if(self.pers["bots"]["skill"]["base"] <= 3) + targetPos = self.origin + (randomIntRange(-512, 512), randomIntRange(-512, 512), 0); + break; + + default: + return; + } + + isAirstrikePos = isDefined(targetPos); + if(self.pers["hardPointItem"] == "airstrike_mp" && !isAirstrikePos) + return; + + self BotStopMoving(true); + + if (self changeToWeapon(self.pers["hardPointItem"])) + { + wait 1; + + if (isAirstrikePos && !isDefined( level.airstrikeInProgress )) { - if (self GetAmmoCount("rpg_mp")) - tube = "rpg_mp"; - else - continue; + self BotFreezeControls(true); + + self notify( "confirm_location", targetPos ); + wait 1; + + self BotFreezeControls(false); } - if (self GetCurrentWeapon() == tube) - continue; - - chance = self.pers["bots"]["behavior"]["nade"]; - - if (randomInt(100) > chance) - continue; - - self ChangeToWeapon(tube); + self thread changeToWeapon(curWeap); } + + self BotStopMoving(false); } /* @@ -2311,98 +2502,62 @@ bot_killstreak_think() if(self isDefusing() || self isPlanting() || self InLastStand()) continue; - curWeap = self GetCurrentWeapon(); - if (curWeap == "none" || !isWeaponDroppable(curWeap)) - curWeap = self.lastDroppableWeapon; - - targetPos = undefined; - switch(self.pers["hardPointItem"]) - { - case "radar_mp": - if(self.bot_radar && self.pers["bots"]["skill"]["base"] > 3) - continue; - break; - - case "helicopter_mp": - chopper = level.chopper; + self bot_killstreak_think_loop(); + } +} - if (isDefined(chopper) && level.teamBased && getDvarInt("doubleHeli")) - chopper = level.chopper[self.team]; +/* + Bot logic for UAV detection here. Checks for UAV and players who are shooting. +*/ +bot_uav_think_loop() +{ + dist = self.pers["bots"]["skill"]["help_dist"]; + dist *= dist * 8; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[i]; - if (isDefined(chopper)) - continue; - - if (isDefined( level.mannedchopper )) - continue; - - break; - - case "airstrike_mp": - if(isDefined( level.airstrikeInProgress )) - continue; - - players = []; - for(i = level.players.size - 1; i >= 0; i--) - { - player = level.players[i]; - - if(!player IsPlayerModelOK()) - continue; - - if(player == self) - continue; - if(!isDefined(player.team)) - continue; - if(level.teamBased && self.team == player.team) - continue; - if(player.sessionstate != "playing") - continue; - if(!isAlive(player)) - continue; - if(player hasPerk("specialty_gpsjammer")) - continue; - if(!bulletTracePassed(player.origin, player.origin+(0,0,512), false, player) && self.pers["bots"]["skill"]["base"] > 3) - continue; - - players[players.size] = player; - } - - target = random(players); - - if(isDefined(target)) - targetPos = target.origin + (randomIntRange((8-self.pers["bots"]["skill"]["base"])*-75, (8-self.pers["bots"]["skill"]["base"])*75), randomIntRange((8-self.pers["bots"]["skill"]["base"])*-75, (8-self.pers["bots"]["skill"]["base"])*75), 0); - else if(self.pers["bots"]["skill"]["base"] <= 3) - targetPos = self.origin + (randomIntRange(-512, 512), randomIntRange(-512, 512), 0); - break; - - default: - continue; - } - - isAirstrikePos = isDefined(targetPos); - if(self.pers["hardPointItem"] == "airstrike_mp" && !isAirstrikePos) + if(!player IsPlayerModelOK()) continue; - - self BotStopMoving(true); - - if (self changeToWeapon(self.pers["hardPointItem"])) + + if(player == self) + continue; + + if(!isDefined(player.team)) + continue; + + if(player.sessionstate != "playing") + continue; + + if(level.teambased && player.team == self.team) + continue; + + if(!isAlive(player)) + continue; + + distFromPlayer = DistanceSquared(self.origin, player.origin); + if(distFromPlayer > dist) + continue; + + if((!isSubStr(player getCurrentWeapon(), "_silencer_") && player.bots_firing) || (self.bot_radar && !player hasPerk("specialty_gpsjammer"))) { - wait 1; - - if (isAirstrikePos && !isDefined( level.airstrikeInProgress )) + distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; + if (distFromPlayer < distSq && bulletTracePassed(self getEyePos(), player getTagOrigin( "j_spineupper" ), false, player)) { - self BotFreezeControls(true); - - self notify( "confirm_location", targetPos ); - wait 1; - - self BotFreezeControls(false); + self SetAttacker(player); } - self thread changeToWeapon(curWeap); - } + if (!self HasScriptGoal() && !self.bot_lock_goal) + { + self thread stop_go_target_on_death(player); + self SetScriptGoal( player.origin, 128 ); - self BotStopMoving(false); + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + } + break; + } } } @@ -2424,57 +2579,43 @@ bot_uav_think() if( level.hardcoreMode && !self.bot_radar ) continue; - dist = self.pers["bots"]["skill"]["help_dist"]; - dist *= dist * 8; - - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[i]; - - if(!player IsPlayerModelOK()) - continue; - - if(player == self) - continue; - - if(!isDefined(player.team)) - continue; - - if(player.sessionstate != "playing") - continue; - - if(level.teambased && player.team == self.team) - continue; - - if(!isAlive(player)) - continue; - - distFromPlayer = DistanceSquared(self.origin, player.origin); - if(distFromPlayer > dist) - continue; - - if((!isSubStr(player getCurrentWeapon(), "_silencer_") && player.bots_firing) || (self.bot_radar && !player hasPerk("specialty_gpsjammer"))) - { - distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; - if (distFromPlayer < distSq && bulletTracePassed(self getEyePos(), player getTagOrigin( "j_spineupper" ), false, player)) - { - self SetAttacker(player); - } - - if (!self HasScriptGoal() && !self.bot_lock_goal) - { - self thread stop_go_target_on_death(player); - self SetScriptGoal( player.origin, 128 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - } - break; - } - } + self bot_uav_think_loop(); } } +/* + Bot logic for detecting the chopper as an enemy. +*/ +bot_target_vehicle_loop() +{ + chopper = level.chopper; + + if(isDefined(chopper) && level.teamBased && getDvarInt("doubleHeli")) + { + chopper = level.chopper[ level.otherTeam[self.team] ]; + } + + if (!isdefined(chopper)) + return; + + if(!isDefined(level.bot_chopper) || !level.bot_chopper)//must be crashing or leaving + return; + + if(isDefined(chopper.owner) && chopper.owner == self) + return; + + if(chopper.team == self.team && level.teamBased) + return; + + if(!bulletTracePassed( self getEyePos(), chopper.origin + (0, 0, -5), false, chopper )) + return; + + self SetScriptEnemy( chopper, (0, 0, -5) ); + self bot_attack_vehicle(chopper); + self ClearScriptEnemy(); + self notify("bot_force_check_switch"); +} + /* Bot logic for detecting the chopper as an enemy. */ @@ -2496,32 +2637,7 @@ bot_target_vehicle() if(!self getAmmoCount("rpg_mp") && self BotGetRandom() < 90) continue; - chopper = level.chopper; - - if(isDefined(chopper) && level.teamBased && getDvarInt("doubleHeli")) - { - chopper = level.chopper[ level.otherTeam[self.team] ]; - } - - if (!isdefined(chopper)) - continue; - - if(!isDefined(level.bot_chopper) || !level.bot_chopper)//must be crashing or leaving - continue; - - if(isDefined(chopper.owner) && chopper.owner == self) - continue; - - if(chopper.team == self.team && level.teamBased) - continue; - - if(!bulletTracePassed( self getEyePos(), chopper.origin + (0, 0, -5), false, chopper )) - continue; - - self SetScriptEnemy( chopper, (0, 0, -5) ); - self bot_attack_vehicle(chopper); - self ClearScriptEnemy(); - self notify("bot_force_check_switch"); + self bot_target_vehicle_loop(); } } @@ -2548,6 +2664,58 @@ bot_attack_vehicle(chopper) } } +/* + Bot logic for targeting equipment. +*/ +bot_equipment_kill_think_loop() +{ + grenades = GetEntArray( "grenade", "classname" ); + myEye = self getEyePos(); + myAngles = self getPlayerAngles(); + target = undefined; + hasDetectExp = self hasPerk("specialty_detectexplosive"); + + for ( i = grenades.size - 1; i >= 0; i-- ) + { + item = grenades[i]; + + if (!isDefined(item)) + continue; + + if ( !IsDefined( item.name ) ) + { + continue; + } + + if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) + { + continue; + } + + if (item.name != "c4_mp" && item.name != "claymore_mp") + continue; + + if(!hasDetectExp && !bulletTracePassed(myEye, item.origin+(0, 0, 0), false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < 512 * 512 ) + { + target = item; + break; + } + } + + if(isDefined(target)) + { + self SetScriptEnemy( target, (0, 0, 0) ); + self bot_equipment_attack(target); + self ClearScriptEnemy(); + } +} + /* Bot logic for targeting equipment. */ @@ -2566,51 +2734,7 @@ bot_equipment_kill_think() if(self.pers["bots"]["skill"]["base"] <= 1) continue; - grenades = GetEntArray( "grenade", "classname" ); - myEye = self getEyePos(); - myAngles = self getPlayerAngles(); - target = undefined; - hasDetectExp = self hasPerk("specialty_detectexplosive"); - - for ( i = grenades.size - 1; i >= 0; i-- ) - { - item = grenades[i]; - - if (!isDefined(item)) - continue; - - if ( !IsDefined( item.name ) ) - { - continue; - } - - if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) - { - continue; - } - - if (item.name != "c4_mp" && item.name != "claymore_mp") - continue; - - if(!hasDetectExp && !bulletTracePassed(myEye, item.origin+(0, 0, 0), false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < 512 * 512 ) - { - target = item; - break; - } - } - - if(isDefined(target)) - { - self SetScriptEnemy( target, (0, 0, 0) ); - self bot_equipment_attack(target); - self ClearScriptEnemy(); - } + self bot_equipment_kill_think_loop(); } } @@ -2634,6 +2758,46 @@ bot_equipment_attack(equ) } } +/* + Bots hang around the enemy's flag to spawn kill em +*/ +bot_dom_spawn_kill_think_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); + + if ( myFlagCount == level.flags.size ) + return; + + otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); + + if (myFlagCount <= otherFlagCount || otherFlagCount != 1) + return; + + flag = undefined; + for ( i = 0; i < level.flags.size; i++ ) + { + if ( level.flags[i] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) + continue; + + flag = level.flags[i]; + } + + if(!isDefined(flag)) + return; + + if(DistanceSquared(self.origin, flag.origin) < 2048*2048) + return; + + self SetScriptGoal( flag.origin, 1024 ); + + self thread bot_dom_watch_flags(myFlagCount, myTeam); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); +} + /* Bots hang around the enemy's flag to spawn kill em */ @@ -2645,9 +2809,6 @@ bot_dom_spawn_kill_think() if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 10, 20 ) ); @@ -2658,35 +2819,7 @@ bot_dom_spawn_kill_think() if ( self HasScriptGoal() || self.bot_lock_goal) continue; - myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); - - if ( myFlagCount == level.flags.size ) - continue; - - otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); - - if (myFlagCount <= otherFlagCount || otherFlagCount != 1) - continue; - - flag = undefined; - for ( i = 0; i < level.flags.size; i++ ) - { - if ( level.flags[i] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) - continue; - } - - if(!isDefined(flag)) - continue; - - if(DistanceSquared(self.origin, flag.origin) < 2048*2048) - continue; - - self SetScriptGoal( flag.origin, 1024 ); - - self thread bot_dom_watch_flags(myFlagCount, myTeam); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); + self bot_dom_spawn_kill_think_loop(); } } @@ -2712,6 +2845,37 @@ bot_dom_watch_flags(count, myTeam) self notify("bad_path"); } +/* + Bots watches their own flags and protects them when they are under capture +*/ +bot_dom_def_think_loop() +{ + myTeam = self.pers[ "team" ]; + flag = undefined; + for ( i = 0; i < level.flags.size; i++ ) + { + if ( level.flags[i] maps\mp\gametypes\dom::getFlagTeam() != myTeam ) + continue; + + if ( !level.flags[i].useObj.objPoints[myTeam].isFlashing ) + continue; + + if ( !isDefined(flag) || DistanceSquared(self.origin,level.flags[i].origin) < DistanceSquared(self.origin,flag.origin) ) + flag = level.flags[i]; + } + + if ( !isDefined(flag) ) + return; + + self SetScriptGoal( flag.origin, 128 ); + + self thread bot_dom_watch_for_flashing(flag, myTeam); + self thread bots_watch_touch_obj(flag); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); +} + /* Bots watches their own flags and protects them when they are under capture */ @@ -2723,8 +2887,6 @@ bot_dom_def_think() if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - for ( ;; ) { wait( randomintrange( 1, 3 ) ); @@ -2734,30 +2896,8 @@ bot_dom_def_think() if ( self HasScriptGoal() || self.bot_lock_goal ) continue; - - flag = undefined; - for ( i = 0; i < level.flags.size; i++ ) - { - if ( level.flags[i] maps\mp\gametypes\dom::getFlagTeam() != myTeam ) - continue; - - if ( !level.flags[i].useObj.objPoints[myTeam].isFlashing ) - continue; - - if ( !isDefined(flag) || DistanceSquared(self.origin,level.flags[i].origin) < DistanceSquared(self.origin,flag.origin) ) - flag = level.flags[i]; - } - - if ( !isDefined(flag) ) - continue; - self SetScriptGoal( flag.origin, 128 ); - - self thread bot_dom_watch_for_flashing(flag, myTeam); - self thread bots_watch_touch_obj(flag); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); + self bot_dom_def_think_loop(); } } @@ -2786,6 +2926,98 @@ bot_dom_watch_for_flashing(flag, myTeam) self notify("bad_path"); } +/* + Bots capture dom flags +*/ +bot_dom_cap_think_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); + + if ( myFlagCount == level.flags.size ) + return; + + otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); + + if (game["teamScores"][myteam] >= game["teamScores"][otherTeam]) + { + if ( myFlagCount < otherFlagCount ) + { + if ( randomint( 100 ) < 15 ) + return; + } + else if ( myFlagCount == otherFlagCount ) + { + if ( randomint( 100 ) < 35 ) + return; + } + else if ( myFlagCount > otherFlagCount ) + { + if ( randomint( 100 ) < 95 ) + return; + } + } + + flag = undefined; + flags = []; + for ( i = 0; i < level.flags.size; i++ ) + { + if ( level.flags[i] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) + continue; + + flags[flags.size] = level.flags[i]; + } + + if (randomInt(100) > 30) + { + for ( i = 0; i < flags.size; i++ ) + { + if ( !isDefined(flag) || DistanceSquared(self.origin,level.flags[i].origin) < DistanceSquared(self.origin,flag.origin) ) + flag = level.flags[i]; + } + } + else if (flags.size) + { + flag = random(flags); + } + + if ( !isDefined(flag) ) + return; + + self.bot_lock_goal = true; + self SetScriptGoal( flag.origin, 64 ); + + self thread bot_dom_go_cap_flag(flag, myteam); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if (event != "goal") + { + self.bot_lock_goal = false; + return; + } + + self SetScriptGoal( self.origin, 64 ); + + while ( flag maps\mp\gametypes\dom::getFlagTeam() != myTeam && self isTouching(flag) ) + { + cur = flag.useObj.curProgress; + wait 0.5; + + if(flag.useObj.curProgress == cur) + break;//some enemy is near us, kill him + } + + self ClearScriptGoal(); + + self.bot_lock_goal = false; +} + /* Bots capture dom flags */ @@ -2797,9 +3029,6 @@ bot_dom_cap_think() if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 12 ) ); @@ -2812,88 +3041,7 @@ bot_dom_cap_think() if ( !isDefined(level.flags) || level.flags.size == 0 ) continue; - myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); - - if ( myFlagCount == level.flags.size ) - continue; - - otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); - - if (game["teamScores"][myteam] >= game["teamScores"][otherTeam]) - { - if ( myFlagCount < otherFlagCount ) - { - if ( randomint( 100 ) < 15 ) - continue; - } - else if ( myFlagCount == otherFlagCount ) - { - if ( randomint( 100 ) < 35 ) - continue; - } - else if ( myFlagCount > otherFlagCount ) - { - if ( randomint( 100 ) < 95 ) - continue; - } - } - - flag = undefined; - flags = []; - for ( i = 0; i < level.flags.size; i++ ) - { - if ( level.flags[i] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) - continue; - - flags[flags.size] = level.flags[i]; - } - - if (randomInt(100) > 30) - { - for ( i = 0; i < flags.size; i++ ) - { - if ( !isDefined(flag) || DistanceSquared(self.origin,level.flags[i].origin) < DistanceSquared(self.origin,flag.origin) ) - flag = level.flags[i]; - } - } - else if (flags.size) - { - flag = random(flags); - } - - if ( !isDefined(flag) ) - continue; - - self.bot_lock_goal = true; - self SetScriptGoal( flag.origin, 64 ); - - self thread bot_dom_go_cap_flag(flag, myteam); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if (event != "new_goal") - self ClearScriptGoal(); - - if (event != "goal") - { - self.bot_lock_goal = false; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - while ( flag maps\mp\gametypes\dom::getFlagTeam() != myTeam && self isTouching(flag) ) - { - cur = flag.useObj.curProgress; - wait 0.5; - - if(flag.useObj.curProgress == cur) - break;//some enemy is near us, kill him - } - - self ClearScriptGoal(); - - self.bot_lock_goal = false; + self bot_dom_cap_think_loop(); } } @@ -2928,6 +3076,101 @@ bot_dom_go_cap_flag(flag, myteam) self notify("goal"); } +/* + Bots play headquarters +*/ +bot_hq_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + radio = level.radio; + gameobj = radio.gameobject; + origin = ( radio.origin[0], radio.origin[1], radio.origin[2]+5 ); + + //if neut or enemy + if(gameobj.ownerTeam != myTeam) + { + if(gameobj.interactTeam == "none")//wait for it to become active + { + if(self HasScriptGoal()) + return; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + //capture it + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_hq_go_cap(gameobj, radio); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if (event != "goal") + { + self.bot_lock_goal = false; + return; + } + + if(!self isTouching(gameobj.trigger) || level.radio != radio) + { + self.bot_lock_goal = false; + return; + } + + self SetScriptGoal( self.origin, 64 ); + + while(self isTouching(gameobj.trigger) && gameobj.ownerTeam != myTeam && level.radio == radio) + { + cur = gameobj.curProgress; + wait 0.5; + + if(cur == gameobj.curProgress) + break;//no prog made, enemy must be capping + } + + self ClearScriptGoal(); + self.bot_lock_goal = false; + } + else//we own it + { + if(gameobj.objPoints[myteam].isFlashing)//underattack + { + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_hq_watch_flashing(gameobj, radio); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + return; + } + + if(self HasScriptGoal()) + return; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + } +} + /* Bots play headquarters */ @@ -2939,9 +3182,6 @@ bot_hq() if ( level.gametype != "koth" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 5 ) ); @@ -2956,92 +3196,8 @@ bot_hq() if(!isDefined(level.radio.gameobject)) continue; - - radio = level.radio; - gameobj = radio.gameobject; - origin = ( radio.origin[0], radio.origin[1], radio.origin[2]+5 ); - - //if neut or enemy - if(gameobj.ownerTeam != myTeam) - { - if(gameobj.interactTeam == "none")//wait for it to become active - { - if(self HasScriptGoal()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - //capture it - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bot_hq_go_cap(gameobj, radio); - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if (event != "new_goal") - self ClearScriptGoal(); - - if (event != "goal") - { - self.bot_lock_goal = false; - continue; - } - - if(!self isTouching(gameobj.trigger) || level.radio != radio) - { - self.bot_lock_goal = false; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - while(self isTouching(gameobj.trigger) && gameobj.ownerTeam != myTeam && level.radio == radio) - { - cur = gameobj.curProgress; - wait 0.5; - - if(cur == gameobj.curProgress) - break;//no prog made, enemy must be capping - } - - self ClearScriptGoal(); - self.bot_lock_goal = false; - } - else//we own it - { - if(gameobj.objPoints[myteam].isFlashing)//underattack - { - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bot_hq_watch_flashing(gameobj, radio); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; - continue; - } - - if(self HasScriptGoal()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - } + self bot_hq_loop(); } } @@ -3106,6 +3262,234 @@ bot_hq_watch_flashing(obj, radio) self notify("bad_path"); } +/* + Bots play sab +*/ +bot_sab_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + bomb = level.sabBomb; + bombteam = bomb.ownerTeam; + carrier = bomb.carrier; + timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; + + // the bomb is ours, we are on the offence + if(bombteam == myTeam) + { + site = level.bombZones[otherTeam]; + origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); + + // protect our planted bomb + if(level.bombPlanted) + { + // kill defuser + if(site isInUse()) //somebody is defusing our bomb we planted + { + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site(site); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + self.bot_lock_goal = false; + return; + } + + //else hang around the site + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + self.bot_lock_goal = false; + return; + } + + // we are not the carrier + if(!self isBombCarrier()) + { + // lets escort the bomb carrier + if(self HasScriptGoal()) + return; + + origin = carrier.origin; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj(bomb, carrier); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + // we are the carrier of the bomb, lets check if we need to plant + timepassed = maps\mp\gametypes\_globallogic::getTimePassed()/1000; + + if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) + return; + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 1 ); + + self thread bot_go_plant(site); + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if(event != "goal" || level.bombPlanted || !self isTouching(site.trigger) || site IsInUse() || self inLastStand() || self HasThreat()) + { + self.bot_lock_goal = false; + return; + } + + self SetScriptGoal( self.origin, 64 ); + + self bot_use_bomb_thread(site); + wait 1; + + self ClearScriptGoal(); + self.bot_lock_goal = false; + } + else if(bombteam == otherTeam) // the bomb is theirs, we are on the defense + { + site = level.bombZones[myteam]; + + if(!isDefined(site.bots)) + site.bots = 0; + + // protect our site from planters + if(!level.bombPlanted) + { + //kill bomb carrier + if(site.bots > 2 || randomInt(100) < 45) + { + if(self HasScriptGoal()) + return; + + if(carrier hasPerk( "specialty_gpsjammer" )) + return; + + origin = carrier.origin; + + self SetScriptGoal( origin, 64 ); + self thread bot_escort_obj(bomb, carrier); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + //protect bomb site + origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); + + self thread bot_inc_bots(site); + + if(site isInUse())//somebody is planting + { + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_inc_bots(site); + + self thread bot_defend_site(site); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + return; + } + + //else hang around the site + if(DistanceSquared(origin, self.origin) <= 1024*1024) + { + wait 4; + self notify("bot_inc_bots"); site.bots--; + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + self thread bot_inc_bots(site); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + self.bot_lock_goal = false; + return; + } + + // bomb is planted we need to defuse + origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); + + // someone else is defusing, lets just hang around + if(site.bots > 1) + { + if(self HasScriptGoal()) + return; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + self thread bot_go_defuse(site); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + // lets go defuse + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 1 ); + self thread bot_inc_bots(site); + self thread bot_go_defuse(site); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if(event != "goal" || !level.bombPlanted || site IsInUse() || !self isTouching(site.trigger) || self InLastStand() || self HasThreat()) + { + self.bot_lock_goal = false; + return; + } + + self SetScriptGoal( self.origin, 64 ); + + self bot_use_bomb_thread(site); + wait 1; + self ClearScriptGoal(); + + self.bot_lock_goal = false; + } + else // we need to go get the bomb! + { + origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_get_obj(bomb); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + return; + } +} + /* Bots play sab */ @@ -3118,9 +3502,6 @@ bot_sab() if ( level.gametype != "sab" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 5 ) ); @@ -3138,226 +3519,156 @@ bot_sab() if (self IsPlanting() || self isDefusing()) continue; - - bomb = level.sabBomb; - bombteam = bomb.ownerTeam; - carrier = bomb.carrier; + + self bot_sab_loop(); + } +} + +/* + Bots play sd defenders +*/ +bot_sd_defenders_loop(data) +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + // bomb not planted, lets protect our sites + if(!level.bombPlanted) + { timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; - // the bomb is ours, we are on the offence - if(bombteam == myTeam) - { - site = level.bombZones[otherTeam]; - origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); - - // protect our planted bomb - if(level.bombPlanted) - { - // kill defuser - if(site isInUse()) //somebody is defusing our bomb we planted - { - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - - self thread bot_defend_site(site); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - self.bot_lock_goal = false; - continue; - } - - //else hang around the site - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - self.bot_lock_goal = false; - continue; - } - - // we are not the carrier - if(!self isBombCarrier()) - { - // lets escort the bomb carrier - if(self HasScriptGoal()) - continue; - - origin = carrier.origin; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_escort_obj(bomb, carrier); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - // we are the carrier of the bomb, lets check if we need to plant - timepassed = maps\mp\gametypes\_globallogic::getTimePassed()/1000; - - if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) - continue; + if(timeleft >= 90) + return; - self.bot_lock_goal = true; - self SetScriptGoal( origin, 1 ); - - self thread bot_go_plant(site); - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if (event != "new_goal") - self ClearScriptGoal(); - - if(event != "goal" || level.bombPlanted || !self isTouching(site.trigger) || site IsInUse() || self inLastStand() || self HasThreat()) - { - self.bot_lock_goal = false; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - self bot_use_bomb_thread(site); - wait 1; - - self ClearScriptGoal(); - self.bot_lock_goal = false; - } - else if(bombteam == otherTeam) // the bomb is theirs, we are on the defense + // check for a bomb carrier, and camp the bomb + if(!level.multiBomb && isDefined(level.sdBomb)) { - site = level.bombZones[myteam]; + bomb = level.sdBomb; + carrier = level.sdBomb.carrier; - if(!isDefined(site.bots)) - site.bots = 0; - - // protect our site from planters - if(!level.bombPlanted) + if(!isDefined(carrier)) { - //kill bomb carrier - if(site.bots > 2 || randomInt(100) < 45) - { - if(self HasScriptGoal()) - continue; - - if(carrier hasPerk( "specialty_gpsjammer" )) - continue; - - origin = carrier.origin; - - self SetScriptGoal( origin, 64 ); - self thread bot_escort_obj(bomb, carrier); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } + origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); - //protect bomb site - origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); - - self thread bot_inc_bots(site); - - if(site isInUse())//somebody is planting - { - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bot_inc_bots(site); - - self thread bot_defend_site(site); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; - continue; - } - - //else hang around the site - if(DistanceSquared(origin, self.origin) <= 1024*1024) - { - wait 4; - self notify("bot_inc_bots"); site.bots--; - continue; - } - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - self thread bot_inc_bots(site); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - self.bot_lock_goal = false; - continue; - } - - // bomb is planted we need to defuse - origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); - - // someone else is defusing, lets just hang around - if(site.bots > 1) - { + //hang around the bomb if(self HasScriptGoal()) - continue; + return; if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; + return; self SetScriptGoal( origin, 256 ); - self thread bot_go_defuse(site); + + self thread bot_get_obj(bomb); if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") self ClearScriptGoal(); - continue; + return; } - - // lets go defuse - self.bot_lock_goal = true; - - self SetScriptGoal( origin, 1 ); - self thread bot_inc_bots(site); - self thread bot_go_defuse(site); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if (event != "new_goal") - self ClearScriptGoal(); - - if(event != "goal" || !level.bombPlanted || site IsInUse() || !self isTouching(site.trigger) || self InLastStand() || self HasThreat()) - { - self.bot_lock_goal = false; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - self bot_use_bomb_thread(site); - wait 1; - self ClearScriptGoal(); - - self.bot_lock_goal = false; } - else // we need to go get the bomb! + + // pick a site to protect + if(!isDefined(level.bombZones) || !level.bombZones.size) + return; + + sites = []; + for(i = 0; i < level.bombZones.size; i++) + { + sites[sites.size] = level.bombZones[i]; + } + + if(!sites.size) + return; + + if (data.rand > 50) + site = self bot_array_nearest_curorigin(sites); + else + site = random(sites); + + if(!isDefined(site)) + return; + + origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); + + if(site isInUse())//somebody is planting { - origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); - self.bot_lock_goal = true; self SetScriptGoal( origin, 64 ); - - self thread bot_get_obj(bomb); + + self thread bot_defend_site(site); if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") self ClearScriptGoal(); self.bot_lock_goal = false; - continue; + return; } + + //else hang around the site + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + return; } + + // bomb is planted, we need to defuse + if(!isDefined(level.defuseObject)) + return; + + defuse = level.defuseObject; + + if(!isDefined(defuse.bots)) + defuse.bots = 0; + + origin = ( defuse.curorigin[0], defuse.curorigin[1], defuse.curorigin[2]+5 ); + + // someone is going to go defuse ,lets just hang around + if(defuse.bots > 1) + { + if(self HasScriptGoal()) + return; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + self thread bot_go_defuse(defuse); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + // lets defuse + self.bot_lock_goal = true; + self SetScriptGoal( origin, 1 ); + self thread bot_inc_bots(defuse); + self thread bot_go_defuse(defuse); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if(event != "goal" || !level.bombPlanted || defuse isInUse() || !self isTouching(defuse.trigger) || self InLastStand() || self HasThreat()) + { + self.bot_lock_goal = false; + return; + } + + self SetScriptGoal( self.origin, 64 ); + + self bot_use_bomb_thread(defuse); + wait 1; + self ClearScriptGoal(); + self.bot_lock_goal = false; } /* @@ -3371,14 +3682,12 @@ bot_sd_defenders() if ( level.gametype != "sd" ) return; - - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - if(myTeam == game["attackers"]) + if(self.team == game["attackers"]) return; - rand = self BotGetRandom(); + data = spawnStruct(); + data.rand = self BotGetRandom(); for ( ;; ) { @@ -3391,145 +3700,184 @@ bot_sd_defenders() if (self IsPlanting() || self isDefusing()) continue; + + self bot_sd_defenders_loop(data); + } +} + +/* + Bots play sd attackers +*/ +bot_sd_attackers_loop(data) +{ + if(data.first) + data.first = false; + else + wait( randomintrange( 3, 5 ) ); + + if ( self.bot_lock_goal ) + { + return; + } + + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + //bomb planted + if(level.bombPlanted) + { + if(!isDefined(level.defuseObject)) + return; - // bomb not planted, lets protect our sites - if(!level.bombPlanted) + site = level.defuseObject; + + origin = ( site.curorigin[0], site.curorigin[1], site.curorigin[2]+5 ); + + if(site IsInUse())//somebody is defusing { - timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; - - if(timeleft >= 90) - continue; - - // check for a bomb carrier, and camp the bomb - if(!level.multiBomb && isDefined(level.sdBomb)) - { - bomb = level.sdBomb; - carrier = level.sdBomb.carrier; - - if(!isDefined(carrier)) - { - origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); - - //hang around the bomb - if(self HasScriptGoal()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - - self thread bot_get_obj(bomb); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - } - - // pick a site to protect - if(!isDefined(level.bombZones) || !level.bombZones.size) - continue; - - sites = []; - for(i = 0; i < level.bombZones.size; i++) - { - sites[sites.size] = level.bombZones[i]; - } - - if(!sites.size) - continue; - - if (rand > 50) - site = self bot_array_nearest_curorigin(sites); - else - site = random(sites); - - if(!isDefined(site)) - continue; - - origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); - - if(site isInUse())//somebody is planting - { - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - - self thread bot_defend_site(site); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; - continue; - } - - //else hang around the site - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - + + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site(site); + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") self ClearScriptGoal(); self.bot_lock_goal = false; - continue; + return; } - // bomb is planted, we need to defuse - if(!isDefined(level.defuseObject)) - continue; + //else hang around the site + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; - defuse = level.defuseObject; - - if(!isDefined(defuse.bots)) - defuse.bots = 0; - - origin = ( defuse.curorigin[0], defuse.curorigin[1], defuse.curorigin[2]+5 ); - - // someone is going to go defuse ,lets just hang around - if(defuse.bots > 1) - { - if(self HasScriptGoal()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_go_defuse(defuse); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - // lets defuse self.bot_lock_goal = true; - self SetScriptGoal( origin, 1 ); - self thread bot_inc_bots(defuse); - self thread bot_go_defuse(defuse); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if (event != "new_goal") + self SetScriptGoal( origin, 256 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") self ClearScriptGoal(); - if(event != "goal" || !level.bombPlanted || defuse isInUse() || !self isTouching(defuse.trigger) || self InLastStand() || self HasThreat()) + self.bot_lock_goal = false; + return; + } + + timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; + timepassed = maps\mp\gametypes\_globallogic::getTimePassed()/1000; + + //dont have a bomb + if(!self IsBombCarrier() && !level.multiBomb) + { + if(!isDefined(level.sdBomb)) + return; + + bomb = level.sdBomb; + carrier = level.sdBomb.carrier; + + //bomb is picked up + if(isDefined(carrier)) { - self.bot_lock_goal = false; - continue; + //escort the bomb carrier + if(self HasScriptGoal()) + return; + + origin = carrier.origin; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj(bomb, carrier); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; } - self SetScriptGoal( self.origin, 64 ); + if(!isDefined(bomb.bots)) + bomb.bots = 0; - self bot_use_bomb_thread(defuse); - wait 1; - self ClearScriptGoal(); + origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); + + //hang around the bomb if other is going to go get it + if(bomb.bots > 1) + { + if(self HasScriptGoal()) + return; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + + self thread bot_get_obj(bomb); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + // go get the bomb + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_inc_bots(bomb); + self thread bot_get_obj(bomb); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + self.bot_lock_goal = false; + return; } + + // check if to plant + if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) + return; + + if(!isDefined(level.bombZones) || !level.bombZones.size) + return; + + sites = []; + for(i = 0; i < level.bombZones.size; i++) + { + sites[sites.size] = level.bombZones[i]; + } + + if(!sites.size) + return; + + if(data.rand > 50) + plant = self bot_array_nearest_curorigin(sites); + else + plant = random(sites); + + if(!isDefined(plant)) + return; + + origin = ( plant.curorigin[0]+50, plant.curorigin[1]+50, plant.curorigin[2]+5 ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 1 ); + self thread bot_go_plant(plant); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if(event != "goal" || level.bombPlanted || plant.visibleTeam == "none" || !self isTouching(plant.trigger) || self InLastStand() || self HasThreat() || plant IsInUse()) + { + self.bot_lock_goal = false; + return; + } + + self SetScriptGoal( self.origin, 64 ); + + self bot_use_bomb_thread(plant); + wait 1; + + self ClearScriptGoal(); + self.bot_lock_goal = false; } /* @@ -3543,183 +3891,16 @@ bot_sd_attackers() if ( level.gametype != "sd" ) return; - - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - if(myTeam != game["attackers"]) + if(self.team != game["attackers"]) return; - rand = self BotGetRandom(); - - first = true; + data = spawnStruct(); + data.rand = self BotGetRandom(); + data.first = true; for ( ;; ) { - if(first) - first = false; - else - wait( randomintrange( 3, 5 ) ); - - if ( self.bot_lock_goal ) - { - continue; - } - - //bomb planted - if(level.bombPlanted) - { - if(!isDefined(level.defuseObject)) - continue; - - site = level.defuseObject; - - origin = ( site.curorigin[0], site.curorigin[1], site.curorigin[2]+5 ); - - if(site IsInUse())//somebody is defusing - { - self.bot_lock_goal = true; - - self SetScriptGoal( origin, 64 ); - - self thread bot_defend_site(site); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; - continue; - } - - //else hang around the site - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; - continue; - } - - timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; - timepassed = maps\mp\gametypes\_globallogic::getTimePassed()/1000; - - //dont have a bomb - if(!self IsBombCarrier() && !level.multiBomb) - { - if(!isDefined(level.sdBomb)) - continue; - - bomb = level.sdBomb; - carrier = level.sdBomb.carrier; - - //bomb is picked up - if(isDefined(carrier)) - { - //escort the bomb carrier - if(self HasScriptGoal()) - continue; - - origin = carrier.origin; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_escort_obj(bomb, carrier); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - if(!isDefined(bomb.bots)) - bomb.bots = 0; - - origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); - - //hang around the bomb if other is going to go get it - if(bomb.bots > 1) - { - if(self HasScriptGoal()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - - self thread bot_get_obj(bomb); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - // go get the bomb - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bot_inc_bots(bomb); - self thread bot_get_obj(bomb); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; - continue; - } - - // check if to plant - if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) - continue; - - if(!isDefined(level.bombZones) || !level.bombZones.size) - continue; - - sites = []; - for(i = 0; i < level.bombZones.size; i++) - { - sites[sites.size] = level.bombZones[i]; - } - - if(!sites.size) - continue; - - if(rand > 50) - plant = self bot_array_nearest_curorigin(sites); - else - plant = random(sites); - - if(!isDefined(plant)) - continue; - - origin = ( plant.curorigin[0]+50, plant.curorigin[1]+50, plant.curorigin[2]+5 ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 1 ); - self thread bot_go_plant(plant); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if (event != "new_goal") - self ClearScriptGoal(); - - if(event != "goal" || level.bombPlanted || plant.visibleTeam == "none" || !self isTouching(plant.trigger) || self InLastStand() || self HasThreat() || plant IsInUse()) - { - self.bot_lock_goal = false; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - self bot_use_bomb_thread(plant); - wait 1; - - self ClearScriptGoal(); - self.bot_lock_goal = false; + self bot_sd_attackers_loop(data); } }