mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-04 22:40:05 +00:00
Mobs roam proper distances now.
* Mob roaming is now integrated into the TransportManager * Doubled the roaming distance, since it was clearly too small * Tripled retreat speed * Made use of NPCManager::sendToViewable() in TransportManager
This commit is contained in:
parent
a53f38b87d
commit
901e011740
@ -5,6 +5,7 @@
|
|||||||
#include "ItemManager.hpp"
|
#include "ItemManager.hpp"
|
||||||
#include "MissionManager.hpp"
|
#include "MissionManager.hpp"
|
||||||
#include "GroupManager.hpp"
|
#include "GroupManager.hpp"
|
||||||
|
#include "TransportManager.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -366,12 +367,14 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
inline void MobManager::incNextMovement(Mob *mob, time_t currTime) {
|
||||||
* TODO: precalculate a path, lerp through it, repeat.
|
if (currTime == 0)
|
||||||
* The way it works right now, mobs only move around a little bit. This will result
|
currTime = getTime();
|
||||||
* in more natural movement, and will mesh well with pre-calculated paths (for Don Doom,
|
|
||||||
* Bad Max, etc.) once those have been made.
|
int delay = (int)mob->data["m_iDelayTime"] * 1000;
|
||||||
*/
|
mob->nextMovement = currTime + delay/2 + rand() % (delay/2);
|
||||||
|
}
|
||||||
|
|
||||||
void MobManager::roamingStep(Mob *mob, time_t currTime) {
|
void MobManager::roamingStep(Mob *mob, time_t currTime) {
|
||||||
/*
|
/*
|
||||||
* We reuse nextAttack to avoid scanning for players all the time, but to still
|
* We reuse nextAttack to avoid scanning for players all the time, but to still
|
||||||
@ -389,34 +392,44 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
||||||
return;
|
return;
|
||||||
|
incNextMovement(mob, currTime);
|
||||||
|
|
||||||
int delay = (int)mob->data["m_iDelayTime"] * 1000;
|
// only calculate a new route if we're not already on one
|
||||||
mob->nextMovement = currTime + delay/2 + rand() % (delay/2);
|
auto it = TransportManager::NPCQueues.find(mob->appearanceData.iNPC_ID);
|
||||||
|
if (it != TransportManager::NPCQueues.end() && it->second.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::cout << "charting new path for Mob " << (int)mob->appearanceData.iNPC_ID << std::endl;
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
|
|
||||||
int xStart = mob->spawnX - mob->idleRange/2;
|
int xStart = mob->spawnX - mob->idleRange/2;
|
||||||
int yStart = mob->spawnY - mob->idleRange/2;
|
int yStart = mob->spawnY - mob->idleRange/2;
|
||||||
|
|
||||||
int farX = xStart + rand() % mob->idleRange;
|
|
||||||
int farY = yStart + rand() % mob->idleRange;
|
|
||||||
int speed = mob->data["m_iWalkSpeed"];
|
int speed = mob->data["m_iWalkSpeed"];
|
||||||
|
|
||||||
|
int farX, farY;
|
||||||
|
int distance; // for short walk detection
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't want the mob to just take one step and stop, so we make sure
|
||||||
|
* it has walked a half-decent distance.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
farX = xStart + rand() % mob->idleRange;
|
||||||
|
farY = yStart + rand() % mob->idleRange;
|
||||||
|
|
||||||
|
distance = std::hypot(mob->appearanceData.iX - farX, mob->appearanceData.iY - farY);
|
||||||
|
} while (distance < 500);
|
||||||
|
|
||||||
// halve movement speed if snared
|
// halve movement speed if snared
|
||||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
||||||
speed /= 2;
|
speed /= 2;
|
||||||
|
|
||||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, farX, farY, speed);
|
std::queue<WarpLocation> queue;
|
||||||
|
WarpLocation from = { mob->appearanceData.iX, mob->appearanceData.iY, mob->appearanceData.iZ };
|
||||||
|
WarpLocation to = { farX, farY, mob->appearanceData.iZ };
|
||||||
|
|
||||||
NPCManager::updateNPCPosition(mob->appearanceData.iNPC_ID, targ.first, targ.second, mob->appearanceData.iZ);
|
// add a route to the queue; to be processed in TransportManager::stepNPCPathing()
|
||||||
|
TransportManager::lerp(&queue, from, to, speed);
|
||||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
TransportManager::NPCQueues[mob->appearanceData.iNPC_ID] = queue;
|
||||||
pkt.iSpeed = speed;
|
|
||||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
|
||||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
|
||||||
pkt.iToZ = mob->appearanceData.iZ;
|
|
||||||
|
|
||||||
// notify all nearby players
|
|
||||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
||||||
@ -432,10 +445,10 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
|||||||
if (distance > 10) {
|
if (distance > 10) {
|
||||||
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
|
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
|
||||||
|
|
||||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->spawnX, mob->spawnY, mob->data["m_iRunSpeed"]);
|
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->spawnX, mob->spawnY, (int)mob->data["m_iRunSpeed"] * 3);
|
||||||
|
|
||||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||||
pkt.iSpeed = mob->data["m_iRunSpeed"];
|
pkt.iSpeed = (int)mob->data["m_iRunSpeed"] * 3;
|
||||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||||
pkt.iToZ = mob->appearanceData.iZ;
|
pkt.iToZ = mob->appearanceData.iZ;
|
||||||
@ -702,7 +715,9 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) {
|
|||||||
lastHealTime = currTime;
|
lastHealTime = currTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool shouldCrit, bool batteryBoost, int attackerStyle, int defenderStyle, int difficulty) {
|
std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool shouldCrit,
|
||||||
|
bool batteryBoost, int attackerStyle,
|
||||||
|
int defenderStyle, int difficulty) {
|
||||||
std::pair<int,int> ret = {0, 1};
|
std::pair<int,int> ret = {0, 1};
|
||||||
if (attackPower + defensePower * 2 == 0)
|
if (attackPower + defensePower * 2 == 0)
|
||||||
return ret;
|
return ret;
|
||||||
@ -816,7 +831,8 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
|||||||
|
|
||||||
int difficulty = (int)mob->data["m_iNpcLevel"];
|
int difficulty = (int)mob->data["m_iNpcLevel"];
|
||||||
|
|
||||||
damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW >= 11 + difficulty), NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
|
damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW >= 11 + difficulty),
|
||||||
|
NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
|
||||||
|
|
||||||
if (plr->batteryW >= 11 + difficulty)
|
if (plr->batteryW >= 11 + difficulty)
|
||||||
plr->batteryW -= 11 + difficulty;
|
plr->batteryW -= 11 + difficulty;
|
||||||
|
@ -35,6 +35,7 @@ struct Mob : public BaseNPC {
|
|||||||
// roaming
|
// roaming
|
||||||
int idleRange;
|
int idleRange;
|
||||||
time_t nextMovement = 0;
|
time_t nextMovement = 0;
|
||||||
|
bool staticPath = false;
|
||||||
|
|
||||||
// combat
|
// combat
|
||||||
CNSocket *target = nullptr;
|
CNSocket *target = nullptr;
|
||||||
@ -50,7 +51,7 @@ struct Mob : public BaseNPC {
|
|||||||
data = d;
|
data = d;
|
||||||
|
|
||||||
regenTime = data["m_iRegenTime"];
|
regenTime = data["m_iRegenTime"];
|
||||||
idleRange = data["m_iIdleRange"];
|
idleRange = (int)data["m_iIdleRange"] * 2; // TODO: tuning?
|
||||||
|
|
||||||
// XXX: temporarily force respawns for Fusions until we implement instancing
|
// XXX: temporarily force respawns for Fusions until we implement instancing
|
||||||
if (regenTime >= 300000000)
|
if (regenTime >= 300000000)
|
||||||
@ -111,5 +112,6 @@ namespace MobManager {
|
|||||||
|
|
||||||
void pcAttackChars(CNSocket *sock, CNPacketData *data);
|
void pcAttackChars(CNSocket *sock, CNPacketData *data);
|
||||||
void resendMobHP(Mob *mob);
|
void resendMobHP(Mob *mob);
|
||||||
|
void incNextMovement(Mob *mob, time_t currTime=0);
|
||||||
bool aggroCheck(Mob *mob, time_t currTime);
|
bool aggroCheck(Mob *mob, time_t currTime);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "NanoManager.hpp"
|
#include "NanoManager.hpp"
|
||||||
#include "TransportManager.hpp"
|
#include "TransportManager.hpp"
|
||||||
#include "TableData.hpp"
|
#include "TableData.hpp"
|
||||||
|
#include "MobManager.hpp"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -275,12 +276,18 @@ void TransportManager::stepNPCPathing() {
|
|||||||
if (NPCManager::NPCs.find(it->first) != NPCManager::NPCs.end())
|
if (NPCManager::NPCs.find(it->first) != NPCManager::NPCs.end())
|
||||||
npc = NPCManager::NPCs[it->first];
|
npc = NPCManager::NPCs[it->first];
|
||||||
|
|
||||||
if (npc == nullptr) {
|
if (npc == nullptr || queue->empty()) {
|
||||||
// pluck out dead path + update iterator
|
// pluck out dead path + update iterator
|
||||||
it = NPCQueues.erase(it);
|
it = NPCQueues.erase(it);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do not roam if not roaming
|
||||||
|
if (npc->npcClass == NPC_MOB && ((Mob*)npc)->state != MobState::ROAMING) {
|
||||||
|
it++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
WarpLocation point = queue->front(); // get point
|
WarpLocation point = queue->front(); // get point
|
||||||
queue->pop(); // remove point from front of queue
|
queue->pop(); // remove point from front of queue
|
||||||
|
|
||||||
@ -291,10 +298,6 @@ void TransportManager::stepNPCPathing() {
|
|||||||
// update NPC location to update viewables
|
// update NPC location to update viewables
|
||||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, point.x, point.y, point.z);
|
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, point.x, point.y, point.z);
|
||||||
|
|
||||||
// get chunks in view
|
|
||||||
auto chunk = ChunkManager::grabChunk(npc->appearanceData.iX, npc->appearanceData.iY, npc->instanceID);
|
|
||||||
auto chunks = ChunkManager::grabChunks(chunk);
|
|
||||||
|
|
||||||
switch (npc->npcClass) {
|
switch (npc->npcClass) {
|
||||||
case NPC_BUS:
|
case NPC_BUS:
|
||||||
INITSTRUCT(sP_FE2CL_TRANSPORTATION_MOVE, busMove);
|
INITSTRUCT(sP_FE2CL_TRANSPORTATION_MOVE, busMove);
|
||||||
@ -306,13 +309,11 @@ void TransportManager::stepNPCPathing() {
|
|||||||
busMove.iToZ = point.z;
|
busMove.iToZ = point.z;
|
||||||
busMove.iSpeed = distanceBetween; // set to distance to match how monkeys work
|
busMove.iSpeed = distanceBetween; // set to distance to match how monkeys work
|
||||||
|
|
||||||
// send packet to players in view
|
NPCManager::sendToViewable(npc, &busMove, P_FE2CL_TRANSPORTATION_MOVE, sizeof(sP_FE2CL_TRANSPORTATION_MOVE));
|
||||||
for (Chunk* chunk : chunks) {
|
|
||||||
for (CNSocket* s : chunk->players) {
|
|
||||||
s->sendPacket(&busMove, P_FE2CL_TRANSPORTATION_MOVE, sizeof(sP_FE2CL_TRANSPORTATION_MOVE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
case NPC_MOB:
|
||||||
|
MobManager::incNextMovement((Mob*)npc);
|
||||||
|
/* fallthrough */
|
||||||
default:
|
default:
|
||||||
INITSTRUCT(sP_FE2CL_NPC_MOVE, move);
|
INITSTRUCT(sP_FE2CL_NPC_MOVE, move);
|
||||||
move.iNPC_ID = npc->appearanceData.iNPC_ID;
|
move.iNPC_ID = npc->appearanceData.iNPC_ID;
|
||||||
@ -322,16 +323,17 @@ void TransportManager::stepNPCPathing() {
|
|||||||
move.iToZ = point.z;
|
move.iToZ = point.z;
|
||||||
move.iSpeed = distanceBetween;
|
move.iSpeed = distanceBetween;
|
||||||
|
|
||||||
// send packet to players in view
|
NPCManager::sendToViewable(npc, &move, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
||||||
for (Chunk* chunk : chunks) {
|
|
||||||
for (CNSocket* s : chunk->players) {
|
|
||||||
s->sendPacket(&move, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue->push(point); // move processed point to the back to maintain cycle
|
/*
|
||||||
|
* Move processed point to the back to maintain cycle, unless this is a
|
||||||
|
* dynamically calculated mob route.
|
||||||
|
*/
|
||||||
|
if (!(npc->npcClass == NPC_MOB && !((Mob*)npc)->staticPath))
|
||||||
|
queue->push(point);
|
||||||
|
|
||||||
it++; // go to next entry in map
|
it++; // go to next entry in map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user