mirror of
https://github.com/ENSL/NS.git
synced 2025-02-19 18:40:57 +00:00
Lerk improvements and bot names
* Improved lerk movement when it is not flying (i.e. being cautious) * Users can now optionally add botnames.txt to the NS folder to define custom bot names
This commit is contained in:
parent
e322e52619
commit
27ed51035c
6 changed files with 130 additions and 51 deletions
|
@ -5,6 +5,8 @@
|
||||||
#include "AvHServerUtil.h"
|
#include "AvHServerUtil.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
BotFillTiming CurrentBotFillTiming = FILLTIMING_ALLHUMANS;
|
BotFillTiming CurrentBotFillTiming = FILLTIMING_ALLHUMANS;
|
||||||
|
|
||||||
|
@ -16,6 +18,43 @@ bot_skill BotSkillLevels[4];
|
||||||
|
|
||||||
AvHMessageID ChamberSequence[3] = { ALIEN_BUILD_DEFENSE_CHAMBER, ALIEN_BUILD_MOVEMENT_CHAMBER, ALIEN_BUILD_SENSORY_CHAMBER };
|
AvHMessageID ChamberSequence[3] = { ALIEN_BUILD_DEFENSE_CHAMBER, ALIEN_BUILD_MOVEMENT_CHAMBER, ALIEN_BUILD_SENSORY_CHAMBER };
|
||||||
|
|
||||||
|
string DefaultBotNames[MAX_PLAYERS] = { "MrRobot",
|
||||||
|
"Wall-E",
|
||||||
|
"BeepBoop",
|
||||||
|
"Robotnik",
|
||||||
|
"JonnyAutomaton",
|
||||||
|
"Burninator",
|
||||||
|
"SteelDeath",
|
||||||
|
"Meatbag",
|
||||||
|
"Undertaker",
|
||||||
|
"Botini",
|
||||||
|
"Robottle",
|
||||||
|
"Rusty",
|
||||||
|
"HeavyMetal",
|
||||||
|
"Combot",
|
||||||
|
"BagelLover",
|
||||||
|
"Screwdriver",
|
||||||
|
"LoveBug",
|
||||||
|
"iSmash",
|
||||||
|
"Chippy",
|
||||||
|
"Baymax",
|
||||||
|
"BoomerBot",
|
||||||
|
"Jarvis",
|
||||||
|
"Marvin",
|
||||||
|
"Data",
|
||||||
|
"Scrappy",
|
||||||
|
"Mortis",
|
||||||
|
"TerrorHertz",
|
||||||
|
"Omicron",
|
||||||
|
"Herbie",
|
||||||
|
"Robogeddon",
|
||||||
|
"Velociripper",
|
||||||
|
"TerminalFerocity"
|
||||||
|
};
|
||||||
|
|
||||||
|
vector<string> BotNames;
|
||||||
|
int CurrentNameIndex = 0;
|
||||||
|
|
||||||
char BotPrefix[32] = "";
|
char BotPrefix[32] = "";
|
||||||
|
|
||||||
extern cvar_t avh_botskill;
|
extern cvar_t avh_botskill;
|
||||||
|
@ -110,6 +149,69 @@ bot_skill CONFIG_GetBotSkillLevel()
|
||||||
return BotSkillLevels[index];
|
return BotSkillLevels[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CONFIG_PopulateBotNames()
|
||||||
|
{
|
||||||
|
BotNames.clear();
|
||||||
|
|
||||||
|
string BotConfigFile = string(getModDirectory()) + "/botnames.txt";
|
||||||
|
|
||||||
|
const char* filename = BotConfigFile.c_str();
|
||||||
|
|
||||||
|
std::ifstream cFile(filename);
|
||||||
|
if (cFile.is_open())
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
while (getline(cFile, line))
|
||||||
|
{
|
||||||
|
if (line[0] == '/' || line.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BotNames.push_back(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BotNames.size() > 2)
|
||||||
|
{
|
||||||
|
auto rng = std::default_random_engine{};
|
||||||
|
std::shuffle(begin(BotNames), end(BotNames), rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<string> DefaultNames;
|
||||||
|
|
||||||
|
// Ensure we have 32 names for all bots
|
||||||
|
for (int i = BotNames.size(); i < MAX_PLAYERS; i++)
|
||||||
|
{
|
||||||
|
DefaultNames.push_back(DefaultBotNames[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DefaultNames.size() > 2)
|
||||||
|
{
|
||||||
|
auto rng = std::default_random_engine{};
|
||||||
|
std::shuffle(begin(DefaultNames), end(DefaultNames), rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
BotNames.insert(BotNames.end(), DefaultNames.begin(), DefaultNames.end());
|
||||||
|
|
||||||
|
CurrentNameIndex = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
string CONFIG_GetNextBotName()
|
||||||
|
{
|
||||||
|
if (BotNames.size() == 0) { return "Bot"; }
|
||||||
|
|
||||||
|
string Result = BotNames[CurrentNameIndex];
|
||||||
|
|
||||||
|
CurrentNameIndex++;
|
||||||
|
|
||||||
|
if (CurrentNameIndex >= BotNames.size())
|
||||||
|
{
|
||||||
|
CurrentNameIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
void CONFIG_ParseConfigFile()
|
void CONFIG_ParseConfigFile()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -62,4 +62,8 @@ BotFillTiming CONFIG_GetBotFillTiming();
|
||||||
|
|
||||||
void CONFIG_RegenerateIniFile();
|
void CONFIG_RegenerateIniFile();
|
||||||
|
|
||||||
|
void CONFIG_PopulateBotNames();
|
||||||
|
|
||||||
|
string CONFIG_GetNextBotName();
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -6213,7 +6213,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
|
||||||
{
|
{
|
||||||
if (bIsFlyingProfile)
|
if (bIsFlyingProfile)
|
||||||
{
|
{
|
||||||
BotFollowFlightPath(pBot);
|
BotFollowFlightPath(pBot, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -6351,7 +6351,7 @@ void SkipAheadInFlightPath(AvHAIPlayer* pBot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotFollowFlightPath(AvHAIPlayer* pBot)
|
void BotFollowFlightPath(AvHAIPlayer* pBot, bool bAllowSkip)
|
||||||
{
|
{
|
||||||
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.CurrentPath.size())
|
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.CurrentPath.size())
|
||||||
{
|
{
|
||||||
|
@ -6392,7 +6392,7 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentPathPoint->area != SAMPLE_POLYAREA_CROUCH && next(CurrentPathPoint) != BotNavInfo->CurrentPath.end() && next(CurrentPathPoint)->area != SAMPLE_POLYAREA_CROUCH)
|
if (bAllowSkip && CurrentPathPoint->area != SAMPLE_POLYAREA_CROUCH && next(CurrentPathPoint) != BotNavInfo->CurrentPath.end() && next(CurrentPathPoint)->area != SAMPLE_POLYAREA_CROUCH)
|
||||||
{
|
{
|
||||||
SkipAheadInFlightPath(pBot);
|
SkipAheadInFlightPath(pBot);
|
||||||
CurrentPathPoint = (BotNavInfo->CurrentPath.begin() + BotNavInfo->CurrentPathPoint);
|
CurrentPathPoint = (BotNavInfo->CurrentPath.begin() + BotNavInfo->CurrentPathPoint);
|
||||||
|
@ -6400,7 +6400,7 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
ClosestPointToPath = vClosestPointOnLine(CurrentPathPoint->FromLocation, CurrentPathPoint->Location, pEdict->v.origin);
|
ClosestPointToPath = vClosestPointOnLine(CurrentPathPoint->FromLocation, CurrentPathPoint->Location, pEdict->v.origin);
|
||||||
|
|
||||||
if (vDist3DSq(pBot->Edict->v.origin, ClosestPointToPath) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f))
|
if (bAllowSkip && vDist3DSq(pBot->Edict->v.origin, ClosestPointToPath) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f))
|
||||||
{
|
{
|
||||||
ClearBotPath(pBot);
|
ClearBotPath(pBot);
|
||||||
return;
|
return;
|
||||||
|
@ -6561,7 +6561,7 @@ void BotFollowSwimPath(AvHAIPlayer* pBot)
|
||||||
// We're at the surface, now tackle the path the usual way
|
// We're at the surface, now tackle the path the usual way
|
||||||
if (pBot->BotNavInfo.NavProfile.bFlyingProfile)
|
if (pBot->BotNavInfo.NavProfile.bFlyingProfile)
|
||||||
{
|
{
|
||||||
BotFollowFlightPath(pBot);
|
BotFollowFlightPath(pBot, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -6633,6 +6633,15 @@ void BotFollowPath(AvHAIPlayer* pBot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsPlayerLerk(pBot->Edict))
|
||||||
|
{
|
||||||
|
if (CurrentNode.flag != SAMPLE_POLYFLAGS_WALK && CurrentNode.flag != SAMPLE_POLYFLAGS_LIFT)
|
||||||
|
{
|
||||||
|
BotFollowFlightPath(pBot, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (IsBotOffPath(pBot))
|
if (IsBotOffPath(pBot))
|
||||||
{
|
{
|
||||||
MoveToWithoutNav(pBot, CurrentNode.Location);
|
MoveToWithoutNav(pBot, CurrentNode.Location);
|
||||||
|
|
|
@ -332,7 +332,7 @@ void UpdateBotStuck(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
// Used by the MoveTo command, handles the bot's movement and inputs to follow a path it has calculated for itself
|
// Used by the MoveTo command, handles the bot's movement and inputs to follow a path it has calculated for itself
|
||||||
void BotFollowPath(AvHAIPlayer* pBot);
|
void BotFollowPath(AvHAIPlayer* pBot);
|
||||||
void BotFollowFlightPath(AvHAIPlayer* pBot);
|
void BotFollowFlightPath(AvHAIPlayer* pBot, bool bAllowSkip);
|
||||||
void BotFollowSwimPath(AvHAIPlayer* pBot);
|
void BotFollowSwimPath(AvHAIPlayer* pBot);
|
||||||
|
|
||||||
void SkipAheadInFlightPath(AvHAIPlayer* pBot);
|
void SkipAheadInFlightPath(AvHAIPlayer* pBot);
|
||||||
|
|
|
@ -4598,7 +4598,7 @@ AvHMessageID GetNextAIPlayerCOAlienUpgrade(AvHAIPlayer* pBot)
|
||||||
// As a bombardier, we can still go fade if we can't afford Onos yet, so calculate our points savings accordingly
|
// As a bombardier, we can still go fade if we can't afford Onos yet, so calculate our points savings accordingly
|
||||||
if (pBot->BotRole == BOT_ROLE_BOMBARDIER)
|
if (pBot->BotRole == BOT_ROLE_BOMBARDIER)
|
||||||
{
|
{
|
||||||
if (NumPointsAvailable <= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FIVE))
|
if (CONFIG_IsOnosAllowed() && NumPointsAvailable <= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FIVE))
|
||||||
{
|
{
|
||||||
return MESSAGE_NULL;
|
return MESSAGE_NULL;
|
||||||
}
|
}
|
||||||
|
@ -5039,7 +5039,7 @@ void AIPlayerSetPrimaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
|
|
||||||
if (pBot->BotRole == BOT_ROLE_ASSAULT)
|
if (pBot->BotRole == BOT_ROLE_ASSAULT)
|
||||||
{
|
{
|
||||||
if (!IsPlayerFade(pBot->Edict) && pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FOUR))
|
if (CONFIG_IsFadeAllowed() && !IsPlayerFade(pBot->Edict) && pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FOUR))
|
||||||
{
|
{
|
||||||
if (Task->TaskType != TASK_EVOLVE)
|
if (Task->TaskType != TASK_EVOLVE)
|
||||||
{
|
{
|
||||||
|
@ -5060,11 +5060,11 @@ void AIPlayerSetPrimaryCOAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
AvHMessageID DesiredEvolution = MESSAGE_NULL;
|
AvHMessageID DesiredEvolution = MESSAGE_NULL;
|
||||||
|
|
||||||
if (pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FIVE))
|
if (CONFIG_IsOnosAllowed() && pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FIVE))
|
||||||
{
|
{
|
||||||
DesiredEvolution = ALIEN_LIFEFORM_FIVE;
|
DesiredEvolution = ALIEN_LIFEFORM_FIVE;
|
||||||
}
|
}
|
||||||
else if (pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FOUR))
|
else if (CONFIG_IsFadeAllowed() && pBot->ExperiencePointsAvailable >= GetGameRules()->GetCostForMessageID(ALIEN_LIFEFORM_FOUR))
|
||||||
{
|
{
|
||||||
DesiredEvolution = ALIEN_LIFEFORM_FOUR;
|
DesiredEvolution = ALIEN_LIFEFORM_FOUR;
|
||||||
}
|
}
|
||||||
|
@ -5587,8 +5587,6 @@ void AIPlayerReceiveMoveOrder(AvHAIPlayer* pBot, Vector Destination)
|
||||||
|
|
||||||
void BotStopCommanderMode(AvHAIPlayer* pBot)
|
void BotStopCommanderMode(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
// Thanks EterniumDev (Alien) for logic to allow commander AI to leave the chair and build structures when needed
|
|
||||||
|
|
||||||
if (IsPlayerCommander(pBot->Edict))
|
if (IsPlayerCommander(pBot->Edict))
|
||||||
{
|
{
|
||||||
pBot->Player->SetUser3(AVH_USER3_MARINE_PLAYER);
|
pBot->Player->SetUser3(AVH_USER3_MARINE_PLAYER);
|
||||||
|
|
|
@ -51,40 +51,6 @@ float CountdownStartedTime = 0.0f;
|
||||||
|
|
||||||
bool bBotsEnabled = false;
|
bool bBotsEnabled = false;
|
||||||
|
|
||||||
string BotNames[MAX_PLAYERS] = { "MrRobot",
|
|
||||||
"Wall-E",
|
|
||||||
"BeepBoop",
|
|
||||||
"Robotnik",
|
|
||||||
"JonnyAutomaton",
|
|
||||||
"Burninator",
|
|
||||||
"SteelDeath",
|
|
||||||
"Meatbag",
|
|
||||||
"Undertaker",
|
|
||||||
"Botini",
|
|
||||||
"Robottle",
|
|
||||||
"Rusty",
|
|
||||||
"HeavyMetal",
|
|
||||||
"Combot",
|
|
||||||
"BagelLover",
|
|
||||||
"Screwdriver",
|
|
||||||
"LoveBug",
|
|
||||||
"iSmash",
|
|
||||||
"Chippy",
|
|
||||||
"Baymax",
|
|
||||||
"BoomerBot",
|
|
||||||
"Jarvis",
|
|
||||||
"Marvin",
|
|
||||||
"Data",
|
|
||||||
"Scrappy",
|
|
||||||
"Mortis",
|
|
||||||
"TerrorHertz",
|
|
||||||
"Omicron",
|
|
||||||
"Herbie",
|
|
||||||
"Robogeddon",
|
|
||||||
"Velociripper",
|
|
||||||
"TerminalFerocity"
|
|
||||||
};
|
|
||||||
|
|
||||||
AvHAICommanderMode AIMGR_GetCommanderMode()
|
AvHAICommanderMode AIMGR_GetCommanderMode()
|
||||||
{
|
{
|
||||||
if (avh_botcommandermode.value == 1)
|
if (avh_botcommandermode.value == 1)
|
||||||
|
@ -442,9 +408,8 @@ void AIMGR_AddAIPlayerToTeam(int Team)
|
||||||
BotNameIndex = RANDOM_LONG(0, 31);
|
BotNameIndex = RANDOM_LONG(0, 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the current bot name and then cycle the index so the names are always unique
|
// Retrieve the next configured bot name from the list
|
||||||
// Slap a [BOT] tag too so players know they're not human
|
string NewName = CONFIG_GetBotPrefix() + CONFIG_GetNextBotName();
|
||||||
string NewName = CONFIG_GetBotPrefix() + BotNames[BotNameIndex];
|
|
||||||
|
|
||||||
BotEnt = (*g_engfuncs.pfnCreateFakeClient)(NewName.c_str());
|
BotEnt = (*g_engfuncs.pfnCreateFakeClient)(NewName.c_str());
|
||||||
|
|
||||||
|
@ -1059,6 +1024,9 @@ void AIMGR_NewMap()
|
||||||
bHasRoundStarted = false;
|
bHasRoundStarted = false;
|
||||||
|
|
||||||
bPlayerSpawned = false;
|
bPlayerSpawned = false;
|
||||||
|
|
||||||
|
CONFIG_ParseConfigFile();
|
||||||
|
CONFIG_PopulateBotNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AIMGR_IsNavmeshLoaded()
|
bool AIMGR_IsNavmeshLoaded()
|
||||||
|
@ -1081,8 +1049,6 @@ void AIMGR_LoadNavigationData()
|
||||||
// Don't reload the nav mesh if it's already loaded
|
// Don't reload the nav mesh if it's already loaded
|
||||||
if (NavmeshLoaded()) { return; }
|
if (NavmeshLoaded()) { return; }
|
||||||
|
|
||||||
CONFIG_ParseConfigFile();
|
|
||||||
|
|
||||||
const char* theCStrLevelName = STRING(gpGlobals->mapname);
|
const char* theCStrLevelName = STRING(gpGlobals->mapname);
|
||||||
|
|
||||||
if (!loadNavigationData(theCStrLevelName))
|
if (!loadNavigationData(theCStrLevelName))
|
||||||
|
|
Loading…
Reference in a new issue