mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-12-23 03:40:05 +00:00
Lerp mob movement a little.
We'll lerp a little harder later. Also retreat if kited too far.
This commit is contained in:
parent
1f18104a6f
commit
cfb3d25bc5
@ -73,7 +73,7 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
||||
mob->target = sock;
|
||||
mob->state = MobState::COMBAT;
|
||||
mob->nextMovement = getTime();
|
||||
std::cout << "combat state\n";
|
||||
//std::cout << "combat state\n";
|
||||
}
|
||||
|
||||
mob->appearanceData.iHP -= 100;
|
||||
@ -131,7 +131,7 @@ void MobManager::npcAttackPc(Mob *mob) {
|
||||
if (plr->HP <= 0) {
|
||||
mob->target = nullptr;
|
||||
mob->state = MobState::RETREAT;
|
||||
std::cout << "retreat state\n";
|
||||
//std::cout << "retreat state\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ void MobManager::killMob(CNSocket *sock, Mob *mob) {
|
||||
mob->appearanceData.iConditionBitFlag = 0;
|
||||
mob->killedTime = getTime(); // XXX: maybe introduce a shard-global time for each step?
|
||||
|
||||
std::cout << "dead state mob " << mob->appearanceData.iNPC_ID << std::endl;
|
||||
//std::cout << "dead state mob " << mob->appearanceData.iNPC_ID << std::endl;
|
||||
|
||||
giveReward(sock);
|
||||
MissionManager::mobKilled(sock, mob->appearanceData.iNPCType);
|
||||
@ -224,7 +224,7 @@ void MobManager::deadStep(Mob *mob, time_t currTime) {
|
||||
|
||||
mob->appearanceData.iHP = mob->maxHealth;
|
||||
mob->state = MobState::ROAMING;
|
||||
std::cout << "roaming state\n";
|
||||
//std::cout << "roaming state\n";
|
||||
|
||||
INITSTRUCT(sP_FE2CL_NPC_NEW, pkt);
|
||||
|
||||
@ -245,7 +245,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
if (PlayerManager::players.find(mob->target) == PlayerManager::players.end()) {
|
||||
mob->target = nullptr;
|
||||
mob->state = MobState::RETREAT;
|
||||
std::cout << "RETREAT state\n";
|
||||
//std::cout << "RETREAT state\n";
|
||||
return;
|
||||
}
|
||||
Player *plr = PlayerManager::getPlayer(mob->target);
|
||||
@ -261,7 +261,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
* No, I'm not 100% sure this is how it's supposed to work.
|
||||
*/
|
||||
if (distance <= (int)mob->data["m_iAtkRange"]) {
|
||||
std::cout << "attack logic\n";
|
||||
//std::cout << "attack logic\n";
|
||||
// attack logic
|
||||
if (mob->nextAttack == 0) {
|
||||
mob->nextAttack = currTime + (int)mob->data["m_iInitalTime"] * 100; // I *think* this is what this is
|
||||
@ -271,20 +271,28 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
npcAttackPc(mob);
|
||||
}
|
||||
} else {
|
||||
std::cout << "movement logic\n";
|
||||
std::cout << "distance: " << distance << " attack range: " << mob->data["m_iAtkRange"] << std::endl;
|
||||
//std::cout << "movement logic\n";
|
||||
//std::cout << "distance: " << distance << " attack range: " << mob->data["m_iAtkRange"] << std::endl;
|
||||
// movement logic
|
||||
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
||||
return;
|
||||
mob->nextMovement = currTime + (int)mob->data["m_iDelayTime"] * 100;
|
||||
|
||||
int speed = mob->data["m_iRunSpeed"];
|
||||
|
||||
// halve movement speed if snared
|
||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
||||
speed /= 2;
|
||||
|
||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->target->plr->x, mob->target->plr->y, speed);
|
||||
|
||||
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
|
||||
|
||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||
pkt.iSpeed = mob->data["m_iWalkSpeed"];
|
||||
pkt.iToX = mob->appearanceData.iX = mob->target->plr->x; // FIXME: lerping
|
||||
pkt.iToY = mob->appearanceData.iY = mob->target->plr->y;
|
||||
pkt.iToZ = mob->appearanceData.iZ = mob->target->plr->z;
|
||||
pkt.iSpeed = speed;
|
||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||
pkt.iToZ = mob->appearanceData.iZ;
|
||||
|
||||
auto chunk = ChunkManager::grabChunk(mob->appearanceData.iX, mob->appearanceData.iY);
|
||||
auto chunks = ChunkManager::grabChunks(chunk);
|
||||
@ -297,10 +305,26 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: retreat if kited too far
|
||||
// retreat if kited too far
|
||||
distance = hypot(mob->appearanceData.iX - mob->spawnX, mob->appearanceData.iY - mob->spawnY);
|
||||
if (distance >= mob->data["m_iCombatRange"]) {
|
||||
mob->target = nullptr;
|
||||
mob->state = MobState::RETREAT;
|
||||
//std::cout << "retreat state\n";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: precalculate a path, lerp through it, repeat.
|
||||
* The way it works right now, mobs only move around a little bit. This will result
|
||||
* in more natural movement, and will mesh well with pre-calculated paths (for Don Doom,
|
||||
* Bad Max, etc.) once those have been made.
|
||||
*/
|
||||
void MobManager::roamingStep(Mob *mob, time_t currTime) {
|
||||
// some mobs don't move (and we mustn't divide/modulus by zero)
|
||||
if (mob->idleRange == 0)
|
||||
return;
|
||||
|
||||
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
||||
return;
|
||||
|
||||
@ -315,18 +339,21 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) {
|
||||
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;
|
||||
int farX = xStart + rand() % mob->idleRange;
|
||||
int farY = yStart + rand() % mob->idleRange;
|
||||
int speed = mob->data["m_iWalkSpeed"];
|
||||
|
||||
// roughly halve movement speed if snared
|
||||
// TODO: this logic isn't quite right yet, since they still get to the same spot
|
||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED) {
|
||||
mob->nextMovement += delay;
|
||||
pkt.iSpeed /= 2;
|
||||
}
|
||||
// halve movement speed if snared
|
||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED)
|
||||
speed /= 2;
|
||||
|
||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, farX, farY, speed);
|
||||
|
||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||
pkt.iSpeed = speed;
|
||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||
pkt.iToZ = mob->appearanceData.iZ;
|
||||
|
||||
auto chunk = ChunkManager::grabChunk(mob->appearanceData.iX, mob->appearanceData.iY);
|
||||
auto chunks = ChunkManager::grabChunks(chunk);
|
||||
@ -349,10 +376,12 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
||||
auto chunk = ChunkManager::grabChunk(mob->appearanceData.iX, mob->appearanceData.iY);
|
||||
auto chunks = ChunkManager::grabChunks(chunk);
|
||||
|
||||
auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->spawnX, mob->spawnY, mob->data["m_iRunSpeed"]);
|
||||
|
||||
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||
pkt.iSpeed = mob->data["m_iWalkSpeed"];
|
||||
pkt.iToX = mob->appearanceData.iX = mob->spawnX;
|
||||
pkt.iToY = mob->appearanceData.iY = mob->spawnY;
|
||||
pkt.iSpeed = mob->data["m_iRunSpeed"];
|
||||
pkt.iToX = mob->appearanceData.iX = targ.first;
|
||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||
pkt.iToZ = mob->appearanceData.iZ;
|
||||
|
||||
// notify all nearby players
|
||||
@ -366,7 +395,7 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
||||
// if we got there
|
||||
if (distance <= mob->data["m_iIdleRange"]) {
|
||||
mob->state = MobState::ROAMING;
|
||||
std::cout << "roaming state\n";
|
||||
//std::cout << "roaming state\n";
|
||||
mob->appearanceData.iHP = mob->maxHealth;
|
||||
mob->killedTime = 0;
|
||||
mob->nextAttack = 0;
|
||||
@ -388,6 +417,9 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
||||
continue;
|
||||
|
||||
switch (pair.second->state) {
|
||||
case MobState::INACTIVE:
|
||||
// no-op
|
||||
break;
|
||||
case MobState::ROAMING:
|
||||
roamingStep(pair.second, currTime);
|
||||
break;
|
||||
@ -400,9 +432,24 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
||||
case MobState::DEAD:
|
||||
deadStep(pair.second, currTime);
|
||||
break;
|
||||
default:
|
||||
// unhandled for now
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dynamic lerp; distinct from TransportManager::lerp(). This one doesn't care about height and
|
||||
* only returns the first step, since the rest will need to be recalculated anyway if chasing player.
|
||||
*/
|
||||
std::pair<int,int> MobManager::lerp(int x1, int y1, int x2, int y2, int speed) {
|
||||
std::pair<int,int> ret = {};
|
||||
|
||||
int distance = hypot(x1 - x2, y1 - y2);
|
||||
int lerps = distance / speed;
|
||||
|
||||
// interpolate only the first point
|
||||
float frac = 1.0f / (lerps+1);
|
||||
ret.first = (x1 * (1.0f - frac)) + (x2 * frac);
|
||||
ret.second = (y1 * (1.0f - frac)) + (y2 * frac);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ struct Mob : public BaseNPC {
|
||||
|
||||
// dead
|
||||
time_t killedTime = 0;
|
||||
int regenTime;
|
||||
time_t regenTime;
|
||||
bool despawned = false; // for the sake of death animations
|
||||
|
||||
// roaming
|
||||
@ -85,4 +85,5 @@ namespace MobManager {
|
||||
void npcAttackPc(Mob *mob);
|
||||
void killMob(CNSocket *sock, Mob *mob);
|
||||
void giveReward(CNSocket *sock);
|
||||
std::pair<int,int> lerp(int, int, int, int, int);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user