diff --git a/src/MobManager.cpp b/src/MobManager.cpp index 2305a7c..c0725af 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -61,6 +61,9 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) { mob->appearanceData.iHP -= 100; + // wake up sleeping monster + mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ; + if (mob->appearanceData.iHP <= 0) killMob(sock, mob); @@ -132,6 +135,7 @@ void MobManager::giveReward(CNSocket *sock) { void MobManager::killMob(CNSocket *sock, Mob *mob) { mob->state = MobState::DEAD; + mob->appearanceData.iConditionBitFlag = 0; mob->killedTime = getTime(); // XXX: maybe introduce a shard-global time for each step? std::cout << "killed mob " << mob->appearanceData.iNPC_ID << std::endl; @@ -188,6 +192,10 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) { int delay = (int)mob->data["m_iDelayTime"] * 1000; mob->nextMovement = currTime + delay/2 + rand() % (delay/2); + // skip move if stunned or asleep + if (mob->appearanceData.iConditionBitFlag & (CSB_BIT_STUN|CSB_BIT_MEZ)) + return; + INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt); int xStart = mob->spawnX - mob->idleRange/2; int yStart = mob->spawnY - mob->idleRange/2; @@ -198,6 +206,13 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) { pkt.iToY = mob->appearanceData.iY = yStart + rand() % mob->idleRange; pkt.iToZ = mob->appearanceData.iZ; + // 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; + } + auto chunk = ChunkManager::grabChunk(mob->appearanceData.iX, mob->appearanceData.iY); auto chunks = ChunkManager::grabChunks(chunk); diff --git a/src/MobManager.hpp b/src/MobManager.hpp index cd770b0..fb8c3ca 100644 --- a/src/MobManager.hpp +++ b/src/MobManager.hpp @@ -20,6 +20,7 @@ enum class MobState { struct Mob : public BaseNPC { MobState state; const int maxHealth; + time_t killedTime = 0; const int regenTime; bool despawned = false; // for the sake of death animations @@ -42,6 +43,8 @@ struct Mob : public BaseNPC { spawnY = appearanceData.iY; spawnZ = appearanceData.iZ; + appearanceData.iConditionBitFlag = 0; + // NOTE: there appear to be discrepancies in the dump appearanceData.iHP = maxHealth; } diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 7f39466..a132b54 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -318,7 +318,7 @@ bool doDebuff(CNSocket *sock, int32_t *pktdata, sSkillResult_Damage_N_Debuff *re respdata[i].iDamage = amount; respdata[i].iID = mob->appearanceData.iNPC_ID; respdata[i].iHP = mob->appearanceData.iHP; - respdata[i].iConditionBitFlag = iCBFlag; + respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag |= iCBFlag; std::cout << (int)mob->appearanceData.iNPC_ID << " was debuffed" << std::endl; @@ -336,7 +336,7 @@ bool doBuff(CNSocket *sock, int32_t *pktdata, sSkillResult_Buff *respdata, int i respdata[i].eCT = 4; respdata[i].iID = mob->appearanceData.iNPC_ID; - respdata[i].iConditionBitFlag = iCBFlag; + respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag |= iCBFlag; std::cout << (int)mob->appearanceData.iNPC_ID << " was debuffed" << std::endl; @@ -382,6 +382,9 @@ bool doDamage(CNSocket *sock, int32_t *pktdata, sSkillResult_Damage *respdata, i mob->appearanceData.iHP -= amount; + // wake up sleeping monster + mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ; + if (mob->appearanceData.iHP <= 0) MobManager::killMob(sock, mob); @@ -432,6 +435,9 @@ bool doLeech(CNSocket *sock, int32_t *pktdata, sSkillResult_Heal_HP *healdata, i mob->appearanceData.iHP -= amount; + // wake up sleeping monster + mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ; + if (mob->appearanceData.iHP <= 0) MobManager::killMob(sock, mob); @@ -506,7 +512,7 @@ std::vector ActivePowers = { ActivePower(StunPowers, activePower, EST_STUN, CSB_BIT_STUN, 0), ActivePower(HealPowers, activePower, EST_HEAL_HP, CSB_BIT_NONE, 333), // TODO: Recall - ActivePower(DrainPowers, activePower, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 0), + ActivePower(DrainPowers, activePower, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 0), ActivePower(SnarePowers, activePower, EST_SNARE, CSB_BIT_DN_MOVE_SPEED, 0), ActivePower(DamagePowers, activePower, EST_DAMAGE, CSB_BIT_NONE, 133), // TODO: GroupRevive