Generalize NPC AI stepping logic

The MobAI::Mobs map still needs to be removed.
This commit is contained in:
dongresource 2021-03-31 21:05:49 +02:00
parent 3325397d17
commit 65462d01e3
7 changed files with 65 additions and 55 deletions

View File

@ -30,12 +30,8 @@ struct Entity {
virtual bool isAlive() { return true; }
// stubs
virtual void enterIntoViewOf(CNSocket *sock) {}
virtual void disappearFromViewOf(CNSocket *sock) {}
// we don't want objects of this base class to exist
protected:
Entity() {}
virtual void enterIntoViewOf(CNSocket *sock) = 0;
virtual void disappearFromViewOf(CNSocket *sock) = 0;
};
struct EntityRef {
@ -106,16 +102,16 @@ struct CombatNPC : public BaseNPC {
int spawnZ = 0;
int level = 0;
void (*_stepAI)() = nullptr;
void (*_stepAI)(CombatNPC*, time_t) = nullptr;
// XXX
CombatNPC(int x, int y, int z, int angle, uint64_t iID, int t, int id, int maxHP) :
BaseNPC(x, y, z, angle, iID, t, id),
maxHealth(maxHP) {}
virtual void stepAI() {
virtual void stepAI(time_t currTime) {
if (_stepAI != nullptr)
_stepAI();
_stepAI(this, currTime);
}
virtual bool isAlive() override { return appearanceData.iHP > 0; }

View File

@ -12,9 +12,8 @@
using namespace MobAI;
std::map<int32_t, Mob*> MobAI::Mobs;
static std::queue<int32_t> RemovalQueue;
bool MobAI::simulateMobs;
bool MobAI::simulateMobs = settings::SIMULATEMOBS;
static void roamingStep(Mob *mob, time_t currTime);
@ -451,7 +450,7 @@ static void deadStep(Mob *mob, time_t currTime) {
// if it was summoned, mark it for removal
if (mob->summoned) {
std::cout << "[INFO] Queueing killed summoned mob for removal" << std::endl;
RemovalQueue.push(mob->appearanceData.iNPC_ID);
NPCManager::queueNPCRemoval(mob->appearanceData.iNPC_ID);
return;
}
@ -774,44 +773,33 @@ static void retreatStep(Mob *mob, time_t currTime) {
}
}
static void step(CNServer *serv, time_t currTime) {
for (auto& pair : Mobs) {
if (pair.second->playersInView < 0)
std::cout << "[WARN] Weird playerview value " << pair.second->playersInView << std::endl;
void MobAI::step(CombatNPC *npc, time_t currTime) {
assert(npc->type == EntityType::MOB);
auto mob = (Mob*)npc;
// skip mob movement and combat if disabled or not in view
if ((!simulateMobs || pair.second->playersInView == 0) && pair.second->state != MobState::DEAD
&& pair.second->state != MobState::RETREAT)
continue;
if (mob->playersInView < 0)
std::cout << "[WARN] Weird playerview value " << mob->playersInView << std::endl;
switch (pair.second->state) {
case MobState::INACTIVE:
// no-op
break;
case MobState::ROAMING:
roamingStep(pair.second, currTime);
break;
case MobState::COMBAT:
combatStep(pair.second, currTime);
break;
case MobState::RETREAT:
retreatStep(pair.second, currTime);
break;
case MobState::DEAD:
deadStep(pair.second, currTime);
break;
}
}
// skip mob movement and combat if disabled or not in view
if ((!simulateMobs || mob->playersInView == 0) && mob->state != MobState::DEAD
&& mob->state != MobState::RETREAT)
return;
// deallocate all NPCs queued for removal
while (RemovalQueue.size() > 0) {
NPCManager::destroyNPC(RemovalQueue.front());
RemovalQueue.pop();
switch (mob->state) {
case MobState::INACTIVE:
// no-op
break;
case MobState::ROAMING:
roamingStep(mob, currTime);
break;
case MobState::COMBAT:
combatStep(mob, currTime);
break;
case MobState::RETREAT:
retreatStep(mob, currTime);
break;
case MobState::DEAD:
deadStep(mob, currTime);
break;
}
}
void MobAI::init() {
REGISTER_SHARD_TIMER(step, 200);
simulateMobs = settings::SIMULATEMOBS;
}

View File

@ -11,6 +11,11 @@ enum class MobState {
DEAD
};
namespace MobAI {
// needs to be declared before Mob's constructor
void step(CombatNPC*, time_t);
};
struct Mob : public CombatNPC {
// general
MobState state = MobState::INACTIVE;
@ -76,6 +81,7 @@ struct Mob : public CombatNPC {
appearanceData.iHP = maxHealth;
type = EntityType::MOB;
_stepAI = MobAI::step;
}
// constructor for /summon
@ -98,8 +104,6 @@ namespace MobAI {
extern bool simulateMobs;
extern std::map<int32_t, Mob*> Mobs;
void init();
// TODO: make this internal later
void incNextMovement(Mob *mob, time_t currTime=0);
bool aggroCheck(Mob *mob, time_t currTime);

View File

@ -23,11 +23,13 @@
using namespace NPCManager;
std::map<int32_t, BaseNPC*> NPCManager::NPCs;
std::unordered_map<int32_t, BaseNPC*> NPCManager::NPCs;
std::map<int32_t, WarpLocation> NPCManager::Warps;
std::vector<WarpLocation> NPCManager::RespawnPoints;
nlohmann::json NPCManager::NPCData;
static std::queue<int32_t> RemovalQueue;
/*
* Initialized at the end of TableData::init().
* This allows us to summon and kill mobs in arbitrary order without
@ -349,10 +351,32 @@ std::vector<NPCEvent> NPCManager::NPCEvents = {
#pragma endregion NPCEvents
void NPCManager::queueNPCRemoval(int32_t id) {
RemovalQueue.push(id);
}
static void step(CNServer *serv, time_t currTime) {
for (auto& pair : NPCs) {
if (pair.second->type != EntityType::COMBAT_NPC && pair.second->type != EntityType::MOB)
continue;
auto npc = (CombatNPC*)pair.second;
npc->stepAI(currTime);
}
// deallocate all NPCs queued for removal
while (RemovalQueue.size() > 0) {
NPCManager::destroyNPC(RemovalQueue.front());
RemovalQueue.pop();
}
}
void NPCManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_NPC, npcWarpHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TIME_TO_GO_WARP, npcWarpTimeMachine);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_SUMMON, npcSummonHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_UNSUMMON, npcUnsummonHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_BARKER, npcBarkHandler);
REGISTER_SHARD_TIMER(step, 200);
}

View File

@ -34,7 +34,7 @@ struct WarpLocation {
};
namespace NPCManager {
extern std::map<int32_t, BaseNPC*> NPCs;
extern std::unordered_map<int32_t, BaseNPC*> NPCs;
extern std::map<int32_t, WarpLocation> Warps;
extern std::vector<WarpLocation> RespawnPoints;
extern std::vector<NPCEvent> NPCEvents;
@ -42,6 +42,7 @@ namespace NPCManager {
extern int32_t nextId;
void init();
void queueNPCRemoval(int32_t);
void destroyNPC(int32_t);
void updateNPCPosition(int32_t, int X, int Y, int Z, uint64_t I, int angle);

View File

@ -1,7 +1,6 @@
#pragma once
#include <map>
#include "JSON.hpp"
#include "NPCManager.hpp"
namespace TableData {

View File

@ -6,7 +6,6 @@
#include "Buddies.hpp"
#include "CustomCommands.hpp"
#include "Combat.hpp"
#include "MobAI.hpp"
#include "Items.hpp"
#include "Missions.hpp"
#include "Nanos.hpp"
@ -107,7 +106,6 @@ int main() {
CustomCommands::init();
Combat::init();
Chat::init();
MobAI::init();
Items::init();
Eggs::init();
Missions::init();