Files
assaultcube-/source/src/bot/ac_bot_ai.cpp
T
driAn ae6f1981da it is v1.0, not v0.94
git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@1965 e016b1c5-ed68-44aa-a2f7-31cac88cffde
2008-05-14 18:13:09 +00:00

319 lines
9.8 KiB
C++

//
// C++ Implementation: ac_bot_ai
//
// Description: The AI part of the bot for ac is here(navigation, shooting etc)
//
//
// Author: <[email protected]>
//
#include "pch.h"
#include "bot.h"
#ifdef AC_CUBE
// UNDONE
weaponinfo_s WeaponInfoTable[MAX_WEAPONS] =
{
// KNIFE
{ TYPE_MELEE, 0.0f, 2.0f, 0.0f, 3.5f, 1 },
// PISTOL
{ TYPE_NORMAL, 0.0f, 20.0f, 0.0f, 50.0f, 6 },
// SHOTGUN
{ TYPE_SHOTGUN, 0.0f, 15.0f, 0.0f, 40.0f, 3 },
// SUBGUN
{ TYPE_AUTO, 0.0f, 25.0f, 0.0f, 60.0f, 10 },
// SNIPER
{ TYPE_SNIPER, 30.0f, 50.0f, 20.0f, 200.0f, 3 },
// ASSAULT
{ TYPE_AUTO, 40.0f, 80.0f, 0.0f, 150.0f, 6 },
// GRENADE
{ TYPE_GRENADE, 30.0f, 25.0f, 0.0f, 50.0f, 1 }
};
// Code of CACBot - Start
bool CACBot::ChoosePreferredWeapon()
{
short bestWeapon = m_pMyEnt->gunselect;
short bestWeaponScore = 0;
short sWeaponScore;
float flDist = GetDistance(m_pMyEnt->enemy->o);
if (m_iChangeWeaponDelay < lastmillis && m_pMyEnt->mag[m_pMyEnt->gunselect])
{
if ((WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType != TYPE_MELEE) || (flDist <= WeaponInfoTable[GUN_KNIFE].flMaxFireDistance))
return true;
};
// Choose a weapon
for(int i=0;i<MAX_WEAPONS;i++)
{
// If no ammo for this weapon, skip it
if (!m_pMyEnt->mag[i] && !m_pMyEnt->ammo[i]) continue;
sWeaponScore = 5; // Minimal score for a weapon
// use the advantage of the melee weapon
if((flDist >= WeaponInfoTable[i].flMinDesiredDistance) &&
(flDist <= WeaponInfoTable[i].flMaxDesiredDistance))
{
if(WeaponInfoTable[i].eWeaponType == TYPE_MELEE) sWeaponScore += 5;
}
if ((flDist > WeaponInfoTable[i].flMinFireDistance) && // inside the range, continue to evaluate
(flDist < WeaponInfoTable[i].flMaxFireDistance))
{
if(m_pMyEnt->mag[i]) sWeaponScore += 5;
if(i > 1) sWeaponScore += 4; // prefer primary guns
}
if(sWeaponScore > bestWeaponScore)
{
bestWeaponScore = sWeaponScore;
bestWeapon = i;
}
}
{
m_iChangeWeaponDelay = lastmillis + 8000; //RandomLong(2000, 8000);
m_bShootAtFeet = false;
SelectGun(bestWeapon);
if(!m_pMyEnt->mag[bestWeapon])
{
tryreload(m_pMyEnt);
m_iShootDelay = lastmillis + reloadtime(bestWeapon) + 10;
}
return true;
}
};
void CACBot::Reload(int Gun)
{
};
entity *CACBot::SearchForEnts(bool bUseWPs, float flRange, float flMaxHeight)
{
/* Entities are scored on the following things:
- Visibility
- For ammo: Need(ie has this bot much of this type or not)
- distance
*/
float flNearestDist = 9999, flDist;
entity *pNewTargetEnt = NULL;
waypoint_s *pWptNearBot = NULL, *pBestWpt = NULL;
short sScore, sHighestScore = 0;
if ((WaypointClass.m_iWaypointCount >= 1) && bUseWPs)
pWptNearBot = GetNearestWaypoint(15.0f);
#ifdef WP_FLOOD
if (!pWptNearBot && bUseWPs)
pWptNearBot = GetNearestFloodWP(5.0f);
#endif
loopv(ents)
{
sScore = 0;
entity &e = ents[i];
vec o(e.x, e.y, S(e.x, e.y)->floor+player1->dyneyeheight());
if (!ents[i].spawned) continue;
if (OUTBORD(e.x, e.y)) continue;
bool bInteresting = false;
short sAmmo = 0, sMaxAmmo = 0;
switch(e.type)
{
case I_CLIPS:
sMaxAmmo = ammostats[GUN_PISTOL].max;
bInteresting = (m_pMyEnt->ammo[GUN_PISTOL]<sMaxAmmo);
sAmmo = m_pMyEnt->ammo[GUN_PISTOL];
break;
case I_AMMO:
sMaxAmmo = ammostats[m_pMyEnt->primary].max;
bInteresting = (m_pMyEnt->ammo[m_pMyEnt->primary]<sMaxAmmo);
sAmmo = m_pMyEnt->ammo[m_pMyEnt->primary];
break;
case I_GRENADE:
sMaxAmmo = ammostats[GUN_GRENADE].max;
bInteresting = (m_pMyEnt->mag[GUN_GRENADE]<sMaxAmmo);
sAmmo = m_pMyEnt->mag[GUN_GRENADE];
break;
case I_HEALTH:
sMaxAmmo = powerupstats[I_HEALTH-I_HEALTH].max; //FIXME
bInteresting = (m_pMyEnt->health < sMaxAmmo);
sAmmo = m_pMyEnt->health;
break;
case I_ARMOUR:
sMaxAmmo = powerupstats[I_ARMOUR-I_HEALTH].max; // FIXME
bInteresting = (m_pMyEnt->armour < sMaxAmmo);
sAmmo = m_pMyEnt->armour;
break;
};
if (!bInteresting)
continue; // Not an interesting item, skip
// Score on ammo and need
if (sAmmo == -1)
{
// This entity doesn't have/need ammo
// Score on type instead
//switch(e.type)
{ // UNDONE
}
}
else
{
// Calculate current percentage of max ammo
float percent = ((float)sAmmo / (float)sMaxAmmo) * 100.0f;
if (percent > 100.0f) percent = 100.0f;
sScore += ((100 - short(percent))/2);
}
flDist = GetDistance(o);
if (flDist > flRange) continue;
// Score on distance
float f = flDist;
if (f > 100.0f) f = 100.0f;
sScore += ((100 - short(f)) / 2);
waypoint_s *pWptNearEnt = NULL;
// If this entity isn't visible check if there is a nearby waypoint
if (!IsReachable(o, flMaxHeight))//(!IsVisible(o))
{
if (!pWptNearBot) continue;
#ifdef WP_FLOOD
if (pWptNearBot->pNode->iFlags & W_FL_FLOOD)
pWptNearEnt = GetNearestFloodWP(o, 8.0f);
else
#endif
pWptNearEnt = GetNearestWaypoint(o, 15.0f);
if (!pWptNearEnt) continue;
}
// Score on visibility
if (pWptNearEnt == NULL) // Ent is visible
sScore += 30;
else
sScore += 15;
if (sScore > sHighestScore)
{
// Found a valid wp near the bot and the ent,so...lets store it :)
if (pWptNearEnt)
pBestWpt = pWptNearEnt;
else
pBestWpt = NULL; // Best ent so far doesn't need any waypoints
sHighestScore = sScore;
flNearestDist = flDist;
pNewTargetEnt = &ents[i];
}
}
if (pNewTargetEnt)
{
// Need waypoints to reach it?
if (pBestWpt)
{
ResetWaypointVars();
SetCurrentWaypoint(pWptNearBot);
SetCurrentGoalWaypoint(pBestWpt);
}
m_vGoal.x = pNewTargetEnt->x;
m_vGoal.y = pNewTargetEnt->y;
m_vGoal.z = S(pNewTargetEnt->x, pNewTargetEnt->y)->floor+player1->dyneyeheight();
}
return pNewTargetEnt;
}
bool CACBot::HeadToTargetEnt()
{
if (m_pTargetEnt)
{
vec o(m_pTargetEnt->x, m_pTargetEnt->y,
S(m_pTargetEnt->x, m_pTargetEnt->y)->floor+m_pMyEnt->dyneyeheight());
if (m_pTargetEnt->spawned && (!UnderWater(m_pMyEnt->o) ||
!UnderWater(o)))
{
bool bIsVisible = false;
if (m_pCurrentGoalWaypoint)
{
if ((GetDistance(o) <= 20.0f) && IsReachable(o, 1.0f))
bIsVisible = true;
else if (HeadToGoal())
{
//debugbeam(m_pMyEnt->o, m_pCurrentWaypoint->pNode->v_origin);
//debugbeam(m_pMyEnt->o,
// m_pCurrentGoalWaypoint->pNode->v_origin);
AddDebugText("Using WPs for ents");
return true;
}
}
else
bIsVisible = IsVisible(o);
if (bIsVisible)
{
if (m_pCurrentWaypoint || m_pCurrentGoalWaypoint)
{
condebug("ent is now visible");
ResetWaypointVars();
}
float flHeightDiff = o.z - m_pMyEnt->o.z;
bool bToHigh = false;
if (Get2DDistance(o) <= 2.0f)
{
if (flHeightDiff >= 1.5f)
{
if (flHeightDiff <= JUMP_HEIGHT)
{
#ifndef RELEASE_BUILD
char sz[64];
sprintf(sz, "Ent z diff: %f", o.z-m_pMyEnt->o.z);
condebug(sz);
#endif
// Jump if close to ent and the ent is high
m_pMyEnt->jumpnext = true;
}
else
bToHigh = true;
}
}
if (!bToHigh)
{
AimToVec(o);
return true;
}
}
}
}
return false;
}
bool CACBot::DoSPStuff()
{
return false;
}
// Code of CACBot - End
#endif