Implemented mob roaming.

Will likely need further tuning.
Mobs in vacant chunks are skipped.
This commit is contained in:
dongresource 2020-09-22 20:33:10 +02:00
parent 94ab5b8b64
commit ac1fd1e5be
5 changed files with 75 additions and 3 deletions

View File

@ -104,3 +104,15 @@ std::vector<Chunk*> ChunkManager::getDeltaChunks(std::vector<Chunk*> from, std::
return delta; return delta;
} }
bool ChunkManager::inPopulatedChunks(int posX, int posY) {
auto chunk = ChunkManager::grabChunk(posX, posY);
auto nearbyChunks = ChunkManager::grabChunks(chunk);
for (Chunk *c: nearbyChunks) {
if (!c->players.empty())
return true;
}
return false;
}

View File

@ -26,4 +26,5 @@ namespace ChunkManager {
std::pair<int, int> grabChunk(int posX, int posY); std::pair<int, int> grabChunk(int posX, int posY);
std::vector<Chunk*> grabChunks(std::pair<int, int> chunkPos); std::vector<Chunk*> grabChunks(std::pair<int, int> chunkPos);
std::vector<Chunk*> getDeltaChunks(std::vector<Chunk*> from, std::vector<Chunk*> to); std::vector<Chunk*> getDeltaChunks(std::vector<Chunk*> from, std::vector<Chunk*> to);
bool inPopulatedChunks(int posX, int posY);
} }

View File

@ -179,9 +179,47 @@ void MobManager::deadStep(Mob *mob, time_t currTime) {
} }
} }
void MobManager::roamingStep(Mob *mob, time_t currTime) {
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
return;
int delay = (int)mob->data["m_iDelayTime"] * 1000;
mob->nextMovement = currTime + delay/2 + rand() % (delay/2);
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
int xStart = mob->spawnX - mob->idleRange/2;
int yStart = mob->spawnY - mob->idleRange/2;
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
pkt.iSpeed = mob->data["m_iWalkSpeed"];
pkt.iToX = mob->appearanceData.iX = xStart + rand() % mob->idleRange;
pkt.iToY = mob->appearanceData.iY = yStart + rand() % mob->idleRange;
pkt.iToZ = mob->appearanceData.iZ;
auto chunk = ChunkManager::grabChunk(mob->appearanceData.iX, mob->appearanceData.iY);
auto chunks = ChunkManager::grabChunks(chunk);
// notify all nearby players
for (Chunk *chunk : chunks) {
for (CNSocket *s : chunk->players) {
s->sendPacket(&pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
}
}
}
void MobManager::step(time_t currTime) { void MobManager::step(time_t currTime) {
for (auto& pair : Mobs) { for (auto& pair : Mobs) {
int x = pair.second->appearanceData.iX;
int y = pair.second->appearanceData.iY;
// skip chunks without players
if (!ChunkManager::inPopulatedChunks(x, y))
continue;
switch (pair.second->state) { switch (pair.second->state) {
case MobState::ROAMING:
roamingStep(pair.second, currTime);
break;
case MobState::DEAD: case MobState::DEAD:
deadStep(pair.second, currTime); deadStep(pair.second, currTime);
break; break;

View File

@ -5,6 +5,8 @@
#include "CNShardServer.hpp" #include "CNShardServer.hpp"
#include "NPC.hpp" #include "NPC.hpp"
#include "contrib/JSON.hpp"
#include <map> #include <map>
enum class MobState { enum class MobState {
@ -22,14 +24,32 @@ struct Mob : public BaseNPC {
const int regenTime; const int regenTime;
bool despawned = false; // for the sake of death animations bool despawned = false; // for the sake of death animations
Mob(int x, int y, int z, int type, int hp, int angle, int rt) int spawnX;
: BaseNPC(x, y, z, type), maxHealth(hp), regenTime(rt) { int spawnY;
int spawnZ;
const int idleRange;
time_t nextMovement = 0;
// temporary; until we're sure what's what
nlohmann::json data;
Mob(int x, int y, int z, int type, int hp, int angle, nlohmann::json d)
: BaseNPC(x, y, z, type), maxHealth(hp), regenTime(d["m_iRegenTime"]), idleRange(d["m_iIdleRange"]), data(d) {
state = MobState::ROAMING; state = MobState::ROAMING;
spawnX = appearanceData.iX;
spawnY = appearanceData.iY;
spawnZ = appearanceData.iZ;
// NOTE: there appear to be discrepancies in the dump // NOTE: there appear to be discrepancies in the dump
appearanceData.iHP = maxHealth; appearanceData.iHP = maxHealth;
} }
~Mob() {} ~Mob() {}
auto operator[](std::string s) {
return data[s];
}
}; };
namespace MobManager { namespace MobManager {
@ -39,6 +59,7 @@ namespace MobManager {
void step(time_t); void step(time_t);
void deadStep(Mob*, time_t); void deadStep(Mob*, time_t);
void roamingStep(Mob*, time_t);
void pcAttackNpcs(CNSocket *sock, CNPacketData *data); void pcAttackNpcs(CNSocket *sock, CNPacketData *data);
void combatBegin(CNSocket *sock, CNPacketData *data); void combatBegin(CNSocket *sock, CNPacketData *data);

View File

@ -162,7 +162,7 @@ void TableData::init() {
for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) { for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) {
auto npc = _npc.value(); auto npc = _npc.value();
auto td = npcTableData[(int)npc["iNPCType"]]; auto td = npcTableData[(int)npc["iNPCType"]];
Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iNPCType"], npc["iHP"], npc["iAngle"], td["m_iRegenTime"]); Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iNPCType"], npc["iHP"], npc["iAngle"], td);
// Temporary fix, IDs will be pulled from json later // Temporary fix, IDs will be pulled from json later
tmp->appearanceData.iNPC_ID = i; tmp->appearanceData.iNPC_ID = i;