FANDOM


//
// C++ Implementation: bot
//
// Description: Code for botmanager
//
// Main bot file
//
// Author:  Rick <rickhelmus@gmail.com>
//
//
//
 
#include "cube.h"
#include "bot.h"
 
 
extern void respawnself();
 
CBotManager BotManager;
 
// Bot manager class begin
 
CBotManager::~CBotManager(void)
{
    EndMap();
}
 
void CBotManager::Init()
{
    m_bBotsShoot = true;
    m_bIdleBots = false;
    m_iFrameTime = 0;
    m_iPrevTime = lastmillis;
 
    LoadBotNamesFile();
    //WaypointClass.Init();
    lsrand(time(NULL));
}
 
void CBotManager::Think()
{
    if (m_bInit)
    {
       Init();
       m_bInit = false;
    }
 
    AddDebugText("m_sMaxAStarBots: %d", m_sMaxAStarBots);
    AddDebugText("m_sCurrentTriggerNr: %d", m_sCurrentTriggerNr);
    short x, y;
    WaypointClass.GetNodeIndexes(player1->o, &x, &y);
    AddDebugText("x: %d y: %d", x, y);
 
    m_iFrameTime = lastmillis - m_iPrevTime;
    if (m_iFrameTime > 250) m_iFrameTime = 250;
    m_iPrevTime = lastmillis;
 
    // Added by Victor: control multiplayer bots
    const int ourcn = getclientnum();
    if(ourcn >= 0 && m_ai(gamemode))
    {
       // handle the bots
       loopv(players)
       {
          if(!players[i] || players[i]->ownernum != ourcn) continue;
          playerent *b = players[i];
          // ensure there is a bot controller
          if(!b->pBot)
          {
             b->pBot = new CACBot;
             b->pBot->m_pMyEnt = b;
 
             // create skills
             b->pBot->m_pBotSkill = NULL;
             b->pBot->MakeSkill(b->level);
 
             // Sync waypoints
             b->pBot->SyncWaypoints();
             // Try spawn
             b->pBot->Spawn();
          }
          b->pBot->Think();
       }
    }
}
 
void CBotManager::LoadBotNamesFile()
{
    // Init bot names array first
    for (int i=0;i<MAXBOTNAMES;i++)
        strcpy(m_szBotNames[i], "Bot");
 
    m_sBotNameCount = 0;
 
    // Load bot file
    char szNameFileName[256];
    MakeBotFileName("bot_names.txt", NULL, szNameFileName);
    FILE *fp = fopen(szNameFileName, "r");
    char szNameBuffer[256];
    int iIndex, iStrIndex;
 
    if (!fp)
    {
        conoutf("Warning: Couldn't load bot names file");
        return;
    }
 
    while (fgets(szNameBuffer, 80, fp) != NULL)
    {
        if (m_sBotNameCount >= MAXBOTNAMES)
        {
            conoutf("Warning: Max bot names reached (%d), ignoring the rest of the names", MAXBOTNAMES);
            break;
        }
 
        // Skip entries starting with //
        if(szNameBuffer[0] == '/' && szNameBuffer[0] == szNameBuffer[1])
            continue;
 
        short length = (short)strlen(szNameBuffer);
 
        if (szNameBuffer[length-1] == '\n')
        {
            szNameBuffer[length-1] = '\0';  // remove '\n'
            length--;
        }
 
        iStrIndex = 0;
        while (iStrIndex < length)
        {
            if ((szNameBuffer[iStrIndex] < ' ') || (szNameBuffer[iStrIndex] > '~') ||
                (szNameBuffer[iStrIndex] == '"'))
            {
                for (iIndex=iStrIndex; iIndex < length; iIndex++)
                    szNameBuffer[iIndex] = szNameBuffer[iIndex+1];
            }
 
            iStrIndex++;
        }
 
        if (szNameBuffer[0] != 0)
        {
            if (strlen(szNameBuffer) > MAXNAMELEN)
                conoutf("Warning: bot name \"%s\" has too many characters (%d is max)", szNameBuffer, MAXNAMELEN);
            copystring(m_szBotNames[m_sBotNameCount], szNameBuffer, MAXNAMELEN);
            m_sBotNameCount++;
        }
    }
    fclose(fp);
}
 
void CBotManager::GetBotName(int seed, playerent *pl)
{
    if(!m_sBotNameCount)
    {
        copystring(pl->name, "a bot");
        return;
    }
    // Use a random name
    const char *name = m_szBotNames[detrnd(seed, m_sBotNameCount)];
    const char *rank = ""; // prepend rank (only if based on skill)
 
    if(name[0] == '*') // rank is based on skill
    {
        name += name[1] == ' ' ? 2 : 1; // skip * and space
        if(pl->level >= 90) rank = "Lt. "; // 10%
        else if(pl->level >= 70) rank = "Sgt. "; // 20%
        else if(pl->level >= 40) rank = "Cpl. "; // 30%
        else if(pl->level >= 20) rank = "Pfc. "; // 20%
        else rank = "Pvt. "; // 20%
    }
 
    defformatstring(fname)("%s%s", rank, name);
    filtername(pl->name, fname);
}
 
void playerent::removeai()
{
    if(pBot)
    {
        DELETEP(pBot->m_pBotSkill);
        DELETEP(pBot);
    }
    loopv(players)
        if(players[i] && this == players[i]->enemy)
            players[i]->enemy = NULL;
}
 
void CBotManager::EndMap()
{
    // Remove all bots
    loopv(players)
        if(players[i])
            players[i]->removeai();
}
 
void CBotManager::BeginMap(const char *szMapName)
{
    EndMap(); // End previous map
 
    WaypointClass.Init();
    WaypointClass.SetMapName(szMapName);
    if (szMapName[0] && !WaypointClass.LoadWaypoints())
        WaypointClass.StartFlood();
    //WaypointClass.LoadWPExpFile(); // UNDONE
 
    CalculateMaxAStarCount();
    m_sUsingAStarBotsCount = 0;
    PickNextTrigger();
}
 
void CBotManager::LetBotsHear(int n, const vec *loc)
{
    if (!loc) return;
 
    loopv(players)
    {
        if (!players[i] || players[i]->ownernum != player1->clientnum || !players[i]->pBot || players[i]->state == CS_DEAD) continue;
        players[i]->pBot->HearSound(n, loc);
    }
}
 
// Notify all bots of a new waypoint
void CBotManager::AddWaypoint(node_s *pNode)
{
    if (players.length())
    {
        short x, y;
        waypoint_s *pWP;
 
        loopv(players)
        {
            if (!players[i] || !players[i]->pBot) continue;
 
            pWP = new waypoint_s;
            pWP->pNode = pNode;
            WaypointClass.GetNodeIndexes(pNode->v_origin, &x, &y);
            players[i]->pBot->m_WaypointList[x][y].AddNode(pWP);
 
#ifndef RELEASE_BUILD
            if (!players[i]->pBot->GetWPFromNode(pNode)) condebug("Error adding bot wp!");
#endif
        }
    }
 
    CalculateMaxAStarCount();
}
 
// Notify all bots of a deleted waypoint
void CBotManager::DelWaypoint(node_s *pNode)
{
    if (players.length())
    {
        short x, y;
        TLinkedList<waypoint_s *>::node_s *p;
 
        loopv(players)
        {
            if (!players[i] || !players[i]->pBot) continue;
 
            WaypointClass.GetNodeIndexes(pNode->v_origin, &x, &y);
            p = players[i]->pBot->m_WaypointList[x][y].GetFirst();
 
            while(p)
            {
                if (p->Entry->pNode == pNode)
                {
                    delete p->Entry;
                    players[i]->pBot->m_WaypointList[x][y].DeleteNode(p);
                    break;
                }
                p = p->next;
            }
        }
    }
 
    CalculateMaxAStarCount();
}
 
void CBotManager::MakeBotFileName(const char *szFileName, const char *szDir1, char *szOutput)
{
    const char *DirSeperator;
 
#ifdef WIN32
    DirSeperator = "\\";
    strcpy(szOutput, "bot\\");
#else
    DirSeperator = "/";
    strcpy(szOutput, "bot/");
#endif
 
    if (szDir1)
    {
        strcat(szOutput, szDir1);
        strcat(szOutput, DirSeperator);
    }
 
    strcat(szOutput, szFileName);
}
 
void CBotManager::CalculateMaxAStarCount()
{
    if (WaypointClass.m_iWaypointCount > 0) // Are there any waypoints?
    {
        m_sMaxAStarBots = 8 - short(ceil((float)WaypointClass.m_iWaypointCount /
                               1000.0f));
        if (m_sMaxAStarBots < 1)
            m_sMaxAStarBots = 1;
    }
    else
        m_sMaxAStarBots = 1;
}
 
void CBotManager::PickNextTrigger()
{
    short lowest = -1;
    bool found0 = false; // True if found a trigger with nr 0
 
    loopv(ents)
    {
        entity &e = ents[i];
 
#if defined AC_CUBE
/*        if ((e.type != TRIGGER) || !e.spawned)
            continue;*/
#elif defined VANILLA_CUBE
        if ((e.type != CARROT) || !e.spawned)
            continue;
#endif
        if (OUTBORD(e.x, e.y)) continue;
 
        vec o(e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight);
 
        node_s *pWptNearEnt = NULL;
 
        pWptNearEnt = WaypointClass.GetNearestTriggerWaypoint(o, 2.0f);
 
        if (pWptNearEnt)
        {
            if ((pWptNearEnt->sTriggerNr > 0) &&
                ((pWptNearEnt->sTriggerNr < lowest) || (lowest == -1)))
                lowest = pWptNearEnt->sTriggerNr;
            if (pWptNearEnt->sTriggerNr == 0) found0 = true;
        }
 
#ifdef WP_FLOOD
        pWptNearEnt = WaypointClass.GetNearestTriggerFloodWP(o, 2.0f);
 
        if (pWptNearEnt)
        {
            if ((pWptNearEnt->sTriggerNr > 0) &&
                ((pWptNearEnt->sTriggerNr < lowest) || (lowest == -1)))
                lowest = pWptNearEnt->sTriggerNr;
            if (pWptNearEnt->sTriggerNr == 0) found0 = true;
        }
 
#endif
    }
 
    if ((lowest == -1) && found0) lowest = 0;
 
    if (lowest != -1)
        m_sCurrentTriggerNr = lowest;
}
 
// Bot manager class end
 
#ifndef RELEASE_BUILD
 
#ifdef VANILLA_CUBE
void drawbeamtocarrots()
{
    loopv(ents)
    {
        entity &e = ents[i];
        vec o = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight };
        if ((e.type != CARROT) || !e.spawned) continue;
        particle_trail(PART_SMOKE, 500, player1->o, o);
    }
}
 
COMMAND(drawbeamtocarrots, "");
 
void drawbeamtoteleporters()
{
    loopv(ents)
    {
        entity &e = ents[i];
        vec o = { e.x, e.y, S(e.x, e.y)->floor+player1->eyeheight };
        if (e.type != TELEPORT) continue;
        particle_trail(PART_SMOKE, 500, player1->o, o);
    }
}
 
COMMAND(drawbeamtoteleporters, "");
#endif
 
void telebot(void)
{
    vec dest = player1->o, forward, right, up;
    vec angles(player1->pitch, player1->yaw, player1->roll);
    traceresult_s tr;
 
    AnglesToVectors(angles, forward, right, up);
    forward.mul(4.0f);
    dest.add(forward);
 
    TraceLine(player1->o, dest, player1, true, &tr);
 
    if (!tr.collided)
    {
        // Get the first bot
        loopv(bots)
        {
            if (!bots[i] || !bots[i]->pBot) continue;
            bots[i]->o = tr.end;
            bots[i]->resetinterp();
            break;
        }
    }
}
 
COMMAND(telebot, "");
 
void testvisible(int iDir)
{
 
    vec angles, end, forward, right, up;
    traceresult_s tr;
    int Dir;
 
    switch(iDir)
    {
        case 0: default: Dir = FORWARD; break;
        case 1: Dir = BACKWARD; break;
        case 2: Dir = LEFT; break;
        case 3: Dir = RIGHT; break;
        case 4: Dir = UP; break;
        case 5: Dir = DOWN; break;
    }
 
    vec from = player1->o;
    from.z -= (player1->eyeheight - 1.25f);
    end = from;
    makevec(&angles, player1->pitch, player1->yaw, player1->roll);
    angles.x=0;
 
    if (Dir & UP)
        angles.x = WrapXAngle(angles.x + 45.0f);
    else if (Dir & DOWN)
        angles.x = WrapXAngle(angles.x - 45.0f);
 
    if ((Dir & FORWARD) || (Dir & BACKWARD))
    {
        if (Dir & BACKWARD)
            angles.y = WrapYZAngle(angles.y + 180.0f);
 
        if (Dir & LEFT)
        {
            if (Dir & FORWARD)
                angles.y = WrapYZAngle(angles.y - 45.0f);
            else
                angles.y = WrapYZAngle(angles.y + 45.0f);
        }
        else if (Dir & RIGHT)
        {
            if (Dir & FORWARD)
                angles.y = WrapYZAngle(angles.y + 45.0f);
            else
                angles.y = WrapYZAngle(angles.y - 45.0f);
        }
    }
    else if (Dir & LEFT)
        angles.y = WrapYZAngle(angles.y - 90.0f);
    else if (Dir & RIGHT)
        angles.y = WrapYZAngle(angles.y + 90.0f);
    else if (Dir & UP)
        angles.x = WrapXAngle(angles.x + 90.0f);
    else if (Dir & DOWN)
        angles.x = WrapXAngle(angles.x - 90.0f);
 
    AnglesToVectors(angles, forward, right, up);
 
    forward.mul(20.0f);
    end.add(forward);
 
    TraceLine(from, end, player1, false, &tr);
 
    //debugbeam(from, tr.end);
    char sz[250];
    sprintf(sz, "dist: %f; hit: %d", GetDistance(from, tr.end), tr.collided);
    condebug(sz);
}
 
COMMANDF(testvisible, "i", (int *dir) { testvisible(*dir); });
 
void mapsize(void)
{
    switch(ssize)
    {
        case 128:  intret(7);  break;
        case 256:  intret(8);  break;
        case 512:  intret(9);  break;
        case 1024: intret(10); break;
        case 2048: intret(11); break;
        case 4096: intret(12); break;
        default:   intret(6);  break;
    }
}
 
COMMAND(mapsize, "");
 
#endif

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.