diff --git a/src/Abilities.cpp b/src/Abilities.cpp index a3b3f86..bed931b 100644 --- a/src/Abilities.cpp +++ b/src/Abilities.cpp @@ -127,6 +127,7 @@ static SkillResult handleSkillBuff(SkillData* skill, int power, ICombatant* sour ICombatant* combatant = dynamic_cast(self.getEntity()); combatant->takeDamage(buff->getLastSource(), 0); // aggro } + Buffs::timeBuffUpdate(self, buff, status, stack); if(drainType == SkillDrainType::ACTIVE && status == ETBU_DEL) Buffs::timeBuffTimeout(self); }, @@ -150,19 +151,24 @@ static SkillResult handleSkillBatteryDrain(SkillData* skill, int power, ICombata Player* plr = dynamic_cast(target); const double scalingFactor = (18 + source->getLevel()) / 36.0; + const bool blocked = target->hasBuff(ECSB_PROTECT_BATTERY); - int boostDrain = (int)(skill->values[0][power] * scalingFactor); - if(boostDrain > plr->batteryW) boostDrain = plr->batteryW; - plr->batteryW -= boostDrain; + int boostDrain = 0; + int potionDrain = 0; + if(!blocked) { + boostDrain = (int)(skill->values[0][power] * scalingFactor); + if(boostDrain > plr->batteryW) boostDrain = plr->batteryW; + plr->batteryW -= boostDrain; - int potionDrain = (int)(skill->values[1][power] * scalingFactor); - if(potionDrain > plr->batteryN) potionDrain = plr->batteryN; - plr->batteryN -= potionDrain; + potionDrain = (int)(skill->values[1][power] * scalingFactor); + if(potionDrain > plr->batteryN) potionDrain = plr->batteryN; + plr->batteryN -= potionDrain; + } sSkillResult_BatteryDrain result{}; result.eCT = target->getCharType(); result.iID = target->getID(); - result.bProtected = target->hasBuff(ECSB_PROTECT_BATTERY); + result.bProtected = blocked; result.iDrainW = boostDrain; result.iBatteryW = plr->batteryW; result.iDrainN = potionDrain; @@ -209,6 +215,11 @@ static std::vector handleSkill(SkillData* skill, int power, ICombat switch(skill->skillType) { + case SkillType::CORRUPTIONATTACK: + case SkillType::CORRUPTIONATTACKLOSE: + case SkillType::CORRUPTIONATTACKWIN: + // skillHandler = handleSkillCorruptionReflect; + // break; case SkillType::DAMAGE: skillHandler = handleSkillDamage; break; diff --git a/src/Eggs.cpp b/src/Eggs.cpp index 04e276d..73f22f6 100644 --- a/src/Eggs.cpp +++ b/src/Eggs.cpp @@ -26,6 +26,7 @@ void Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) { return; } + SkillResult result = SkillResult(); SkillData* skill = &Abilities::SkillTable[skillId]; if(skill->drainType == SkillDrainType::PASSIVE) { // apply buff @@ -50,12 +51,57 @@ void Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) { // no-op }, &eggBuff); + + sSkillResult_Buff resultBuff{}; + resultBuff.eCT = plr->getCharType(); + resultBuff.iID = plr->getID(); + resultBuff.bProtected = false; + resultBuff.iConditionBitFlag = plr->getCompositeCondition(); + result = SkillResult(sizeof(sSkillResult_Buff), &resultBuff); + } else { + int value = plr->getMaxHP() * skill->values[0][0] / 1000; + sSkillResult_Damage resultDamage{}; + sSkillResult_Heal_HP resultHeal{}; + switch(skill->skillType) + { + case SkillType::DAMAGE: + resultDamage.bProtected = false; + resultDamage.eCT = plr->getCharType(); + resultDamage.iID = plr->getID(); + resultDamage.iDamage = plr->takeDamage(src, value); + resultDamage.iHP = plr->getCurrentHP(); + result = SkillResult(sizeof(sSkillResult_Damage), &resultDamage); + break; + case SkillType::HEAL_HP: + resultHeal.eCT = plr->getCharType(); + resultHeal.iID = plr->getID(); + resultHeal.iHealHP = plr->heal(src, value); + resultHeal.iHP = plr->getCurrentHP(); + result = SkillResult(sizeof(sSkillResult_Heal_HP), &resultHeal); + break; + default: + std::cout << "[WARN] oops, egg with active skill type " << (int)skill->skillType << " unhandled"; + return; + } } - // use skill - std::vector targets; - targets.push_back(dynamic_cast(plr)); - Abilities::useNPCSkill(src, skillId, targets); + // initialize response struct + size_t resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + result.size; + uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; + memset(respbuf, 0, resplen); + + sP_FE2CL_NPC_SKILL_HIT* pkt = (sP_FE2CL_NPC_SKILL_HIT*)respbuf; + pkt->iNPC_ID = eggId; + pkt->iSkillID = skillId; + pkt->eST = (int32_t)skill->skillType; + pkt->iTargetCnt = 1; + + if(result.size > 0) { + void* attached = (void*)(pkt + 1); + memcpy(attached, result.payload, result.size); + } + + NPCManager::sendToViewable(src.getEntity(), pkt, P_FE2CL_NPC_SKILL_HIT, resplen); } static void eggStep(CNServer* serv, time_t currTime) { diff --git a/src/MobAI.cpp b/src/MobAI.cpp index 1d5b8f2..ae29a20 100644 --- a/src/MobAI.cpp +++ b/src/MobAI.cpp @@ -227,7 +227,7 @@ bool MobAI::aggroCheck(Mob *mob, time_t currTime) { return false; } -static void dealCorruption(Mob *mob, std::vector targetData, int skillID, int style) { +static void dealCorruption(Mob *mob, std::vector targetData, int skillID, int mobStyle) { Player *plr = PlayerManager::getPlayer(mob->target); size_t resplen = sizeof(sP_FE2CL_NPC_SKILL_CORRUPTION_HIT) + targetData[0] * sizeof(sCAttackResult); @@ -246,7 +246,7 @@ static void dealCorruption(Mob *mob, std::vector targetData, int skillID, i resp->iNPC_ID = mob->id; resp->iSkillID = skillID; - resp->iStyle = style; + resp->iStyle = mobStyle; resp->iValue1 = plr->x; resp->iValue2 = plr->y; resp->iValue3 = plr->z; @@ -280,27 +280,37 @@ static void dealCorruption(Mob *mob, std::vector targetData, int skillID, i respdata[i].iActiveNanoSlotNum = n; respdata[i].iNanoID = plr->activeNano; - int style2 = Nanos::nanoStyle(plr->activeNano); - if (style2 == -1) { // no nano + int nanoStyle = Nanos::nanoStyle(plr->activeNano); + if (nanoStyle == -1) { // no nano respdata[i].iHitFlag = HF_BIT_STYLE_TIE; respdata[i].iDamage = Abilities::SkillTable[skillID].values[0][0] * PC_MAXHEALTH((int)mob->data["m_iNpcLevel"]) / 1500; - } else if (style == style2) { + } else if (mobStyle == nanoStyle) { respdata[i].iHitFlag = HF_BIT_STYLE_TIE; respdata[i].iDamage = 0; respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina; - } else if (style - style2 == 1 || style2 - style == 2) { + } else if (mobStyle - nanoStyle == 1 || nanoStyle - mobStyle == 2) { respdata[i].iHitFlag = HF_BIT_STYLE_WIN; respdata[i].iDamage = 0; respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina += 45; if (plr->Nanos[plr->activeNano].iStamina > 150) respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina = 150; // fire damage power disguised as a corruption attack back at the enemy - SkillData skill = Abilities::SkillTable[skillID]; - skill.durationTime[0] = 0; - skill.values[0][0] = 200; // have to set - skill.values[0][1] = 200; // all of these - skill.values[0][2] = 200; // because the player might - skill.values[0][3] = 200; // have a boost + SkillData skill = { + SkillType::DAMAGE, // skillType + SkillEffectTarget::POINT, // effectTarget + 1, // effectType + SkillTargetType::MOBS, // targetType + SkillDrainType::ACTIVE, // drainType + 0, // effectArea + {0, 0, 0, 0}, // batteryUse + {0, 0, 0, 0}, // durationTime + {0, 0, 0}, // valueTypes (unused) + { + {200, 200, 200, 200}, + {200, 200, 200, 200}, + {200, 200, 200, 200}, + } + }; Abilities::useNanoSkill(sock, &skill, *plr->getActiveNano(), { mob }); } else { respdata[i].iHitFlag = HF_BIT_STYLE_LOSE;