mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
Refactor PlayerBot to use a separate controller class, alongside classes that manage bots
This commit is contained in:
parent
7dbf1d7bf5
commit
0b07858bfc
8 changed files with 607 additions and 249 deletions
|
@ -159,10 +159,16 @@ Begin spawning a new bot entity
|
|||
*/
|
||||
void G_BotBegin(gentity_t *ent)
|
||||
{
|
||||
PlayerBot *player;
|
||||
BotController *controller;
|
||||
|
||||
level.spawn_entnum = ent->s.number;
|
||||
new PlayerBot;
|
||||
player = new PlayerBot;
|
||||
|
||||
G_ClientBegin(ent, NULL);
|
||||
|
||||
controller = botManager.getControllerManager().createController(player);
|
||||
player->setController(controller);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -174,6 +180,7 @@ Called each server frame to make bots think
|
|||
*/
|
||||
void G_BotThink(gentity_t *ent, int msec)
|
||||
{
|
||||
/*
|
||||
usercmd_t ucmd;
|
||||
usereyes_t eyeinfo;
|
||||
PlayerBot *bot;
|
||||
|
@ -189,6 +196,7 @@ void G_BotThink(gentity_t *ent, int msec)
|
|||
bot->GetEyeInfo(&eyeinfo);
|
||||
|
||||
G_ClientThink(ent, &ucmd, &eyeinfo);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -468,6 +476,12 @@ Remove the specified bot
|
|||
*/
|
||||
void G_RemoveBot(gentity_t *ent)
|
||||
{
|
||||
if (ent->entity) {
|
||||
BotController *controller = botManager.getControllerManager().findController(ent->entity);
|
||||
|
||||
botManager.getControllerManager().removeController(controller);
|
||||
}
|
||||
|
||||
G_ClientDisconnect(ent);
|
||||
current_bot_count--;
|
||||
}
|
||||
|
@ -658,10 +672,36 @@ void G_ResetBots()
|
|||
{
|
||||
G_SaveBots();
|
||||
|
||||
botManager.Cleanup();
|
||||
|
||||
current_bot_count = 0;
|
||||
botId = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
G_BotInit
|
||||
|
||||
Called to initialize bots
|
||||
============
|
||||
*/
|
||||
void G_BotInit()
|
||||
{
|
||||
botManager.Init();
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
G_BotFrame
|
||||
|
||||
Called each frame to manage bots
|
||||
============
|
||||
*/
|
||||
void G_BotFrame()
|
||||
{
|
||||
botManager.Frame();
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
G_SpawnBots
|
||||
|
|
|
@ -42,4 +42,6 @@ void G_RemoveBots(unsigned int num);
|
|||
bool G_IsBot(gentity_t *ent);
|
||||
bool G_IsPlayer(gentity_t *ent);
|
||||
void G_ResetBots();
|
||||
void G_BotInit();
|
||||
void G_BotFrame();
|
||||
void G_SpawnBots();
|
|
@ -271,7 +271,7 @@ void G_InitGame(int levelTime, int randomSeed)
|
|||
|
||||
Director.Reset();
|
||||
Actor::Init();
|
||||
PlayerBot::Init();
|
||||
G_BotInit();
|
||||
|
||||
sv_numtraces = 0;
|
||||
sv_numpmtraces = 0;
|
||||
|
@ -556,11 +556,7 @@ void G_RunFrame(int levelTime, int frameTime)
|
|||
start = clock();
|
||||
}
|
||||
|
||||
for (edict = active_edicts.next; edict != &active_edicts; edict = edict->next) {
|
||||
if (edict->entity->IsSubclassOfBot()) {
|
||||
G_BotThink(edict, frameTime);
|
||||
}
|
||||
}
|
||||
G_BotFrame();
|
||||
|
||||
for (edict = active_edicts.next; edict != &active_edicts; edict = edict->next) {
|
||||
for (num = edict->s.parent; num != ENTITYNUM_NONE; num = g_entities[num].s.parent) {
|
||||
|
|
|
@ -1687,15 +1687,13 @@ void G_BroadcastAIEvent(Entity *originator, Vector origin, int iType, float radi
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!ent->IsSubclassOfActor() && !ent->IsSubclassOfBot()) {
|
||||
if (!ent->IsSubclassOfActor()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ent->IsSubclassOfActor()) {
|
||||
act = static_cast<Actor *>(ent);
|
||||
if (act->IgnoreSound(iType)) {
|
||||
continue;
|
||||
}
|
||||
act = static_cast<Actor*>(ent);
|
||||
if (act->IgnoreSound(iType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delta = origin - ent->centroid;
|
||||
|
@ -1717,15 +1715,10 @@ void G_BroadcastAIEvent(Entity *originator, Vector origin, int iType, float radi
|
|||
continue;
|
||||
}
|
||||
|
||||
if (ent->IsSubclassOfActor()) {
|
||||
act->ReceiveAIEvent(origin, iType, originator, dist2, r2);
|
||||
} else if (ent->IsSubclassOfBot()) {
|
||||
PlayerBot *bot = static_cast<PlayerBot *>(ent);
|
||||
|
||||
bot->NoticeEvent(origin, iType, originator, dist2, r2);
|
||||
}
|
||||
act->ReceiveAIEvent(origin, iType, originator, dist2, r2);
|
||||
}
|
||||
|
||||
botManager.BroadcastEvent(originator, origin, iType, radius);
|
||||
#if 0
|
||||
gi.DPrintf("Broadcast event %s to %d entities\n", ev->getName(), count);
|
||||
#endif
|
||||
|
|
|
@ -678,9 +678,9 @@ qboolean G_RemoveBotCommand(gentity_t *ent)
|
|||
qboolean G_BotCommand(gentity_t *ent)
|
||||
{
|
||||
const char *command;
|
||||
PlayerBot *bot;
|
||||
BotController *bot;
|
||||
|
||||
if (!G_GetFirstBot() || !G_GetFirstBot()->entity) {
|
||||
if (botManager.getControllerManager().getControllers().NumObjects() < 1) {
|
||||
gi.Printf("No bot spawned.\n");
|
||||
return qfalse;
|
||||
}
|
||||
|
@ -690,7 +690,7 @@ qboolean G_BotCommand(gentity_t *ent)
|
|||
return qfalse;
|
||||
}
|
||||
|
||||
bot = (PlayerBot *)G_GetFirstBot()->entity;
|
||||
bot = botManager.getControllerManager().getControllers().ObjectAt(1);
|
||||
|
||||
command = gi.Argv(1);
|
||||
|
||||
|
@ -713,7 +713,7 @@ qboolean G_BotCommand(gentity_t *ent)
|
|||
|
||||
bot->AvoidPath(ent->entity->origin, rad);
|
||||
} else if (!Q_stricmp(command, "telehere")) {
|
||||
bot->setOrigin(ent->s.origin);
|
||||
bot->getControlledEntity()->setOrigin(ent->s.origin);
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -34,19 +34,42 @@ typedef struct nodeAttract_s {
|
|||
AttractiveNodePtr m_pNode;
|
||||
} nodeAttract_t;
|
||||
|
||||
class BotController;
|
||||
|
||||
class PlayerBot : public Player
|
||||
{
|
||||
public:
|
||||
CLASS_PROTOTYPE(PlayerBot);
|
||||
|
||||
public:
|
||||
PlayerBot();
|
||||
|
||||
void setController(BotController *controlledBy);
|
||||
|
||||
void Spawned(void);
|
||||
|
||||
void Killed(Event *ev);
|
||||
void GotKill(Event *ev);
|
||||
|
||||
private:
|
||||
BotController *controller;
|
||||
};
|
||||
|
||||
class BotController : public Listener
|
||||
{
|
||||
public:
|
||||
struct botfunc_t {
|
||||
bool (PlayerBot::*CheckCondition)(void);
|
||||
void (PlayerBot::*BeginState)(void);
|
||||
void (PlayerBot::*EndState)(void);
|
||||
void (PlayerBot::*ThinkState)(void);
|
||||
bool (BotController::*CheckCondition)(void);
|
||||
void (BotController::*BeginState)(void);
|
||||
void (BotController::*EndState)(void);
|
||||
void (BotController::*ThinkState)(void);
|
||||
};
|
||||
|
||||
private:
|
||||
static botfunc_t botfuncs[];
|
||||
|
||||
// Paths
|
||||
Vector m_vCurrentOrigin;
|
||||
ActorPath m_Path;
|
||||
Vector m_vTargetPos;
|
||||
Vector m_vCurrentGoal;
|
||||
|
@ -138,9 +161,9 @@ private:
|
|||
void CheckStates(void);
|
||||
|
||||
public:
|
||||
CLASS_PROTOTYPE(PlayerBot);
|
||||
CLASS_PROTOTYPE(BotController);
|
||||
|
||||
PlayerBot();
|
||||
BotController();
|
||||
|
||||
static void Init(void);
|
||||
|
||||
|
@ -175,15 +198,61 @@ public:
|
|||
|
||||
void SendCommand(const char *text);
|
||||
|
||||
void setAngles(Vector angles) override;
|
||||
void updateOrigin(void) override;
|
||||
void Think();
|
||||
|
||||
void Spawned(void) override;
|
||||
void Spawned(void);
|
||||
|
||||
void Killed(Event *ev) override;
|
||||
void Killed(Event *ev);
|
||||
void GotKill(Event *ev);
|
||||
void EventStuffText(Event *ev);
|
||||
|
||||
private:
|
||||
void NewMove();
|
||||
|
||||
public:
|
||||
void setControlledEntity(Player *player);
|
||||
Player *getControlledEntity() const;
|
||||
|
||||
private:
|
||||
SafePtr<Player> controlledEnt;
|
||||
};
|
||||
|
||||
class BotControllerManager : public Listener
|
||||
{
|
||||
public:
|
||||
CLASS_PROTOTYPE(BotControllerManager);
|
||||
|
||||
public:
|
||||
~BotControllerManager();
|
||||
|
||||
BotController *createController(Player *player);
|
||||
void removeController(BotController *controller);
|
||||
BotController *findController(Entity *ent);
|
||||
const Container<BotController *>& getControllers() const;
|
||||
|
||||
void Init();
|
||||
void Cleanup();
|
||||
void ThinkControllers();
|
||||
|
||||
private:
|
||||
Container<BotController *> controllers;
|
||||
};
|
||||
|
||||
class BotManager : public Listener
|
||||
{
|
||||
public:
|
||||
CLASS_PROTOTYPE(BotManager);
|
||||
|
||||
public:
|
||||
BotControllerManager& getControllerManager();
|
||||
|
||||
void Init();
|
||||
void Cleanup();
|
||||
void Frame();
|
||||
void BroadcastEvent(Entity *originator, Vector origin, int iType, float radius);
|
||||
|
||||
private:
|
||||
BotControllerManager botControllerManager;
|
||||
};
|
||||
|
||||
extern BotManager botManager;
|
||||
|
|
114
code/fgame/playerbot_master.cpp
Normal file
114
code/fgame/playerbot_master.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
#include "playerbot.h"
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2024 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// playerbot_master.cpp: Multiplayer bot system.
|
||||
|
||||
#include "g_local.h"
|
||||
#include "actor.h"
|
||||
#include "playerbot.h"
|
||||
#include "consoleevent.h"
|
||||
#include "debuglines.h"
|
||||
#include "scriptexception.h"
|
||||
#include "vehicleturret.h"
|
||||
#include "weaputils.h"
|
||||
|
||||
BotManager botManager;
|
||||
|
||||
CLASS_DECLARATION(Listener, BotControllerManager, NULL) {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
CLASS_DECLARATION(Listener, BotManager, NULL) {
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
void BotManager::Init()
|
||||
{
|
||||
botControllerManager.Init();
|
||||
}
|
||||
|
||||
void BotManager::Cleanup()
|
||||
{
|
||||
botControllerManager.Cleanup();
|
||||
}
|
||||
|
||||
void BotManager::Frame()
|
||||
{
|
||||
botControllerManager.ThinkControllers();
|
||||
}
|
||||
|
||||
void BotManager::BroadcastEvent(Entity *originator, Vector origin, int iType, float radius)
|
||||
{
|
||||
Sentient *ent;
|
||||
Actor *act;
|
||||
Vector delta;
|
||||
str name;
|
||||
float r2;
|
||||
float dist2;
|
||||
int i;
|
||||
int iNumSentients;
|
||||
int iAreaNum;
|
||||
BotController *controller;
|
||||
|
||||
if (radius <= 0.0f) {
|
||||
radius = G_AIEventRadius(iType);
|
||||
}
|
||||
|
||||
assert(originator);
|
||||
|
||||
r2 = Square(radius);
|
||||
|
||||
const Container<BotController *>& controllers = getControllerManager().getControllers();
|
||||
for (i = 1; i <= controllers.NumObjects(); i++) {
|
||||
controller = controllers.ObjectAt(i);
|
||||
ent = controller->getControlledEntity();
|
||||
if (!ent || ent == originator || ent->deadflag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delta = origin - ent->centroid;
|
||||
|
||||
// dot product returns length squared
|
||||
dist2 = Square(delta);
|
||||
|
||||
if (originator) {
|
||||
iAreaNum = originator->edict->r.areanum;
|
||||
} else {
|
||||
iAreaNum = gi.AreaForPoint(origin);
|
||||
}
|
||||
|
||||
if (dist2 > r2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iAreaNum != ent->edict->r.areanum && !gi.AreasConnected(iAreaNum, ent->edict->r.areanum)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
controller->NoticeEvent(origin, iType, originator, dist2, r2);
|
||||
}
|
||||
}
|
||||
|
||||
BotControllerManager& BotManager::getControllerManager()
|
||||
{
|
||||
return botControllerManager;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue