2019-09-23 00:09:58 +03:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2 of the License, or (at
|
|
|
|
* your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* In addition, as a special exception, the author gives permission to
|
|
|
|
* link the code of this program with the Half-Life Game Engine ("HL
|
|
|
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
|
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
|
|
* respects for all of the code used other than the HL Engine and MODs
|
|
|
|
* from Valve. If you modify this file, you may extend this exception
|
|
|
|
* to your version of the file, but you are not obligated to do so. If
|
|
|
|
* you do not wish to do so, delete this exception statement from your
|
|
|
|
* version.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "precompiled.h"
|
|
|
|
|
|
|
|
// Begin the hunt
|
|
|
|
void HuntState::OnEnter(CCSBot *me)
|
|
|
|
{
|
|
|
|
// lurking death
|
|
|
|
if (me->IsUsingKnife() && me->IsWellPastSafe() && !me->IsHurrying())
|
|
|
|
me->Walk();
|
|
|
|
else
|
|
|
|
me->Run();
|
|
|
|
|
|
|
|
me->StandUp();
|
|
|
|
me->SetDisposition(CCSBot::ENGAGE_AND_INVESTIGATE);
|
|
|
|
me->SetTask(CCSBot::SEEK_AND_DESTROY);
|
|
|
|
me->DestroyPath();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hunt down our enemies
|
|
|
|
void HuntState::OnUpdate(CCSBot *me)
|
|
|
|
{
|
|
|
|
// if we've been hunting for a long time, drop into Idle for a moment to
|
|
|
|
// select something else to do
|
|
|
|
const float huntingTooLongTime = 30.0f;
|
|
|
|
if (gpGlobals->time - me->GetStateTimestamp() > huntingTooLongTime)
|
|
|
|
{
|
|
|
|
// stop being a rogue and do the scenario, since there must not be many enemies left to hunt
|
|
|
|
me->PrintIfWatched("Giving up hunting, and being a rogue\n");
|
|
|
|
me->SetRogue(false);
|
|
|
|
me->Idle();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// scenario logic
|
|
|
|
if (TheCSBots()->GetScenario() == CCSBotManager::SCENARIO_DEFUSE_BOMB)
|
|
|
|
{
|
|
|
|
if (me->m_iTeam == TERRORIST)
|
|
|
|
{
|
|
|
|
// if we have the bomb and it's time to plant, or we happen to be in a bombsite and it seems safe, do it
|
|
|
|
if (me->IsCarryingBomb())
|
|
|
|
{
|
|
|
|
const float safeTime = 3.0f;
|
|
|
|
if (TheCSBots()->IsTimeToPlantBomb() || (me->IsAtBombsite() && gpGlobals->time - me->GetLastSawEnemyTimestamp() > safeTime))
|
|
|
|
{
|
|
|
|
me->Idle();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we notice the bomb lying on the ground, go get it
|
|
|
|
if (me->NoticeLooseBomb())
|
|
|
|
{
|
|
|
|
me->FetchBomb();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if bomb has been planted, and we hear it, move to a hiding spot near the bomb and watch it
|
|
|
|
const Vector *bombPos = me->GetGameState()->GetBombPosition();
|
|
|
|
if (!me->IsRogue() && me->GetGameState()->IsBombPlanted() && bombPos)
|
|
|
|
{
|
|
|
|
me->SetTask(CCSBot::GUARD_TICKING_BOMB);
|
|
|
|
me->Hide(TheNavAreaGrid.GetNavArea(bombPos));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// CT
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!me->IsRogue() && me->CanSeeLooseBomb())
|
|
|
|
{
|
2023-12-31 13:30:29 +03:00
|
|
|
CNavArea *looseBombArea = TheCSBots()->GetLooseBombArea();
|
|
|
|
|
2019-09-23 00:09:58 +03:00
|
|
|
// if we are near the loose bomb and can see it, hide nearby and guard it
|
|
|
|
me->SetTask(CCSBot::GUARD_LOOSE_BOMB);
|
2023-12-31 13:30:29 +03:00
|
|
|
me->Hide(looseBombArea);
|
|
|
|
|
|
|
|
if (looseBombArea)
|
|
|
|
me->GetChatter()->AnnouncePlan("GoingToGuardLooseBomb", looseBombArea->GetPlace());
|
|
|
|
|
2019-09-23 00:09:58 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (TheCSBots()->IsBombPlanted())
|
|
|
|
{
|
|
|
|
// rogues will defuse a bomb, but not guard the defuser
|
|
|
|
if (!me->IsRogue() || !TheCSBots()->GetBombDefuser())
|
|
|
|
{
|
|
|
|
// search for the planted bomb to defuse
|
|
|
|
me->Idle();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (TheCSBots()->GetScenario() == CCSBotManager::SCENARIO_RESCUE_HOSTAGES)
|
|
|
|
{
|
|
|
|
if (me->m_iTeam == TERRORIST)
|
|
|
|
{
|
|
|
|
if (me->GetGameState()->AreAllHostagesBeingRescued())
|
|
|
|
{
|
|
|
|
// all hostages are being rescued, head them off at the escape zones
|
|
|
|
if (me->GuardRandomZone())
|
|
|
|
{
|
|
|
|
me->SetTask(CCSBot::GUARD_HOSTAGE_RESCUE_ZONE);
|
|
|
|
me->PrintIfWatched("Trying to beat them to an escape zone!\n");
|
|
|
|
me->SetDisposition(CCSBot::OPPORTUNITY_FIRE);
|
|
|
|
me->GetChatter()->GuardingHostageEscapeZone(IS_PLAN);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if safe time is up, and we stumble across a hostage, guard it
|
|
|
|
if (!me->IsRogue() && !me->IsSafe())
|
|
|
|
{
|
|
|
|
CHostage *pHostage = me->GetGameState()->GetNearestVisibleFreeHostage();
|
|
|
|
if (pHostage)
|
|
|
|
{
|
|
|
|
CNavArea *area = TheNavAreaGrid.GetNearestNavArea(&pHostage->pev->origin);
|
|
|
|
if (area)
|
|
|
|
{
|
|
|
|
// we see a free hostage, guard it
|
|
|
|
me->SetTask(CCSBot::GUARD_HOSTAGES);
|
|
|
|
me->Hide(area);
|
|
|
|
me->PrintIfWatched("I'm guarding hostages\n");
|
|
|
|
me->GetChatter()->GuardingHostages(area->GetPlace(), IS_PLAN);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// listen for enemy noises
|
|
|
|
if (me->ShouldInvestigateNoise())
|
|
|
|
{
|
|
|
|
me->InvestigateNoise();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// look around
|
|
|
|
me->UpdateLookAround();
|
|
|
|
|
|
|
|
// if we have reached our destination area, pick a new one
|
|
|
|
// if our path fails, pick a new one
|
|
|
|
if (me->GetLastKnownArea() == m_huntArea || me->UpdatePathMovement() != CCSBot::PROGRESSING)
|
|
|
|
{
|
|
|
|
m_huntArea = nullptr;
|
|
|
|
float oldest = 0.0f;
|
|
|
|
|
|
|
|
int areaCount = 0;
|
|
|
|
const float minSize = 150.0f;
|
|
|
|
for (auto area : TheNavAreaList)
|
|
|
|
{
|
|
|
|
areaCount++;
|
|
|
|
|
|
|
|
// skip the small areas
|
|
|
|
const Extent *extent = area->GetExtent();
|
|
|
|
if (extent->hi.x - extent->lo.x < minSize || extent->hi.y - extent->lo.y < minSize)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// keep track of the least recently cleared area
|
|
|
|
real_t age = gpGlobals->time - area->GetClearedTimestamp(me->m_iTeam - 1);
|
|
|
|
if (age > oldest)
|
|
|
|
{
|
|
|
|
oldest = age;
|
|
|
|
m_huntArea = area;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if all the areas were too small, pick one at random
|
|
|
|
int which = RANDOM_LONG(0, areaCount - 1);
|
|
|
|
|
|
|
|
areaCount = 0;
|
|
|
|
for (auto area : TheNavAreaList)
|
|
|
|
{
|
|
|
|
m_huntArea = area;
|
|
|
|
|
|
|
|
if (which == areaCount)
|
|
|
|
break;
|
|
|
|
|
|
|
|
which--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_huntArea)
|
|
|
|
{
|
|
|
|
// create a new path to a far away area of the map
|
|
|
|
me->ComputePath(m_huntArea, nullptr, SAFEST_ROUTE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Done hunting
|
|
|
|
void HuntState::OnExit(CCSBot *me)
|
|
|
|
{
|
|
|
|
;
|
|
|
|
}
|