Various bugfixes and adjustments

* Nano missions should now stop repeating.
* Bitwise operators are now used to handle buff/debuff bitfields.
* Changing nano powers will no longer grant you infinite buffs.
* Mobs now heal up client-side after retreating, this comes with candy effect being played however.
* Lower level mobs now hit harder.
* Nanos drain stamina quicker when they grant passive powers.
* Healing, damage and leech powers scale up with your level.
* Player on player damage now accounts for damage and armor.
This commit is contained in:
2020-09-29 22:27:48 +01:00
parent 3f35d2e960
commit ab990116a2
5 changed files with 96 additions and 45 deletions

View File

@@ -114,7 +114,7 @@ void MobManager::npcAttackPc(Mob *mob) {
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(440 + (int)mob->data["m_iPower"], plr->defense, false, 36 - (int)mob->data["m_iNpcLevel"]);
auto damage = getDamage(470 + (int)mob->data["m_iPower"], plr->defense, false, 1);
plr->HP -= damage.first;
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
@@ -443,6 +443,11 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
mob->killedTime = 0;
mob->nextAttack = 0;
mob->appearanceData.iConditionBitFlag = 0;
//INITSTRUCT(sP_FE2CL_NPC_ENTER, enterData);
//enterData.NPCAppearanceData = mob->appearanceData;
//NPCManager::sendToViewable(mob, &enterData, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER));
resendMobHP(mob);
}
}
@@ -489,19 +494,21 @@ void MobManager::step(CNServer *serv, time_t currTime) {
* 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 = {};
std::pair<int,int> ret = {x1, y1};
speed /= 2;
if (speed == 0)
return ret;
int distance = hypot(x1 - x2, y1 - y2);
if (distance > speed) {
if (speed == 0)
speed = 1;
int lerps = distance / speed;
// interpolate only the first point
float frac = 1.0f / (lerps);
float frac = 1.0f / lerps;
ret.first = (x1 + (x2 - x1) * frac);
ret.second = (y1 + (y2 - y1) * frac);
@@ -579,15 +586,11 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) {
// fm patch/lake damage
if (plr->dotDamage)
dealGooDamage(sock, 150);
// a somewhat hacky way tick goo damage faster than heal, but eh
if (currTime - lastHealTime < 4000)
continue;
dealGooDamage(sock, PC_MAXHEALTH(plr->level) * 3 / 20);
// heal
if (!plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) {
plr->HP += 200;
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;
@@ -595,7 +598,10 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) {
for (int i = 0; i < 3; i++) {
if (plr->activeNano != 0 && plr->equippedNanos[i] == plr->activeNano) { // spend stamina
plr->Nanos[plr->activeNano].iStamina -= 3;
plr->Nanos[plr->activeNano].iStamina -= 1;
if (plr->passiveNanoOut)
plr->Nanos[plr->activeNano].iStamina -= 1;
if (plr->Nanos[plr->activeNano].iStamina < 0)
plr->activeNano = 0;
@@ -603,7 +609,7 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) {
transmit = true;
} else if (plr->Nanos[plr->equippedNanos[i]].iStamina < 150) { // regain stamina
sNano& nano = plr->Nanos[plr->equippedNanos[i]];
nano.iStamina += 3;
nano.iStamina += 1;
if (nano.iStamina > 150)
nano.iStamina = 150;
@@ -627,7 +633,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 < 4000)
if (currTime - lastHealTime >= 6000)
lastHealTime = currTime;
}
@@ -694,14 +700,21 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
std::cout << "[WARN] pcAttackChars: player ID not found" << std::endl;
return;
}
std::pair<int,int> damage;
if (pkt->iTargetCnt > 1)
damage = getDamage(plr->groupDamage, target->defense, true, 1);
else
damage = getDamage(plr->pointDamage, target->defense, true, 1);
target->HP -= 700;
target->HP -= damage.first;
respdata[i].eCT = pktdata[i*2+1];
respdata[i].iID = target->iID;
respdata[i].iDamage = 700;
respdata[i].iDamage = damage.first;
respdata[i].iHP = target->HP;
respdata[i].iHitFlag = 2; // hitscan, not a rocket or a grenade
respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade
} else { // eCT == 4; attack mob
if (Mobs.find(pktdata[i*2]) == Mobs.end()) {
// not sure how to best handle this
@@ -738,3 +751,25 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
// send to other players
PlayerManager::sendToViewable(sock, (void*)respbuf, P_FE2CL_PC_ATTACK_CHARs, resplen);
}
void MobManager::resendMobHP(Mob *mob) {
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));
pkt->iID = mob->appearanceData.iNPC_ID;
pkt->eCT = 4; // mob
pkt->iTB_ID = ECSB_HEAL; // sSkillResult_Heal_HP
heal->eCT = 4;
heal->iID = mob->appearanceData.iNPC_ID;
heal->iHealHP = 0;
heal->iHP = mob->appearanceData.iHP;
NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
}