- Moved bot thinking logic into DBot.

This commit is contained in:
ChillyDoom 2014-11-14 16:54:56 +00:00
parent 5e6c375974
commit ee977f94d7
12 changed files with 154 additions and 136 deletions

View file

@ -30,6 +30,7 @@ DBot::DBot ()
void DBot::Clear () void DBot::Clear ()
{ {
player = NULL;
angle = 0; angle = 0;
dest = NULL; dest = NULL;
prev = NULL; prev = NULL;
@ -64,6 +65,10 @@ void DBot::Serialize (FArchive &arc)
arc << savedyaw arc << savedyaw
<< savedpitch; << savedpitch;
} }
else if (SaveVersion >= 4516)
{
arc << player;
}
arc << angle arc << angle
<< dest << dest
@ -88,6 +93,22 @@ void DBot::Serialize (FArchive &arc)
<< oldy; << oldy;
} }
void DBot::Tick ()
{
Super::Tick ();
if (player->mo == NULL || bglobal.freeze)
{
return;
}
BotThinkCycles.Clock();
bglobal.m_Thinking = true;
bglobal.Think (player->mo, &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS]);
bglobal.m_Thinking = false;
BotThinkCycles.Unclock();
}
CVAR (Int, bot_next_color, 11, 0) CVAR (Int, bot_next_color, 11, 0)
CVAR (Bool, bot_observer, false, 0) CVAR (Bool, bot_observer, false, 0)

View file

@ -14,6 +14,7 @@
#include "d_ticcmd.h" #include "d_ticcmd.h"
#include "r_defs.h" #include "r_defs.h"
#include "a_pickups.h" #include "a_pickups.h"
#include "stats.h"
#define FORWARDWALK 0x1900 #define FORWARDWALK 0x1900
#define FORWARDRUN 0x3200 #define FORWARDRUN 0x3200
@ -89,20 +90,22 @@ public:
void ClearPlayer (int playernum, bool keepTeam); void ClearPlayer (int playernum, bool keepTeam);
//(B_Game.c) //(B_Game.c)
void Main (int buf); void Main ();
void Init (); void Init ();
void End(); void End();
bool SpawnBot (const char *name, int color = NOCOLOR); bool SpawnBot (const char *name, int color = NOCOLOR);
bool LoadBots ();
void ForgetBots ();
void TryAddBot (BYTE **stream, int player); void TryAddBot (BYTE **stream, int player);
void RemoveAllBots (bool fromlist); void RemoveAllBots (bool fromlist);
void DestroyAllBots (); bool LoadBots ();
void ForgetBots ();
//(B_Func.c) //(B_Func.c)
bool Check_LOS (AActor *mobj1, AActor *mobj2, angle_t vangle); bool Check_LOS (AActor *mobj1, AActor *mobj2, angle_t vangle);
void StartTravel ();
void FinishTravel ();
//(B_Think.c) //(B_Think.c)
void Think (AActor *actor, ticcmd_t *cmd);
void WhatToGet (AActor *actor, AActor *item); void WhatToGet (AActor *actor, AActor *item);
//(B_move.c) //(B_move.c)
@ -144,7 +147,6 @@ private:
bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm); bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm);
//(B_Think.c) //(B_Think.c)
void Think (AActor *actor, ticcmd_t *cmd);
void ThinkForMove (AActor *actor, ticcmd_t *cmd); void ThinkForMove (AActor *actor, ticcmd_t *cmd);
void Set_enemy (AActor *actor); void Set_enemy (AActor *actor);
@ -155,16 +157,18 @@ protected:
bool observer; //Consoleplayer is observer. bool observer; //Consoleplayer is observer.
}; };
class DBot : public DObject class DBot : public DThinker
{ {
DECLARE_CLASS(DBot,DObject) DECLARE_CLASS(DBot,DThinker)
HAS_OBJECT_POINTERS HAS_OBJECT_POINTERS
public: public:
DBot (); DBot ();
void Clear (); void Clear ();
void Serialize (FArchive &arc); void Serialize (FArchive &arc);
void Tick ();
player_t *player;
angle_t angle; // The wanted angle that the bot try to get every tic. angle_t angle; // The wanted angle that the bot try to get every tic.
// (used to get a smooth view movement) // (used to get a smooth view movement)
TObjPtr<AActor> dest; // Move Destination. TObjPtr<AActor> dest; // Move Destination.
@ -205,6 +209,7 @@ public:
//Externs //Externs
extern FCajunMaster bglobal; extern FCajunMaster bglobal;
extern cycle_t BotThinkCycles, BotSupportCycles;
EXTERN_CVAR (Float, bot_flag_return_time) EXTERN_CVAR (Float, bot_flag_return_time)
EXTERN_CVAR (Int, bot_next_color) EXTERN_CVAR (Int, bot_next_color)

View file

@ -272,10 +272,12 @@ shootmissile:
bool FCajunMaster::IsLeader (player_t *player) bool FCajunMaster::IsLeader (player_t *player)
{ {
for (int count = 0; count < MAXPLAYERS; count++) DBot *Bot;
TThinkerIterator<DBot> it;
while ((Bot = it.Next ()) != NULL)
{ {
if (players[count].Bot != NULL if (Bot->mate == player->mo)
&& players[count].Bot->mate == player->mo)
{ {
return true; return true;
} }
@ -402,7 +404,7 @@ AActor *FCajunMaster::Find_enemy (AActor *bot)
&& bot != client->mo) && bot != client->mo)
{ {
if (Check_LOS (bot, client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up. if (Check_LOS (bot, client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up.
//if(P_CheckSight( bot, players[count].mo)) //if(P_CheckSight(bot, players[count].mo))
{ {
temp = P_AproxDistance (client->mo->x - bot->x, temp = P_AproxDistance (client->mo->x - bot->x,
client->mo->y - bot->y); client->mo->y - bot->y);
@ -552,3 +554,25 @@ bool FCajunMaster::SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FChec
actor->flags = savedFlags; actor->flags = savedFlags;
return res; return res;
} }
void FCajunMaster::StartTravel ()
{
DBot *Bot;
TThinkerIterator<DBot> it;
while ((Bot = it.Next ()) != NULL)
{
Bot->ChangeStatNum (STAT_TRAVELLING);
}
}
void FCajunMaster::FinishTravel ()
{
DBot *Bot;
TThinkerIterator<DBot> it(STAT_TRAVELLING);
while ((Bot = it.Next ()) != NULL)
{
Bot->ChangeStatNum (STAT_DEFAULT);
}
}

View file

@ -94,71 +94,46 @@ FCajunMaster::~FCajunMaster()
ForgetBots(); ForgetBots();
} }
//This function is called every tick (from g_game.c), //This function is called every tick (from g_game.c).
//send bots into thinking (+more). void FCajunMaster::Main ()
void FCajunMaster::Main (int buf)
{ {
int i;
BotThinkCycles.Reset(); BotThinkCycles.Reset();
if (demoplayback) if (demoplayback || gamestate != GS_LEVEL || consoleplayer != Net_Arbitrator)
return; return;
if (gamestate != GS_LEVEL) //Add new bots?
return; if (wanted_botnum > botnum && !freeze)
m_Thinking = true;
//Think for bots.
if (botnum)
{ {
BotThinkCycles.Clock(); if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY))
for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && players[i].mo && !freeze && players[i].Bot != NULL) if (!SpawnBot (getspawned[spawn_tries]))
Think (players[i].mo, &netcmds[i][buf]); wanted_botnum--;
spawn_tries++;
} }
BotThinkCycles.Unclock();
t_join--;
} }
if (consoleplayer == Net_Arbitrator) //Check if player should go observer. Or un observe
if (bot_observer && !observer && !netgame)
{ {
//Add new bots? Printf ("%s is now observer\n", players[consoleplayer].userinfo.GetName());
if (wanted_botnum > botnum && !freeze) observer = true;
{ players[consoleplayer].mo->UnlinkFromWorld ();
if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY)) players[consoleplayer].mo->flags = MF_DROPOFF|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH|MF_NOGRAVITY|MF_FRIENDLY;
{ players[consoleplayer].mo->flags2 |= MF2_FLY;
if (!SpawnBot (getspawned[spawn_tries])) players[consoleplayer].mo->LinkToWorld ();
wanted_botnum--; }
spawn_tries++; else if (!bot_observer && observer && !netgame) //Go back
} {
Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.GetName());
t_join--; observer = false;
} players[consoleplayer].mo->UnlinkFromWorld ();
players[consoleplayer].mo->flags = MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY;
//Check if player should go observer. Or un observe players[consoleplayer].mo->flags2 &= ~MF2_FLY;
if (bot_observer && !observer && !netgame) players[consoleplayer].mo->LinkToWorld ();
{
Printf ("%s is now observer\n", players[consoleplayer].userinfo.GetName());
observer = true;
players[consoleplayer].mo->UnlinkFromWorld ();
players[consoleplayer].mo->flags = MF_DROPOFF|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH|MF_NOGRAVITY|MF_FRIENDLY;
players[consoleplayer].mo->flags2 |= MF2_FLY;
players[consoleplayer].mo->LinkToWorld ();
}
else if (!bot_observer && observer && !netgame) //Go back
{
Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.GetName());
observer = false;
players[consoleplayer].mo->UnlinkFromWorld ();
players[consoleplayer].mo->flags = MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY;
players[consoleplayer].mo->flags2 &= ~MF2_FLY;
players[consoleplayer].mo->LinkToWorld ();
}
} }
m_Thinking = false;
} }
void FCajunMaster::Init () void FCajunMaster::Init ()
@ -195,22 +170,18 @@ void FCajunMaster::Init ()
//Called on each level exit (from g_game.c). //Called on each level exit (from g_game.c).
void FCajunMaster::End () void FCajunMaster::End ()
{ {
int i;
//Arrange wanted botnum and their names, so they can be spawned next level. //Arrange wanted botnum and their names, so they can be spawned next level.
getspawned.Clear(); getspawned.Clear();
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].Bot != NULL)
{
if (deathmatch)
{
getspawned.Push(players[i].userinfo.GetName());
}
}
}
if (deathmatch) if (deathmatch)
{ {
DBot *Bot;
TThinkerIterator<DBot> it;
while ((Bot = it.Next ()) != NULL)
{
getspawned.Push(Bot->player->userinfo.GetName());
}
wanted_botnum = botnum; wanted_botnum = botnum;
} }
} }
@ -400,7 +371,7 @@ bool FCajunMaster::DoAddBot (BYTE *info, botskill_t skill)
multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost). multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost).
players[bnum].Bot = new DBot; players[bnum].Bot = new DBot;
GC::WriteBarrier (players[bnum].Bot); players[bnum].Bot->player = &players[bnum];
players[bnum].Bot->skill = skill; players[bnum].Bot->skill = skill;
playeringame[bnum] = true; playeringame[bnum] = true;
players[bnum].mo = NULL; players[bnum].mo = NULL;
@ -422,31 +393,30 @@ bool FCajunMaster::DoAddBot (BYTE *info, botskill_t skill)
void FCajunMaster::RemoveAllBots (bool fromlist) void FCajunMaster::RemoveAllBots (bool fromlist)
{ {
int i, j; DBot *Bot;
TThinkerIterator<DBot> it;
int i;
for (i = 0; i < MAXPLAYERS; ++i) while ((Bot = it.Next ()) != NULL)
{ {
if (playeringame[i] && players[i].Bot != NULL) // If a player is looking through this bot's eyes, make him
// look through his own eyes instead.
for (i = 0; i < MAXPLAYERS; ++i)
{ {
// If a player is looking through this bot's eyes, make him if (Bot->player != &players[i] && playeringame[i] && players[i].Bot == NULL)
// look through his own eyes instead.
for (j = 0; j < MAXPLAYERS; ++j)
{ {
if (i != j && playeringame[j] && players[j].Bot == NULL) if (players[i].camera == Bot->player->mo)
{ {
if (players[j].camera == players[i].mo) players[i].camera = players[i].mo;
if (i == consoleplayer)
{ {
players[j].camera = players[j].mo; StatusBar->AttachToPlayer (players + i);
if (j == consoleplayer)
{
StatusBar->AttachToPlayer (players + j);
}
} }
} }
} }
ClearPlayer (i, !fromlist);
FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, NULL, true, i);
} }
ClearPlayer (Bot->player - players, !fromlist);
FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, NULL, true, Bot->player - players);
} }
if (fromlist) if (fromlist)
@ -456,18 +426,6 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
botnum = 0; botnum = 0;
} }
void FCajunMaster::DestroyAllBots ()
{
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (players[i].Bot != NULL)
{
players[i].Bot->Destroy ();
players[i].Bot = NULL;
}
}
}
//------------------ //------------------
//Reads data for bot from //Reads data for bot from

View file

@ -1127,11 +1127,8 @@ void G_Ticker ()
// check, not just the player's x position like BOOM. // check, not just the player's x position like BOOM.
DWORD rngsum = FRandom::StaticSumSeeds (); DWORD rngsum = FRandom::StaticSumSeeds ();
if ((gametic % ticdup) == 0) //Added by MC: For some of that bot stuff. The main bot function.
{ bglobal.Main ();
//Added by MC: For some of that bot stuff. The main bot function.
bglobal.Main (buf);
}
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
@ -1394,7 +1391,6 @@ void G_PlayerReborn (int player)
if (gamestate != GS_TITLELEVEL) if (gamestate != GS_TITLELEVEL)
{ {
// [GRB] Give inventory specified in DECORATE // [GRB] Give inventory specified in DECORATE
actor->GiveDefaultInventory (); actor->GiveDefaultInventory ();
p->ReadyWeapon = p->PendingWeapon; p->ReadyWeapon = p->PendingWeapon;
@ -1405,6 +1401,7 @@ void G_PlayerReborn (int player)
{ {
botskill_t skill = p->Bot->skill; botskill_t skill = p->Bot->skill;
p->Bot->Clear (); p->Bot->Clear ();
p->Bot->player = p;
p->Bot->skill = skill; p->Bot->skill = skill;
} }
} }

View file

@ -1164,6 +1164,8 @@ void G_StartTravel ()
} }
} }
} }
bglobal.StartTravel ();
} }
//========================================================================== //==========================================================================
@ -1261,6 +1263,8 @@ void G_FinishTravel ()
} }
} }
} }
bglobal.FinishTravel ();
} }
//========================================================================== //==========================================================================

View file

@ -1021,11 +1021,14 @@ void AInventory::Touch (AActor *toucher)
P_GiveSecret(toucher, true, true, -1); P_GiveSecret(toucher, true, true, -1);
} }
DBot *Bot;
TThinkerIterator<DBot> it;
//Added by MC: Check if item taken was the roam destination of any bot //Added by MC: Check if item taken was the roam destination of any bot
for (int i = 0; i < MAXPLAYERS; i++) while ((Bot = it.Next ()) != NULL)
{ {
if (playeringame[i] && players[i].Bot != NULL && this == players[i].Bot->dest) if (Bot->dest == this)
players[i].Bot->dest = NULL; Bot->dest = NULL;
} }
} }

View file

@ -611,14 +611,17 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
if (player->Bot != NULL) if (player->Bot != NULL)
player->Bot->t_respawn = (pr_botrespawn()%15)+((bglobal.botnum-1)*2)+TICRATE+1; player->Bot->t_respawn = (pr_botrespawn()%15)+((bglobal.botnum-1)*2)+TICRATE+1;
DBot *Bot;
TThinkerIterator<DBot> it;
//Added by MC: Discard enemies. //Added by MC: Discard enemies.
for (int i = 0; i < MAXPLAYERS; i++) while ((Bot = it.Next ()) != NULL)
{ {
if (players[i].Bot != NULL && this == players[i].Bot->enemy) if (this == Bot->enemy)
{ {
if (players[i].Bot->dest == players[i].Bot->enemy) if (Bot->dest == Bot->enemy)
players[i].Bot->dest = NULL; Bot->dest = NULL;
players[i].Bot->enemy = NULL; Bot->enemy = NULL;
} }
} }

View file

@ -84,7 +84,6 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj);
// EXTERNAL DATA DECLARATIONS ---------------------------------------------- // EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern cycle_t BotSupportCycles;
extern int BotWTG; extern int BotWTG;
EXTERN_CVAR (Int, cl_rockettrails) EXTERN_CVAR (Int, cl_rockettrails)
@ -3043,7 +3042,6 @@ void AActor::Tick ()
AActor *onmo; AActor *onmo;
int i;
//assert (state != NULL); //assert (state != NULL);
if (state == NULL) if (state == NULL)
@ -3233,35 +3231,36 @@ void AActor::Tick ()
{ {
BotSupportCycles.Clock(); BotSupportCycles.Clock();
bglobal.m_Thinking = true; bglobal.m_Thinking = true;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].Bot == NULL)
continue;
DBot *Bot;
TThinkerIterator<DBot> it;
while ((Bot = it.Next ()) != NULL)
{
if (flags3 & MF3_ISMONSTER) if (flags3 & MF3_ISMONSTER)
{ {
if (health > 0 if (health > 0
&& !players[i].Bot->enemy && !Bot->enemy
&& player ? !IsTeammate (players[i].mo) : true && player ? !IsTeammate (Bot->player->mo) : true
&& P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST && P_AproxDistance (Bot->player->mo->x-x, Bot->player->mo->y-y) < MAX_MONSTER_TARGET_DIST
&& P_CheckSight (players[i].mo, this, SF_SEEPASTBLOCKEVERYTHING)) && P_CheckSight (Bot->player->mo, this, SF_SEEPASTBLOCKEVERYTHING))
{ //Probably a monster, so go kill it. { //Probably a monster, so go kill it.
players[i].Bot->enemy = this; Bot->enemy = this;
} }
} }
else if (flags & MF_SPECIAL) else if (flags & MF_SPECIAL)
{ //Item pickup time { //Item pickup time
//clock (BotWTG); //clock (BotWTG);
bglobal.WhatToGet (players[i].mo, this); bglobal.WhatToGet (Bot->player->mo, this);
//unclock (BotWTG); //unclock (BotWTG);
BotWTG++; BotWTG++;
} }
else if (flags & MF_MISSILE) else if (flags & MF_MISSILE)
{ {
if (!players[i].Bot->missile && (flags3 & MF3_WARNBOT)) if (!Bot->missile && (flags3 & MF3_WARNBOT))
{ //warn for incoming missiles. { //warn for incoming missiles.
if (target != players[i].mo && bglobal.Check_LOS (players[i].mo, this, ANGLE_90)) if (target != Bot->player->mo && bglobal.Check_LOS (Bot->player->mo, this, ANGLE_90))
players[i].Bot->missile = this; Bot->missile = this;
} }
} }
} }

View file

@ -4175,7 +4175,6 @@ static void P_Shutdown ()
P_FreeLevelData (); P_FreeLevelData ();
P_FreeExtraLevelData (); P_FreeExtraLevelData ();
ST_Clear(); ST_Clear();
bglobal.DestroyAllBots ();
} }
#if 0 #if 0

View file

@ -3066,7 +3066,6 @@ void player_t::Serialize (FArchive &arc)
if (SaveVersion < 4514 && IsBot) if (SaveVersion < 4514 && IsBot)
{ {
Bot = new DBot; Bot = new DBot;
GC::WriteBarrier (Bot);
arc << Bot->angle arc << Bot->angle
<< Bot->dest << Bot->dest
@ -3089,6 +3088,12 @@ void player_t::Serialize (FArchive &arc)
<< Bot->oldx << Bot->oldx
<< Bot->oldy; << Bot->oldy;
} }
if (SaveVersion < 4516 && Bot != NULL)
{
Bot->player = this;
}
if (arc.IsLoading ()) if (arc.IsLoading ())
{ {
// If the player reloaded because they pressed +use after dying, we // If the player reloaded because they pressed +use after dying, we

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the // Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got. // SVN revision ever got.
#define SAVEVER 4515 #define SAVEVER 4516
#define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)