diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index fc41df3..03ba987 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -411,6 +411,7 @@ void minfoCommand(std::string full, std::vector& args, CNSocket* so ChatManager::sendServerMessage(sock, "[MINFO] Current task ID: " + std::to_string(plr->tasks[i])); ChatManager::sendServerMessage(sock, "[MINFO] Current task type: " + std::to_string((int)(task["m_iHTaskType"]))); ChatManager::sendServerMessage(sock, "[MINFO] Current waypoint NPC ID: " + std::to_string((int)(task["m_iSTGrantWayPoint"]))); + ChatManager::sendServerMessage(sock, "[MINFO] Current terminator NPC ID: " + std::to_string((int)(task["m_iHTerminatorNPCID"]))); for (int j = 0; j < 3; j++) if ((int)(task["m_iCSUEnemyID"][j]) != 0) diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 1df9571..b06b88b 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -29,12 +29,12 @@ void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) { Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_To); if (plr == nullptr || otherPlr == nullptr) - return; + return; otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup); if (otherPlr == nullptr) - return; + return; // fail if the group is full or the other player is already in a group if (plr->groupCnt >= 4 || otherPlr->groupCnt > 1) { @@ -50,9 +50,9 @@ void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) { INITSTRUCT(sP_FE2CL_PC_GROUP_INVITE, resp); - resp.iHostID = plr->iIDGroup; + resp.iHostID = plr->iIDGroup; - otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE, sizeof(sP_FE2CL_PC_GROUP_INVITE)); + otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE, sizeof(sP_FE2CL_PC_GROUP_INVITE)); } void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) { @@ -61,7 +61,7 @@ void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) { sP_CL2FE_REQ_PC_GROUP_INVITE_REFUSE* recv = (sP_CL2FE_REQ_PC_GROUP_INVITE_REFUSE*)data->buf; - CNSocket* otherSock = PlayerManager::getSockFromID(recv->iID_From); + CNSocket* otherSock = PlayerManager::getSockFromID(recv->iID_From); if (otherSock == nullptr) return; @@ -69,13 +69,13 @@ void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) { Player* plr = PlayerManager::getPlayer(sock); if (plr == nullptr) - return; + return; INITSTRUCT(sP_FE2CL_PC_GROUP_INVITE_REFUSE, resp); resp.iID_To = plr->iID; - otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE_REFUSE, sizeof(sP_FE2CL_PC_GROUP_INVITE_REFUSE)); + otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE_REFUSE, sizeof(sP_FE2CL_PC_GROUP_INVITE_REFUSE)); } void GroupManager::joinGroup(CNSocket* sock, CNPacketData* data) { @@ -87,12 +87,12 @@ void GroupManager::joinGroup(CNSocket* sock, CNPacketData* data) { Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_From); if (plr == nullptr || otherPlr == nullptr) - return; + return; otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup); if (otherPlr == nullptr) - return; + return; // fail if the group is full or the other player is already in a group if (plr->groupCnt > 1 || plr->iIDGroup != plr->iID || otherPlr->groupCnt >= 4) { @@ -172,7 +172,7 @@ void GroupManager::chatGroup(CNSocket* sock, CNPacketData* data) { Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); if (plr == nullptr || otherPlr == nullptr) - return; + return; // send to client INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, resp); @@ -184,14 +184,14 @@ void GroupManager::chatGroup(CNSocket* sock, CNPacketData* data) { void GroupManager::menuChatGroup(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE)) - return; // malformed packet + return; // malformed packet sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE*)data->buf; Player* plr = PlayerManager::getPlayer(sock); Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); if (plr == nullptr || otherPlr == nullptr) - return; + return; // send to client INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, resp); @@ -276,7 +276,7 @@ void GroupManager::groupKickPlayer(Player* plr) { Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); if (otherPlr == nullptr) - return; + return; if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_LEAVE), otherPlr->groupCnt - 1, sizeof(sPCGroupMemberInfo))) { std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_LEAVE packet size\n"; @@ -340,7 +340,7 @@ void GroupManager::groupKickPlayer(Player* plr) { CNSocket* sock = PlayerManager::getSockFromID(plr->iID); if (sock == nullptr) - return; + return; INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1); sock->sendPacket((void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC)); diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index 4a22745..09ccaa2 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -140,12 +140,12 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) { INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, equipChange); equipChange.iPC_ID = plr.plr->iID; - if (itemmove->eFrom == (int)SlotType::EQUIP) { - equipChange.iEquipSlotNum = itemmove->iFromSlotNum; - equipChange.EquipSlotItem = resp.ToSlotItem; - } else { + if (itemmove->eTo == (int)SlotType::EQUIP) { equipChange.iEquipSlotNum = itemmove->iToSlotNum; equipChange.EquipSlotItem = resp.FromSlotItem; + } else { + equipChange.iEquipSlotNum = itemmove->iFromSlotNum; + equipChange.EquipSlotItem = resp.ToSlotItem; } // unequip vehicle if equip slot 8 is 0 diff --git a/src/MissionManager.cpp b/src/MissionManager.cpp index fadbccb..c905195 100644 --- a/src/MissionManager.cpp +++ b/src/MissionManager.cpp @@ -77,20 +77,27 @@ void MissionManager::taskStart(CNSocket* sock, CNPacketData* data) { return; } + TaskData& task = *Tasks[missionData->iTaskNum]; + response.iTaskNum = missionData->iTaskNum; + response.iRemainTime = task["m_iSTGrantTimer"]; sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_START_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_START_SUCC)); - // HACK: auto-succeed Eduardo escort task - // TODO: maybe check for iTaskType == 6 and skip all escort missions? - if (missionData->iTaskNum == 576) { + // HACK: auto-succeed escort task + if (task["m_iHTaskType"] == 6) { std::cout << "Sending Eduardo success packet" << std::endl; INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response); - endTask(sock, 576); - response.iTaskNum = 576; + endTask(sock, missionData->iTaskNum); + response.iTaskNum = missionData->iTaskNum; sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC)); } + + // Give player their delivery items at the start. + for (int i = 0; i < 3; i++) + if (task["m_iSTItemID"][i] != 0 && task["m_iSTItemNumNeeded"][i] > 0) + dropQuestItem(sock, missionData->iTaskNum, task["m_iSTItemNumNeeded"][i], task["m_iSTItemID"][i], 0); } void MissionManager::taskEnd(CNSocket* sock, CNPacketData* data) { @@ -98,6 +105,25 @@ void MissionManager::taskEnd(CNSocket* sock, CNPacketData* data) { return; // malformed packet sP_CL2FE_REQ_PC_TASK_END* missionData = (sP_CL2FE_REQ_PC_TASK_END*)data->buf; + + // failed timed missions give an iNPC_ID of 0 + if (missionData->iNPC_ID == 0) { + TaskData* task = MissionManager::Tasks[missionData->iTaskNum]; + // double-checking + if (task->task["m_iHTaskType"] == 3) { + Player* plr = PlayerManager::getPlayer(sock); + int failTaskID = task->task["m_iFOutgoingTask"]; + if (failTaskID != 0) { + MissionManager::quitTask(sock, missionData->iTaskNum, false); + + for (int i = 0; i < 6; i++) + if (plr->tasks[i] == missionData->iTaskNum) + plr->tasks[i] = failTaskID; + return; + } + } + } + INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response); response.iTaskNum = missionData->iTaskNum; diff --git a/src/MobManager.cpp b/src/MobManager.cpp index 4a96a4f..01693ff 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -85,11 +85,12 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) { damage.first = plr->pointDamage; 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); - - if (plr->batteryW >= 11 + difficulty) - plr->batteryW -= 11 + difficulty; + damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW > 6 + difficulty), NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty); + + if (plr->batteryW >= 6 + difficulty) + plr->batteryW -= 6 + difficulty; + else + plr->batteryW = 0; damage.first = hitMob(sock, mob, damage.first); @@ -126,7 +127,7 @@ void MobManager::npcAttackPc(Mob *mob, time_t currTime) { sP_FE2CL_NPC_ATTACK_PCs *pkt = (sP_FE2CL_NPC_ATTACK_PCs*)respbuf; sAttackResult *atk = (sAttackResult*)(respbuf + sizeof(sP_FE2CL_NPC_ATTACK_PCs)); - auto damage = getDamage(475 + (int)mob->data["m_iPower"], plr->defense, false, false, -1, -1, 1); + auto damage = getDamage(450 + (int)mob->data["m_iPower"], plr->defense, false, false, -1, -1, rand() % plr->level + 1); plr->HP -= damage.first; pkt->iNPC_ID = mob->appearanceData.iNPC_ID; @@ -329,16 +330,16 @@ int MobManager::hitMob(CNSocket *sock, Mob *mob, int damage) { mob->appearanceData.iHP -= damage; - // wake up sleeping monster - if (mob->appearanceData.iConditionBitFlag & CSB_BIT_MEZ) { - mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ; + // wake up sleeping monster + if (mob->appearanceData.iConditionBitFlag & CSB_BIT_MEZ) { + mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ; - INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1); - pkt1.eCT = 2; - pkt1.iID = mob->appearanceData.iNPC_ID; - pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag; - NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT)); - } + INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1); + pkt1.eCT = 2; + pkt1.iID = mob->appearanceData.iNPC_ID; + pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT)); + } if (mob->appearanceData.iHP <= 0) killMob(mob->target, mob); @@ -492,7 +493,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) { // movement logic if (mob->nextMovement != 0 && currTime < mob->nextMovement) return; - mob->nextMovement = currTime + 399; + mob->nextMovement = currTime + 400; if (currTime >= mob->nextAttack) mob->nextAttack = 0; @@ -598,7 +599,7 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) { if (mob->nextMovement != 0 && currTime < mob->nextMovement) return; - mob->nextMovement = currTime + 399; + mob->nextMovement = currTime + 400; // distance between spawn point and current location int distance = hypot(mob->appearanceData.iX - mob->roamX, mob->appearanceData.iY - mob->roamY); @@ -611,11 +612,9 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) { pkt.iNPC_ID = mob->appearanceData.iNPC_ID; pkt.iSpeed = (int)mob->data["m_iRunSpeed"] * 2; - mob->appearanceData.iX = targ.first; - mob->appearanceData.iY = targ.second; pkt.iToX = mob->appearanceData.iX = targ.first; pkt.iToY = mob->appearanceData.iY = targ.second; - pkt.iToZ = mob->appearanceData.iZ; + pkt.iToZ = mob->appearanceData.iZ = mob->spawnZ; // notify all nearby players NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE)); @@ -629,12 +628,15 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) { mob->killedTime = 0; mob->nextAttack = 0; mob->appearanceData.iConditionBitFlag = 0; - - resendMobHP(mob); + + // HACK: we haven't found a better way to refresh a mob's client-side status + drainMobHP(mob, 0); } } void MobManager::step(CNServer *serv, time_t currTime) { + static time_t lastDrainTime = 0; + for (auto& pair : Mobs) { int x = pair.second->appearanceData.iX; int y = pair.second->appearanceData.iY; @@ -644,9 +646,8 @@ void MobManager::step(CNServer *serv, time_t currTime) { continue; // drain - if (pair.second->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) { - pair.second->appearanceData.iHP -= pair.second->maxHealth / 50; // lose 10% every second - // TODO: Make this send a damage packet + if (currTime - lastDrainTime >= 600 && pair.second->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) { + drainMobHP(pair.second, pair.second->maxHealth * 3 / 50); // lose 10% every second } // unbuffing @@ -692,6 +693,9 @@ void MobManager::step(CNServer *serv, time_t currTime) { break; } } + + if (currTime - lastDrainTime >= 600) + lastDrainTime = currTime; // deallocate all NPCs queued for removal while (RemovalQueue.size() > 0) { @@ -752,8 +756,10 @@ void MobManager::combatBegin(CNSocket *sock, CNPacketData *data) { void MobManager::combatEnd(CNSocket *sock, CNPacketData *data) { Player *plr = PlayerManager::getPlayer(sock); - if (plr != nullptr) + if (plr != nullptr) { plr->inCombat = false; + plr->healCooldown = 4000; + } } void MobManager::dotDamageOnOff(CNSocket *sock, CNPacketData *data) { @@ -848,11 +854,14 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) { dealGooDamage(sock, PC_MAXHEALTH(plr->level) * 3 / 20); // heal - if (currTime - lastHealTime >= 6000 && !plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) { - plr->HP += PC_MAXHEALTH(plr->level) / 5; - if (plr->HP > PC_MAXHEALTH(plr->level)) - plr->HP = PC_MAXHEALTH(plr->level); - transmit = true; + if (currTime - lastHealTime >= 4000 && !plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) { + if (currTime - lastHealTime - plr->healCooldown >= 4000) { + plr->HP += PC_MAXHEALTH(plr->level) / 5; + if (plr->HP > PC_MAXHEALTH(plr->level)) + plr->HP = PC_MAXHEALTH(plr->level); + transmit = true; + } else + plr->healCooldown -= 4000; } for (int i = 0; i < 3; i++) { @@ -894,7 +903,7 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) { } // if this was a heal tick, update the counter outside of the loop - if (currTime - lastHealTime >= 6000) + if (currTime - lastHealTime >= 4000) lastHealTime = currTime; } @@ -907,15 +916,15 @@ std::pair MobManager::getDamage(int attackPower, int defensePower, bool // base calculation int damage = attackPower * attackPower / (attackPower + defensePower); - damage = std::max(std::max(29, attackPower / 7), damage - defensePower * (12 + difficulty) / 65); + damage = std::max(10 + attackPower / 10, damage - defensePower * (4 + difficulty) / 40); damage = damage * (rand() % 40 + 80) / 100; // Adaptium/Blastons/Cosmix if (attackerStyle != -1 && defenderStyle != -1 && attackerStyle != defenderStyle) { - if (attackerStyle < defenderStyle || attackerStyle - defenderStyle == 2) - damage = damage * 5 / 4; + if (attackerStyle < defenderStyle || attackerStyle - defenderStyle == 2) + damage = damage * 3 / 2; else - damage = damage * 4 / 5; + damage = damage * 2 / 3; } // weapon boosts @@ -988,10 +997,12 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) { else damage.first = plr->pointDamage; - damage = getDamage(damage.first, target->defense, true, (plr->batteryW >= 12), -1, -1, 1); + damage = getDamage(damage.first, target->defense, true, (plr->batteryW > 6 + plr->level), -1, -1, 1); - if (plr->batteryW >= 12) - plr->batteryW -= 12; + if (plr->batteryW >= 6 + plr->level) + plr->batteryW -= 6 + plr->level; + else + plr->batteryW = 0; target->HP -= damage.first; @@ -1017,11 +1028,13 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) { int difficulty = (int)mob->data["m_iNpcLevel"]; - damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW >= 11 + difficulty), + damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW > 6 + difficulty), NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty); - if (plr->batteryW >= 11 + difficulty) - plr->batteryW -= 11 + difficulty; + if (plr->batteryW >= 6 + difficulty) + plr->batteryW -= 6 + difficulty; + else + plr->batteryW = 0; damage.first = hitMob(sock, mob, damage.first); @@ -1045,25 +1058,24 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) { PlayerManager::sendToViewable(sock, (void*)respbuf, P_FE2CL_PC_ATTACK_CHARs, resplen); } -// HACK: we haven't found a better way to refresh a mob's client-side status -void MobManager::resendMobHP(Mob *mob) { - size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_Heal_HP); +void MobManager::drainMobHP(Mob *mob, int amount) { + size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_Damage); assert(resplen < CN_PACKET_BUFFER_SIZE - 8); uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; memset(respbuf, 0, resplen); sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf; - sSkillResult_Heal_HP *heal = (sSkillResult_Heal_HP*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK)); + sSkillResult_Damage *drain = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK)); pkt->iID = mob->appearanceData.iNPC_ID; pkt->eCT = 4; // mob - pkt->iTB_ID = ECSB_HEAL; // sSkillResult_Heal_HP + pkt->iTB_ID = ECSB_BOUNDINGBALL; - heal->eCT = 4; - heal->iID = mob->appearanceData.iNPC_ID; - heal->iHealHP = 0; - heal->iHP = mob->appearanceData.iHP; + drain->eCT = 4; + drain->iID = mob->appearanceData.iNPC_ID; + drain->iDamage = amount; + drain->iHP = mob->appearanceData.iHP -= amount; NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen); } diff --git a/src/MobManager.hpp b/src/MobManager.hpp index 73682e2..cf11c67 100644 --- a/src/MobManager.hpp +++ b/src/MobManager.hpp @@ -139,7 +139,7 @@ namespace MobManager { std::pair getDamage(int, int, bool, bool, int, int, int); void pcAttackChars(CNSocket *sock, CNPacketData *data); - void resendMobHP(Mob *mob); + void drainMobHP(Mob *mob, int amount); void incNextMovement(Mob *mob, time_t currTime=0); bool aggroCheck(Mob *mob, time_t currTime); } diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index ed854f8..d8ab954 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -608,13 +608,6 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) { if (otherPlr == nullptr || sockTo == nullptr) continue; - if (otherPlr->instanceID == 0) { - otherPlr->lastX = otherPlr->x; - otherPlr->lastY = otherPlr->y; - otherPlr->lastZ = otherPlr->z; - otherPlr->lastAngle = otherPlr->angle; - } - PlayerManager::sendPlayerTo(sockTo, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID); } } diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index f661e6d..8ff9bb4 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -672,8 +672,8 @@ void activePower(CNSocket *sock, CNPacketData *data, // active nano power dispatch table std::vector ActivePowers = { ActivePower(StunPowers, activePower, EST_STUN, CSB_BIT_STUN, 2250), - ActivePower(HealPowers, activePower, EST_HEAL_HP, CSB_BIT_NONE, 25), - ActivePower(GroupHealPowers, activePower,EST_HEAL_HP, CSB_BIT_NONE, 15), + ActivePower(HealPowers, activePower, EST_HEAL_HP, CSB_BIT_NONE, 35), + ActivePower(GroupHealPowers, activePower,EST_HEAL_HP, CSB_BIT_NONE, 20), // TODO: Recall ActivePower(DrainPowers, activePower, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 3000), ActivePower(SnarePowers, activePower, EST_SNARE, CSB_BIT_DN_MOVE_SPEED, 4500), diff --git a/src/Player.hpp b/src/Player.hpp index e90dbef..b60d73e 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -50,6 +50,7 @@ struct Player { bool inCombat; bool passiveNanoOut; + int healCooldown; int pointDamage; int groupDamage; diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index ffcb8a8..fa6b375 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -280,7 +280,6 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z) { plrv.currentChunks.clear(); plrv.chunkPos = std::make_tuple(0, 0, plrv.plr->instanceID); sock->sendPacket((void*)&pkt, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC)); - updatePlayerPosition(sock, X, Y, Z); } void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {