From 86dbc6c00af5bd09c71c99222b524fdea7668054 Mon Sep 17 00:00:00 2001 From: ineedbots Date: Thu, 27 May 2021 21:40:28 -0600 Subject: [PATCH] Greatly reduce var usage (prevent exceeded child0/1 vars) --- maps/mp/bots/_bot.gsc | 742 ++-- maps/mp/bots/_bot_internal.gsc | 1458 ++++---- maps/mp/bots/_bot_script.gsc | 6313 +++++++++++++++++--------------- 3 files changed, 4414 insertions(+), 4099 deletions(-) diff --git a/maps/mp/bots/_bot.gsc b/maps/mp/bots/_bot.gsc index 1405931..5be289b 100644 --- a/maps/mp/bots/_bot.gsc +++ b/maps/mp/bots/_bot.gsc @@ -264,12 +264,10 @@ fixDem() for (i = 0; i < level.bombZones.size; i++) { - bombzone = level.bombZones[i]; - - if (isDefined(bombzone.trigger.trigger_off)) - bombzone.bombExploded = true; + if (isDefined(level.bombZones[i].trigger.trigger_off)) + level.bombZones[i].bombExploded = true; else - bombzone.bombExploded = undefined; + level.bombZones[i].bombExploded = undefined; } wait 0.05; @@ -306,6 +304,31 @@ fixKoth() } } +/* + Loop +*/ +auditModels_loop() +{ + s_models = getEntArray("script_model", "classname"); + + for (i = s_models.size - 1; i >= 0; i--) + { + model = s_models[i]; + + if (!isDefined(model)) + continue; + + if (isDefined(model.bot_audit_model)) + continue; + + if (model.model == "com_deploy_ballistic_vest_friend_world") + { + model.bot_audit_model = true; + level.vest_boxes[level.vest_boxes.size] = model; + } + } +} + /* Audits all the important models cause iw5 script is kek */ @@ -319,23 +342,51 @@ auditModels() level.vest_boxes = array_removeUndefined(level.vest_boxes); - s_models = getEntArray("script_model", "classname"); + auditModels_loop(); + } +} - for (i = s_models.size - 1; i >= 0; i--) +/* + Loop +*/ +watchRadar_loop() +{ + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[i]; + player.bot_isInRadar = false; + } + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + grenade = level.players[i].deployedPortableRadar; + + if ( !isDefined( grenade ) ) + continue; + + if (grenade.model != "weapon_radar") + continue; + + for ( h = level.players.size - 1; h >= 0; h-- ) { - model = s_models[i]; + player = level.players[h]; - if (!isDefined(model)) + if (!isReallyAlive(player)) continue; - if (isDefined(model.bot_audit_model)) + if (isDefined(grenade.owner) && grenade.owner == player) continue; - if (model.model == "com_deploy_ballistic_vest_friend_world") - { - model.bot_audit_model = true; - level.vest_boxes[level.vest_boxes.size] = model; - } + if(level.teamBased && grenade.team == player.team) + continue; + + if (player _hasPerk("specialty_coldblooded")) + continue; + + if (DistanceSquared(player.origin, grenade.origin) > 256*256) + continue; + + player.bot_isInRadar = true; } } } @@ -349,43 +400,48 @@ watchRadar() { wait 1; - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[i]; - player.bot_isInRadar = false; - } + watchRadar_loop(); + } +} - for ( i = level.players.size - 1; i >= 0; i-- ) - { - grenade = level.players[i].deployedPortableRadar; +/* + Loop +*/ +watchScrabler_loop() +{ + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[i]; + player.bot_isScrambled = false; + } - if ( !isDefined( grenade ) ) + for (i = level.scramblers.size - 1; i >= 0; i--) + { + scrambler = level.scramblers[i]; + + if ( !isDefined( scrambler ) ) + continue; + + for ( h = level.players.size - 1; h >= 0; h-- ) + { + player = level.players[h]; + + if (!isReallyAlive(player)) continue; - if (grenade.model != "weapon_radar") + if (isDefined(scrambler.owner) && scrambler.owner == player) continue; - for ( h = level.players.size - 1; h >= 0; h-- ) - { - player = level.players[h]; + if(level.teamBased && scrambler.team == player.team) + continue; - if (!isReallyAlive(player)) - continue; + if (player _hasPerk("specialty_spygame")) + continue; - if (isDefined(grenade.owner) && grenade.owner == player) - continue; + if (DistanceSquared(player.origin, scrambler.origin) > 256*256) + continue; - if(level.teamBased && grenade.team == player.team) - continue; - - if (player _hasPerk("specialty_coldblooded")) - continue; - - if (DistanceSquared(player.origin, grenade.origin) > 256*256) - continue; - - player.bot_isInRadar = true; - } + player.bot_isScrambled = true; } } } @@ -399,41 +455,29 @@ watchScrabler() { wait 1; - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[i]; - player.bot_isScrambled = false; - } + watchScrabler_loop(); + } +} - for (i = level.scramblers.size - 1; i >= 0; i--) - { - scrambler = level.scramblers[i]; +/* + Loop +*/ +addNotifyOnAirdrops_loop() +{ + dropCrates = getEntArray( "care_package", "targetname" ); - if ( !isDefined( scrambler ) ) - continue; + for (i = dropCrates.size - 1; i >= 0; i--) + { + airdrop = dropCrates[i]; - for ( h = level.players.size - 1; h >= 0; h-- ) - { - player = level.players[h]; + if (!isDefined(airdrop.owner)) + continue; - if (!isReallyAlive(player)) - continue; + if (isDefined(airdrop.doingPhysics)) + continue; - if (isDefined(scrambler.owner) && scrambler.owner == player) - continue; - - if(level.teamBased && scrambler.team == player.team) - continue; - - if (player _hasPerk("specialty_spygame")) - continue; - - if (DistanceSquared(player.origin, scrambler.origin) > 256*256) - continue; - - player.bot_isScrambled = true; - } - } + airdrop.doingPhysics = true; + airdrop thread doNotifyOnAirdrop(); } } @@ -445,21 +489,7 @@ addNotifyOnAirdrops() for (;;) { wait 1; - dropCrates = getEntArray( "care_package", "targetname" ); - - for (i = dropCrates.size - 1; i >= 0; i--) - { - airdrop = dropCrates[i]; - - if (!isDefined(airdrop.owner)) - continue; - - if (isDefined(airdrop.doingPhysics)) - continue; - - airdrop.doingPhysics = true; - airdrop thread doNotifyOnAirdrop(); - } + addNotifyOnAirdrops_loop(); } } @@ -564,6 +594,82 @@ add_bot() } } +/* + Loop +*/ +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. */ @@ -573,73 +679,130 @@ diffBots() { wait 1.5; - 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"); + diffBots_loop(); + } +} + +/* + Loop +*/ +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]; - allies_hard = 0; - allies_med = 0; - axis_hard = 0; - axis_med = 0; + if(!isDefined(player.pers["team"])) + continue; - 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; + } } } } @@ -653,124 +816,113 @@ teamBots() for(;;) { wait 1.5; - teamAmount = getDvarInt("bots_team_amount"); - toTeam = getDvar("bots_team"); + teamBots_loop(); + } +} + +/* + Loops +*/ +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")) + { + tempBot = random(getBotArray()); + if (isDefined(tempBot)) + kick(tempBot getEntityNumber()); } } @@ -787,105 +939,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")) - { - tempBot = random(getBotArray()); - if (isDefined(tempBot)) - kick(tempBot getEntityNumber()); - } + addBots_loop(); } } diff --git a/maps/mp/bots/_bot_internal.gsc b/maps/mp/bots/_bot_internal.gsc index 93788fa..cab9548 100644 --- a/maps/mp/bots/_bot_internal.gsc +++ b/maps/mp/bots/_bot_internal.gsc @@ -250,13 +250,10 @@ reload_watch() while(true) { - ret = self waittill_any_timeout(7.5, "reload"); - - if (ret == "timeout") + if (self waittill_any_timeout(7.5, "reload") == "timeout") break; - weap = self GetCurrentWeapon(); - if (self GetWeaponAmmoClip(weap) >= WeaponClipSize(weap)) + if (self GetWeaponAmmoClip(self GetCurrentWeapon()) >= WeaponClipSize(self GetCurrentWeapon())) break; } self.bot.isreloading = false; @@ -296,21 +293,6 @@ onLastStand() self notify("kill_goal"); - if (!self inFinalStand() && !self IsUsingRemote()) - { - pistol = undefined; - weaponsList = self GetWeaponsListPrimaries(); - for (i = 0; i < weaponsList.size; i++) - { - weapon = weaponsList[i]; - if ( maps\mp\gametypes\_weapons::isSideArm( weapon ) ) - pistol = weapon; - } - - if (isDefined(pistol)) - self changeToWeap(pistol); - } - while (self inLastStand()) wait 0.05; } @@ -459,6 +441,9 @@ watchGrenadeFire() { self waittill( "grenade_fire", nade, weapname ); + if (!isDefined(nade)) + continue; + if (weapname == "c4_mp") self thread watchC4Thrown(nade); } @@ -509,6 +494,81 @@ watchC4Thrown(c4) self thread pressFire(); } +/* + Bot moves towards the point +*/ +doBotMovement_loop(data) +{ + move_To = self.bot.moveTo; + angles = self GetPlayerAngles(); + dir = (0, 0, 0); + + if (DistanceSquared(self.origin, move_To) >= 49) + { + cosa = cos(0-angles[1]); + sina = sin(0-angles[1]); + + // get the direction + dir = move_To - self.origin; + + // rotate our direction according to our angles + dir = (dir[0] * cosa - dir[1] * sina, + dir[0] * sina + dir[1] * cosa, + 0); + + // make the length 127 + dir = VectorNormalize(dir) * 127; + + // invert the second component as the engine requires this + dir = (dir[0], 0-dir[1], 0); + } + + // 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(); + } + + // move! + self botMovement(int(dir[0]), int(dir[1])); +} + /* Bot moves towards the point */ @@ -517,82 +577,15 @@ 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;; data.i+=0.05) { wait 0.05; waittillframeend; - move_To = self.bot.moveTo; - angles = self GetPlayerAngles(); - dir = (0, 0, 0); - - if (DistanceSquared(self.origin, move_To) >= 49) - { - cosa = cos(0-angles[1]); - sina = sin(0-angles[1]); - - // get the direction - dir = move_To - self.origin; - - // rotate our direction according to our angles - dir = (dir[0] * cosa - dir[1] * sina, - dir[0] * sina + dir[1] * cosa, - 0); - - // make the length 127 - dir = VectorNormalize(dir) * 127; - - // invert the second component as the engine requires this - dir = (dir[0], 0-dir[1], 0); - } - - // 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(); - } - - // move! - self botMovement(int(dir[0]), int(dir[1])); + self doBotMovement_loop(data); } } @@ -615,6 +608,33 @@ watchHoldBreath() } } +/* + Throws back frag grenades +*/ +grenade_danager_loop() +{ + myEye = self getEye(); + for (i = level.bots_fragList.count-1; i >= 0; i--) + { + frag = level.bots_fragList.data[i]; + + if (level.teamBased && frag.team == self.team) + continue; + + if (lengthSquared(frag.velocity) > 10000) + continue; + + if(DistanceSquared(self.origin, frag.origin) > 20000) + continue; + + if (!bulletTracePassed( myEye, frag.origin, false, frag.grenade )) + continue; + + self thread frag(); + break; + } +} + /* Throws back frag grenades */ @@ -642,29 +662,69 @@ grenade_danager() if (!getDvarInt("bots_play_nade")) continue; - myEye = self getEye(); - for (i = level.bots_fragList.count-1; i >= 0; i--) - { - frag = level.bots_fragList.data[i]; - - if (level.teamBased && frag.team == self.team) - continue; - - if (lengthSquared(frag.velocity) > 10000) - continue; - - if(DistanceSquared(self.origin, frag.origin) > 20000) - continue; - - if (!bulletTracePassed( myEye, frag.origin, false, frag.grenade )) - continue; - - self thread frag(); - break; - } + self grenade_danager_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() +{ + 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. */ @@ -681,59 +741,8 @@ stance() if(self.bot.isfrozen || self IsUsingRemote()) 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(); } } @@ -901,6 +910,220 @@ 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 GetEye(); + 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); + usingRemote = self isUsingRemote(); + ignoreSmoke = isSubStr(self GetCurrentWeapon(), "_thermal"); + vehEnt = undefined; + adsAmount = self PlayerADS(); + adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"]; + + if (usingRemote) + { + if ( isDefined(level.ac130player) && level.ac130player == self ) + vehEnt = level.ac130.planeModel; + if ( isDefined(level.chopper) && isDefined(level.chopper.gunner) && level.chopper.gunner == self ) + vehEnt = level.chopper; + } + + // 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(ignoreSmoke || (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, usingRemote); + } + 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 == 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" || !isReallyAlive(player)) + { + if(isObjDef) + self.bot.targets[key] = undefined; + + continue; + } + + canTargetPlayer = false; + + if (usingRemote) + { + canTargetPlayer = (bulletTracePassed(myEye, player getTagOrigin( "j_head" ), false, vehEnt) + && !player _hasPerk("specialty_blindeye")); + } + else + { + 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) + + && (distanceSquared(PhysicsTrace( myEye, targetHead, false, self ), targetHead) < 0.05 || + distanceSquared(PhysicsTrace( myEye, targetAnkleLeft, false, self ), targetAnkleLeft) < 0.05 || + distanceSquared(PhysicsTrace( myEye, targetAnkleRight, false, self ), targetAnkleRight) < 0.05) + + && (ignoreSmoke || + 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, usingRemote); + } + 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. */ @@ -919,213 +1142,7 @@ target() if(self maps\mp\_flashgrenades::isFlashbanged()) continue; - myEye = self GetEye(); - 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); - usingRemote = self isUsingRemote(); - ignoreSmoke = isSubStr(self GetCurrentWeapon(), "_thermal"); - vehEnt = undefined; - adsAmount = self PlayerADS(); - adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"]; - - if (usingRemote) - { - if ( isDefined(level.ac130player) && level.ac130player == self ) - vehEnt = level.ac130.planeModel; - if ( isDefined(level.chopper) && isDefined(level.chopper.gunner) && level.chopper.gunner == self ) - vehEnt = level.chopper; - } - - // 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(ignoreSmoke || (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, usingRemote); - } - 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 == 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" || !isReallyAlive(player)) - { - if(isObjDef) - self.bot.targets[key] = undefined; - - continue; - } - - canTargetPlayer = false; - - if (usingRemote) - { - canTargetPlayer = (bulletTracePassed(myEye, player getTagOrigin( "j_head" ), false, vehEnt) - && !player _hasPerk("specialty_blindeye")); - } - else - { - 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) - - && (distanceSquared(PhysicsTrace( myEye, targetHead, false, self ), targetHead) < 0.05 || - distanceSquared(PhysicsTrace( myEye, targetAnkleLeft, false, self ), targetAnkleLeft) < 0.05 || - distanceSquared(PhysicsTrace( myEye, targetAnkleRight, false, self ), targetAnkleRight) < 0.05) - - && (ignoreSmoke || - 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, usingRemote); - } - 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(); } } @@ -1184,12 +1201,11 @@ 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) @@ -1201,8 +1217,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"]) @@ -1210,7 +1225,7 @@ watchToLook() if(self getStance() != "stand") continue; - self.bot.jump_time = thetime; + self.bot.jump_time = getTime(); self thread jump(); } else @@ -1218,7 +1233,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; @@ -1255,6 +1270,260 @@ 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; + + usingRemote = self IsUsingRemote(); + curweap = self getCurrentWeapon(); + eyePos = self getEye(); + 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.jav_loc) && !usingRemote) + { + aimpos = self.bot.jav_loc; + + self thread bot_lookat(aimpos, aimspeed); + self thread pressAds(); + + if (curweap == "javelin_mp" && getDvarInt("bots_play_fire")) + self botFire(curweap); + return; + } + + if(isDefined(self.bot.target) && isDefined(self.bot.target.entity)) + { + no_trace_look_time = self.pers["bots"]["skill"]["no_trace_look_time"]; + no_trace_time = self.bot.target.no_trace_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 && !usingRemote) + { + if(isplay) + { + //better room to nade? cook time function with dist? + if(!self.bot.isfraggingafter && !self.bot.issmokingafter && getDvarInt("bots_play_nade")) + { + 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) + { + time = 0.5; + if (nade == "frag_grenade_mp") + time = 2; + + if (isSecondaryGrenade(nade)) + self thread smoke(time); + else + self thread frag(time); + + self notify("kill_goal"); + } + } + } + } + else + { + if (self canAds(dist, curweap)) + { + if (!self.bot.is_cur_sniper || !self.pers["bots"]["behavior"]["quickscope"]) + self thread pressAds(); + } + } + + if (!usingRemote) + self thread bot_lookat(last_pos + (0, 0, self getEyeHeight() + nadeAimOffset), aimspeed); + else + self thread bot_lookat(last_pos, aimspeed); + return; + } + + if (trace_time) + { + if(isplay) + { + aimpos = target getTagOrigin( bone ); + aimpos += offset; + aimpos += aimoffset; + aimpos += (0, 0, nadeAimOffset); + + conedot = getConeDot(aimpos, eyePos, angles); + + if (conedot > 0.999 && lengthsquared(aimoffset) < 0.05) + self thread bot_lookat(aimpos, 0.05); + else + self thread bot_lookat(aimpos, aimspeed, target getVelocity()); + } + else + { + aimpos = target.origin; + aimpos += offset; + aimpos += aimoffset; + aimpos += (0, 0, nadeAimOffset); + + conedot = getConeDot(aimpos, eyePos, angles); + + if (conedot > 0.999 && lengthsquared(aimoffset) < 0.05) + self thread bot_lookat(aimpos, 0.05); + else + self thread bot_lookat(aimpos, aimspeed); + } + + knifeDist = level.bots_maxKnifeDistance; + if((isplay || target.classname == "misc_turret") && !self.bot.isknifingafter && conedot > 0.9 && dist < knifeDist && trace_time > reaction_time && !usingRemote && 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(curweap == "iw5_smaw_mp" && entIsVehicle(self.bot.target.entity) && (!IsDefined( self.stingerStage ) || self.stingerStage != 2)) + return; + + 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(curweap); + + 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); + if (usingRemote) + aimpos = last_pos; + conedot = getConeDot(aimpos, eyePos, angles); + + self thread bot_lookat(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(curweap); + + 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 thread bot_lookat(eyePos + forwardPos, aimspeed); + } + else if (isDefined(self.bot.script_aimpos)) + { + self thread bot_lookat(self.bot.script_aimpos, aimspeed); + } + else if (!usingRemote) + { + 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 thread bot_lookat(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. */ @@ -1273,253 +1542,7 @@ aim() if(!gameFlag( "prematch_done" ) || 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; - - usingRemote = self IsUsingRemote(); - curweap = self getCurrentWeapon(); - eyePos = self getEye(); - 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.jav_loc) && !usingRemote) - { - aimpos = self.bot.jav_loc; - - self thread bot_lookat(aimpos, aimspeed); - self thread pressAds(); - - if (curweap == "javelin_mp" && getDvarInt("bots_play_fire")) - self botFire(curweap); - continue; - } - - if(isDefined(self.bot.target) && isDefined(self.bot.target.entity)) - { - no_trace_look_time = self.pers["bots"]["skill"]["no_trace_look_time"]; - no_trace_time = self.bot.target.no_trace_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 && !usingRemote) - { - if(isplay) - { - //better room to nade? cook time function with dist? - if(!self.bot.isfraggingafter && !self.bot.issmokingafter && getDvarInt("bots_play_nade")) - { - 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) - { - time = 0.5; - if (nade == "frag_grenade_mp") - time = 2; - - if (isSecondaryGrenade(nade)) - self thread smoke(time); - else - self thread frag(time); - - self notify("kill_goal"); - } - } - } - } - else - { - if (self canAds(dist, curweap)) - { - if (!self.bot.is_cur_sniper || !self.pers["bots"]["behavior"]["quickscope"]) - self thread pressAds(); - } - } - - if (!usingRemote) - self thread bot_lookat(last_pos + (0, 0, self getEyeHeight() + nadeAimOffset), aimspeed); - else - self thread bot_lookat(last_pos, aimspeed); - continue; - } - - if (trace_time) - { - if(isplay) - { - aimpos = target getTagOrigin( bone ); - aimpos += offset; - aimpos += aimoffset; - aimpos += (0, 0, nadeAimOffset); - - conedot = getConeDot(aimpos, eyePos, angles); - - if (conedot > 0.999 && lengthsquared(aimoffset) < 0.05) - self thread bot_lookat(aimpos, 0.05); - else - self thread bot_lookat(aimpos, aimspeed, target getVelocity()); - } - else - { - aimpos = target.origin; - aimpos += offset; - aimpos += aimoffset; - aimpos += (0, 0, nadeAimOffset); - - conedot = getConeDot(aimpos, eyePos, angles); - - if (conedot > 0.999 && lengthsquared(aimoffset) < 0.05) - self thread bot_lookat(aimpos, 0.05); - else - self thread bot_lookat(aimpos, aimspeed); - } - - knifeDist = level.bots_maxKnifeDistance; - if((isplay || target.classname == "misc_turret") && !self.bot.isknifingafter && conedot > 0.9 && dist < knifeDist && trace_time > reaction_time && !usingRemote && 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(curweap == "iw5_smaw_mp" && entIsVehicle(self.bot.target.entity) && (!IsDefined( self.stingerStage ) || self.stingerStage != 2)) - continue; - - 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(curweap); - - 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); - if (usingRemote) - aimpos = last_pos; - conedot = getConeDot(aimpos, eyePos, angles); - - self thread bot_lookat(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(curweap); - - 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 thread bot_lookat(eyePos + forwardPos, aimspeed); - } - else if (isDefined(self.bot.script_aimpos)) - { - self thread bot_lookat(self.bot.script_aimpos, aimspeed); - } - else if (!usingRemote) - { - 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 thread bot_lookat(lookat + (0, 0, self getEyeHeight()), aimspeed); - } + self aim_loop(); } } @@ -1645,6 +1668,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)) || isDefined(self.bot.jav_loc)); + if(hasTarget) + { + curweap = self getCurrentWeapon(); + + if(isDefined(self.bot.jav_loc) || entIsVehicle(self.bot.target.entity) || 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. */ @@ -1676,88 +1788,7 @@ walk() continue; } - hasTarget = ((isDefined(self.bot.target) && isDefined(self.bot.target.entity)) || isDefined(self.bot.jav_loc)); - if(hasTarget) - { - curweap = self getCurrentWeapon(); - - if(isDefined(self.bot.jav_loc) || entIsVehicle(self.bot.target.entity) || 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(); } } @@ -1889,12 +1920,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 @@ -1904,9 +1935,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) { @@ -1930,7 +1959,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; @@ -1940,7 +1969,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"); } @@ -1976,6 +2005,7 @@ movetowards(goal) self botMoveTo(randomDir); wait stucks; + self stand(); } lastOri = self.origin; diff --git a/maps/mp/bots/_bot_script.gsc b/maps/mp/bots/_bot_script.gsc index 4250823..3c13267 100644 --- a/maps/mp/bots/_bot_script.gsc +++ b/maps/mp/bots/_bot_script.gsc @@ -1168,9 +1168,7 @@ classWatch() wait 0.5; - class = self chooseRandomClass(); - - 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)) @@ -1249,9 +1247,7 @@ difficulty() for(;;) { - rankVar = GetDvarInt("bots_skill"); - - if(rankVar != 9) + if(GetDvarInt("bots_skill") != 9) { switch(self.pers["bots"]["skill"]["base"]) { @@ -2026,6 +2022,30 @@ follow_target() } } +/* + Used so that variables are free'd (in gsc, loops retain their variables they create, eats up child0 vars) +*/ +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. */ @@ -2044,23 +2064,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(); } } @@ -2122,6 +2126,41 @@ CampAtSpot(origin, anglePos) self notify("kill_camp_bot"); } +/* + Loop +*/ +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 == self) + continue; + + if(!isReallyAlive(player)) + continue; + + if (player.team != self.team) + continue; + + if (DistanceSquared(player.origin, self.origin) > distSq) + continue; + + follows[follows.size] = player; + } + toFollow = random(follows); + follows = undefined; + + if (!isDefined(toFollow)) + return; + + self thread killFollowAfterTime(randomIntRange(10,20)); + self followPlayer(toFollow); +} + /* Bot logic for bot determining to follow another player. */ @@ -2143,33 +2182,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 == self) - continue; - - if(!isReallyAlive(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(); } } @@ -2246,6 +2259,110 @@ followPlayer(who) self notify("kill_follow_bot"); } +/* + Loop +*/ +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 HasBotJavelinLocation() || self HasScriptAimPos()) + return; + + if(self BotIsFrozen()) + return; + + if (self IsBotFragging() || self IsBotSmoking()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self IsUsingRemote()) + return; + + if (self InLastStand() && !self InFinalStand()) + 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 */ @@ -2255,110 +2372,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 HasBotJavelinLocation() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if (self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self IsUsingRemote()) - continue; - - if (self InLastStand() && !self InFinalStand()) - 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); } } +/* + Loop +*/ +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("flare_mp")) + nade = "flare_mp"; + if (self GetAmmoCount("c4_mp")) + nade = "c4_mp"; + if (self GetAmmoCount("bouncingbetty_mp")) + nade = "bouncingbetty_mp"; + if (self GetAmmoCount("portable_radar_mp")) + nade = "portable_radar_mp"; + if (self GetAmmoCount("scrambler_mp")) + nade = "scrambler_mp"; + if (self GetAmmoCount("trophy_mp")) + nade = "trophy_mp"; + + if (!isDefined(nade)) + return; + + if (self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos()) + return; + + if(self BotIsFrozen()) + return; + + if(self IsBotFragging() || self IsBotSmoking()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self IsUsingRemote()) + return; + + if (self inLastStand() && !self _hasPerk("specialty_laststandoffhand") && !self inFinalStand()) + return; + + 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; + + self botThrowGrenade(nade, 0.05); + + self ClearScriptAimPos(); + self BotStopMoving(false); +} + /* Bots thinking of using claymores and TIs */ @@ -2368,111 +2495,118 @@ 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("flare_mp")) - nade = "flare_mp"; - if (self GetAmmoCount("c4_mp")) - nade = "c4_mp"; - if (self GetAmmoCount("bouncingbetty_mp")) - nade = "bouncingbetty_mp"; - if (self GetAmmoCount("portable_radar_mp")) - nade = "portable_radar_mp"; - if (self GetAmmoCount("scrambler_mp")) - nade = "scrambler_mp"; - if (self GetAmmoCount("trophy_mp")) - nade = "trophy_mp"; - - if (!isDefined(nade)) - continue; - - if (self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if(self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self IsUsingRemote()) - continue; - - if (self inLastStand() && !self _hasPerk("specialty_laststandoffhand") && !self inFinalStand()) - continue; - - 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; - - self botThrowGrenade(nade, 0.05); - - self ClearScriptAimPos(); - self BotStopMoving(false); + self bot_use_equipment_think_loop(data); } } +/* + Loop +*/ +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 HasBotJavelinLocation() || self HasScriptAimPos()) + return; + + if(self BotIsFrozen()) + return; + + if(self IsBotFragging() || self IsBotSmoking()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self IsUsingRemote()) + return; + + if (self inLastStand() && !self _hasPerk("specialty_laststandoffhand") && !self inFinalStand()) + 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 */ @@ -2482,109 +2616,42 @@ 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 HasBotJavelinLocation() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if(self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self IsUsingRemote()) - continue; - - if (self inLastStand() && !self _hasPerk("specialty_laststandoffhand") && !self inFinalStand()) - 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); } } +/* + Bots play mw2 +*/ +bot_watch_think_mw2_loop() +{ + tube = self getValidTube(); + if (!isDefined(tube)) + { + if (self GetAmmoCount("iw5_smaw_mp")) + tube = "iw5_smaw_mp"; + else if (self GetAmmoCount("rpg_mp")) + tube = "rpg_mp"; + else if (self GetAmmoCount("xm25_mp")) + tube = "xm25_mp"; + else + return; + } + + if (self GetCurrentWeapon() == tube) + return; + + if (randomInt(100) > self.pers["bots"]["behavior"]["nade"]) + return; + + self ChangeToWeapon(tube); +} + /* Bots play mw2 */ @@ -2613,28 +2680,63 @@ bot_watch_think_mw2() if (self HasThreat()) continue; - tube = self getValidTube(); - if (!isDefined(tube)) + self bot_watch_think_mw2_loop(); + } +} + +/* + Loop +*/ +bot_watch_riot_weapons_loop() +{ + threat = self GetThreat(); + dist = DistanceSquared(threat.origin, self.origin); + curWeap = self GetCurrentWeapon(); + + if (randomInt(2)) + { + nade = self getValidGrenade(); + + if (!isDefined(nade)) + return; + + if (dist <= level.bots_minGrenadeDistance || dist >= level.bots_maxGrenadeDistance) + return; + + if (randomInt(100) > self.pers["bots"]["behavior"]["nade"]) + return; + + self botThrowGrenade(nade); + } + else + { + if (randomInt(100) > self.pers["bots"]["behavior"]["switch"] * 10) + return; + + weaponslist = self getweaponslistall(); + weap = ""; + while(weaponslist.size) { - if (self GetAmmoCount("iw5_smaw_mp")) - tube = "iw5_smaw_mp"; - else if (self GetAmmoCount("rpg_mp")) - tube = "rpg_mp"; - else if (self GetAmmoCount("xm25_mp")) - tube = "xm25_mp"; - else + weapon = weaponslist[randomInt(weaponslist.size)]; + weaponslist = array_remove(weaponslist, weapon); + + if(!self getAmmoCount(weapon)) continue; + + if (!isWeaponPrimary(weapon)) + continue; + + if(curWeap == weapon || weapon == "none" || weapon == "" || weapon == "javelin_mp" || weapon == "stinger_mp") + continue; + + weap = weapon; + break; } - - if (self GetCurrentWeapon() == tube) - continue; - - chance = self.pers["bots"]["behavior"]["nade"]; - - if (randomInt(100) > chance) - continue; - - self ChangeToWeapon(tube); + + if(weap == "") + return; + + self ChangeToWeapon(weap); } } @@ -2669,56 +2771,105 @@ bot_watch_riot_weapons() if (!self.hasRiotShieldEquipped) continue; - threat = self GetThreat(); - dist = DistanceSquared(threat.origin, self.origin); - curWeap = self GetCurrentWeapon(); + self bot_watch_riot_weapons_loop(); + } +} - if (randomInt(2)) +/* + Loop +*/ +bot_jav_loc_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; + } + + if (!self GetAmmoCount("javelin_mp")) + return; + + if (self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos()) + return; + + if(self BotIsFrozen()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self IsUsingRemote()) + return; + + if (self InLastStand() && !self InFinalStand()) + return; + + if (self isEMPed()) + return; + + loc = undefined; + + if (!self nearAnyOfWaypoints(128, getWaypointsOfType("javelin"))) + { + javWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("javelin"), 1024))); + + if (!isDefined(javWp) || self HasScriptGoal() || self.bot_lock_goal) { - nade = self getValidGrenade(); + traceForward = self maps\mp\_javelin::EyeTraceForward(); + if (!isDefined(traceForward)) + return; - if (!isDefined(nade)) - continue; + loc = traceForward[0]; + if (self maps\mp\_javelin::TargetPointTooClose(loc)) + return; - if (dist <= level.bots_minGrenadeDistance || dist >= level.bots_maxGrenadeDistance) - continue; + if (!bulletTracePassed(self.origin + (0, 0, 5), self.origin + (0, 0, 2048), false, self)) + return; - if (randomInt(100) > self.pers["bots"]["behavior"]["nade"]) - continue; - - self botThrowGrenade(nade); + if (!bulletTracePassed(loc + (0, 0, 5), loc + (0, 0, 2048), false, self)) + return; } else { - if (randomInt(100) > self.pers["bots"]["behavior"]["switch"] * 10) - continue; + self SetScriptGoal(javWp.origin, 16); - weaponslist = self getweaponslistall(); - weap = ""; - while(weaponslist.size) - { - weapon = weaponslist[randomInt(weaponslist.size)]; - weaponslist = array_remove(weaponslist, weapon); - - if(!self getAmmoCount(weapon)) - continue; - - if (!isWeaponPrimary(weapon)) - continue; - - if(curWeap == weapon || weapon == "none" || weapon == "" || weapon == "javelin_mp" || weapon == "stinger_mp") - continue; - - weap = weapon; - break; - } - - if(weap == "") - continue; - - self ChangeToWeapon(weap); + 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 + { + javWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("javelin"))); + loc = javWp.jav_point; + } + + if (!isDefined(loc)) + return; + + self SetBotJavelinLocation(loc); + + if (self changeToWeapon("javelin_mp")) + { + self waittill_any_timeout(10, "missile_fire", "weapon_change"); + } + + self ClearBotJavelinLocation(); } /* @@ -2730,143 +2881,203 @@ bot_jav_loc_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; - } - - if (!self GetAmmoCount("javelin_mp")) - continue; - - if (self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self IsUsingRemote()) - continue; - - if (self InLastStand() && !self InFinalStand()) - continue; - - if (self isEMPed()) - continue; - - loc = undefined; - - if (!self nearAnyOfWaypoints(128, getWaypointsOfType("javelin"))) - { - javWp = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("javelin"), 1024))); - - if (!isDefined(javWp) || self HasScriptGoal() || self.bot_lock_goal) - { - traceForward = self maps\mp\_javelin::EyeTraceForward(); - if (!isDefined(traceForward)) - continue; - - loc = traceForward[0]; - if (self maps\mp\_javelin::TargetPointTooClose(loc)) - 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; - } - else - { - self SetScriptGoal(javWp.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 - { - javWp = getWaypointForIndex(self getNearestWaypointOfWaypoints(getWaypointsOfType("javelin"))); - loc = javWp.jav_point; - } - - if (!isDefined(loc)) - continue; - - self SetBotJavelinLocation(loc); - - if (self changeToWeapon("javelin_mp")) - { - self waittill_any_timeout(10, "missile_fire", "weapon_change"); - } - - self ClearBotJavelinLocation(); + self bot_jav_loc_think_loop(data); } } /* - Bots thinking of targeting equipment, c4, claymores and TIs + Loop */ -bot_equipment_kill_think() +bot_equipment_kill_think_loop() { - self endon( "death" ); - self endon( "disconnect" ); - level endon ( "game_ended" ); - myteam = self.pers[ "team" ]; + hasSitrep = self _HasPerk( "specialty_detectexplosive" ); + grenades = getEntArray( "grenade", "classname" ); + myEye = self getEye(); + myAngles = self getPlayerAngles(); + dist = 512*512; + target = undefined; - for ( ;; ) + // check legacy nades, c4 and claymores + for ( i = 0; i < grenades.size; i++ ) { - wait( RandomIntRange( 1, 3 ) ); + item = grenades[i]; + + if (!isDefined(item)) + continue; + + if ( !IsDefined( item.name ) ) + continue; + + if (item.name != "c4_mp" && item.name != "claymore_mp") + continue; + + if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) + continue; + + if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; - if(self HasScriptEnemy()) - continue; - - if(self.pers["bots"]["skill"]["base"] <= 1) - continue; - - hasSitrep = self _HasPerk( "specialty_detectexplosive" ); - grenades = getEntArray( "grenade", "classname" ); - myEye = self getEye(); - myAngles = self getPlayerAngles(); - dist = 512*512; - target = undefined; - - // check legacy nades, c4 and claymores - for ( i = 0; i < grenades.size; i++ ) + if ( DistanceSquared( item.origin, self.origin ) < dist ) { - item = grenades[i]; + target = item; + break; + } + } + + grenades = undefined; // clean up, reduces child1 vars + + // check for player stuff, tis and throphys and radars + if ( !IsDefined( target ) ) + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[i]; + + if ( player == self ) + continue; + + if(!isDefined(player.team)) + continue; + + if ( level.teamBased && player.team == myteam ) + continue; + + // check for thorphys + if (isDefined(player.trophyArray)) + { + for (h = 0; h < player.trophyArray.size; h++) + { + item = player.trophyArray[h]; + + if (!isDefined(item)) + continue; + + if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) + { + if (item.damageTaken >= item.maxHealth) + continue; + } + + if (!isDefined(item.bots)) + item.bots = 0; + + if (item.bots >= 2) + continue; + + if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + // check for ti + if (!isDefined(target)) + { + for (h = 0; h < 1; h++) + { + item = player.setSpawnPoint; + if(!isDefined(item)) + continue; + + if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) + { + if (item.damageTaken >= item.maxHealth) + continue; + } + + if(!isDefined(item.bots)) + item.bots = 0; + + if(item.bots >= 2) + continue; + + if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + // check for radar + if (!isDefined(target)) + { + for (h = 0; h < 1; h++) + { + item = player.deployedPortableRadar; + if(!isDefined(item)) + continue; + + if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) + { + if (item.damageTaken >= item.maxHealth) + continue; + } + + if(!isDefined(item.bots)) + item.bots = 0; + + if(item.bots >= 2) + continue; + + if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + if (isDefined(target)) + break; + } + } + + // check for ims + if ( !IsDefined( target ) ) + { + imsKeys = getArrayKeys(level.ims); + + for (i = 0; i < imsKeys.size; i++) + { + item = level.ims[imsKeys[i]]; if (!isDefined(item)) continue; - if ( !IsDefined( item.name ) ) - continue; - - if (item.name != "c4_mp" && item.name != "claymore_mp") - continue; + if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) + { + if (item.damageTaken >= item.maxHealth) + continue; + } if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) continue; @@ -2884,304 +3095,163 @@ bot_equipment_kill_think() } } - grenades = undefined; // clean up, reduces child1 vars - - // check for player stuff, tis and throphys and radars - if ( !IsDefined( target ) ) + imsKeys = undefined; + } + + // check for vest + if ( !IsDefined( target ) ) + { + for (i = 0; i < level.vest_boxes.size; i++) { - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[i]; + item = level.vest_boxes[i]; - if ( player == self ) - continue; - - if(!isDefined(player.team)) - continue; - - if ( level.teamBased && player.team == myteam ) - continue; - - // check for thorphys - if (isDefined(player.trophyArray)) - { - for (h = 0; h < player.trophyArray.size; h++) - { - item = player.trophyArray[h]; - - if (!isDefined(item)) - continue; - - if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) - { - if (item.damageTaken >= item.maxHealth) - continue; - } - - if (!isDefined(item.bots)) - item.bots = 0; - - if (item.bots >= 2) - continue; - - if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - // check for ti - if (!isDefined(target)) - { - for (h = 0; h < 1; h++) - { - item = player.setSpawnPoint; - if(!isDefined(item)) - continue; - - if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) - { - if (item.damageTaken >= item.maxHealth) - continue; - } - - if(!isDefined(item.bots)) - item.bots = 0; - - if(item.bots >= 2) - continue; - - if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - // check for radar - if (!isDefined(target)) - { - for (h = 0; h < 1; h++) - { - item = player.deployedPortableRadar; - if(!isDefined(item)) - continue; - - if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) - { - if (item.damageTaken >= item.maxHealth) - continue; - } - - if(!isDefined(item.bots)) - item.bots = 0; - - if(item.bots >= 2) - continue; - - if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - if (isDefined(target)) - break; - } - } - - // check for ims - if ( !IsDefined( target ) ) - { - imsKeys = getArrayKeys(level.ims); - - for (i = 0; i < imsKeys.size; i++) - { - item = level.ims[imsKeys[i]]; - - if (!isDefined(item)) - continue; - - if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) - { - if (item.damageTaken >= item.maxHealth) - continue; - } - - if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) - continue; - - if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - - imsKeys = undefined; - } - - // check for vest - if ( !IsDefined( target ) ) - { - for (i = 0; i < level.vest_boxes.size; i++) - { - item = level.vest_boxes[i]; - - if (!isDefined(item)) - continue; - - if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) - { - if (item.damageTaken >= item.maxHealth) - continue; - } - - if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) - continue; - - if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - // check for jammers - if ( !IsDefined( target ) ) - { - for (i = 0; i < level.scramblers.size; i++) - { - item = level.scramblers[i]; - - if (!isDefined(item)) - continue; - - if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) - { - if (item.damageTaken >= item.maxHealth) - continue; - } - - if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) - continue; - - if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - // check for mines - if ( !IsDefined( target ) ) - { - for (i = 0; i < level.mines.size; i++) - { - item = level.mines[i]; - - if (!isDefined(item)) - continue; - - if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) - { - if (item.damageTaken >= item.maxHealth) - continue; - } - - if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) - continue; - - if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - if ( !IsDefined( target ) ) - continue; - - // must be ti - if (isDefined(target.enemyTrigger) && !self HasScriptGoal() && !self.bot_lock_goal) - { - self SetScriptGoal(target.origin, 64); - self thread bot_inc_bots(target, true); - self thread bots_watch_touch_obj( target ); - - path = self waittill_any_return("bad_path", "goal", "new_goal"); - - if (path != "new_goal") - self ClearScriptGoal(); - - if (path != "goal" || !isDefined(target)) + if (!isDefined(item)) continue; - if (randomInt(100) < self.pers["bots"]["behavior"]["camp"] * 8) + if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) { - self thread killCampAfterTime(randomIntRange(10,20)); - self thread killCampAfterEntGone(target); - self CampAtSpot(target.origin, target.origin + (0, 0, 42)); + if (item.damageTaken >= item.maxHealth) + continue; } - - self thread BotPressUse(); - - continue; - } - self SetScriptEnemy( target ); - self bot_equipment_attack(target); - self ClearScriptEnemy(); + if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) + continue; + + if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + // check for jammers + if ( !IsDefined( target ) ) + { + for (i = 0; i < level.scramblers.size; i++) + { + item = level.scramblers[i]; + + if (!isDefined(item)) + continue; + + if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) + { + if (item.damageTaken >= item.maxHealth) + continue; + } + + if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) + continue; + + if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + // check for mines + if ( !IsDefined( target ) ) + { + for (i = 0; i < level.mines.size; i++) + { + item = level.mines[i]; + + if (!isDefined(item)) + continue; + + if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) + { + if (item.damageTaken >= item.maxHealth) + continue; + } + + if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) + continue; + + if(!hasSitrep && !bulletTracePassed(myEye, item.origin, false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + if ( !IsDefined( target ) ) + return; + + // must be ti + if (isDefined(target.enemyTrigger) && !self HasScriptGoal() && !self.bot_lock_goal) + { + self SetScriptGoal(target.origin, 64); + self thread bot_inc_bots(target, true); + self thread bots_watch_touch_obj( target ); + + path = self waittill_any_return("bad_path", "goal", "new_goal"); + + if (path != "new_goal") + self ClearScriptGoal(); + + if (path != "goal" || !isDefined(target)) + return; + + if (randomInt(100) < self.pers["bots"]["behavior"]["camp"] * 8) + { + self thread killCampAfterTime(randomIntRange(10,20)); + self thread killCampAfterEntGone(target); + self CampAtSpot(target.origin, target.origin + (0, 0, 42)); + } + + self thread BotPressUse(); + + return; + } + + self SetScriptEnemy( target ); + self bot_equipment_attack(target); + self ClearScriptEnemy(); +} + +/* + Bots thinking of targeting equipment, c4, claymores and TIs +*/ +bot_equipment_kill_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon ( "game_ended" ); + + for ( ;; ) + { + wait( RandomIntRange( 1, 3 ) ); + + if(self HasScriptEnemy()) + continue; + + if(self.pers["bots"]["skill"]["base"] <= 1) + continue; + + self bot_equipment_kill_think_loop(); } } @@ -3209,6 +3279,100 @@ bot_equipment_attack(equ) } } +/* + Loop +*/ +bot_listen_to_steps_loop() +{ + dist = level.bots_listenDist; + if(self _hasPerk("specialty_selectivehearing")) + dist *= 1.4; + + dist *= dist; + + heard = undefined; + for(i = level.players.size-1 ; i >= 0; i--) + { + player = level.players[i]; + + if(player == self) + continue; + if(level.teamBased && self.team == player.team) + continue; + if(player.sessionstate != "playing") + continue; + if(!isReallyAlive(player)) + continue; + + if( lengthsquared( player getVelocity() ) < 20000 ) + continue; + + if( distanceSquared(player.origin, self.origin) > dist ) + continue; + + if( player _hasPerk("specialty_quieter")) + continue; + + heard = player; + break; + } + + hasHeartbeat = (isSubStr(self GetCurrentWeapon(), "_heartbeat") && ((!self IsEMPed() && !self isNuked()) || self _hasPerk("specialty_spygame"))); + heartbeatDist = 350*350; + + if(!IsDefined(heard) && hasHeartbeat) + { + for(i = level.players.size-1 ; i >= 0; i--) + { + player = level.players[i]; + + if(player == self) + continue; + if(level.teamBased && self.team == player.team) + continue; + if(player.sessionstate != "playing") + continue; + if(!isReallyAlive(player)) + continue; + + if (player _hasPerk("specialty_heartbreaker")) + continue; + + if (distanceSquared(player.origin, self.origin) > heartbeatDist) + continue; + + if (GetConeDot(player.origin, self.origin, self GetPlayerAngles()) < 0.6) + continue; + + heard = player; + break; + } + } + + if (!isDefined(heard)) + { + if (self _hasPerk("specialty_revenge") && isDefined(self.lastKilledBy)) + heard = self.lastKilledBy; + } + + if(!IsDefined(heard)) + return; + + if(bulletTracePassed(self getEye(), 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(); +} + /* Bots will listen to foot steps and target nearby targets */ @@ -3224,93 +3388,73 @@ bot_listen_to_steps() if(self.pers["bots"]["skill"]["base"] < 3) continue; - dist = level.bots_listenDist; - if(self _hasPerk("specialty_selectivehearing")) - dist *= 1.4; + self bot_listen_to_steps_loop(); + } +} + +/* + Loop +*/ +bot_uav_think_loop() +{ + hasAssPro = self _hasPerk("specialty_spygame"); + if (!hasAssPro) + { + if (self isEMPed() || self.bot_isScrambled || self isNuked()) + return; + + if ((level.teamBased && level.activeCounterUAVs[level.otherTeam[self.team]]) || (!level.teamBased && self.isRadarBlocked)) + return; + } + + hasRadar = ((level.teamBased && level.activeUAVs[self.team]) || (!level.teamBased && level.activeUAVs[self.guid])); + if( level.hardcoreMode && !hasRadar ) + return; - dist *= dist; + dist = self.pers["bots"]["skill"]["help_dist"]; + dist *= dist * 8; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[i]; - heard = undefined; - for(i = level.players.size-1 ; i >= 0; i--) + if(player == self) + continue; + + if(!isDefined(player.team)) + continue; + + if(player.sessionstate != "playing") + continue; + + if(level.teambased && player.team == self.team) + continue; + + if(!isReallyAlive(player)) + continue; + + distFromPlayer = DistanceSquared(self.origin, player.origin); + if(distFromPlayer > dist) + continue; + + if((!isSubStr(player getCurrentWeapon(), "_silencer") && player.bots_firing) || (hasRadar && !player _hasPerk("specialty_coldblooded")) || player maps\mp\perks\_perkfunctions::isPainted() || player.bot_isInRadar) { - player = level.players[i]; + distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; + if (distFromPlayer < distSq && bulletTracePassed(self getEye(), player getTagOrigin( "j_spineupper" ), false, player)) + { + self SetAttacker(player); + } - if(player == self) - continue; - if(level.teamBased && self.team == player.team) - continue; - if(player.sessionstate != "playing") - continue; - if(!isReallyAlive(player)) - continue; + if (!self HasScriptGoal() && !self.bot_lock_goal) + { + self thread stop_go_target_on_death(player); + self SetScriptGoal( player.origin, 128 ); - if( lengthsquared( player getVelocity() ) < 20000 ) - continue; - - if( distanceSquared(player.origin, self.origin) > dist ) - continue; - - if( player _hasPerk("specialty_quieter")) - continue; - - heard = player; + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + } break; } - - hasHeartbeat = (isSubStr(self GetCurrentWeapon(), "_heartbeat") && ((!self IsEMPed() && !self isNuked()) || self _hasPerk("specialty_spygame"))); - heartbeatDist = 350*350; - - if(!IsDefined(heard) && hasHeartbeat) - { - for(i = level.players.size-1 ; i >= 0; i--) - { - player = level.players[i]; - - if(player == self) - continue; - if(level.teamBased && self.team == player.team) - continue; - if(player.sessionstate != "playing") - continue; - if(!isReallyAlive(player)) - continue; - - if (player _hasPerk("specialty_heartbreaker")) - continue; - - if (distanceSquared(player.origin, self.origin) > heartbeatDist) - continue; - - if (GetConeDot(player.origin, self.origin, self GetPlayerAngles()) < 0.6) - continue; - - heard = player; - break; - } - } - - if (!isDefined(heard)) - { - if (self _hasPerk("specialty_revenge") && isDefined(self.lastKilledBy)) - heard = self.lastKilledBy; - } - - if(!IsDefined(heard)) - continue; - - if(bulletTracePassed(self getEye(), 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(); } } @@ -3329,65 +3473,7 @@ bot_uav_think() if(self.pers["bots"]["skill"]["base"] <= 1) continue; - hasAssPro = self _hasPerk("specialty_spygame"); - if (!hasAssPro) - { - if (self isEMPed() || self.bot_isScrambled || self isNuked()) - continue; - - if ((level.teamBased && level.activeCounterUAVs[level.otherTeam[self.team]]) || (!level.teamBased && self.isRadarBlocked)) - continue; - } - - hasRadar = ((level.teamBased && level.activeUAVs[self.team]) || (!level.teamBased && level.activeUAVs[self.guid])); - if( level.hardcoreMode && !hasRadar ) - 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 == self) - continue; - - if(!isDefined(player.team)) - continue; - - if(player.sessionstate != "playing") - continue; - - if(level.teambased && player.team == self.team) - continue; - - if(!isReallyAlive(player)) - continue; - - distFromPlayer = DistanceSquared(self.origin, player.origin); - if(distFromPlayer > dist) - continue; - - if((!isSubStr(player getCurrentWeapon(), "_silencer") && player.bots_firing) || (hasRadar && !player _hasPerk("specialty_coldblooded")) || player maps\mp\perks\_perkfunctions::isPainted() || player.bot_isInRadar) - { - distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; - if (distFromPlayer < distSq && bulletTracePassed(self getEye(), 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(); } } @@ -3485,6 +3571,97 @@ bot_turret_attack( enemy ) } } +/* + Loops +*/ +bot_turret_think_loop() +{ + myteam = self.pers[ "team" ]; + turretsKeys = getArrayKeys(level.turrets); + if ( turretsKeys.size == 0 ) + { + wait( randomintrange( 3, 5 ) ); + return; + } + + if(self.pers["bots"]["skill"]["base"] <= 1) + return; + + if (self HasScriptEnemy() || self IsUsingRemote()) + return; + + myEye = self GetEye(); + turret = undefined; + for (i = turretsKeys.size - 1; i >= 0; i--) + { + tempTurret = level.turrets[turretsKeys[i]]; + + if (!isDefined(tempTurret)) + continue; + + if(tempTurret.damageTaken >= tempTurret.maxHealth) + continue; + if (isDefined(tempTurret.carriedBy)) + continue; + if(isDefined(tempTurret.owner) && tempTurret.owner == self) + continue; + if(tempTurret.team == self.pers["team"] && level.teamBased) + continue; + if(!bulletTracePassed(myEye, tempTurret.origin + (0, 0, 15), false, tempTurret)) + continue; + + turret = tempTurret; + } + turretsKeys = undefined; + + if (!isDefined(turret)) + return; + + forward = AnglesToForward( turret.angles ); + forward = VectorNormalize( forward ); + + delta = self.origin - turret.origin; + delta = VectorNormalize( delta ); + + dot = VectorDot( forward, delta ); + + facing = true; + if ( dot < 0.342 ) // cos 70 degrees + facing = false; + if ( turret isStunned() ) + facing = false; + if(self _hasPerk("specialty_blindeye")) + facing = false; + if (!isDefined(turret.sentryType) || turret.sentryType == "sam_turret") + facing = false; + + if ( facing && !BulletTracePassed( myEye, turret.origin + ( 0, 0, 15 ), false, turret ) ) + return; + + if ( !IsDefined( turret.bots ) ) + turret.bots = 0; + if ( turret.bots >= 2 ) + return; + + if(!facing && !self HasScriptGoal() && !self.bot_lock_goal) + { + self SetScriptGoal(turret.origin, 32); + self thread bot_inc_bots(turret, true); + self thread turret_death_monitor( turret ); + self thread bots_watch_touch_obj( turret ); + + if(self waittill_any_return("bad_path", "goal", "new_goal") != "new_goal") + self ClearScriptGoal(); + } + + if(!isDefined(turret)) + return; + + self SetScriptEnemy( turret, (0, 0, 25) ); + self bot_turret_attack(turret); + self ClearScriptEnemy(); +} + /* Bots will think when to target a turret */ @@ -3494,98 +3671,77 @@ bot_turret_think() self endon( "disconnect" ); level endon ( "game_ended" ); - myteam = self.pers[ "team" ]; - for ( ;; ) { wait( 1 ); - turretsKeys = getArrayKeys(level.turrets); - if ( turretsKeys.size == 0 ) - { - wait( randomintrange( 3, 5 ) ); - continue; - } - - if(self.pers["bots"]["skill"]["base"] <= 1) - continue; - - if (self HasScriptEnemy() || self IsUsingRemote()) - continue; - - myEye = self GetEye(); - turret = undefined; - for (i = turretsKeys.size - 1; i >= 0; i--) - { - tempTurret = level.turrets[turretsKeys[i]]; - - if (!isDefined(tempTurret)) - continue; - - if(tempTurret.damageTaken >= tempTurret.maxHealth) - continue; - if (isDefined(tempTurret.carriedBy)) - continue; - if(isDefined(tempTurret.owner) && tempTurret.owner == self) - continue; - if(tempTurret.team == self.pers["team"] && level.teamBased) - continue; - if(!bulletTracePassed(myEye, tempTurret.origin + (0, 0, 15), false, tempTurret)) - continue; - - turret = tempTurret; - } - turretsKeys = undefined; - - if (!isDefined(turret)) - continue; - - forward = AnglesToForward( turret.angles ); - forward = VectorNormalize( forward ); - - delta = self.origin - turret.origin; - delta = VectorNormalize( delta ); - - dot = VectorDot( forward, delta ); - - facing = true; - if ( dot < 0.342 ) // cos 70 degrees - facing = false; - if ( turret isStunned() ) - facing = false; - if(self _hasPerk("specialty_blindeye")) - facing = false; - if (!isDefined(turret.sentryType) || turret.sentryType == "sam_turret") - facing = false; - - if ( facing && !BulletTracePassed( myEye, turret.origin + ( 0, 0, 15 ), false, turret ) ) - continue; - - if ( !IsDefined( turret.bots ) ) - turret.bots = 0; - if ( turret.bots >= 2 ) - continue; - - if(!facing && !self HasScriptGoal() && !self.bot_lock_goal) - { - self SetScriptGoal(turret.origin, 32); - self thread bot_inc_bots(turret, true); - self thread turret_death_monitor( turret ); - self thread bots_watch_touch_obj( turret ); - - if(self waittill_any_return("bad_path", "goal", "new_goal") != "new_goal") - self ClearScriptGoal(); - } - - if(!isDefined(turret)) - continue; - - self SetScriptEnemy( turret, (0, 0, 25) ); - self bot_turret_attack(turret); - self ClearScriptEnemy(); + self bot_turret_think_loop(); } } +/* + Loops +*/ +bot_box_think_loop() +{ + box = undefined; + myteam = self.pers[ "team" ]; + + dist = 2048*2048; + + for ( i = 0; i < level.vest_boxes.size; i++ ) + { + item = level.vest_boxes[i]; + + if (!isDefined(item)) + continue; + + if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) + { + if (item.damageTaken >= item.maxHealth) + continue; + } + + if ( !IsDefined( item.owner ) || (level.teamBased && item.owner.team != myteam) || (!level.teamBased && item.owner != self)) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + box = item; + break; + } + } + + if (!isDefined(box)) + return; + + self.bot_lock_goal = true; + + radius = GetDvarFloat( "player_useRadius" ) / 2; + self SetScriptGoal(box.origin, radius); + self thread bot_inc_bots(box, true); + self thread bots_watch_touch_obj(box); + + path = self waittill_any_return("bad_path", "goal", "new_goal"); + + self.bot_lock_goal = false; + + if (path != "new_goal") + self ClearScriptGoal(); + + if (path != "goal" || !isDefined(box) || DistanceSquared(self.origin, box.origin) > radius*radius) + return; + + self BotFreezeControls(true); + + waitTime = 2.25; + + self thread BotPressUse(waitTime); + wait waitTime; + + self BotFreezeControls(false); +} + /* Bots think to use boxes */ @@ -3595,8 +3751,6 @@ bot_box_think() self endon( "disconnect" ); level endon("game_ended"); - myteam = self.pers[ "team" ]; - for ( ;; ) { wait( randomintrange( 3, 5 ) ); @@ -3616,62 +3770,57 @@ bot_box_think() if (self inLastStand()) continue; - box = undefined; + self bot_box_think_loop(); + } +} - dist = 2048*2048; +/* + Loops +*/ +bot_watch_stuck_on_crate_loop() +{ + crates = getEntArray( "care_package", "targetname" ); + if ( crates.size == 0 ) + return; - for ( i = 0; i < level.vest_boxes.size; i++ ) + crate = undefined; + for (i = crates.size - 1; i >= 0; i--) + { + tempCrate = crates[i]; + + if (!isDefined(tempCrate)) + continue; + + if (isDefined(tempCrate.owner) && isDefined(tempCrate.bomb)) { - item = level.vest_boxes[i]; - - if (!isDefined(item)) + if (tempCrate.owner == self) continue; - if (isDefined(item.damageTaken) && isDefined(item.maxHealth)) - { - if (item.damageTaken >= item.maxHealth) - continue; - } - - if ( !IsDefined( item.owner ) || (level.teamBased && item.owner.team != myteam) || (!level.teamBased && item.owner != self)) + if (level.teamBased && tempCrate.owner.team == self.team) + continue; + + if (self _hasPerk("specialty_detectexplosive")) continue; - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - box = item; - break; - } } - if (!isDefined(box)) + if (!isDefined(tempCrate.doingPhysics) || tempCrate.doingPhysics) continue; - self.bot_lock_goal = true; - - radius = GetDvarFloat( "player_useRadius" ) / 2; - self SetScriptGoal(box.origin, radius); - self thread bot_inc_bots(box, true); - self thread bots_watch_touch_obj(box); - - path = self waittill_any_return("bad_path", "goal", "new_goal"); - - self.bot_lock_goal = false; - - if (path != "new_goal") - self ClearScriptGoal(); - - if (path != "goal" || !isDefined(box) || DistanceSquared(self.origin, box.origin) > radius*radius) + if (isDefined(crate) && DistanceSquared(crate.origin, self.origin) < DistanceSquared(tempCrate.origin, self.origin)) continue; - self BotFreezeControls(true); - - waitTime = 2.25; - - self thread BotPressUse(waitTime); - wait waitTime; - - self BotFreezeControls(false); + crate = tempCrate; } + + if (!isDefined(crate)) + return; + + radius = GetDvarFloat( "player_useRadius" ); + if (DistanceSquared(crate.origin, self.origin) > radius * radius) + return; + + self.bot_stuck_on_carepackage = crate; + self notify("crate_physics_done"); } /* @@ -3690,9 +3839,46 @@ bot_watch_stuck_on_crate() if (self HasThreat()) continue; + self bot_watch_stuck_on_crate_loop(); + } +} + +/* + Loops +*/ +bot_crate_think_loop(data) +{ + myteam = self.pers[ "team" ]; + ret = "crate_physics_done"; + if(data.first) + data.first = false; + else + ret = self waittill_any_timeout( randomintrange( 3, 5 ), "crate_physics_done" ); + + crate = self.bot_stuck_on_carepackage; + self.bot_stuck_on_carepackage = undefined; + if (!isDefined(crate)) + { + if ( RandomInt( 100 ) < 20 && ret != "crate_physics_done" ) + return; + + if ( self HasScriptGoal() || self.bot_lock_goal ) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if(self IsUsingRemote() || self BotIsFrozen()) + return; + + if (self inLastStand()) + return; + crates = getEntArray( "care_package", "targetname" ); if ( crates.size == 0 ) - continue; + return; + + wantsClosest = randomint(2); crate = undefined; for (i = crates.size - 1; i >= 0; i--) @@ -3717,22 +3903,62 @@ bot_watch_stuck_on_crate() if (!isDefined(tempCrate.doingPhysics) || tempCrate.doingPhysics) continue; - if (isDefined(crate) && DistanceSquared(crate.origin, self.origin) < DistanceSquared(tempCrate.origin, self.origin)) + if ( !IsDefined( tempCrate.bots ) ) + tempCrate.bots = 0; + + if ( tempCrate.bots >= 3 ) continue; + if (isDefined(crate)) + { + if (wantsClosest) + { + if (DistanceSquared(crate.origin, self.origin) < DistanceSquared(tempCrate.origin, self.origin)) + continue; + } + else + { + if (maps\mp\killstreaks\_killstreaks::getStreakCost(crate.crateType) > maps\mp\killstreaks\_killstreaks::getStreakCost(tempCrate.crateType)) + continue; + } + } + crate = tempCrate; } + crates = undefined; + if (!isDefined(crate)) - continue; + return; - radius = GetDvarFloat( "player_useRadius" ); - if (DistanceSquared(crate.origin, self.origin) > radius * radius) - continue; + self.bot_lock_goal = true; - self.bot_stuck_on_carepackage = crate; - self notify("crate_physics_done"); + radius = GetDvarFloat( "player_useRadius" ) - 16; + self SetScriptGoal(crate.origin, radius); + self thread bot_inc_bots(crate, true); + self thread bots_watch_touch_obj(crate); + + path = self waittill_any_return("bad_path", "goal", "new_goal"); + + self.bot_lock_goal = false; + + if (path != "new_goal") + self ClearScriptGoal(); + + if (path != "goal" || !isDefined(crate) || DistanceSquared(self.origin, crate.origin) > radius*radius) + return; } + + self BotFreezeControls(true); + + waitTime = 3.25; + if (isDefined(crate.owner) && crate.owner == self) + waitTime = 0.75; + + self thread BotPressUse(waitTime); + wait waitTime; + + self BotFreezeControls(false); } /* @@ -3744,125 +3970,79 @@ bot_crate_think() self endon( "disconnect" ); level endon("game_ended"); - myteam = self.pers[ "team" ]; - - first = true; + data = spawnStruct(); + data.first = true; for ( ;; ) { - ret = "crate_physics_done"; - if(first) - first = false; - else - ret = self waittill_any_timeout( randomintrange( 3, 5 ), "crate_physics_done" ); - - crate = self.bot_stuck_on_carepackage; - self.bot_stuck_on_carepackage = undefined; - if (!isDefined(crate)) - { - if ( RandomInt( 100 ) < 20 && ret != "crate_physics_done" ) - continue; - - if ( self HasScriptGoal() || self.bot_lock_goal ) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if(self IsUsingRemote() || self BotIsFrozen()) - continue; - - if (self inLastStand()) - continue; - - crates = getEntArray( "care_package", "targetname" ); - if ( crates.size == 0 ) - continue; - - wantsClosest = randomint(2); - - crate = undefined; - for (i = crates.size - 1; i >= 0; i--) - { - tempCrate = crates[i]; - - if (!isDefined(tempCrate)) - continue; - - if (isDefined(tempCrate.owner) && isDefined(tempCrate.bomb)) - { - if (tempCrate.owner == self) - continue; - - if (level.teamBased && tempCrate.owner.team == self.team) - continue; - - if (self _hasPerk("specialty_detectexplosive")) - continue; - } - - if (!isDefined(tempCrate.doingPhysics) || tempCrate.doingPhysics) - continue; - - if ( !IsDefined( tempCrate.bots ) ) - tempCrate.bots = 0; - - if ( tempCrate.bots >= 3 ) - continue; - - if (isDefined(crate)) - { - if (wantsClosest) - { - if (DistanceSquared(crate.origin, self.origin) < DistanceSquared(tempCrate.origin, self.origin)) - continue; - } - else - { - if (maps\mp\killstreaks\_killstreaks::getStreakCost(crate.crateType) > maps\mp\killstreaks\_killstreaks::getStreakCost(tempCrate.crateType)) - continue; - } - } - - crate = tempCrate; - } - - crates = undefined; - - if (!isDefined(crate)) - continue; - - self.bot_lock_goal = true; - - radius = GetDvarFloat( "player_useRadius" ) - 16; - self SetScriptGoal(crate.origin, radius); - self thread bot_inc_bots(crate, true); - self thread bots_watch_touch_obj(crate); - - path = self waittill_any_return("bad_path", "goal", "new_goal"); - - self.bot_lock_goal = false; - - if (path != "new_goal") - self ClearScriptGoal(); - - if (path != "goal" || !isDefined(crate) || DistanceSquared(self.origin, crate.origin) > radius*radius) - continue; - } - - self BotFreezeControls(true); - - waitTime = 3.25; - if (isDefined(crate.owner) && crate.owner == self) - waitTime = 0.75; - - self thread BotPressUse(waitTime); - wait waitTime; - - self BotFreezeControls(false); + self bot_crate_think_loop(data); } } +/* + Reload cancels +*/ +doReloadCancel_loop() +{ + ret = self waittill_any_return("reload", "weapon_change"); + + if(self BotIsFrozen()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self IsUsingRemote()) + return; + + if (self InLastStand() && !self InFinalStand()) + return; + + curWeap = self GetCurrentWeapon(); + + if (!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::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 */ @@ -3873,64 +4053,95 @@ doReloadCancel() for (;;) { - ret = self waittill_any_return("reload", "weapon_change"); + self doReloadCancel_loop(); + } +} - if(self BotIsFrozen()) +/* + Loops +*/ +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()) + return; + + if (self IsUsingRemote()) + return; + + if (self InLastStand() && !self InFinalStand()) + return; + + curWeap = self GetCurrentWeapon(); + hasTarget = self hasThreat(); + if(hasTarget) + { + threat = self getThreat(); + rocketAmmo = self getRocketAmmo(); + + if(entIsVehicle(threat) && isDefined(rocketAmmo)) + { + if (curWeap != rocketAmmo) + self thread ChangeToWeapon(rocketAmmo); + return; + } + } + + if (self HasBotJavelinLocation() && self GetAmmoCount("javelin_mp")) + { + if (curWeap != "javelin_mp") + self thread ChangeToWeapon("javelin_mp"); + + return; + } + + if (data.first) + { + data.first = false; + + if(randomInt(100) > self.pers["bots"]["behavior"]["initswitch"]) + return; + } + else + { + if(curWeap != "none" && self getAmmoCount(curWeap) && curWeap != "stinger_mp" && curWeap != "javelin_mp") + { + if(randomInt(100) > self.pers["bots"]["behavior"]["switch"]) + return; + + if(hasTarget) + return; + } + } + + weaponslist = self getweaponslistall(); + weap = ""; + while(weaponslist.size) + { + weapon = weaponslist[randomInt(weaponslist.size)]; + weaponslist = array_remove(weaponslist, weapon); + + if(!self getAmmoCount(weapon)) + continue; + + if (!isWeaponPrimary(weapon)) continue; - if(self isDefusing() || self isPlanting()) + if(curWeap == weapon || weapon == "none" || weapon == "" || weapon == "javelin_mp" || weapon == "stinger_mp") continue; - - if (self IsUsingRemote()) - continue; - - if (self InLastStand() && !self InFinalStand()) - continue; - - curWeap = self GetCurrentWeapon(); - - if (!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::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); } /* @@ -3942,93 +4153,77 @@ 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()) - continue; - - if (self IsUsingRemote()) - continue; - - if (self InLastStand() && !self InFinalStand()) - continue; - - curWeap = self GetCurrentWeapon(); - hasTarget = self hasThreat(); - if(hasTarget) - { - threat = self getThreat(); - rocketAmmo = self getRocketAmmo(); - - if(entIsVehicle(threat) && isDefined(rocketAmmo)) - { - if (curWeap != rocketAmmo) - self thread ChangeToWeapon(rocketAmmo); - continue; - } - } - - if (self HasBotJavelinLocation() && self GetAmmoCount("javelin_mp")) - { - if (curWeap != "javelin_mp") - self thread ChangeToWeapon("javelin_mp"); - - continue; - } - - if (first) - { - first = false; - - if(randomInt(100) > self.pers["bots"]["behavior"]["initswitch"]) - continue; - } - else - { - if(curWeap != "none" && self getAmmoCount(curWeap) && curWeap != "stinger_mp" && curWeap != "javelin_mp") - { - if(randomInt(100) > self.pers["bots"]["behavior"]["switch"]) - continue; - - if(hasTarget) - continue; - } - } - - weaponslist = self getweaponslistall(); - weap = ""; - while(weaponslist.size) - { - weapon = weaponslist[randomInt(weaponslist.size)]; - weaponslist = array_remove(weaponslist, weapon); - - if(!self getAmmoCount(weapon)) - continue; - - if (!isWeaponPrimary(weapon)) - continue; - - if(curWeap == weapon || weapon == "none" || weapon == "" || weapon == "javelin_mp" || weapon == "stinger_mp") - continue; - - weap = weapon; - break; - } - - if(weap == "") - continue; - - self thread ChangeToWeapon(weap); + self bot_weapon_think_loop(data); } } +/* + Bots think when to target vehicles +*/ +bot_target_vehicle_loop() +{ + rocketAmmo = self getRocketAmmo(); + + if (isDefined(rocketAmmo) && rocketAmmo == "javelin_mp" && self isEMPed()) + return; + + targets = maps\mp\_stinger::GetTargetList(); + + if (!targets.size) + return; + + lockOnAmmo = self getLockonAmmo(); + myEye = self GetEye(); + target = undefined; + for (i = targets.size - 1; i >= 0; i--) + { + tempTarget = targets[i]; + + if (isPlayer(tempTarget)) + continue; + + if (isDefined(tempTarget.owner) && tempTarget.owner == self) + continue; + + if(!bulletTracePassed( myEye, tempTarget.origin, false, tempTarget )) + continue; + + if (tempTarget.health <= 0) + continue; + + if (isDefined(tempTarget.damageTaken) && isDefined(tempTarget.maxHealth)) + { + if (tempTarget.damageTaken >= tempTarget.maxHealth) + continue; + } + + if (tempTarget.classname != "script_vehicle" && !isDefined(lockOnAmmo)) + continue; + + target = tempTarget; + } + targets = undefined; + + if (!isDefined(target)) + return; + + if (target.model != "vehicle_ugv_talon_mp") + { + if(!isDefined(rocketAmmo) && self BotGetRandom() < 90) + return; + } + + self SetScriptEnemy( target, (0, 0, 0) ); + self bot_attack_vehicle( target ); + self ClearScriptEnemy(); + self notify("bot_force_check_switch"); +} + /* Bots think when to target vehicles */ @@ -4050,61 +4245,7 @@ bot_target_vehicle() if (self IsUsingRemote()) continue; - rocketAmmo = self getRocketAmmo(); - - if (isDefined(rocketAmmo) && rocketAmmo == "javelin_mp" && self isEMPed()) - continue; - - targets = maps\mp\_stinger::GetTargetList(); - - if (!targets.size) - continue; - - lockOnAmmo = self getLockonAmmo(); - myEye = self GetEye(); - target = undefined; - for (i = targets.size - 1; i >= 0; i--) - { - tempTarget = targets[i]; - - if (isPlayer(tempTarget)) - continue; - - if (isDefined(tempTarget.owner) && tempTarget.owner == self) - continue; - - if(!bulletTracePassed( myEye, tempTarget.origin, false, tempTarget )) - continue; - - if (tempTarget.health <= 0) - continue; - - if (isDefined(tempTarget.damageTaken) && isDefined(tempTarget.maxHealth)) - { - if (tempTarget.damageTaken >= tempTarget.maxHealth) - continue; - } - - if (tempTarget.classname != "script_vehicle" && !isDefined(lockOnAmmo)) - continue; - - target = tempTarget; - } - targets = undefined; - - if (!isDefined(target)) - continue; - - if (target.model != "vehicle_ugv_talon_mp") - { - if(!isDefined(rocketAmmo) && self BotGetRandom() < 90) - continue; - } - - self SetScriptEnemy( target, (0, 0, 0) ); - self bot_attack_vehicle( target ); - self ClearScriptEnemy(); - self notify("bot_force_check_switch"); + self bot_target_vehicle_loop(); } } @@ -4185,6 +4326,353 @@ clear_remote_on_death(isac130) self ClearUsingRemote(); } +/* + Bots think to use killstreaks +*/ +bot_killstreak_think_loop(data) +{ + if (!isDefined(data.doFastContinue)) + { + wait randomIntRange(1, 3); + } + + if(self BotIsFrozen()) + return; + + if(self HasThreat() || self HasBotJavelinLocation()) + return; + + if(self isDefusing() || self isPlanting()) + return; + + if (self isEMPed() || self isNuked()) + return; + + if (self IsUsingRemote()) + return; + + if (self InLastStand() && !self InFinalStand()) + return; + + useableStreaks = []; + + if (!isDefined(data.doFastContinue)) + { + if (self.pers["killstreaks"][0].available) + useableStreaks[useableStreaks.size] = 0; + + if (self.pers["killstreaks"][1].available && self.streakType != "specialist") + useableStreaks[useableStreaks.size] = 1; + + if (self.pers["killstreaks"][2].available && self.streakType != "specialist") + useableStreaks[useableStreaks.size] = 2; + + if (self.pers["killstreaks"][3].available && self.streakType != "specialist") + useableStreaks[useableStreaks.size] = 3; + } + else + { + useableStreaks[0] = data.doFastContinue; + data.doFastContinue = undefined; + } + + if (!useableStreaks.size) + return; + + self.killstreakIndexWeapon = random(useableStreaks); + streakName = self.pers["killstreaks"][self.killstreakIndexWeapon].streakName; + + if (level.inGracePeriod && maps\mp\killstreaks\_killstreaks::deadlyKillstreak(streakName)) + return; + + ksWeap = maps\mp\killstreaks\_killstreaks::getKillstreakWeapon( streakName ); + curWeap = self GetCurrentWeapon(); + + if (curWeap == "none" || !isWeaponPrimary(curWeap)) + curWeap = self GetLastWeapon(); + + lifeId = self.pers["killstreaks"][0].lifeId; + if (!isDefined(lifeId)) + lifeId = -1; + + print (self.name + " " + streakName); + + if (maps\mp\killstreaks\_killstreaks::isRideKillstreak(streakName) || maps\mp\killstreaks\_killstreaks::isCarryKillstreak(streakName) || streakName == "sam_turret" || streakName == "remote_mg_turret") + { + if (self inLastStand()) + return; + + if (lifeId == self.deaths && !self HasScriptGoal() && !self.bot_lock_goal && maps\mp\killstreaks\_killstreaks::isRideKillstreak(streakName) && !self nearAnyOfWaypoints(128, getWaypointsOfType("camp"))) + { + campSpot = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("camp"), 1024))); + + if (isDefined(campSpot)) + { + self SetScriptGoal(campSpot.origin, 16); + + if (self waittill_any_return("new_goal", "goal", "bad_path") != "new_goal") + self ClearScriptGoal(); + + data.doFastContinue = self.killstreakIndexWeapon; + return; + } + } + + if (streakName == "sentry" || streakName == "sam_turret" || streakName == "remote_mg_turret" || streakName == "ims") + { + if (self HasScriptAimPos()) + return; + + myEye = self GetEye(); + angles = self GetPlayerAngles(); + + forwardTrace = bulletTrace(myEye, myEye + AnglesToForward(angles)*1024, false, self); + placeNot = "place_sentry"; + cancelNot = "cancel_sentry"; + distCheck = 1000*1000; + switch (streakName) + { + case "sam_turret": + forwardTrace = bulletTrace(myEye, myEye + (0, 0, 1024), false, self); + break; + case "remote_mg_turret": + placeNot = "place_turret"; + cancelNot = "cancel_turret"; + break; + case "ims": + forwardTrace = bulletTrace(myEye, myEye + AnglesToForward(angles)*128, false, self); + placeNot = "place_ims"; + cancelNot = "cancel_ims"; + distCheck = 100*100; + break; + } + + if (DistanceSquared(self.origin, forwardTrace["position"]) < distCheck && self.pers["bots"]["skill"]["base"] > 3) + return; + + self BotStopMoving(true); + self SetScriptAimPos(forwardTrace["position"]); + + if (!self changeToWeapon(ksWeap)) + { + self BotStopMoving(false); + self ClearScriptAimPos(); + return; + } + + wait 1; + self notify(placeNot); + wait 0.05; + self notify(cancelNot); + wait 0.5; + + self thread changeToWeapon(curWeap); + + self BotStopMoving(false); + self ClearScriptAimPos(); + } + else if (streakName == "predator_missile" && false) + { + location = self getKillstreakTargetLocation(); + + if(!isDefined(location)) + return; + + self setUsingRemote( "remotemissile" ); + self thread clear_remote_on_death(); + self BotStopMoving(true); + + if (!self changeToWeapon(ksWeap)) + { + self ClearUsingRemote(); + self notify("bot_clear_remote_on_death"); + self BotStopMoving(false); + return; + } + + wait 1; + self notify("bot_clear_remote_on_death"); + self BotStopMoving(false); + + if (self isEMPed()) + { + self ClearUsingRemote(); + self thread changeToWeapon(curWeap); + return; + } + + self BotFreezeControls(true); + + self maps\mp\killstreaks\_killstreaks::usedKillstreak( "predator_missile", true ); + //self maps\mp\killstreaks\_killstreaks::shuffleKillStreaksFILO( "predator_missile" ); + self maps\mp\killstreaks\_killstreaks::giveOwnedKillstreakItem(); + + rocket = MagicBullet( "remotemissile_projectile_mp", self.origin + (0.0,0.0,7000.0 - (self.pers["bots"]["skill"]["base"] * 400)), location, self ); + rocket.lifeId = lifeId; + rocket.type = "remote"; + + rocket thread maps\mp\gametypes\_weapons::AddMissileToSightTraces( self.pers["team"] ); + //rocket thread maps\mp\killstreaks\_remotemissile::handleDamage(); + thread maps\mp\killstreaks\_remotemissile::MissileEyes( self, rocket ); + + self waittill( "stopped_using_remote" ); + + wait 1; + self BotFreezeControls(false); + self thread changeToWeapon(curWeap); + } + else if (streakName == "ac130" && false) + { + if ( isDefined( level.ac130player ) || level.ac130InUse ) + return; + + self BotStopMoving(true); + self changeToWeapon(ksWeap); + self BotStopMoving(false); + + wait 3; + + if ( !isDefined( level.ac130player ) || level.ac130player != self ) + self thread changeToWeapon(curWeap); + } + } + else + { + if (streakName == "escort_airdrop" || streakName == "airdrop_juggernaut_recon" || streakName == "airdrop_trap" || streakName == "airdrop_juggernaut" || streakName == "airdrop_remote_tank" || streakName == "airdrop_sentry_minigun" || streakName == "airdrop_assault") + { + if (self HasScriptAimPos()) + return; + + if( ( level.littleBirds.size >= 4 || level.fauxVehicleCount >= 4 ) && !isSubStr( toLower( streakName ), "juggernaut" ) ) + return; + + if( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + 1 >= maxVehiclesAllowed() ) + return; + + if( IsSubStr( toLower( streakName ), "escort_airdrop" ) && isDefined( level.chopper ) ) + return; + + if(!bulletTracePassed(self.origin, self.origin+(0,0,2048), false, self) && self.pers["bots"]["skill"]["base"] > 3) + return; + + myEye = self GetEye(); + angles = self GetPlayerAngles(); + + forwardTrace = bulletTrace(myEye, myEye + AnglesToForward(angles)*256, false, self); + + if (DistanceSquared(self.origin, forwardTrace["position"]) < 96*96 && self.pers["bots"]["skill"]["base"] > 3) + return; + + if (!bulletTracePassed(forwardTrace["position"], forwardTrace["position"]+(0,0,2048), false, self) && self.pers["bots"]["skill"]["base"] > 3) + return; + + self BotStopMoving(true); + self SetScriptAimPos(forwardTrace["position"]); + + if (!self changeToWeapon(ksWeap)) + { + self BotStopMoving(false); + self ClearScriptAimPos(); + return; + } + + self thread fire_current_weapon(); + + ret = self waittill_any_timeout( 5, "grenade_fire" ); + + self notify("stop_firing_weapon"); + self thread changeToWeapon(curWeap); + + if (ret == "timeout") + { + self BotStopMoving(false); + self ClearScriptAimPos(); + return; + } + + if (randomInt(100) < 80 && !self HasScriptGoal() && !self.bot_lock_goal) + self waittill_any_timeout( 15, "crate_physics_done", "new_goal" ); + + self BotStopMoving(false); + self ClearScriptAimPos(); + } + else + { + if (streakName == "nuke" && isDefined( level.nukeIncoming )) + return; + + if (streakName == "counter_uav" && self.pers["bots"]["skill"]["base"] > 3 && ((level.teamBased && level.activeCounterUAVs[self.team]) || (!level.teamBased && level.activeCounterUAVs[self.guid]))) + return; + + if ((streakName == "uav" || streakName == "uav_support" || streakName == "triple_uav") && self.pers["bots"]["skill"]["base"] > 3 && ((level.teamBased && (level.activeUAVs[self.team] || level.activeCounterUAVs[level.otherTeam[self.team]])) || (!level.teamBased && (level.activeUAVs[self.guid] || self.isRadarBlocked)))) + return; + + if (streakName == "emp" && self.pers["bots"]["skill"]["base"] > 3 && ((level.teamBased && level.teamEMPed[level.otherTeam[self.team]]) || (!level.teamBased && isDefined( level.empPlayer )))) + return; + + if (streakName == "littlebird_flock" || streakName == "helicopter" || streakName == "helicopter_flares" || streakName == "littlebird_support") + { + numIncomingVehicles = 1; + if (streakName == "littlebird_flock") + numIncomingVehicles = 5; + + if (currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + numIncomingVehicles >= maxVehiclesAllowed()) + return; + + if (streakName == "helicopter" && isDefined( level.chopper )) + return; + + if (streakName == "littlebird_support" && (isDefined( level.littlebirdGuard ) || maps\mp\killstreaks\_helicopter::exceededMaxLittlebirds( "littlebird_support" ))) + return; + } + + location = undefined; + directionYaw = undefined; + switch (streakName) + { + case "littlebird_flock": + case "stealth_airstrike": + case "precision_airstrike": + location = self getKillstreakTargetLocation(); + directionYaw = randomInt(360); + + if (!isDefined(location)) + return; + case "helicopter": + case "helicopter_flares": + case "littlebird_support": + case "uav": + case "uav_support": + case "counter_uav": + case "triple_uav": + case "nuke": + case "emp": + self BotStopMoving(true); + + if (self changeToWeapon(ksWeap)) + { + wait 1; + + if (isDefined(location)) + { + self BotFreezeControls(true); + + self notify( "confirm_location", location, directionYaw ); + wait 1; + + self BotFreezeControls(false); + } + + self thread changeToWeapon(curWeap); + } + + self BotStopMoving(false); + break; + } + } + } +} + /* Bots think to use killstreaks */ @@ -4194,353 +4682,55 @@ bot_killstreak_think() self endon("death"); level endon("game_ended"); - doFastContinue = undefined; + data = spawnStruct(); + data.doFastContinue = undefined; for (;;) { - if (!isDefined(doFastContinue)) - { - wait randomIntRange(1, 3); - } - - if(self BotIsFrozen()) - continue; - - if(self HasThreat() || self HasBotJavelinLocation()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self isEMPed() || self isNuked()) - continue; - - if (self IsUsingRemote()) - continue; - - if (self InLastStand() && !self InFinalStand()) - continue; - - useableStreaks = []; - - if (!isDefined(doFastContinue)) - { - if (self.pers["killstreaks"][0].available) - useableStreaks[useableStreaks.size] = 0; - - if (self.pers["killstreaks"][1].available && self.streakType != "specialist") - useableStreaks[useableStreaks.size] = 1; - - if (self.pers["killstreaks"][2].available && self.streakType != "specialist") - useableStreaks[useableStreaks.size] = 2; - - if (self.pers["killstreaks"][3].available && self.streakType != "specialist") - useableStreaks[useableStreaks.size] = 3; - } - else - { - useableStreaks[0] = doFastContinue; - doFastContinue = undefined; - } - - if (!useableStreaks.size) - continue; - - self.killstreakIndexWeapon = random(useableStreaks); - streakName = self.pers["killstreaks"][self.killstreakIndexWeapon].streakName; - - if (level.inGracePeriod && maps\mp\killstreaks\_killstreaks::deadlyKillstreak(streakName)) - continue; - - ksWeap = maps\mp\killstreaks\_killstreaks::getKillstreakWeapon( streakName ); - curWeap = self GetCurrentWeapon(); - - if (curWeap == "none" || !isWeaponPrimary(curWeap)) - curWeap = self GetLastWeapon(); - - lifeId = self.pers["killstreaks"][0].lifeId; - if (!isDefined(lifeId)) - lifeId = -1; - - print (self.name + " " + streakName); - - if (maps\mp\killstreaks\_killstreaks::isRideKillstreak(streakName) || maps\mp\killstreaks\_killstreaks::isCarryKillstreak(streakName) || streakName == "sam_turret" || streakName == "remote_mg_turret") - { - if (self inLastStand()) - continue; - - if (lifeId == self.deaths && !self HasScriptGoal() && !self.bot_lock_goal && maps\mp\killstreaks\_killstreaks::isRideKillstreak(streakName) && !self nearAnyOfWaypoints(128, getWaypointsOfType("camp"))) - { - campSpot = getWaypointForIndex(random(self waypointsNear(getWaypointsOfType("camp"), 1024))); - - if (isDefined(campSpot)) - { - self SetScriptGoal(campSpot.origin, 16); - - if (self waittill_any_return("new_goal", "goal", "bad_path") != "new_goal") - self ClearScriptGoal(); - - doFastContinue = self.killstreakIndexWeapon; - continue; - } - } - - if (streakName == "sentry" || streakName == "sam_turret" || streakName == "remote_mg_turret" || streakName == "ims") - { - if (self HasScriptAimPos()) - continue; - - myEye = self GetEye(); - angles = self GetPlayerAngles(); - - forwardTrace = bulletTrace(myEye, myEye + AnglesToForward(angles)*1024, false, self); - placeNot = "place_sentry"; - cancelNot = "cancel_sentry"; - distCheck = 1000*1000; - switch (streakName) - { - case "sam_turret": - forwardTrace = bulletTrace(myEye, myEye + (0, 0, 1024), false, self); - break; - case "remote_mg_turret": - placeNot = "place_turret"; - cancelNot = "cancel_turret"; - break; - case "ims": - forwardTrace = bulletTrace(myEye, myEye + AnglesToForward(angles)*128, false, self); - placeNot = "place_ims"; - cancelNot = "cancel_ims"; - distCheck = 100*100; - break; - } - - if (DistanceSquared(self.origin, forwardTrace["position"]) < distCheck && self.pers["bots"]["skill"]["base"] > 3) - continue; - - self BotStopMoving(true); - self SetScriptAimPos(forwardTrace["position"]); - - if (!self changeToWeapon(ksWeap)) - { - self BotStopMoving(false); - self ClearScriptAimPos(); - continue; - } - - wait 1; - self notify(placeNot); - wait 0.05; - self notify(cancelNot); - wait 0.5; - - self thread changeToWeapon(curWeap); - - self BotStopMoving(false); - self ClearScriptAimPos(); - } - else if (streakName == "predator_missile" && false) - { - location = self getKillstreakTargetLocation(); - - if(!isDefined(location)) - continue; - - self setUsingRemote( "remotemissile" ); - self thread clear_remote_on_death(); - self BotStopMoving(true); - - if (!self changeToWeapon(ksWeap)) - { - self ClearUsingRemote(); - self notify("bot_clear_remote_on_death"); - self BotStopMoving(false); - continue; - } - - wait 1; - self notify("bot_clear_remote_on_death"); - self BotStopMoving(false); - - if (self isEMPed()) - { - self ClearUsingRemote(); - self thread changeToWeapon(curWeap); - continue; - } - - self BotFreezeControls(true); - - self maps\mp\killstreaks\_killstreaks::usedKillstreak( "predator_missile", true ); - //self maps\mp\killstreaks\_killstreaks::shuffleKillStreaksFILO( "predator_missile" ); - self maps\mp\killstreaks\_killstreaks::giveOwnedKillstreakItem(); - - rocket = MagicBullet( "remotemissile_projectile_mp", self.origin + (0.0,0.0,7000.0 - (self.pers["bots"]["skill"]["base"] * 400)), location, self ); - rocket.lifeId = lifeId; - rocket.type = "remote"; - - rocket thread maps\mp\gametypes\_weapons::AddMissileToSightTraces( self.pers["team"] ); - //rocket thread maps\mp\killstreaks\_remotemissile::handleDamage(); - thread maps\mp\killstreaks\_remotemissile::MissileEyes( self, rocket ); - - self waittill( "stopped_using_remote" ); - - wait 1; - self BotFreezeControls(false); - self thread changeToWeapon(curWeap); - } - else if (streakName == "ac130" && false) - { - if ( isDefined( level.ac130player ) || level.ac130InUse ) - continue; - - self BotStopMoving(true); - self changeToWeapon(ksWeap); - self BotStopMoving(false); - - wait 3; - - if ( !isDefined( level.ac130player ) || level.ac130player != self ) - self thread changeToWeapon(curWeap); - } - } - else - { - if (streakName == "escort_airdrop" || streakName == "airdrop_juggernaut_recon" || streakName == "airdrop_trap" || streakName == "airdrop_juggernaut" || streakName == "airdrop_remote_tank" || streakName == "airdrop_sentry_minigun" || streakName == "airdrop_assault") - { - if (self HasScriptAimPos()) - continue; - - if( ( level.littleBirds.size >= 4 || level.fauxVehicleCount >= 4 ) && !isSubStr( toLower( streakName ), "juggernaut" ) ) - continue; - - if( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + 1 >= maxVehiclesAllowed() ) - continue; - - if( IsSubStr( toLower( streakName ), "escort_airdrop" ) && isDefined( level.chopper ) ) - continue; - - if(!bulletTracePassed(self.origin, self.origin+(0,0,2048), false, self) && self.pers["bots"]["skill"]["base"] > 3) - continue; - - myEye = self GetEye(); - angles = self GetPlayerAngles(); - - forwardTrace = bulletTrace(myEye, myEye + AnglesToForward(angles)*256, false, self); - - if (DistanceSquared(self.origin, forwardTrace["position"]) < 96*96 && self.pers["bots"]["skill"]["base"] > 3) - continue; - - if (!bulletTracePassed(forwardTrace["position"], forwardTrace["position"]+(0,0,2048), false, self) && self.pers["bots"]["skill"]["base"] > 3) - continue; - - self BotStopMoving(true); - self SetScriptAimPos(forwardTrace["position"]); - - if (!self changeToWeapon(ksWeap)) - { - self BotStopMoving(false); - self ClearScriptAimPos(); - continue; - } - - self thread fire_current_weapon(); - - ret = self waittill_any_timeout( 5, "grenade_fire" ); - - self notify("stop_firing_weapon"); - self thread changeToWeapon(curWeap); - - if (ret == "timeout") - { - self BotStopMoving(false); - self ClearScriptAimPos(); - continue; - } - - if (randomInt(100) < 80 && !self HasScriptGoal() && !self.bot_lock_goal) - self waittill_any_timeout( 15, "crate_physics_done", "new_goal" ); - - self BotStopMoving(false); - self ClearScriptAimPos(); - } - else - { - if (streakName == "nuke" && isDefined( level.nukeIncoming )) - continue; - - if (streakName == "counter_uav" && self.pers["bots"]["skill"]["base"] > 3 && ((level.teamBased && level.activeCounterUAVs[self.team]) || (!level.teamBased && level.activeCounterUAVs[self.guid]))) - continue; - - if ((streakName == "uav" || streakName == "uav_support" || streakName == "triple_uav") && self.pers["bots"]["skill"]["base"] > 3 && ((level.teamBased && (level.activeUAVs[self.team] || level.activeCounterUAVs[level.otherTeam[self.team]])) || (!level.teamBased && (level.activeUAVs[self.guid] || self.isRadarBlocked)))) - continue; - - if (streakName == "emp" && self.pers["bots"]["skill"]["base"] > 3 && ((level.teamBased && level.teamEMPed[level.otherTeam[self.team]]) || (!level.teamBased && isDefined( level.empPlayer )))) - continue; - - if (streakName == "littlebird_flock" || streakName == "helicopter" || streakName == "helicopter_flares" || streakName == "littlebird_support") - { - numIncomingVehicles = 1; - if (streakName == "littlebird_flock") - numIncomingVehicles = 5; - - if (currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + numIncomingVehicles >= maxVehiclesAllowed()) - continue; - - if (streakName == "helicopter" && isDefined( level.chopper )) - continue; - - if (streakName == "littlebird_support" && (isDefined( level.littlebirdGuard ) || maps\mp\killstreaks\_helicopter::exceededMaxLittlebirds( "littlebird_support" ))) - continue; - } - - location = undefined; - directionYaw = undefined; - switch (streakName) - { - case "littlebird_flock": - case "stealth_airstrike": - case "precision_airstrike": - location = self getKillstreakTargetLocation(); - directionYaw = randomInt(360); - - if (!isDefined(location)) - continue; - case "helicopter": - case "helicopter_flares": - case "littlebird_support": - case "uav": - case "uav_support": - case "counter_uav": - case "triple_uav": - case "nuke": - case "emp": - self BotStopMoving(true); - - if (self changeToWeapon(ksWeap)) - { - wait 1; - - if (isDefined(location)) - { - self BotFreezeControls(true); - - self notify( "confirm_location", location, directionYaw ); - wait 1; - - self BotFreezeControls(false); - } - - self thread changeToWeapon(curWeap); - } - - self BotStopMoving(false); - break; - } - } - } + self bot_killstreak_think_loop(data); } } +/* + 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 */ @@ -4552,9 +4742,6 @@ bot_dom_spawn_kill_think() if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 10, 20 ) ); @@ -4565,35 +4752,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(); } } @@ -4619,6 +4778,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 */ @@ -4630,8 +4820,6 @@ bot_dom_def_think() if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - for ( ;; ) { wait( randomintrange( 1, 3 ) ); @@ -4641,30 +4829,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(); } } @@ -4693,6 +4859,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 */ @@ -4704,9 +4962,6 @@ bot_dom_cap_think() if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 12 ) ); @@ -4719,88 +4974,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(); } } @@ -4835,6 +5009,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 */ @@ -4846,9 +5115,6 @@ bot_hq() if ( level.gametype != "koth" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 5 ) ); @@ -4863,92 +5129,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(); } } @@ -5013,6 +5195,773 @@ 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\_gamelogic::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 = 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_coldblooded" )) + 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 +*/ +bot_sab() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon("game_ended"); + + if ( level.gametype != "sab" ) + return; + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if(!isDefined(level.sabBomb)) + continue; + + if(!isDefined(level.bombZones) || !level.bombZones.size) + continue; + + if (self IsPlanting() || self isDefusing()) + continue; + + 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\_gamelogic::getTimeRemaining()/1000; + + if(timeleft >= 90) + return; + + // 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()) + 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; + } + } + + // 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 + { + 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; + } + + // 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; +} + +/* + Bots play sd defenders +*/ +bot_sd_defenders() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon("game_ended"); + + if ( level.gametype != "sd" ) + return; + + if(self.team == game["attackers"]) + return; + + data = spawnStruct(); + data.rand = self BotGetRandom(); + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + 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 IsUsingRemote() || self.bot_lock_goal ) + { + return; + } + + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + //bomb planted + if(level.bombPlanted) + { + if(!isDefined(level.defuseObject)) + return; + + 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; + 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; + } + + timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining()/1000; + timepassed = 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)) + { + //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; + } + + 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()) + 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; +} + +/* + Bots play sd attackers +*/ +bot_sd_attackers() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon("game_ended"); + + if ( level.gametype != "sd" ) + return; + + if(self.team != game["attackers"]) + return; + + data = spawnStruct(); + data.rand = self BotGetRandom(); + data.first = true; + + for ( ;; ) + { + self bot_sd_attackers_loop(data); + } +} + +/* + Bots play capture the flag +*/ +bot_cap_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + myflag = level.teamFlags[myteam]; + myzone = level.capZones[myteam]; + + theirflag = level.teamFlags[otherTeam]; + theirzone = level.capZones[otherTeam]; + + if(!myflag maps\mp\gametypes\_gameobjects::isHome()) + { + carrier = myflag.carrier; + + if(!isDefined(carrier))//someone doesnt has our flag + { + if(!isDefined(theirflag.carrier) && DistanceSquared(self.origin, theirflag.curorigin) < DistanceSquared(self.origin, myflag.curorigin)) //no one has their flag and its closer + self bot_cap_get_flag(theirflag); + else//go get it + self bot_cap_get_flag(myflag); + + return; + } + else + { + if(theirflag maps\mp\gametypes\_gameobjects::isHome() && randomint(100) < 50) + { //take their flag + self bot_cap_get_flag(theirflag); + } + else + { + if(self HasScriptGoal()) + return; + + if(!isDefined(theirzone.bots)) + theirzone.bots = 0; + + origin = theirzone.curorigin; + + if(theirzone.bots > 2 || randomInt(100) < 45) + { + //kill carrier + if(carrier hasPerk( "specialty_coldblooded" )) + return; + + origin = carrier.origin; + + self SetScriptGoal( origin, 64 ); + self thread bot_escort_obj(myflag, carrier); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + self thread bot_inc_bots(theirzone); + + //camp their zone + if(DistanceSquared(origin, self.origin) <= 1024*1024) + { + wait 4; + self notify("bot_inc_bots"); theirzone.bots--; + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_inc_bots(theirzone); + self thread bot_escort_obj(myflag, carrier); + + if(self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + } + } + } + else//our flag is ok + { + if(self isFlagCarrier())//if have flag + { + //go cap + origin = myzone.curorigin; + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 32 ); + + self thread bot_get_obj(myflag); + evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + wait 1; + if (evt != "new_goal") + self ClearScriptGoal(); + self.bot_lock_goal = false; + return; + } + + carrier = theirflag.carrier; + + if(!isDefined(carrier))//if no one has enemy flag + { + self bot_cap_get_flag(theirflag); + return; + } + + //escort them + + if(self HasScriptGoal()) + return; + + origin = carrier.origin; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj(theirflag, carrier); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + } +} + /* Bots play capture the flag */ @@ -5025,9 +5974,6 @@ bot_cap() if ( level.gametype != "ctf" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 5 ) ); @@ -5042,121 +5988,8 @@ bot_cap() if(!isDefined(level.teamFlags)) continue; - - myflag = level.teamFlags[myteam]; - myzone = level.capZones[myteam]; - - theirflag = level.teamFlags[otherTeam]; - theirzone = level.capZones[otherTeam]; - - if(!myflag maps\mp\gametypes\_gameobjects::isHome()) - { - carrier = myflag.carrier; - - if(!isDefined(carrier))//someone doesnt has our flag - { - if(!isDefined(theirflag.carrier) && DistanceSquared(self.origin, theirflag.curorigin) < DistanceSquared(self.origin, myflag.curorigin)) //no one has their flag and its closer - self bot_cap_get_flag(theirflag); - else//go get it - self bot_cap_get_flag(myflag); - - continue; - } - else - { - if(theirflag maps\mp\gametypes\_gameobjects::isHome() && randomint(100) < 50) - { //take their flag - self bot_cap_get_flag(theirflag); - } - else - { - if(self HasScriptGoal()) - continue; - - if(!isDefined(theirzone.bots)) - theirzone.bots = 0; - - origin = theirzone.curorigin; - - if(theirzone.bots > 2 || randomInt(100) < 45) - { - //kill carrier - if(carrier _hasPerk( "specialty_coldblooded" )) - continue; - - origin = carrier.origin; - - self SetScriptGoal( origin, 64 ); - self thread bot_escort_obj(myflag, carrier); - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - self thread bot_inc_bots(theirzone); - - //camp their zone - if(DistanceSquared(origin, self.origin) <= 1024*1024) - { - wait 4; - self notify("bot_inc_bots"); theirzone.bots--; - continue; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_inc_bots(theirzone); - self thread bot_escort_obj(myflag, carrier); - - if(self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - } - } - } - else//our flag is ok - { - if(self isFlagCarrier())//if have flag - { - //go cap - origin = myzone.curorigin; - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 32 ); - - self thread bot_get_obj(myflag); - evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - wait 1; - if (evt != "new_goal") - self ClearScriptGoal(); - self.bot_lock_goal = false; - continue; - } - - carrier = theirflag.carrier; - - if(!isDefined(carrier))//if no one has enemy flag - { - self bot_cap_get_flag(theirflag); - continue; - } - - //escort them - - if(self HasScriptGoal()) - continue; - - origin = carrier.origin; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_escort_obj(theirflag, carrier); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - } + self bot_cap_loop(); } } @@ -5183,624 +6016,6 @@ bot_cap_get_flag(flag) self ClearScriptGoal(); } -/* - Bots play sab -*/ -bot_sab() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon("game_ended"); - - if ( level.gametype != "sab" ) - return; - - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if(!isDefined(level.sabBomb)) - continue; - - if(!isDefined(level.bombZones) || !level.bombZones.size) - continue; - - if (self IsPlanting() || self isDefusing()) - continue; - - bomb = level.sabBomb; - bombteam = bomb.ownerTeam; - carrier = bomb.carrier; - timeleft = maps\mp\gametypes\_gamelogic::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 = getTimePassed()/1000; - - if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) - continue; - - 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 - { - 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()) - continue; - - if(carrier _hasPerk( "specialty_coldblooded" )) - 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; - } - - //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) - { - if(self HasScriptGoal()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_go_defuse(site); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - // 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! - { - 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; - continue; - } - } -} - -/* - Bots play sd defenders -*/ -bot_sd_defenders() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon("game_ended"); - - if ( level.gametype != "sd" ) - return; - - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - if(myTeam == game["attackers"]) - return; - - rand = self BotGetRandom(); - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if (self IsPlanting() || self isDefusing()) - continue; - - // bomb not planted, lets protect our sites - if(!level.bombPlanted) - { - timeleft = maps\mp\gametypes\_gamelogic::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 ); - - 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 - if(!isDefined(level.defuseObject)) - continue; - - 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 ClearScriptGoal(); - - if(event != "goal" || !level.bombPlanted || defuse isInUse() || !self isTouching(defuse.trigger) || self InLastStand() || self HasThreat()) - { - self.bot_lock_goal = false; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - //self bot_use_bomb_thread(defuse); - wait 1; - self ClearScriptGoal(); - self.bot_lock_goal = false; - } -} - -/* - Bots play sd attackers -*/ -bot_sd_attackers() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon("game_ended"); - - if ( level.gametype != "sd" ) - return; - - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - if(myTeam != game["attackers"]) - return; - - rand = self BotGetRandom(); - - first = true; - - for ( ;; ) - { - if(first) - first = false; - else - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || 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\_gamelogic::getTimeRemaining()/1000; - timepassed = 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; - } -} - /* Bots go plant the demo bomb */ @@ -5856,6 +6071,195 @@ bot_dem_attack_spawnkill() self notify("bad_path"); } +/* + Bots play demo attackers +*/ +bot_dem_attackers_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + bombs = [];//sites with bombs + sites = [];//sites to bomb at + bombed = 0;//exploded sites + for ( i = 0; i < level.bombZones.size; i++ ) + { + bomb = level.bombZones[i]; + + if(isDefined(bomb.bombExploded) && bomb.bombExploded) + { + bombed++; + continue; + } + + if(bomb.label == "_a") + { + if(level.bombAPlanted) + bombs[bombs.size] = bomb; + else + sites[sites.size] = bomb; + + continue; + } + + if(bomb.label == "_b") + { + if(level.bombBPlanted) + bombs[bombs.size] = bomb; + else + sites[sites.size] = bomb; + + continue; + } + } + timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining()/1000; + + shouldLet = (game["teamScores"][myteam] > game["teamScores"][otherTeam] && timeleft < 90 && bombed == 1); + //spawnkill conditions + //if we have bombed one site or 1 bomb is planted with lots of time left, spawn kill + //if we want the other team to win for overtime and they do not need to defuse, spawn kill + if(((bombed + bombs.size == 1 && timeleft >= 90) || (shouldLet && !bombs.size)) && randomInt(100) < 95) + { + if(self HasScriptGoal()) + return; + + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_defender_start" ); + + if(!spawnPoints.size) + return; + + spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + + if(DistanceSquared(spawnpoint.origin, self.origin) <= 2048*2048) + return; + + self SetScriptGoal( spawnpoint.origin, 1024 ); + + self thread bot_dem_attack_spawnkill(); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + //let defuse conditions + //if enemy is going to lose and lots of time left, let them defuse to play longer + //or if want to go into overtime near end of the extended game + if(((bombs.size + bombed == 2 && timeleft >= 90) || (shouldLet && bombs.size)) && randomInt(100) < 95) + { + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_attacker_start" ); + + if(!spawnPoints.size) + return; + + spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + + if(DistanceSquared(spawnpoint.origin, self.origin) <= 1024*1024) + return; + + self.bot_lock_goal = true; + self SetScriptGoal( spawnpoint.origin, 512 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + return; + } + + //defend bomb conditions + //if time is running out and we have a bomb planted + if(bombs.size && timeleft < 90 && (!sites.size || randomInt(100) < 95)) + { + site = self bot_array_nearest_curorigin(bombs); + origin = ( site.curorigin[0]+50, site.curorigin[1]+50, 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; + 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; + } + + //else go plant + if(!sites.size) + return; + + plant = self bot_array_nearest_curorigin(sites); + + if(!isDefined(plant)) + return; + + if(!isDefined(plant.bots)) + plant.bots = 0; + + origin = ( plant.curorigin[0]+50, plant.curorigin[1]+50, plant.curorigin[2]+5 ); + + //hang around the site if lots of time left + if(plant.bots > 1 && timeleft >= 60) + { + if(self HasScriptGoal()) + return; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + self thread bot_dem_go_plant(plant); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 1 ); + self thread bot_inc_bots(plant); + self thread bot_dem_go_plant(plant); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if(event != "goal" || (plant.label == "_b" && level.bombBPlanted) || (plant.label == "_a" && level.bombAPlanted) || plant IsInUse() || !self isTouching(plant.trigger) || self InLastStand() || self HasThreat()) + { + 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; +} + /* Bots play demo attackers */ @@ -5867,11 +6271,8 @@ bot_dem_attackers() if ( level.gametype != "dd" ) return; - - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - if(myTeam != game["attackers"]) + if(self.team != game["attackers"]) return; for ( ;; ) @@ -5885,187 +6286,202 @@ bot_dem_attackers() if(!isDefined(level.bombZones) || !level.bombZones.size) continue; - - bombs = [];//sites with bombs - sites = [];//sites to bomb at - bombed = 0;//exploded sites - for ( i = 0; i < level.bombZones.size; i++ ) - { - bomb = level.bombZones[i]; - - if(isDefined(bomb.bombExploded) && bomb.bombExploded) - { - bombed++; - continue; - } - - if(bomb.label == "_a") - { - if(level.bombAPlanted) - bombs[bombs.size] = bomb; - else - sites[sites.size] = bomb; - - continue; - } - - if(bomb.label == "_b") - { - if(level.bombBPlanted) - bombs[bombs.size] = bomb; - else - sites[sites.size] = bomb; - - continue; - } - } - timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining()/1000; - - shouldLet = (game["teamScores"][myteam] > game["teamScores"][otherTeam] && timeleft < 90 && bombed == 1); - //spawnkill conditions - //if we have bombed one site or 1 bomb is planted with lots of time left, spawn kill - //if we want the other team to win for overtime and they do not need to defuse, spawn kill - if(((bombed + bombs.size == 1 && timeleft >= 90) || (shouldLet && !bombs.size)) && randomInt(100) < 95) - { - if(self HasScriptGoal()) - continue; - - spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_defender_start" ); - - if(!spawnPoints.size) - continue; - - spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); - - if(DistanceSquared(spawnpoint.origin, self.origin) <= 2048*2048) - continue; - - self SetScriptGoal( spawnpoint.origin, 1024 ); - - self thread bot_dem_attack_spawnkill(); - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } + self bot_dem_attackers_loop(); + } +} + +/* + Bots play demo defenders +*/ +bot_dem_defenders_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + bombs = [];//sites with bombs + sites = [];//sites to bomb at + bombed = 0;//exploded sites + for ( i = 0; i < level.bombZones.size; i++ ) + { + bomb = level.bombZones[i]; - //let defuse conditions - //if enemy is going to lose and lots of time left, let them defuse to play longer - //or if want to go into overtime near end of the extended game - if(((bombs.size + bombed == 2 && timeleft >= 90) || (shouldLet && bombs.size)) && randomInt(100) < 95) + if(isDefined(bomb.bombExploded) && bomb.bombExploded) { - spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_attacker_start" ); - - if(!spawnPoints.size) - continue; - - spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); - - if(DistanceSquared(spawnpoint.origin, self.origin) <= 1024*1024) - continue; - - self.bot_lock_goal = true; - self SetScriptGoal( spawnpoint.origin, 512 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; + bombed++; continue; } - //defend bomb conditions - //if time is running out and we have a bomb planted - if(bombs.size && timeleft < 90 && (!sites.size || randomInt(100) < 95)) + if(bomb.label == "_a") { - site = self bot_array_nearest_curorigin(bombs); - origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); + if(level.bombAPlanted) + bombs[bombs.size] = bomb; + else + sites[sites.size] = bomb; - 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; } - //else go plant - if(!sites.size) - continue; - - plant = self bot_array_nearest_curorigin(sites); - - if(!isDefined(plant)) - continue; - - if(!isDefined(plant.bots)) - plant.bots = 0; - - origin = ( plant.curorigin[0]+50, plant.curorigin[1]+50, plant.curorigin[2]+5 ); - - //hang around the site if lots of time left - if(plant.bots > 1 && timeleft >= 60) + if(bomb.label == "_b") { - if(self HasScriptGoal()) - continue; + if(level.bombBPlanted) + bombs[bombs.size] = bomb; + else + sites[sites.size] = bomb; - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_dem_go_plant(plant); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); continue; } + } + timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining()/1000; + + shouldLet = (timeleft < 60 && ((bombed == 0 && bombs.size != 2) || (game["teamScores"][myteam] > game["teamScores"][otherTeam] && bombed == 1)) && randomInt(100) < 98); + + //spawnkill conditions + //if nothing to defuse with a lot of time left, spawn kill + //or letting a bomb site to explode but a bomb is planted, so spawnkill + if((!bombs.size && timeleft >= 60 && randomInt(100) < 95) || (shouldLet && bombs.size == 1)) + { + if(self HasScriptGoal()) + return; + + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_attacker_start" ); + + if(!spawnPoints.size) + return; + + spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + + if(DistanceSquared(spawnpoint.origin, self.origin) <= 2048*2048) + return; + + self SetScriptGoal( spawnpoint.origin, 1024 ); + + self thread bot_dem_defend_spawnkill(); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + //let blow up conditions + //let enemy blow up at least one to extend play time + //or if want to go into overtime after extended game + if(shouldLet) + { + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_defender_start" ); + + if(!spawnPoints.size) + return; + + spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + + if(DistanceSquared(spawnpoint.origin, self.origin) <= 1024*1024) + return; self.bot_lock_goal = true; + self SetScriptGoal( spawnpoint.origin, 512 ); - self SetScriptGoal( origin, 1 ); - self thread bot_inc_bots(plant); - self thread bot_dem_go_plant(plant); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if (event != "new_goal") + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") self ClearScriptGoal(); - if(event != "goal" || (plant.label == "_b" && level.bombBPlanted) || (plant.label == "_a" && level.bombAPlanted) || plant IsInUse() || !self isTouching(plant.trigger) || self InLastStand() || self HasThreat()) + self.bot_lock_goal = false; + return; + } + + //defend conditions + //if no bombs planted with little time left + if(!bombs.size && timeleft < 60 && randomInt(100) < 95 && sites.size) + { + site = self bot_array_nearest_curorigin(sites); + 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; + return; } - self SetScriptGoal( self.origin, 64 ); + //else hang around the site - //self bot_use_bomb_thread(plant); - wait 1; + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; - self ClearScriptGoal(); + 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; } + + //else go defuse + + if(!bombs.size) + return; + + defuse = self bot_array_nearest_curorigin(bombs); + + if(!isDefined(defuse)) + return; + + if(!isDefined(defuse.bots)) + defuse.bots = 0; + + origin = ( defuse.curorigin[0]+50, defuse.curorigin[1]+50, defuse.curorigin[2]+5 ); + + //hang around the site if not in danger of losing + if(defuse.bots > 1 && bombed + bombs.size != 2) + { + if(self HasScriptGoal()) + return; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + return; + + self SetScriptGoal( origin, 256 ); + + self thread bot_dem_go_defuse(defuse); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + return; + } + + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 1 ); + self thread bot_inc_bots(defuse); + self thread bot_dem_go_defuse(defuse); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if(event != "goal" || (defuse.label == "_b" && !level.bombBPlanted) || (defuse.label == "_a" && !level.bombAPlanted) || 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; } /* @@ -6079,11 +6495,8 @@ bot_dem_defenders() if ( level.gametype != "dd" ) return; - - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - if(myTeam == game["attackers"]) + if(self.team == game["attackers"]) return; for ( ;; ) @@ -6097,190 +6510,8 @@ bot_dem_defenders() if(!isDefined(level.bombZones) || !level.bombZones.size) continue; - - bombs = [];//sites with bombs - sites = [];//sites to bomb at - bombed = 0;//exploded sites - for ( i = 0; i < level.bombZones.size; i++ ) - { - bomb = level.bombZones[i]; - - if(isDefined(bomb.bombExploded) && bomb.bombExploded) - { - bombed++; - continue; - } - - if(bomb.label == "_a") - { - if(level.bombAPlanted) - bombs[bombs.size] = bomb; - else - sites[sites.size] = bomb; - - continue; - } - - if(bomb.label == "_b") - { - if(level.bombBPlanted) - bombs[bombs.size] = bomb; - else - sites[sites.size] = bomb; - - continue; - } - } - timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining()/1000; - - shouldLet = (timeleft < 60 && ((bombed == 0 && bombs.size != 2) || (game["teamScores"][myteam] > game["teamScores"][otherTeam] && bombed == 1)) && randomInt(100) < 98); - - //spawnkill conditions - //if nothing to defuse with a lot of time left, spawn kill - //or letting a bomb site to explode but a bomb is planted, so spawnkill - if((!bombs.size && timeleft >= 60 && randomInt(100) < 95) || (shouldLet && bombs.size == 1)) - { - if(self HasScriptGoal()) - continue; - - spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_attacker_start" ); - - if(!spawnPoints.size) - continue; - - spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); - - if(DistanceSquared(spawnpoint.origin, self.origin) <= 2048*2048) - continue; - - self SetScriptGoal( spawnpoint.origin, 1024 ); - - self thread bot_dem_defend_spawnkill(); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - //let blow up conditions - //let enemy blow up at least one to extend play time - //or if want to go into overtime after extended game - if(shouldLet) - { - spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_defender_start" ); - - if(!spawnPoints.size) - continue; - - spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); - - if(DistanceSquared(spawnpoint.origin, self.origin) <= 1024*1024) - continue; - - self.bot_lock_goal = true; - self SetScriptGoal( spawnpoint.origin, 512 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; - continue; - } - - //defend conditions - //if no bombs planted with little time left - if(!bombs.size && timeleft < 60 && randomInt(100) < 95 && sites.size) - { - site = self bot_array_nearest_curorigin(sites); - 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 ); - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - - self.bot_lock_goal = false; - continue; - } - - //else go defuse - - if(!bombs.size) - continue; - - defuse = self bot_array_nearest_curorigin(bombs); - - if(!isDefined(defuse)) - continue; - - if(!isDefined(defuse.bots)) - defuse.bots = 0; - - origin = ( defuse.curorigin[0]+50, defuse.curorigin[1]+50, defuse.curorigin[2]+5 ); - - //hang around the site if not in danger of losing - if(defuse.bots > 1 && bombed + bombs.size != 2) - { - if(self HasScriptGoal()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - - self thread bot_dem_go_defuse(defuse); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - self.bot_lock_goal = true; - - self SetScriptGoal( origin, 1 ); - self thread bot_inc_bots(defuse); - self thread bot_dem_go_defuse(defuse); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if (event != "new_goal") - self ClearScriptGoal(); - - if(event != "goal" || (defuse.label == "_b" && !level.bombBPlanted) || (defuse.label == "_a" && !level.bombAPlanted) || defuse IsInUse() || !self isTouching(defuse.trigger) || self InLastStand() || self HasThreat()) - { - self.bot_lock_goal = false; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - //self bot_use_bomb_thread(defuse); - wait 1; - - self ClearScriptGoal(); - - self.bot_lock_goal = false; + self bot_dem_defenders_loop(); } }