diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 85c73ba..377ed2e 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -146,7 +146,7 @@ void GroupManager::joinGroup(CNSocket* sock, CNPacketData* data) { respdata[i].iZ = varPlr->z; // client doesnt read nano data here - if (varPlr != plr) { + if (varPlr != plr) { // apply the new member's buffs to the group and the group's buffs to the new member NanoManager::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 1, 1, bitFlag); NanoManager::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 1, 1, bitFlag); } @@ -340,7 +340,7 @@ void GroupManager::groupKickPlayer(Player* plr) { if (varPlr == plr) { moveDown = 1; otherPlr->groupIDs[i] = 0; - } else { + } else { // remove the leaving member's buffs from the group and remove the group buffs from the leaving member. NanoManager::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 2, 1, 0); NanoManager::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 2, 1, bitFlag); } @@ -360,7 +360,7 @@ void GroupManager::groupUnbuff(Player* plr) { for (int n = 0; n < plr->groupCnt; n++) { if (i == n) continue; - + Player* otherPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]); CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[n]); diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index 6235ad2..6ca70d8 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -266,7 +266,7 @@ void ItemManager::itemUseHandler(CNSocket* sock, CNPacketData* data) { size_t resplen = sizeof(sP_FE2CL_REP_PC_ITEM_USE_SUCC) + sizeof(sSkillResult_Buff); - // validate response packet + // validate response packet if (!validOutVarPacket(sizeof(sP_FE2CL_REP_PC_ITEM_USE_SUCC), 1, sizeof(sSkillResult_Buff))) { std::cout << "[WARN] bad sP_FE2CL_REP_PC_ITEM_USE_SUCC packet size" << std::endl; return; diff --git a/src/MissionManager.cpp b/src/MissionManager.cpp index 2e1147f..d916101 100644 --- a/src/MissionManager.cpp +++ b/src/MissionManager.cpp @@ -396,7 +396,20 @@ int MissionManager::giveMissionReward(CNSocket *sock, int task) { // update player plr->money += reward->money; - updateFusionMatter(sock, reward->fusionmatter); + if (plr->iConditionBitFlag & CSB_BIT_REWARD_CASH) { // nano boost for taros + int boost = 0; + if (NanoManager::getNanoBoost(plr)) + boost = 1; + plr->money += reward->money * (5 + boost) / 25; + } + + if (plr->iConditionBitFlag & CSB_BIT_REWARD_BLOB) { // nano boost for fm + int boost = 0; + if (NanoManager::getNanoBoost(plr)) + boost = 1; + updateFusionMatter(sock, reward->fusionmatter * (30 + boost) / 25); + } else + updateFusionMatter(sock, reward->fusionmatter); // simple rewards resp->m_iCandy = plr->money; diff --git a/src/MobManager.cpp b/src/MobManager.cpp index 8a6f592..a5f4757 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -181,12 +181,26 @@ void MobManager::giveReward(CNSocket *sock, Mob* mob) { MobDrop& drop = MobDrops[mob->dropType]; plr->money += drop.taros; + // money nano boost + if (plr->iConditionBitFlag & CSB_BIT_REWARD_CASH) { + int boost = 0; + if (NanoManager::getNanoBoost(plr)) // for gumballs + boost = 1; + plr->money += drop.taros * (5 + boost) / 25; + } // formula for scaling FM with player/mob level difference // TODO: adjust this better int levelDifference = plr->level - mob->level; int fm = drop.fm; if (levelDifference > 0) fm = levelDifference < 10 ? fm - (levelDifference * fm / 10) : 0; + // scavenger nano boost + if (plr->iConditionBitFlag & CSB_BIT_REWARD_BLOB) { + int boost = 0; + if (NanoManager::getNanoBoost(plr)) // for gumballs + boost = 1; + fm += fm * (5 + boost) / 25; + } MissionManager::updateFusionMatter(sock, fm); @@ -870,8 +884,8 @@ void MobManager::dealGooDamage(CNSocket *sock, int amount) { amount = -2; // -2 is the magic number for "Protected" to appear as the damage number dmg->bProtected = 1; - // it's hypothetically possible to have the protection bit without a nano - if (plr->activeNano != -1) + // eggs allow protection without nanos + if (plr->activeNano != -1 && (plr->iSelfConditionBitFlag & CSB_BIT_PROTECT_INFECTION)) plr->Nanos[plr->activeNano].iStamina -= 3; } else { plr->HP -= amount; diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index 527f842..befa9cb 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -582,6 +582,56 @@ int NPCManager::eggBuffPlayer(CNSocket* sock, int skillId, int eggId) { int bitFlag = GroupManager::getGroupFlags(otherPlr); CBFlag = NanoManager::applyBuff(sock, skillId, 1, 3, bitFlag); + + size_t resplen; + + if (skillId == 183) { + resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Damage); + } else if (skillId == 147) { + resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Heal_HP); + } else + sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Buff); + + assert(resplen < CN_PACKET_BUFFER_SIZE - 8); + // we know it's only one trailing struct, so we can skip full validation + + uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; + sP_FE2CL_NPC_SKILL_HIT* skillUse = (sP_FE2CL_NPC_SKILL_HIT*)respbuf; + + if (skillId == 183) { // damage egg + sSkillResult_Damage* skill = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT)); + memset(respbuf, 0, resplen); + skill->eCT = 1; + skill->iID = plr->iID; + skill->iDamage = PC_MAXHEALTH(plr->level) * NanoManager::SkillTable[skillId].powerIntensity[0] / 1000; + plr->HP -= skill->iDamage; + skill->iHP = plr->HP; + } else if (skillId == 147) { // heal egg + sSkillResult_Heal_HP* skill = (sSkillResult_Heal_HP*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT)); + memset(respbuf, 0, resplen); + skill->eCT = 1; + skill->iID = plr->iID; + skill->iHealHP = PC_MAXHEALTH(plr->level) * NanoManager::SkillTable[skillId].powerIntensity[0] / 1000; + plr->HP += skill->iHealHP; + if (plr->HP > PC_MAXHEALTH(plr->level)) + plr->HP = PC_MAXHEALTH(plr->level); + skill->iHP = plr->HP; + } else { // regular buff egg + sSkillResult_Buff* skill = (sSkillResult_Buff*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT)); + memset(respbuf, 0, resplen); + skill->eCT = 1; + skill->iID = plr->iID; + skill->iConditionBitFlag = plr->iConditionBitFlag; + } + + skillUse->iNPC_ID = eggId; + skillUse->iSkillID = skillId; + skillUse->eST = NanoManager::SkillTable[skillId].skillType; + skillUse->iTargetCnt = 1; + + sock->sendPacket((void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen); + PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen); + if (CBFlag == 0) return -1; @@ -589,33 +639,9 @@ int NPCManager::eggBuffPlayer(CNSocket* sock, int skillId, int eggId) { // save the buff serverside; // if you get the same buff again, new duration will override the previous one - time_t until = getTime() + (time_t)NanoManager::SkillTable[skillId].durationTime[0] * 10; + time_t until = getTime() + (time_t)NanoManager::SkillTable[skillId].durationTime[0] * 25; EggBuffs[key] = until; - const size_t resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Buff); - assert(resplen < CN_PACKET_BUFFER_SIZE - 8); - // we know it's only one trailing struct, so we can skip full validation - - uint8_t respbuf[resplen]; // not a variable length array, don't worry - sP_FE2CL_NPC_SKILL_HIT* skillUse = (sP_FE2CL_NPC_SKILL_HIT*)respbuf; - sSkillResult_Buff* skill = (sSkillResult_Buff*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT)); - - memset(respbuf, 0, resplen); - skillUse->iNPC_ID = eggId; - skillUse->iSkillID = skillId; - if (skillId == 183) // The only exception - skillUse->eST = EST_INFECTIONDAMAGE; - else - skillUse->eST = NanoManager::SkillTable[skillId].skillType; - skillUse->iTargetCnt = 1; - - skill->eCT = 1; - skill->iID = plr->iID; - skill->iConditionBitFlag = plr->iConditionBitFlag; - - sock->sendPacket((void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen); - PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen); - return 0; } @@ -640,7 +666,7 @@ void NPCManager::eggStep(CNServer* serv, time_t currTime) { int groupFlags = GroupManager::getGroupFlags(otherPlr); for (auto& pwr : NanoManager::NanoPowers) { - if (pwr.bitFlag == CBFlag) { + if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp); resp.eCSTB = pwr.timeBuffID; resp.eTBU = 2; @@ -720,57 +746,6 @@ void NPCManager::eggPickup(CNSocket* sock, CNPacketData* data) { if (type->effectId != 0) eggBuffPlayer(sock, type->effectId, eggId); - // damage egg - if (type->effectId == 183) { - 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_Damage* dmg = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK)); - - dmg->iDamage = PC_MAXHEALTH(plr->level) * 73 / 100; - - plr->HP -= dmg->iDamage; - - pkt->iID = plr->iID; - pkt->eCT = 1; // player - pkt->iTB_ID = 19; - dmg->iHP = plr->HP; - - sock->sendPacket((void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen); - PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen); - } - // heal egg - else if (type->effectId == 150) { - size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_Heal_HP); - 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)); - - heal->iHealHP = PC_MAXHEALTH(plr->level) * 35 / 100; - plr->HP += heal->iHealHP; - if (plr->HP > PC_MAXHEALTH(plr->level)) - plr->HP = PC_MAXHEALTH(plr->level); - - heal->iHP = plr->HP; - heal->iID = plr->iID; - heal->eCT = 1; - - pkt->iID = plr->iID; - pkt->eCT = 1; // player - pkt->iTB_ID = ECSB_HEAL; - - sock->sendPacket((void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen); - PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen); - } - /* * SHINY_PICKUP_SUCC is only causing a GUI effect in the client * (buff icon pops up in the bottom of the screen) diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 5287f9d..b9475cc 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -33,7 +33,7 @@ void NanoManager::nanoEquipHandler(CNSocket* sock, CNPacketData* data) { Player *plr = PlayerManager::getPlayer(sock); // sanity checks - if (plr == nullptr || nano->iNanoSlotNum > 2 || nano->iNanoSlotNum < 0 || nano->iNanoID > 36) + if (plr == nullptr || nano->iNanoSlotNum > 2 || nano->iNanoSlotNum < 0) return; resp.iNanoID = nano->iNanoID; @@ -138,10 +138,8 @@ void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { int *targetData = findTargets(plr, skillID, data); int boost = 0; - for (int i = 0; i < 3; i++) - if (plr->equippedNanos[i] == plr->activeNano) - if (plr->iConditionBitFlag & (CSB_BIT_STIMPAKSLOT1 << i)) - boost = 1; + if (getNanoBoost(plr)) + boost = 1; plr->Nanos[plr->activeNano].iStamina -= SkillTable[skillID].batteryUse[boost*3]; if (plr->Nanos[plr->activeNano].iStamina < 0) @@ -323,11 +321,9 @@ void NanoManager::summonNano(CNSocket *sock, int slot) { if (SkillTable[skillID].drainType == 2) { int *targetData = findTargets(plr, skillID); - int boost = 0; - for (int i = 0; i < 3; i++) - if (plr->equippedNanos[i] == plr->activeNano) - if (plr->iConditionBitFlag & (CSB_BIT_STIMPAKSLOT1 << i)) - boost = 1; + int boost = 0; + if (getNanoBoost(plr)) + boost = 1; for (auto& pwr : NanoPowers) { if (pwr.skillType == SkillTable[skillID].skillType) { @@ -547,6 +543,14 @@ int* NanoManager::findTargets(Player* plr, int skillID, CNPacketData* data) { return tD; } + +bool NanoManager::getNanoBoost(Player* plr) { + for (int i = 0; i < 3; i++) + if (plr->equippedNanos[i] == plr->activeNano) + if (plr->iConditionBitFlag & (CSB_BIT_STIMPAKSLOT1 << i)) + return true; + return false; +} #pragma endregion #pragma region Nano Powers @@ -575,7 +579,7 @@ bool doBuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t targetID Player *plr = nullptr; for (auto& pair : PlayerManager::players) { - if (pair.second->iID == pktdata[i]) { + if (pair.second->iID == targetID) { plr = pair.second; break; } @@ -631,7 +635,7 @@ bool doHeal(CNSocket *sock, sSkillResult_Heal_HP *respdata, int i, int32_t targe Player *plr = nullptr; for (auto& pair : PlayerManager::players) { - if (pair.second->iID == pktdata[0]) { + if (pair.second->iID == targetID) { plr = pair.second; break; } @@ -742,8 +746,8 @@ bool doResurrect(CNSocket *sock, sSkillResult_Resurrect *respdata, int i, int32_ Player *plr = nullptr; for (auto& pair : PlayerManager::players) { - if (pair.second.plr->iID == targetID) { - plr = pair.second.plr; + if (pair.second->iID == targetID) { + plr = pair.second; break; } } @@ -765,8 +769,8 @@ bool doMove(CNSocket *sock, sSkillResult_Move *respdata, int i, int32_t targetID Player *plr = nullptr; for (auto& pair : PlayerManager::players) { - if (pair.second.plr->iID == targetID) { - plr = pair.second.plr; + if (pair.second->iID == targetID) { + plr = pair.second; break; } } diff --git a/src/NanoManager.hpp b/src/NanoManager.hpp index 8c93dd4..5aa9942 100644 --- a/src/NanoManager.hpp +++ b/src/NanoManager.hpp @@ -68,4 +68,5 @@ namespace NanoManager { int applyBuff(CNSocket* sock, int skillID, int eTBU, int eTBT, int32_t groupFlags); int nanoStyle(int nanoID); int* findTargets(Player* plr, int skillID, CNPacketData* data = nullptr); + bool getNanoBoost(Player* plr); } diff --git a/src/Player.hpp b/src/Player.hpp index 25d9e0a..91bd3bc 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -73,8 +73,6 @@ struct Player { int32_t groupIDs[4]; int32_t iGroupConditionBitFlag; - int32_t iEggConditionBitFlag; - bool notify; bool buddiesSynced;