home *** CD-ROM | disk | FTP | other *** search
- //
- // C++ Implementation: bot
- //
- // Description: Code for botmanager
- //
- // Main bot file
- //
- // Author: Rick <rickhelmus@gmail.com>
- //
- //
- //
-
- #include "bot.h"
-
- #ifndef VANILLA_CUBE // UNDONE
- bool dedserv = false;
- #define CS_DEDHOST 0xFF
- #endif
-
- extern ENetHost *clienthost;
-
- extern void respawnself();
-
- CBotManager BotManager;
-
- // Bot manager class begin
-
- CBotManager::~CBotManager(void)
- {
- EndMap();
-
- while(m_StoredBots.Empty() == false)
- delete m_StoredBots.Pop();
- }
-
- void CBotManager::Init()
- {
- m_pBotToView = NULL;
-
- m_bBotsShoot = true;
- m_bIdleBots = false;
- m_iFrameTime = 0;
- m_iPrevTime = lastmillis;
- m_sBotSkill = 1; // Default all bots have the skill 'Good'
-
- CreateSkillData();
- LoadBotNamesFile();
- LoadBotTeamsFile();
- //WaypointClass.Init();
- lsrand(time(NULL));
- }
-
- void CBotManager::Think()
- {
- if (m_bInit)
- {
- Init();
- m_bInit = false;
- }
-
- if (m_pBotToView)
- ViewBot();
-
- 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;
-
- // Is it time to re-add bots?
- if ((m_fReAddBotDelay < lastmillis) && (m_fReAddBotDelay != -1.0f))
- {
- while(m_StoredBots.Empty() == false)
- {
- CStoredBot *pStoredBot = m_StoredBots.Pop();
- ReAddBot(pStoredBot);
- delete pStoredBot;
- }
-
- m_fReAddBotDelay = -1.0f;
- }
-
- // If this is a ded server check if there are any players, if not bots should be idle
- if (dedserv)
- {
- bool botsbeidle = true;
- loopv(players)
- {
- if (players[i] && (players[i]->state != CS_DEDHOST)) { botsbeidle = false; break; }
- }
-
- if (botsbeidle) return;
- }
-
- // Let all bots 'think'
- loopv(bots)
- {
- if (!bots[i])
- continue;
-
- if (bots[i]->pBot)
- bots[i]->pBot->Think();
- else
- condebug("Error: pBot == NULL in bot ent\n");
- }
- }
-
- void CBotManager::LoadBotNamesFile()
- {
- // Init bot names array first
- for (int i=0;i<100;i++)
- strcpy(m_szBotNames[i], "Bot");
-
- m_sBotNameCount = 0;
-
- // Load bot file
- char szNameFileName[256];
- MakeBotFileName("bot_names.txt", NULL, 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 >= 150)
- {
- conoutf("Warning: Max bot names reached(150), ignoring the rest of the"
- "names");
- break;
- }
-
- 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) >= 16)
- { conoutf("Warning: bot name \"%s\" has to many characters(16 is max)",
- szNameBuffer);
- }
- s_strncpy(m_szBotNames[m_sBotNameCount], szNameBuffer, 16);
- m_sBotNameCount++;
- }
- }
- fclose(fp);
- }
-
- char *CBotManager::GetBotName()
- {
- char *szOutput = NULL;
- TMultiChoice<char *> BotNameChoices;
- short ChoiceVal;
-
- for(int j=0;j<m_sBotNameCount;j++)
- {
- ChoiceVal = 50;
-
- loopv(players)
- {
- if (players[i] && (players[i]->state != CS_DEDHOST) &&
- !strcasecmp(players[i]->name, m_szBotNames[j]))
- ChoiceVal -= 10;
- }
-
- loopv(bots)
- {
- if (bots[i] && (!strcasecmp(bots[i]->name, m_szBotNames[j])))
- ChoiceVal -= 10;
- }
-
- if ((player1->state != CS_DEDHOST) && !strcasecmp(player1->name, m_szBotNames[j]))
- ChoiceVal -= 10;
-
- if (ChoiceVal <= 0)
- ChoiceVal = 1;
-
- BotNameChoices.Insert(m_szBotNames[j], ChoiceVal);
- }
-
- // Couldn't find a selection?
- if (!BotNameChoices.GetSelection(szOutput))
- szOutput = "Bot";
-
- return szOutput;
- }
-
- void CBotManager::LoadBotTeamsFile()
- {
- // Init bot teams array first
- for (int i=0;i<20;i++)
- strcpy(m_szBotTeams[i], "b0ts");
-
- m_sBotTeamCount = 0;
-
- // Load bot file
- char szNameFileName[256];
- MakeBotFileName("bot_teams.txt", NULL, NULL, szNameFileName);
- FILE *fp = fopen(szNameFileName, "r");
- char szNameBuffer[256];
- int iIndex, iStrIndex;
-
- if (!fp)
- {
- conoutf("Warning: Couldn't load bot teams file");
- return;
- }
-
- while ((m_sBotTeamCount < 20) && (fgets(szNameBuffer, 80, fp) != NULL))
- {
- 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)
- {
- s_strncpy(m_szBotTeams[m_sBotTeamCount], szNameBuffer, 5);
- m_sBotTeamCount++;
- }
- }
- fclose(fp);
- }
-
- char *CBotManager::GetBotTeam()
- {
- char *szOutput = NULL;
- TMultiChoice<char *> BotTeamChoices;
- short ChoiceVal;
-
- for(int j=0;j<m_sBotTeamCount;j++)
- {
- ChoiceVal = 50;
- /* UNDONE?
- loopv(players)
- {
- if (players[i] && (!strcasecmp(players[i]->name, m_szBotNames[j])))
- ChoiceVal -= 10;
- }
-
- loopv(bots)
- {
- if (bots[i] && (!strcasecmp(bots[i]->name, m_szBotNames[j])))
- ChoiceVal -= 10;
- }
-
- if (!strcasecmp(player1->name, m_szBotNames[j]))
- ChoiceVal -= 10;
-
- if (ChoiceVal <= 0)
- ChoiceVmonsterclearal = 1;*/
-
- BotTeamChoices.Insert(m_szBotTeams[j], ChoiceVal);
- }
-
- // Couldn't find a selection?
- if (!BotTeamChoices.GetSelection(szOutput))
- szOutput = "b0t";
-
- return szOutput;
- }
-
- void CBotManager::RenderBots()
- {
- //static bool drawblue;
-
- loopv(bots)
- {
- if (bots[i] && (bots[i] != m_pBotToView))
- {
- /*drawblue = (m_sp || isteam(player1->team, bots[i]->team));
- renderclient(bots[i], drawblue, "playermodels/counterterrorist", 1.6f);*/
- renderclient(bots[i]);
- }
- }
- }
-
- void CBotManager::EndMap()
- {
- // Remove all bots
- loopv(bots)
- {
- if(!bots[i] || !bots[i]->pBot)
- continue;
-
- // Store bots so they can be re-added after map change
- if (bots[i]->pBot && bots[i]->name[0] && bots[i]->team[0])
- {
- CStoredBot *pStoredBot = new CStoredBot(bots[i]->name, bots[i]->team,
- bots[i]->pBot->m_sSkillNr);
- m_StoredBots.AddNode(pStoredBot);
- }
- delete bots[i]->pBot;
-
- bots[i]->pBot = NULL;
- freebotent(bots[i]);
- }
- bots.setsize(0);
- condebug("Cleared all bots");
- m_fReAddBotDelay = lastmillis + 7500;
- //if(ishost()) WaypointClass.SaveWPExpFile(); //UNDONE
- }
-
- void CBotManager::BeginMap(char *szMapName)
- {
- EndMap(); // End previous map
-
- WaypointClass.Init();
- WaypointClass.SetMapName(szMapName);
- if (!WaypointClass.LoadWaypoints())
- WaypointClass.StartFlood();
- //WaypointClass.LoadWPExpFile(); // UNDONE
-
- CalculateMaxAStarCount();
- m_sUsingAStarBotsCount = 0;
- PickNextTrigger();
- }
-
- int CBotManager::GetBotIndex(botent *m)
- {
- loopv(bots)
- {
- if (!bots[i])
- continue;
-
- if (bots[i] == m)
- return i;
- }
-
- return -1;
- }
-
- void CBotManager::LetBotsUpdateStats()
- {
- loopv(bots) if (bots[i] && bots[i]->pBot) bots[i]->pBot->m_bSendC2SInit = false;
- }
-
- void CBotManager::LetBotsHear(int n, vec *loc)
- {
- if (bots.length() == 0 || !loc) return;
-
- loopv(bots)
- {
- if (!bots[i] || !bots[i]->pBot || (bots[i]->state == CS_DEAD)) continue;
- bots[i]->pBot->HearSound(n, loc);
- }
- }
-
- // Notify all bots of a new waypoint
- void CBotManager::AddWaypoint(node_s *pNode)
- {
- if (bots.length())
- {
- short x, y;
- waypoint_s *pWP;
-
- loopv(bots)
- {
- if (!bots[i] || !bots[i]->pBot) continue;
-
- pWP = new waypoint_s;
- pWP->pNode = pNode;
- WaypointClass.GetNodeIndexes(pNode->v_origin, &x, &y);
- bots[i]->pBot->m_WaypointList[x][y].AddNode(pWP);
-
- #ifndef RELEASE_BUILD
- if (!bots[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 (bots.length())
- {
- short x, y;
- TLinkedList<waypoint_s *>::node_s *p;
-
- loopv(bots)
- {
- if (!bots[i] || !bots[i]->pBot) continue;
-
- WaypointClass.GetNodeIndexes(pNode->v_origin, &x, &y);
- p = bots[i]->pBot->m_WaypointList[x][y].GetFirst();
-
- while(p)
- {
- if (p->Entry->pNode == pNode)
- {
- delete p->Entry;
- bots[i]->pBot->m_WaypointList[x][y].DeleteNode(p);
- break;
- }
- p = p->next;
- }
- }
- }
-
- CalculateMaxAStarCount();
- }
-
- void CBotManager::MakeBotFileName(const char *szFileName, const char *szDir1, const char *szDir2, char *szOutput)
- {
- char *DirSeperator;
-
- #ifdef WIN32
- DirSeperator = "\\";
- strcpy(szOutput, "bot\\");
- #else
- DirSeperator = "/";
- strcpy(szOutput, "bot/");
- #endif
-
- if (szDir1)
- {
- strcat(szOutput, szDir1);
- strcat(szOutput, DirSeperator);
- }
-
- if (szDir2)
- {
- strcat(szOutput, szDir2);
- strcat(szOutput, DirSeperator);
- }
-
- strcat(szOutput, szFileName);
- }
-
- void CBotManager::CreateSkillData()
- {
- // First give the bot skill structure some default data
- InitSkillData();
-
- // Now see if we can load the skill.cfg file
- char SkillFileName[256] = "";
- FILE *pSkillFile = NULL;
- int SkillNr = -1;
- float value = 0;
-
- MakeBotFileName("bot_skill.cfg", NULL, NULL, SkillFileName);
-
- pSkillFile = fopen(SkillFileName, "r");
-
- conoutf("Reading bot_skill.cfg file... ");
-
- if (pSkillFile == NULL) // file doesn't exist
- {
- conoutf("skill file not found, default settings will be used\n");
- return;
- }
-
- int ch;
- char cmd_line[256];
- int cmd_index;
- char *cmd, *arg1;
-
- while (pSkillFile)
- {
- cmd_index = 0;
- cmd_line[cmd_index] = 0;
-
- ch = fgetc(pSkillFile);
-
- // skip any leading blanks
- while (ch == ' ')
- ch = fgetc(pSkillFile);
-
- while ((ch != EOF) && (ch != '\r') && (ch != '\n'))
- {
- if (ch == '\t') // convert tabs to spaces
- ch = ' ';
-
- cmd_line[cmd_index] = ch;
-
- ch = fgetc(pSkillFile);
-
- // skip multiple spaces in input file
- while ((cmd_line[cmd_index] == ' ') && (ch == ' '))
- ch = fgetc(pSkillFile);
-
- cmd_index++;
- }
-
- if (ch == '\r') // is it a carriage return?
- {
- ch = fgetc(pSkillFile); // skip the linefeed
- }
-
- // if reached end of file, then close it
- if (ch == EOF)
- {
- fclose(pSkillFile);
- pSkillFile = NULL;
- }
-
- cmd_line[cmd_index] = 0; // terminate the command line
-
- cmd_index = 0;
- cmd = cmd_line;
- arg1 = NULL;
-
- // skip to blank or end of string...
- while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0))
- cmd_index++;
-
- if (cmd_line[cmd_index] == ' ')
- {
- cmd_line[cmd_index++] = 0;
- arg1 = &cmd_line[cmd_index];
- }
-
- if ((cmd_line[0] == '#') || (cmd_line[0] == 0))
- continue; // skip if comment or blank line
-
-
- if (strcasecmp(cmd, "[SKILL1]") == 0)
- SkillNr = 0;
- else if (strcasecmp(cmd, "[SKILL2]") == 0)
- SkillNr = 1;
- else if (strcasecmp(cmd, "[SKILL3]") == 0)
- SkillNr = 2;
- else if (strcasecmp(cmd, "[SKILL4]") == 0)
- SkillNr = 3;
- else if (strcasecmp(cmd, "[SKILL5]") == 0)
- SkillNr = 4;
-
- if ((arg1 == NULL) || (*arg1 == 0))
- continue;
-
- if (SkillNr == -1) // Not in a skill block yet?
- continue;
-
- value = atof(arg1);
-
- if (strcasecmp(cmd, "min_x_aim_speed") == 0)
- {
- m_BotSkills[SkillNr].flMinAimXSpeed = value;
- }
- else if (strcasecmp(cmd, "max_x_aim_speed") == 0)
- {
- m_BotSkills[SkillNr].flMaxAimXSpeed = value;
- }
- else if (strcasecmp(cmd, "min_y_aim_speed") == 0)
- {
- m_BotSkills[SkillNr].flMinAimYSpeed = value;
- }
- else if (strcasecmp(cmd, "max_y_aim_speed") == 0)
- {
- m_BotSkills[SkillNr].flMaxAimYSpeed = value;
- }
- else if (strcasecmp(cmd, "min_x_aim_offset") == 0)
- {
- m_BotSkills[SkillNr].flMinAimXOffset = value;
- }
- else if (strcasecmp(cmd, "max_x_aim_offset") == 0)
- {
- m_BotSkills[SkillNr].flMaxAimXOffset = value;
- }
- else if (strcasecmp(cmd, "min_y_aim_offset") == 0)
- {
- m_BotSkills[SkillNr].flMinAimYOffset = value;
- }
- else if (strcasecmp(cmd, "max_y_aim_offset") == 0)
- {
- m_BotSkills[SkillNr].flMaxAimYOffset = value;
- }
- else if (strcasecmp(cmd, "min_attack_delay") == 0)
- {
- m_BotSkills[SkillNr].flMinAttackDelay = value;
- }
- else if (strcasecmp(cmd, "max_attack_delay") == 0)
- {
- m_BotSkills[SkillNr].flMaxAttackDelay = value;
- }
- else if (strcasecmp(cmd, "min_enemy_search_delay") == 0)
- {
- m_BotSkills[SkillNr].flMinEnemySearchDelay = value;
- }
- else if (strcasecmp(cmd, "max_enemy_search_delay") == 0)
- {
- m_BotSkills[SkillNr].flMaxEnemySearchDelay = value;
- }
- else if (strcasecmp(cmd, "shoot_at_feet_percent") == 0)
- {
- if (value < 0) value = 0;
- else if (value > 100) value = 100;
- m_BotSkills[SkillNr].sShootAtFeetWithRLPercent = (short)value;
- }
- else if (strcasecmp(cmd, "can_predict_position") == 0)
- {
- m_BotSkills[SkillNr].bCanPredict = value!=0;
- }
- else if (strcasecmp(cmd, "max_hear_volume") == 0)
- {
- if (value < 0) value = 0;
- else if (value > 255) value = 100;
- m_BotSkills[SkillNr].iMaxHearVolume = (int)value;
- }
- else if (strcasecmp(cmd, "can_circle_strafe") == 0)
- {
- m_BotSkills[SkillNr].bCircleStrafe = value!=0;
- }
- else if (strcasecmp(cmd, "can_search_items_in_combat") == 0)
- {
- m_BotSkills[SkillNr].bCanSearchItemsInCombat = value!=0;
- }
- }
-
- conoutf("done\n");
- }
-
- void CBotManager::InitSkillData()
- {
- // Best skill
- m_BotSkills[0].flMinReactionDelay = 0.015f;
- m_BotSkills[0].flMaxReactionDelay = 0.035f;
- m_BotSkills[0].flMinAimXOffset = 15.0f;
- m_BotSkills[0].flMaxAimXOffset = 20.0f;
- m_BotSkills[0].flMinAimYOffset = 10.0f;
- m_BotSkills[0].flMaxAimYOffset = 15.0f;
- m_BotSkills[0].flMinAimXSpeed = 330.0f;
- m_BotSkills[0].flMaxAimXSpeed = 355.0f;
- m_BotSkills[0].flMinAimYSpeed = 400.0f;
- m_BotSkills[0].flMaxAimYSpeed = 450.0f;
- m_BotSkills[0].flMinAttackDelay = 0.1f;
- m_BotSkills[0].flMaxAttackDelay = 0.4f;
- m_BotSkills[0].flMinEnemySearchDelay = 0.09f;
- m_BotSkills[0].flMaxEnemySearchDelay = 0.12f;
- m_BotSkills[0].sShootAtFeetWithRLPercent = 85;
- m_BotSkills[0].bCanPredict = true;
- m_BotSkills[0].iMaxHearVolume = 75;
- m_BotSkills[0].bCircleStrafe = true;
- m_BotSkills[0].bCanSearchItemsInCombat = true;
-
- // Good skill
- m_BotSkills[1].flMinReactionDelay = 0.035f;
- m_BotSkills[1].flMaxReactionDelay = 0.045f;
- m_BotSkills[1].flMinAimXOffset = 20.0f;
- m_BotSkills[1].flMaxAimXOffset = 25.0f;
- m_BotSkills[1].flMinAimYOffset = 15.0f;
- m_BotSkills[1].flMaxAimYOffset = 20.0f;
- m_BotSkills[1].flMinAimXSpeed = 250.0f;
- m_BotSkills[1].flMaxAimXSpeed = 265.0f;
- m_BotSkills[1].flMinAimYSpeed = 260.0f;
- m_BotSkills[1].flMaxAimYSpeed = 285.0f;
- m_BotSkills[1].flMinAttackDelay = 0.3f;
- m_BotSkills[1].flMaxAttackDelay = 0.6f;
- m_BotSkills[1].flMinEnemySearchDelay = 0.12f;
- m_BotSkills[1].flMaxEnemySearchDelay = 0.17f;
- m_BotSkills[1].sShootAtFeetWithRLPercent = 60;
- m_BotSkills[1].bCanPredict = true;
- m_BotSkills[1].iMaxHearVolume = 60;
- m_BotSkills[1].bCircleStrafe = true;
- m_BotSkills[1].bCanSearchItemsInCombat = true;
-
- // Medium skill
- m_BotSkills[2].flMinReactionDelay = 0.075f;
- m_BotSkills[2].flMaxReactionDelay = 0.010f;
- m_BotSkills[2].flMinAimXOffset = 25.0f;
- m_BotSkills[2].flMaxAimXOffset = 30.0f;
- m_BotSkills[2].flMinAimYOffset = 20.0f;
- m_BotSkills[2].flMaxAimYOffset = 25.0f;
- m_BotSkills[2].flMinAimXSpeed = 190.0f;
- m_BotSkills[2].flMaxAimXSpeed = 125.0f;
- m_BotSkills[2].flMinAimYSpeed = 210.0f;
- m_BotSkills[2].flMaxAimYSpeed = 240.0f;
- m_BotSkills[2].flMinAttackDelay = 0.75f;
- m_BotSkills[2].flMaxAttackDelay = 1.0f;
- m_BotSkills[2].flMinEnemySearchDelay = 0.18f;
- m_BotSkills[2].flMaxEnemySearchDelay = 0.22f;
- m_BotSkills[2].sShootAtFeetWithRLPercent = 25;
- m_BotSkills[2].bCanPredict = false;
- m_BotSkills[2].iMaxHearVolume = 45;
- m_BotSkills[2].bCircleStrafe = true;
- m_BotSkills[2].bCanSearchItemsInCombat = false;
-
- // Worse skill
- m_BotSkills[3].flMinReactionDelay = 0.15f;
- m_BotSkills[3].flMaxReactionDelay = 0.20f;
- m_BotSkills[3].flMinAimXOffset = 30.0f;
- m_BotSkills[3].flMaxAimXOffset = 35.0f;
- m_BotSkills[3].flMinAimYOffset = 25.0f;
- m_BotSkills[3].flMaxAimYOffset = 30.0f;
- m_BotSkills[3].flMinAimXSpeed = 155.0f;
- m_BotSkills[3].flMaxAimXSpeed = 170.0f;
- m_BotSkills[3].flMinAimYSpeed = 160.0f;
- m_BotSkills[3].flMaxAimYSpeed = 210.0f;
- m_BotSkills[3].flMinAttackDelay = 1.2f;
- m_BotSkills[3].flMaxAttackDelay = 1.6f;
- m_BotSkills[3].flMinEnemySearchDelay = 0.25f;
- m_BotSkills[3].flMaxEnemySearchDelay = 0.30f;
- m_BotSkills[3].sShootAtFeetWithRLPercent = 10;
- m_BotSkills[3].bCanPredict = false;
- m_BotSkills[3].iMaxHearVolume = 30;
- m_BotSkills[3].bCircleStrafe = false;
- m_BotSkills[3].bCanSearchItemsInCombat = false;
-
- // Bad skill
- m_BotSkills[4].flMinReactionDelay = 0.30f;
- m_BotSkills[4].flMaxReactionDelay = 0.50f;
- m_BotSkills[4].flMinAimXOffset = 35.0f;
- m_BotSkills[4].flMaxAimXOffset = 40.0f;
- m_BotSkills[4].flMinAimYOffset = 30.0f;
- m_BotSkills[4].flMaxAimYOffset = 35.0f;
- m_BotSkills[4].flMinAimXSpeed = 45.0f;
- m_BotSkills[4].flMaxAimXSpeed = 60.0f;
- m_BotSkills[4].flMinAimYSpeed = 125.0f;
- m_BotSkills[4].flMaxAimYSpeed = 180.0f;
- m_BotSkills[4].flMinAttackDelay = 1.5f;
- m_BotSkills[4].flMaxAttackDelay = 2.0f;
- m_BotSkills[4].flMinEnemySearchDelay = 0.30f;
- m_BotSkills[4].flMaxEnemySearchDelay = 0.36f;
- m_BotSkills[4].sShootAtFeetWithRLPercent = 0;
- m_BotSkills[4].bCanPredict = false;
- m_BotSkills[4].iMaxHearVolume = 15;
- m_BotSkills[4].bCircleStrafe = false;
- m_BotSkills[4].bCanSearchItemsInCombat = false;
- }
-
- void CBotManager::ChangeBotSkill(short Skill, botent *bot)
- {
- static char *SkillNames[5] = { "best", "good", "medium", "worse", "bad" };
-
- if (bot && bot->pBot)
- {
- // Only change skill of a single bot
- bot->pBot->m_pBotSkill = &m_BotSkills[Skill];
- bot->pBot->m_sSkillNr = Skill;
- conoutf("Skill of %s is now %s", bot->name, SkillNames[Skill]);
- return;
- }
-
- // Change skill of all bots
- loopv(bots)
- {
- if (!bots[i] || !bots[i]->pBot) continue;
-
- bots[i]->pBot->m_pBotSkill = &m_BotSkills[Skill];
- bots[i]->pBot->m_sSkillNr = Skill;
- }
-
- // Change default bot skill
- m_sBotSkill = Skill;
-
- conoutf("Skill of all bots is now %s", SkillNames[Skill]);
- }
-
- void CBotManager::ViewBot()
- {
- // Check if this bot is still in game
- bool bFound = false;
- loopv(bots)
- {
- if (bots[i] == m_pBotToView)
- {
- bFound = true;
- break;
- }
- }
-
- if (!bFound)
- {
- DisableBotView();
- return;
- }
-
- player1->state = CS_DEAD; // Fake dead
-
- player1->o = m_pBotToView->o;
- player1->o.z += 1.0f;
- player1->yaw = m_pBotToView->yaw;
- player1->pitch = m_pBotToView->pitch;
- player1->roll = m_pBotToView->roll;
- player1->radius = 0; // Don't collide
- }
-
- void CBotManager::DisableBotView()
- {
- m_pBotToView = NULL;
- respawnself();
- player1->radius = 1.1f;
- }
-
- 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;
- }
-
- botent *CBotManager::CreateBot(const char *team, const char *skill, const char *name)
- {
- botent *m = newbotent();
- if (!m) return NULL;
- loopi(NUMGUNS) m->ammo[i] = m->mag[i] = 0;
- setskin(m, rnd(6));
- // Create new bot class, dependand on the current mod
- #if defined VANILLA_CUBE
- m->pBot = new CCubeBot;
- #elif defined AC_CUBE
- m->pBot = new CACBot;
- #else
- #error "Unsupported mod!"
- #endif
- m->type = ENT_BOT;
- m->pBot->m_pMyEnt = m;
- m->pBot->m_iLastBotUpdate = 0;
- m->pBot->m_bSendC2SInit = false;
-
- if (name && *name)
- s_strncpy(m->name, name, 16);
- else
- s_strncpy(m->name, BotManager.GetBotName(), 16);
-
- if (team && *team && strcmp(team, "random"))
- s_strncpy(m->team, team, 5);
- else
- s_strncpy(m->team, BotManager.GetBotTeam(), 5);
-
- if (skill && *skill && strcmp(skill, "random"))
- {
- if (!strcasecmp(skill, "best"))
- m->pBot->m_sSkillNr = 0;
- else if (!strcasecmp(skill, "good"))
- m->pBot->m_sSkillNr = 1;
- else if (!strcasecmp(skill, "medium"))
- m->pBot->m_sSkillNr = 2;
- else if (!strcasecmp(skill, "worse"))
- m->pBot->m_sSkillNr = 3;
- else if (!strcasecmp(skill, "bad"))
- m->pBot->m_sSkillNr = 4;
- else
- {
- conoutf("Wrong skill specified. Should be best, good, medium, "
- "worse or bad");
- conoutf("Using default skill instead...");
- m->pBot->m_sSkillNr = BotManager.m_sBotSkill;
- }
- }
- else // No skill specified, use default
- m->pBot->m_sSkillNr = BotManager.m_sBotSkill;
-
- m->pBot->m_pBotSkill = &BotManager.m_BotSkills[m->pBot->m_sSkillNr];
-
- // Sync waypoints
- m->pBot->SyncWaypoints();
-
- m->pBot->Spawn();
-
- bots.add(m);
-
- return m;
- }
-
- bool botmode()
- {
- if(m_botmode) return true;
- conoutf("the current game mode does not support bots");
- return false;
- }
-
- // Bot manager class end
-
- void addbot(char *arg1, char *arg2, char *arg3)
- {
- if(!botmode()) return;
- conoutf("Creating bot...\n");
- botent *b = BotManager.CreateBot(arg1, arg2, arg3);
- if (b)
- conoutf("connected: %s", b->name);
- else
- {
- conoutf("Error: Couldn't create bot!");
- return;
- }
- }
-
- COMMAND(addbot, ARG_3STR);
-
- void addnbot(char *arg1, char *arg2, char *arg3)
- {
- if(!botmode()) return;
- if (!arg1 || !arg1[0]) return;
-
- int i = atoi(arg1);
-
- while(i > 0)
- {
- addbot(arg2, arg3, NULL);
- i--;
- }
- }
-
- COMMAND(addnbot, ARG_3STR);
-
- void botsshoot(int Shoot)
- {
- if (Shoot)
- {
- BotManager.SetBotsShoot(true);
- conoutf("Bots will shoot");
- }
- else
- {
- BotManager.SetBotsShoot(false);
- conoutf("Bots won't shoot");
- }
- }
-
- COMMAND(botsshoot, ARG_1INT);
-
- void idlebots(int Idle)
- {
- if (Idle)
- {
- BotManager.SetIdleBots(true);
- conoutf("Bots are idle");
- }
- else
- {
- BotManager.SetIdleBots(false);
- conoutf("Bots aren't idle");
- }
- }
-
- COMMAND(idlebots, ARG_1INT);
-
- void drawbeamtobots()
- {
- if(!botmode()) return;
- loopv(bots)
- {
- if (bots[i])
- particle_trail(1, 500, player1->o, bots[i]->o);
- }
- }
-
- COMMAND(drawbeamtobots, ARG_NONE);
-
- void kickbot(const char *szName)
- {
- if(!botmode()) return;
- if (!szName || !(*szName))
- return;
-
- int iBotInd = -1;
- loopv(bots)
- {
- if (!bots[i]) continue;
-
- if (!strcmp(bots[i]->name, szName))
- {
- iBotInd = i;
- break;
- }
- }
-
- if (iBotInd != -1)
- {
- botent *d = bots[iBotInd];
- if(d->name[0]) conoutf("bot %s disconnected", d->name);
- delete d->pBot;
- bots.remove(iBotInd);
- freebotent(d);
- }
- }
-
- COMMAND(kickbot, ARG_1STR);
-
- void kickallbots(void)
- {
- BotManager.ClearStoredBots();
-
- loopv(bots)
- {
- if (bots[i])
- {
- if(bots[i]->name[0]) conoutf("bot %s disconnected", bots[i]->name);
- delete bots[i]->pBot;
- freebotent(bots[i]);
- }
- };
-
- bots.setsize(0);
- }
-
- COMMAND(kickallbots, ARG_NONE);
-
- void togglegrap()
- {
- if(!botmode()) return;
- if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GrabMode(0))
- SDL_WM_GrabInput(SDL_GRAB_ON);
- else
- SDL_WM_GrabInput(SDL_GrabMode(0));
- }
-
- COMMAND(togglegrap, ARG_NONE);
-
- void togglebotview(char *bot)
- {
- if(!botmode()) return;
- if (BotManager.m_pBotToView)
- BotManager.DisableBotView();
- else if (bot && *bot)
- {
- loopv(bots)
- {
- if (!bots[i]) continue;
-
- if (!strcmp(bots[i]->name, bot))
- {
- BotManager.EnableBotView(bots[i]);
- break;
- }
- }
- }
- }
-
- COMMAND(togglebotview, ARG_1STR);
-
- void botskill(char *bot, char *skill)
- {
- if (!skill || !(*skill))
- return;
-
- short SkillNr;
-
- if (!strcasecmp(skill, "best"))
- SkillNr = 0;
- else if (!strcasecmp(skill, "good"))
- SkillNr = 1;
- else if (!strcasecmp(skill, "medium"))
- SkillNr = 2;
- else if (!strcasecmp(skill, "worse"))
- SkillNr = 3;
- else if (!strcasecmp(skill, "bad"))
- SkillNr = 4;
- else
- {
- conoutf("Wrong skill specified. Should be best, good, medium, worse or bad");
- return;
- }
-
- if (bot)
- {
- loopv(bots)
- {
- if (bots[i] && !strcmp(bots[i]->name, bot))
- {
- BotManager.ChangeBotSkill(SkillNr, bots[i]);
- break;
- }
- }
- }
- else
- BotManager.ChangeBotSkill(SkillNr);
- }
-
- COMMAND(botskill, ARG_2STR);
-
- void botskillall(char *skill)
- {
- botskill(NULL, skill);
- }
-
- COMMAND(botskillall, ARG_1STR);
-
- #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(1, 500, player1->o, o);
- }
- }
-
- COMMAND(drawbeamtocarrots, ARG_NONE);
-
- 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(1, 500, player1->o, o);
- }
- }
-
- COMMAND(drawbeamtoteleporters, ARG_NONE);
- #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;
- break;
- }
- }
- }
-
- COMMAND(telebot, ARG_NONE);
-
- 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);
- }
-
- COMMAND(testvisible, ARG_1INT);
-
- void mapsize(void)
- {
- conoutf("ssize: %d", ssize);
- }
-
- COMMAND(mapsize, ARG_NONE);
-
- #endif
-