From 950d4cab02ef4693b57a320d987105870ffa942f Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sat, 28 Nov 2020 00:54:24 -0600 Subject: [PATCH] some fix --- main_shared/maps/mp/bots/_bot_internal.gsc | 13 +- main_shared/maps/mp/bots/_bot_script.gsc | 2682 ++++++++++++++++++++ main_shared/maps/mp/bots/_bot_utility.gsc | 8 + 3 files changed, 2697 insertions(+), 6 deletions(-) diff --git a/main_shared/maps/mp/bots/_bot_internal.gsc b/main_shared/maps/mp/bots/_bot_internal.gsc index da38e7d..f0cda60 100644 --- a/main_shared/maps/mp/bots/_bot_internal.gsc +++ b/main_shared/maps/mp/bots/_bot_internal.gsc @@ -495,9 +495,6 @@ watch_grenade(grenade) if(self.bot.isfraggingafter || self.bot.issmokingafter) continue; - - if (self.disabledWeapon) - continue; self thread frag(); } @@ -1033,10 +1030,14 @@ aim() nade = self getValidGrenade(); if(isDefined(nade) && rand <= self.pers["bots"]["behavior"]["nade"] && bulletTracePassed(eyePos, eyePos + (0, 0, 75), false, self) && bulletTracePassed(last_pos, last_pos + (0, 0, 100), false, target) && dist > level.bots_minGrenadeDistance && dist < level.bots_maxGrenadeDistance && getDvarInt("bots_play_nade")) { - if(nade == "frag_grenade_mp") - self thread frag(2.5); + time = 0.5; + if (nade == "frag_grenade_mp") + time = 2; + + if(!isSecondaryGrenade(nade)) + self thread frag(time); else - self thread smoke(0.5); + self thread smoke(time); self notify("kill_goal"); } diff --git a/main_shared/maps/mp/bots/_bot_script.gsc b/main_shared/maps/mp/bots/_bot_script.gsc index 0c4e890..cc858b0 100644 --- a/main_shared/maps/mp/bots/_bot_script.gsc +++ b/main_shared/maps/mp/bots/_bot_script.gsc @@ -864,6 +864,9 @@ onSpawned() self.bot_lock_goal = false; self.help_time = undefined; self.bot_was_follow_script_update = undefined; + + if (getDvarInt("bots_play_obj")) + self thread bot_dom_cap_think(); } } @@ -894,4 +897,2683 @@ start_bot_threads() while(level.inPrematchPeriod) wait 0.05; + + // inventory usage + if (getDvarInt("bots_play_killstreak")) + self thread bot_killstreak_think(); + + self thread bot_weapon_think(); + + // script targeting + if (getDvarInt("bots_play_target_other")) + { + self thread bot_target_vehicle(); + self thread bot_equipment_kill_think(); + } + + // awareness + self thread bot_revenge_think(); + self thread bot_uav_think(); + self thread bot_listen_to_steps(); + self thread follow_target(); + + // camp and follow + if (getDvarInt("bots_play_camp")) + { + self thread bot_think_follow(); + self thread bot_think_camp(); + } + + // nades + if (getDvarInt("bots_play_nade")) + { + self thread bot_use_tube_think(); + self thread bot_use_grenade_think(); + self thread bot_use_equipment_think(); + } + + // obj + if (getDvarInt("bots_play_obj")) + { + self thread bot_dom_def_think(); + self thread bot_dom_spawn_kill_think(); + + self thread bot_hq(); + + self thread bot_sab(); + + self thread bot_sd_defenders(); + self thread bot_sd_attackers(); + } +} + +/* + Increments the number of bots approching the obj, decrements when needed + Used for preventing too many bots going to one obj, or unreachable objs +*/ +bot_inc_bots(obj, unreach) +{ + level endon("game_ended"); + self endon("bot_inc_bots"); + + if (!isDefined(obj.bots)) + obj.bots = 0; + + obj.bots++; + + ret = self waittill_any_return("death", "disconnect", "bad_path", "goal", "new_goal"); + + if (isDefined(obj) && (ret != "bad_path" || !isDefined(unreach))) + obj.bots--; +} + +/* + Watches when the bot is touching the obj and calls 'goal' +*/ +bots_watch_touch_obj(obj) +{ + self endon ("death"); + self endon ("disconnect"); + self endon ("bad_path"); + self endon ("goal"); + self endon ("new_goal"); + + for (;;) + { + wait 0.5; + + if (!isDefined(obj)) + { + self notify("bad_path"); + return; + } + + if (self IsTouching(obj)) + { + self notify("goal"); + return; + } + } +} + +/* + Is bot near any of the given waypoints +*/ +nearAnyOfWaypoints(dist, waypoints) +{ + dist *= dist; + for (i = 0; i < waypoints.size; i++) + { + waypoint = waypoints[i]; + + if (DistanceSquared(waypoint.origin, self.origin) > dist) + continue; + + return true; + } + + return false; +} + +/* + Returns nearest waypoint of waypoints +*/ +getNearestWaypointOfWaypoints(waypoints) +{ + answer = undefined; + closestDist = 999999999999; + for (i = 0; i < waypoints.size; i++) + { + waypoint = waypoints[i]; + thisDist = DistanceSquared(self.origin, waypoint.origin); + + if (isDefined(answer) && thisDist > closestDist) + continue; + + answer = waypoint; + closestDist = thisDist; + } + + return answer; +} + +/* + Watches while the obj is being carried, calls 'goal' when complete +*/ +bot_escort_obj(obj, carrier) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait 0.5; + + if (!isDefined(obj)) + break; + + if (!isDefined(obj.carrier) || carrier == obj.carrier) + break; + } + + self notify("goal"); +} + +/* + Watches while the obj is not being carried, calls 'goal' when complete +*/ +bot_get_obj(obj) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait 0.5; + + if (!isDefined(obj)) + break; + + if (isDefined(obj.carrier)) + break; + } + + self notify("goal"); +} + +/* + bots will defend their site from a planter/defuser +*/ +bot_defend_site(site) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon("game_ended"); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait 0.5; + + if (!site isInUse()) + break; + } + + self notify("bad_path"); +} + +/* + Bots will go plant the bomb +*/ +bot_go_plant(plant) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon("game_ended"); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait 1; + + if (level.bombPlanted) + break; + + if (self isTouching(plant.trigger)) + break; + } + + if(level.bombPlanted) + self notify("bad_path"); + else + self notify("goal"); +} + +/* + Bots will go defuse the bomb +*/ +bot_go_defuse(plant) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon("game_ended"); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait 1; + + if (!level.bombPlanted) + break; + + if (self isTouching(plant.trigger)) + break; + } + + if(!level.bombPlanted) + self notify("bad_path"); + else + self notify("goal"); +} + +/* + Creates a bomb use thread and waits for an output +*/ +bot_use_bomb_thread(bomb) +{ + self thread bot_use_bomb(bomb); + self waittill_any("bot_try_use_fail", "bot_try_use_success"); +} + +/* + Waits for the time to call bot_try_use_success or fail +*/ +bot_bomb_use_time(wait_time) +{ + level endon("game_ended"); + self endon("death"); + self endon("disconnect"); + self endon("bot_try_use_fail"); + self endon("bot_try_use_success"); + + self waittill("bot_try_use_weapon"); + + wait 0.05; + elapsed = 0; + while(wait_time > elapsed) + { + wait 0.05;//wait first so waittill can setup + elapsed += 0.05; + + if(self InLastStand()) + { + self notify("bot_try_use_fail"); + return;//needed? + } + } + + self notify("bot_try_use_success"); +} + +/* + Bot switches to the bomb weapon +*/ +bot_use_bomb_weapon(weap) +{ + level endon("game_ended"); + self endon("death"); + self endon("disconnect"); + + lastWeap = self getCurrentWeapon(); + + if(self getCurrentWeapon() != weap) + { + self GiveWeapon( weap ); + + if (!self ChangeToWeapon(weap)) + { + self notify("bot_try_use_fail"); + return; + } + } + else + { + wait 0.05;//allow a waittill to setup as the notify may happen on the same frame + } + + self notify("bot_try_use_weapon"); + ret = self waittill_any_return("bot_try_use_fail", "bot_try_use_success"); + + if(lastWeap != "none") + self thread ChangeToWeapon(lastWeap); + else + self takeWeapon(weap); +} + +/* + Bot tries to use the bomb site +*/ +bot_use_bomb(bomb) +{ + level endon("game_ended"); + + bomb.inUse = true; + + myteam = self.team; + + self BotFreezeControls(true); + + bomb [[bomb.onBeginUse]](self); + + self clientClaimTrigger( bomb.trigger ); + self.claimTrigger = bomb.trigger; + + self thread bot_bomb_use_time(bomb.useTime / 1000); + self thread bot_use_bomb_weapon(bomb.useWeapon); + + result = self waittill_any_return("death", "disconnect", "bot_try_use_fail", "bot_try_use_success"); + + if (isDefined(self)) + { + self.claimTrigger = undefined; + self BotFreezeControls(false); + } + + bomb [[bomb.onEndUse]](myteam, self, (result == "bot_try_use_success")); + bomb.trigger releaseClaimedTrigger(); + + if(result == "bot_try_use_success") + bomb [[bomb.onUse]](self); + + bomb.inUse = false; +} + +/* + Fires the bots weapon until told to stop +*/ +fire_current_weapon() +{ + self endon("death"); + self endon("disconnect"); + self endon("weapon_change"); + self endon("stop_firing_weapon"); + + for (;;) + { + self thread BotPressAttack(0.05); + wait 0.1; + } +} + +/* + Changes to the weap +*/ +changeToWeapon(weap) +{ + self endon("disconnect"); + self endon("death"); + level endon("game_ended"); + + if (!self HasWeapon(weap)) + return false; + + if (self GetCurrentWeapon() == weap) + return true; + + self BotChangeToWeapon(weap); + + self waittill_any_timeout(5, "weapon_change"); + + return (self GetCurrentWeapon() == weap); +} + +/* + Bots throw the grenade +*/ +botThrowGrenade(nade, time) +{ + self endon("disconnect"); + self endon("death"); + level endon("game_ended"); + + if (!self GetAmmoCount(nade)) + return false; + + if (isSecondaryNade(nade)) + self thread BotPressSmoke(time); + else + self thread BotPressFrag(time); + + ret = self waittill_any_timeout(5, "grenade_fire"); + + return (ret == "grenade_fire"); +} + +/* + Gets the object thats the closest in the array +*/ +bot_array_nearest_curorigin(array) +{ + result = undefined; + + for(i = 0; i < array.size; i++) + if(!isDefined(result) || DistanceSquared(self.origin,array[i].curorigin) < DistanceSquared(self.origin,result.curorigin)) + result = array[i]; + + return result; +} + +/* + Clears goal when events death +*/ +stop_go_target_on_death(tar) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "new_goal" ); + self endon( "bad_path" ); + self endon( "goal" ); + + tar waittill_either("death", "disconnect"); + + self ClearScriptGoal(); +} + +/* + Bot logic for bot determining to camp. +*/ +bot_think_camp() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for(;;) + { + wait randomintrange(4,7); + + if ( self HasScriptGoal() || self.bot_lock_goal || self HasScriptAimPos() ) + continue; + + if(randomInt(100) > self.pers["bots"]["behavior"]["camp"]) + continue; + + campSpots = []; + distSq = 1024*1024; + for (i = 0; i < level.waypointsCamp.size; i++) + { + if (DistanceSquared(self.origin, level.waypointsCamp[i].origin) > distSq) + continue; + + campSpots[campSpots.size] = level.waypointsCamp[i]; + } + campSpot = random(campSpots); + + 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); + } +} + +/* + Kills the camping thread when time +*/ +killCampAfterTime(time) +{ + self endon("death"); + self endon("disconnect"); + self endon("kill_camp_bot"); + + wait time + 0.05; + self ClearScriptGoal(); + self ClearScriptAimPos(); + + self notify("kill_camp_bot"); +} + +/* + Kills the camping thread when ent gone +*/ +killCampAfterEntGone(ent) +{ + self endon("death"); + self endon("disconnect"); + self endon("kill_camp_bot"); + + for (;;) + { + wait 0.05; + + if (!isDefined(ent)) + break; + } + + self ClearScriptGoal(); + self ClearScriptAimPos(); + + self notify("kill_camp_bot"); +} + +/* + Camps at the spot +*/ +CampAtSpot(origin, anglePos) +{ + self endon("kill_camp_bot"); + + self SetScriptGoal(origin, 64); + if (isDefined(anglePos)) + { + self SetScriptAimPos(anglePos); + } + + self waittill("new_goal"); + self ClearScriptAimPos(); + + self notify("kill_camp_bot"); +} + +/* + Bot logic for bot determining to follow another player. +*/ +bot_think_follow() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for(;;) + { + wait randomIntRange(3,5); + + if ( self HasScriptGoal() || self.bot_lock_goal || self HasScriptAimPos() ) + continue; + + if(randomInt(100) > self.pers["bots"]["behavior"]["follow"]) + continue; + + 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(!isAlive(player)) + continue; + + if (player.team != self.team) + continue; + + if (DistanceSquared(player.origin, self.origin) > distSq) + continue; + + follows[follows.size] = player; + } + toFollow = random(follows); + + if (!isDefined(toFollow)) + continue; + + self thread killFollowAfterTime(randomIntRange(10,20)); + self followPlayer(toFollow); + } +} + +/* + Kills follow when new goal +*/ +watchForFollowNewGoal() +{ + self endon("death"); + self endon("disconnect"); + self endon("kill_follow_bot"); + + for (;;) + { + self waittill("new_goal"); + + if (!isDefined(self.bot_was_follow_script_update)) + break; + } + + self ClearScriptAimPos(); + self notify("kill_follow_bot"); +} + +/* + Kills follow when time +*/ +killFollowAfterTime(time) +{ + self endon("death"); + self endon("disconnect"); + self endon("kill_follow_bot"); + + wait time; + + self ClearScriptGoal(); + self ClearScriptAimPos(); + self notify("kill_follow_bot"); +} + +/* + Determine bot to follow a player +*/ +followPlayer(who) +{ + self endon("kill_follow_bot"); + + self thread watchForFollowNewGoal(); + + for (;;) + { + wait 0.05; + + if (!isDefined(who) || !isAlive(who)) + break; + + self SetScriptAimPos(who.origin + (0, 0, 42)); + myGoal = self GetScriptGoal(); + + if (isDefined(myGoal) && DistanceSquared(myGoal, who.origin) < 64*64) + continue; + + self.bot_was_follow_script_update = true; + self SetScriptGoal(who.origin, 32); + waittillframeend; + self.bot_was_follow_script_update = undefined; + + self waittill_either("goal", "bad_path"); + } + + self ClearScriptGoal(); + self ClearScriptAimPos(); + + self notify("kill_follow_bot"); +} + +/* + Bots thinking of using a noobtube +*/ +bot_use_tube_think() +{ + self endon("disconnect"); + self endon("death"); + level endon("game_ended"); + + doFastContinue = false; + + for (;;) + { + if (doFastContinue) + doFastContinue = false; + else + { + wait randomintRange(3, 7); + + chance = self.pers["bots"]["behavior"]["nade"] / 2; + if (chance > 20) + chance = 20; + + if (randomInt(100) > chance) + continue; + } + + tube = self getValidTube(); + if (!isDefined(tube)) + continue; + + if (self HasThreat() || self HasScriptAimPos()) + continue; + + if(self BotIsFrozen()) + continue; + + if (self IsBotFragging() || self IsBotSmoking()) + continue; + + if(self isDefusing() || self isPlanting()) + continue; + + if (self InLastStand()) + continue; + + loc = undefined; + + if (!self nearAnyOfWaypoints(128, level.waypointsTube)) + { + tubeWps = []; + distSq = 1024*1024; + for (i = 0; i < level.waypointsTube.size; i++) + { + if (DistanceSquared(self.origin, level.waypointsTube[i].origin) > distSq) + continue; + + tubeWps[tubeWps.size] = level.waypointsTube[i]; + } + tubeWp = random(tubeWps); + + 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 = self getNearestWaypointOfWaypoints(level.waypointsTube); + 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); + } +} + +/* + Bots thinking of using claymores +*/ +bot_use_equipment_think() +{ + self endon("disconnect"); + self endon("death"); + level endon("game_ended"); + + 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 (!isDefined(nade)) + continue; + + if (self HasThreat() || self HasScriptAimPos()) + continue; + + if(self BotIsFrozen()) + continue; + + if(self IsBotFragging() || self IsBotSmoking()) + continue; + + if(self isDefusing() || self isPlanting()) + continue; + + if (self inLastStand()) + continue; + + loc = undefined; + + if (!self nearAnyOfWaypoints(128, level.waypointsClay)) + { + clayWps = []; + distSq = 1024*1024; + for (i = 0; i < level.waypointsClay.size; i++) + { + if (DistanceSquared(self.origin, level.waypointsClay[i].origin) > distSq) + continue; + + clayWps[clayWps.size] = level.waypointsClay[i]; + } + clayWp = random(clayWps); + + 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 = self getNearestWaypointOfWaypoints(level.waypointsClay); + loc = clayWp.origin + AnglesToForward(clayWp.angles) * 2048; + } + + if (!isDefined(loc)) + continue; + + self SetScriptAimPos(loc); + self BotStopMoving(true); + wait 1; + + if (self changeToWeapon(nade)) + { + self thread fire_current_weapon(); + self waittill_any_timeout(5, "grenade_fire", "weapon_change"); + self notify("stop_firing_weapon"); + } + + self ClearScriptAimPos(); + self BotStopMoving(false); + } +} + +/* + Bots thinking of using grenades +*/ +bot_use_grenade_think() +{ + self endon("disconnect"); + self endon("death"); + level endon("game_ended"); + + doFastContinue = false; + + for (;;) + { + if (doFastContinue) + doFastContinue = false; + else + { + wait randomintRange(4, 7); + + chance = self.pers["bots"]["behavior"]["nade"] / 2; + if (chance > 20) + chance = 20; + + if (randomInt(100) > chance) + continue; + } + + nade = self getValidGrenade(); + if (!isDefined(nade)) + continue; + + if (self HasThreat() || self HasScriptAimPos()) + continue; + + if(self BotIsFrozen()) + continue; + + if(self IsBotFragging() || self IsBotSmoking()) + continue; + + if(self isDefusing() || self isPlanting()) + continue; + + if (self inLastStand()) + continue; + + loc = undefined; + + if (!self nearAnyOfWaypoints(128, level.waypointsGren)) + { + nadeWps = []; + distSq = 1024*1024; + for (i = 0; i < level.waypointsGren.size; i++) + { + if (DistanceSquared(self.origin, level.waypointsGren[i].origin) > distSq) + continue; + + nadeWps[nadeWps.size] = level.waypointsGren[i]; + } + nadeWp = random(nadeWps); + + 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 = self getNearestWaypointOfWaypoints(level.waypointsGren); + 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); + } +} + +/* + Goes to the target's location if it had one +*/ +follow_target() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for(;;) + { + wait 1; + + if ( self HasScriptGoal() || self.bot_lock_goal ) + continue; + + if ( !self HasThreat() ) + continue; + + threat = self GetThreat(); + + if (!isPlayer(threat)) + continue; + + if(randomInt(100) > self.pers["bots"]["behavior"]["follow"]*5) + continue; + + self thread stop_go_target_on_death(threat); + + self SetScriptGoal(threat.origin, 64); + if (self waittill_any_return("new_goal", "goal", "bad_path") != "new_goal") + self ClearScriptGoal(); + } +} + +/* + Bot logic for detecting nearby players. +*/ +bot_listen_to_steps() +{ + self endon("disconnect"); + self endon("death"); + + for(;;) + { + wait 1; + + if(self HasScriptGoal() || self.bot_lock_goal) + continue; + + if(self.pers["bots"]["skill"]["base"] < 3) + continue; + + dist = level.bots_listenDist; + if(self hasPerk("specialty_parabolic")) + dist *= 1.4; + + dist *= dist; + + heard = undefined; + for(i = level.players.size-1 ; i >= 0; i--) + { + player = level.players[i]; + + if(!isDefined(player.bot_model_fix)) + continue; + + if(player == self) + continue; + if(level.teamBased && self.team == player.team) + continue; + if(player.sessionstate != "playing") + continue; + if(!isAlive(player)) + continue; + if(player hasPerk("specialty_quieter")) + continue; + + if(lengthsquared( player getVelocity() ) < 20000) + continue; + + if(distanceSquared(player.origin, self.origin) > dist) + continue; + + heard = player; + break; + } + + if(!IsDefined(heard)) + continue; + + if(bulletTracePassed(self getEyePos(), heard getTagOrigin( "j_spineupper" ), false, heard)) + { + self setAttacker(heard); + continue; + } + + self SetScriptGoal( heard.origin, 64 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + } +} + +/* + bots will go to their target's kill location +*/ +bot_revenge_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if(self.pers["bots"]["skill"]["base"] <= 1) + return; + + if(!isDefined(self.killerLocation)) + return; + + for(;;) + { + wait( RandomIntRange( 1, 5 ) ); + + if(self HasScriptGoal() || self.bot_lock_goal) + return; + + if ( randomint( 100 ) < 75 ) + return; + + self SetScriptGoal( self.killerLocation, 64 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + } +} + +/* + Bot logic for switching weapons. +*/ +bot_weapon_think() +{ + self endon("death"); + self endon("disconnect"); + level endon("game_ended"); + + for(;;) + { + self waittill_any_timeout(randomIntRange(2, 4), "bot_force_check_switch"); + + if(self BotIsFrozen()) + continue; + + if(self isDefusing() || self isPlanting() || self InLastStand()) + continue; + + hasTarget = self hasThreat(); + curWeap = self GetCurrentWeapon(); + + if(hasTarget) + { + threat = self getThreat(); + + if(threat.classname == "script_vehicle" && self getAmmoCount("rpg_mp")) + { + if (curWeap != "rpg_mp") + self thread ChangeToWeapon("rpg_mp"); + continue; + } + } + + if(curWeap != "none" && self getAmmoCount(curWeap)) + { + if(randomInt(100) > self.pers["bots"]["behavior"]["switch"]) + continue; + + if(hasTarget) + continue; + } + + weaponslist = self getweaponslist(); + weap = ""; + while(weaponslist.size) + { + weapon = weaponslist[randomInt(weaponslist.size)]; + weaponslist = array_remove(weaponslist, weapon); + + if(!self getAmmoCount(weapon)) + continue; + + if (maps\mp\gametypes\_weapons::isHackWeapon( weapon )) + continue; + + if (maps\mp\gametypes\_weapons::isGrenade( weapon )) + continue; + + if(curWeap == weapon || weapon == "c4_mp" || weapon == "none" || weapon == "claymore_mp" || weapon == "")//c4 no work + continue; + + weap = weapon; + break; + } + + if(weap == "") + continue; + + self thread ChangeToWeapon(weap); + } +} + +/* + Bot logic for killstreaks. +*/ +bot_killstreak_think() +{ + self endon("death"); + self endon("disconnect"); + level endon("game_ended"); + + for(;;) + { + wait randomIntRange(1, 3); + + if(self BotIsFrozen()) + continue; + + if(!isDefined(self.pers["hardPointItem"])) + continue; + + if(self HasThreat()) + continue; + + if(self isDefusing() || self isPlanting() || self InLastStand()) + continue; + + curWeap = self GetCurrentWeapon(); + + targetPos = undefined; + switch(self.pers["hardPointItem"]) + { + case "radar_mp": + if(self.bot_radar && self.pers["bots"]["skill"]["base"] > 3) + continue; + break; + + case "helicopter_mp": + chopper = level.chopper; + + if (isDefined(chopper) && !isEntity(chopper)) + chopper = level.chopper[self.team]; + + if (isDefined(chopper)) + continue; + + if (isDefined( level.mannedchopper )) + continue; + + break; + + case "airstrike_mp": + if(isDefined( level.airstrikeInProgress )) + continue; + + players = []; + for(i = level.players.size - 1; i >= 0; i--) + { + player = level.players[i]; + + if(player == self) + continue; + if(!isDefined(player.team)) + continue; + if(level.teamBased && self.team == player.team) + continue; + if(player.sessionstate != "playing") + continue; + if(!isAlive(player)) + continue; + if(player hasPerk("specialty_gpsjammer")) + continue; + if(!bulletTracePassed(player.origin, player.origin+(0,0,512), false, player) && self.pers["bots"]["skill"]["base"] > 3) + continue; + + players[players.size] = player; + } + + target = random(players); + + if(isDefined(target)) + targetPos = target.origin + (randomIntRange((8-self.pers["bots"]["skill"]["base"])*-75, (8-self.pers["bots"]["skill"]["base"])*75), randomIntRange((8-self.pers["bots"]["skill"]["base"])*-75, (8-self.pers["bots"]["skill"]["base"])*75), 0); + else if(self.pers["bots"]["skill"]["base"] <= 3) + targetPos = self.origin + (randomIntRange(-512, 512), randomIntRange(-512, 512), 0); + break; + + default: + continue; + } + + isAirstrikePos = isDefined(targetPos); + if(self.pers["hardPointItem"] == "airstrike_mp" && !isAirstrikePos) + continue; + + self BotStopMoving(true); + + if (self changeToWeapon(self.pers["hardPointItem"])) + { + wait 1; + + if (isAirstrikePos && !isDefined( level.airstrikeInProgress )) + { + self notify( "confirm_location", targetPos ); + wait 1; + } + + self thread changeToWeapon(curWeap); + } + + self BotStopMoving(false); + } +} + +/* + Bot logic for UAV detection here. Checks for UAV and players who are shooting. +*/ +bot_uav_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for(;;) + { + wait 0.75; + + if(self.pers["bots"]["skill"]["base"] <= 1) + continue; + + if( level.hardcoreMode && !self.bot_radar ) + continue; + + dist = self.pers["bots"]["skill"]["help_dist"]; + dist *= dist * 8; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[i]; + + if(player == self) + continue; + + if(!isDefined(player.team)) + continue; + + if(player.sessionstate != "playing") + continue; + + if(level.teambased && player.team == self.team) + continue; + + if(!isAlive(player)) + continue; + + distFromPlayer = DistanceSquared(self.origin, player.origin); + if(distFromPlayer > dist) + continue; + + if((!isSubStr(player getCurrentWeapon(), "_silencer_") && player.bots_firing) || (self.bot_radar && !player hasPerk("specialty_gpsjammer"))) + { + distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; + if (distFromPlayer < distSq && bulletTracePassed(self getEyePos(), player getTagOrigin( "j_spineupper" ), false, player)) + { + self SetAttacker(player); + } + + if (!self HasScriptGoal() && !self.bot_lock_goal) + { + self thread stop_go_target_on_death(player); + self SetScriptGoal( player.origin, 128 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + } + break; + } + } + } +} + +/* + Bot logic for detecting the chopper as an enemy. +*/ +bot_target_vehicle() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for(;;) + { + wait( RandomIntRange( 2, 4 ) ); + + if(self.pers["bots"]["skill"]["base"] <= 1) + continue; + + if(self HasScriptEnemy()) + continue; + + if(!self getAmmoCount("rpg_mp") && self BotGetRandom() < 90) + continue; + + chopper = level.chopper; + + if(isDefined(chopper) && !isEntity(chopper)) + { + chopper = level.chopper[ level.otherTeam[self.team] ]; + } + + if (!isdefined(chopper)) + continue; + + if(!isDefined(level.bot_chopper) || !level.bot_chopper)//must be crashing or leaving + continue; + + if(isDefined(chopper.owner) && chopper.owner == self) + continue; + + if(chopper.team == self.team && level.teamBased) + continue; + + if(!bulletTracePassed( self getEyePos(), chopper.origin + (0, 0, -5), false, chopper )) + continue; + + self SetScriptEnemy( chopper, (0, 0, -5) ); + self bot_attack_vehicle(chopper); + self ClearScriptEnemy(); + self notify("bot_force_check_switch"); + } +} + +/* + Bot logic for how long to keep targeting chopper. +*/ +bot_attack_vehicle(chopper) +{ + chopper endon( "death" ); + chopper endon( "crashing" ); + chopper endon( "leaving" ); + + wait_time = RandomIntRange( 7, 10 ); + + for ( i = 0; i < wait_time; i++ ) + { + self notify("bot_force_check_switch"); + wait( 1 ); + + if ( !IsDefined( chopper ) ) + { + return; + } + } +} + +/* + Bot logic for targeting equipment. +*/ +bot_equipment_kill_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for(;;) + { + wait( RandomIntRange( 1, 3 ) ); + + if(self HasScriptEnemy()) + continue; + + if(self.pers["bots"]["skill"]["base"] <= 1) + continue; + + grenades = GetEntArray( "grenade", "classname" ); + myEye = self getEyePos(); + myAngles = self getPlayerAngles(); + target = undefined; + hasDetectExp = self hasPerk("specialty_detectexplosive"); + + for ( i = grenades.size - 1; i >= 0; i-- ) + { + item = grenades[i]; + + if ( !IsDefined( item.name ) ) + { + continue; + } + + if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) + { + continue; + } + + if (item.name != "c4_mp" && item.name != "claymore_mp") + continue; + + if(!hasDetectExp && !bulletTracePassed(myEye, item.origin+(0, 0, 0), false, item)) + continue; + + if(getConeDot(item.origin, self.origin, myAngles) < 0.6) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < 512 * 512 ) + { + target = item; + break; + } + } + + if(isDefined(target)) + { + self SetScriptEnemy( target, (0, 0, 0) ); + self bot_equipment_attack(target); + self ClearScriptEnemy(); + } + } +} + +/* + How long to keep targeting the equipment. +*/ +bot_equipment_attack(equ) +{ + equ endon("death"); + + wait_time = RandomIntRange( 7, 10 ); + + for ( i = 0; i < wait_time; i++ ) + { + wait( 1 ); + + if ( !IsDefined( equ ) ) + { + return; + } + } +} + +/* + Bots hang around the enemy's flag to spawn kill em +*/ +bot_dom_spawn_kill_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( level.gametype != "dom" ) + return; + + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + for ( ;; ) + { + wait( randomintrange( 10, 20 ) ); + + if ( randomint( 100 ) < 20 ) + continue; + + 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(); + } +} + +/* + Calls 'bad_path' when the flag count changes +*/ +bot_dom_watch_flags(count, myTeam) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait 0.5; + + if (maps\mp\gametypes\dom::getTeamFlagCount( myTeam ) != count) + break; + } + + self notify("bad_path"); +} + +/* + Bots watches their own flags and protects them when they are under capture +*/ +bot_dom_def_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( level.gametype != "dom" ) + return; + + myTeam = self.pers[ "team" ]; + + for ( ;; ) + { + wait( randomintrange( 1, 3 ) ); + + if ( randomint( 100 ) < 35 ) + continue; + + 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(); + } +} + +/* + Watches while the flag is under capture +*/ +bot_dom_watch_for_flashing(flag, myTeam) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait 0.5; + + if (!isDefined(flag)) + break; + + if (flag maps\mp\gametypes\dom::getFlagTeam() != myTeam || !flag.useObj.objPoints[myTeam].isFlashing) + break; + } + + self notify("bad_path"); +} + +/* + Bots capture dom flags +*/ +bot_dom_cap_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( level.gametype != "dom" ) + return; + + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + for ( ;; ) + { + wait( randomintrange( 3, 12 ) ); + + if ( self.bot_lock_goal ) + { + continue; + } + + 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 ( 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; + } +} + +/* + Bot goes to the flag, watching while they don't have the flag +*/ +bot_dom_go_cap_flag(flag, myteam) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait randomintrange(2,4); + + if (!isDefined(flag)) + break; + + if (flag maps\mp\gametypes\dom::getFlagTeam() == myTeam) + break; + + if (self isTouching(flag)) + break; + } + + if (flag maps\mp\gametypes\dom::getFlagTeam() == myTeam) + self notify("bad_path"); + else + self notify("goal"); +} + +/* + Bots play headquarters +*/ +bot_hq() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( level.gametype != "koth" ) + return; + + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self.bot_lock_goal ) + { + continue; + } + + if(!isDefined(level.radio)) + continue; + + 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(); + } + } +} + +/* + Waits until not touching the trigger and it is the current radio. +*/ +bot_hq_go_cap(obj, radio) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for (;;) + { + wait randomintrange(2,4); + + if (!isDefined(obj)) + break; + + if (self isTouching(obj.trigger)) + break; + + if (level.radio != radio) + break; + } + + if(level.radio != radio) + self notify("bad_path"); + else + self notify("goal"); +} + +/* + Waits while the radio is under attack. +*/ +bot_hq_watch_flashing(obj, radio) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + myteam = self.team; + + for (;;) + { + wait 0.5; + + if (!isDefined(obj)) + break; + + if (!obj.objPoints[myteam].isFlashing) + break; + + if (level.radio != radio) + break; + } + + self notify("bad_path"); +} + +/* + 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.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\_globallogic::getTimeRemaining()/1000; + + // the bomb is ours, we are on the offence + if(bombteam == myTeam) + { + site = level.bombZones[otherTeam]; + origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); + + // protect our planted bomb + if(level.bombPlanted) + { + // kill defuser + if(site isInUse()) //somebody is defusing our bomb we planted + { + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site(site); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + self.bot_lock_goal = false; + continue; + } + + //else hang around the site + if(DistanceSquared(origin, self.origin) <= 1024*1024) + continue; + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + self.bot_lock_goal = false; + continue; + } + + // we are not the carrier + if(!self isBombCarrier()) + { + // lets escort the bomb carrier + if(self HasScriptGoal()) + continue; + + origin = carrier.origin; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + continue; + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj(bomb, carrier); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + continue; + } + + // we are the carrier of the bomb, lets check if we need to plant + timepassed = maps\mp\gametypes\_globallogic::getTimePassed()/1000; + + if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) + continue; + + 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_gpsjammer" )) + continue; + + origin = carrier.origin; + + self SetScriptGoal( origin, 64 ); + self thread bot_escort_obj(bomb, carrier); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + continue; + } + + //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.bot_lock_goal ) + { + continue; + } + + if (self IsPlanting() || self isDefusing()) + continue; + + // bomb not planted, lets protect our sites + if(!level.bombPlanted) + { + timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; + + if(timeleft >= 90) + continue; + + // check for a bomb carrier, and camp the bomb + if(!level.multiBomb && isDefined(level.sdBomb)) + { + bomb = level.sdBomb; + carrier = level.sdBomb.carrier; + + if(!isDefined(carrier)) + { + origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); + + //hang around the bomb + if(self HasScriptGoal()) + continue; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + continue; + + self SetScriptGoal( origin, 256 ); + + self thread bot_get_obj(bomb); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + continue; + } + } + + // pick a site to protect + if(!isDefined(level.bombZones) || !level.bombZones.size) + continue; + + sites = []; + for(i = 0; i < level.bombZones.size; i++) + { + sites[sites.size] = level.bombZones[i]; + } + + if(!sites.size) + continue; + + if (rand > 50) + site = self bot_array_nearest_curorigin(sites); + else + site = random(sites); + + if(!isDefined(site)) + continue; + + origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); + + if(site isInUse())//somebody is planting + { + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site(site); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + continue; + } + + //else hang around the site + if(DistanceSquared(origin, self.origin) <= 1024*1024) + continue; + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + 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.bot_lock_goal ) + { + continue; + } + + //bomb planted + if(level.bombPlanted) + { + if(!isDefined(level.defuseObject)) + continue; + + site = level.defuseObject; + + origin = ( site.curorigin[0], site.curorigin[1], site.curorigin[2]+5 ); + + if(site IsInUse())//somebody is defusing + { + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site(site); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + continue; + } + + //else hang around the site + if(DistanceSquared(origin, self.origin) <= 1024*1024) + continue; + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + continue; + } + + timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; + timepassed = maps\mp\gametypes\_globallogic::getTimePassed()/1000; + + //dont have a bomb + if(!self IsBombCarrier() && !level.multiBomb) + { + if(!isDefined(level.sdBomb)) + continue; + + bomb = level.sdBomb; + carrier = level.sdBomb.carrier; + + //bomb is picked up + if(isDefined(carrier)) + { + //escort the bomb carrier + if(self HasScriptGoal()) + continue; + + origin = carrier.origin; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + continue; + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj(bomb, carrier); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + continue; + } + + if(!isDefined(bomb.bots)) + bomb.bots = 0; + + origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); + + //hang around the bomb if other is going to go get it + if(bomb.bots > 1) + { + if(self HasScriptGoal()) + continue; + + if(DistanceSquared(origin, self.origin) <= 1024*1024) + continue; + + self SetScriptGoal( origin, 256 ); + + self thread bot_get_obj(bomb); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + continue; + } + + // go get the bomb + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_inc_bots(bomb); + self thread bot_get_obj(bomb); + + if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + self ClearScriptGoal(); + + self.bot_lock_goal = false; + continue; + } + + // check if to plant + if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) + continue; + + if(!isDefined(level.bombZones) || !level.bombZones.size) + continue; + + sites = []; + for(i = 0; i < level.bombZones.size; i++) + { + sites[sites.size] = level.bombZones[i]; + } + + if(!sites.size) + continue; + + if(rand > 50) + plant = self bot_array_nearest_curorigin(sites); + else + plant = random(sites); + + if(!isDefined(plant)) + continue; + + origin = ( plant.curorigin[0]+50, plant.curorigin[1]+50, plant.curorigin[2]+5 ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 1 ); + self thread bot_go_plant(plant); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if (event != "new_goal") + self ClearScriptGoal(); + + if(event != "goal" || level.bombPlanted || plant.visibleTeam == "none" || !self isTouching(plant.trigger) || self InLastStand() || self HasThreat() || plant IsInUse()) + { + self.bot_lock_goal = false; + continue; + } + + self SetScriptGoal( self.origin, 64 ); + + self bot_use_bomb_thread(plant); + wait 1; + + self ClearScriptGoal(); + self.bot_lock_goal = false; + } } diff --git a/main_shared/maps/mp/bots/_bot_utility.gsc b/main_shared/maps/mp/bots/_bot_utility.gsc index 3b3cb17..abc5857 100644 --- a/main_shared/maps/mp/bots/_bot_utility.gsc +++ b/main_shared/maps/mp/bots/_bot_utility.gsc @@ -415,6 +415,14 @@ getValidGrenade() return random(possibles); } +/* + If weap is a secondary gnade +*/ +isSecondaryGrenade(gnade) +{ + return (gnade == "tabun_gas_mp" || gnade == "m8_white_smoke_mp" || gnade == "signal_flare_mp"); +} + /* Returns if the given weapon is full auto. */