mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-12-23 03:40:05 +00:00
Various bugfixes
- Eruption is now blocked by stun and sleep. - Corruption should block all nano abilities. - Buffs time out for other players - Timed mission bugfixes (AGAIN) - Corruption and Eruptions fire quicker. - Heal egg ids fix - No power nanos no longer break the system. - Mobs should no longer restun. - Mob ability chance calculation adjustments. - Duration of the power's debuff is sent as iDamage instead of 0, this removes the ugly "Block" that shows up on successful hits. - Group mob respawning bugfixes - a bit of a cleanup
This commit is contained in:
parent
1474ff10ac
commit
b947ff65cf
@ -106,17 +106,39 @@ void MissionManager::taskEnd(CNSocket* sock, CNPacketData* data) {
|
||||
// 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_iSTGrantTimer"] > 0) {
|
||||
if (task->task["m_iSTGrantTimer"] > 0) { // its a timed mission
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
int failTaskID = task->task["m_iFOutgoingTask"];
|
||||
if (failTaskID != 0) {
|
||||
MissionManager::quitTask(sock, missionData->iTaskNum, false);
|
||||
/*
|
||||
* Enemy killing missions
|
||||
* this is gross and should be cleaned up later
|
||||
* once we comb over mission logic more throughly
|
||||
*/
|
||||
bool mobsAreKilled = false;
|
||||
if (task->task["m_iHTaskType"] == 5) {
|
||||
mobsAreKilled = true;
|
||||
for (int i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||
if (plr->tasks[i] == missionData->iTaskNum) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (plr->RemainingNPCCount[i][j] > 0) {
|
||||
mobsAreKilled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mobsAreKilled) {
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
if (plr->tasks[i] == missionData->iTaskNum)
|
||||
plr->tasks[i] = failTaskID;
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -443,6 +443,11 @@ void MobManager::deadStep(Mob *mob, time_t currTime) {
|
||||
RemovalQueue.push(mob->appearanceData.iNPC_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
// pre-set spawn coordinates if not marked for removal
|
||||
mob->appearanceData.iX = mob->spawnX;
|
||||
mob->appearanceData.iY = mob->spawnY;
|
||||
mob->appearanceData.iZ = mob->spawnZ;
|
||||
}
|
||||
|
||||
// to guide their groupmates, group leaders still need to move despite being dead
|
||||
@ -457,9 +462,8 @@ void MobManager::deadStep(Mob *mob, time_t currTime) {
|
||||
mob->appearanceData.iHP = mob->maxHealth;
|
||||
mob->state = MobState::ROAMING;
|
||||
|
||||
// reset position
|
||||
// if mob is a group leader/follower, spawn where the group is.
|
||||
if (mob->groupLeader != 0) {
|
||||
// mob is a group leader/follower, spawn where the group is.
|
||||
if (Mobs.find(mob->groupLeader) != Mobs.end()) {
|
||||
Mob* leaderMob = Mobs[mob->groupLeader];
|
||||
mob->appearanceData.iX = leaderMob->appearanceData.iX + mob->offsetX;
|
||||
@ -467,14 +471,7 @@ void MobManager::deadStep(Mob *mob, time_t currTime) {
|
||||
mob->appearanceData.iZ = leaderMob->appearanceData.iZ;
|
||||
} else {
|
||||
std::cout << "[WARN] deadStep: mob cannot find it's leader!" << std::endl;
|
||||
mob->appearanceData.iX = mob->spawnX;
|
||||
mob->appearanceData.iY = mob->spawnY;
|
||||
mob->appearanceData.iZ = mob->spawnZ;
|
||||
}
|
||||
} else {
|
||||
mob->appearanceData.iX = mob->spawnX;
|
||||
mob->appearanceData.iY = mob->spawnY;
|
||||
mob->appearanceData.iZ = mob->spawnZ;
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_NPC_NEW, pkt);
|
||||
@ -540,8 +537,10 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
||||
}
|
||||
|
||||
// skip attack if stunned or asleep
|
||||
if (mob->appearanceData.iConditionBitFlag & (CSB_BIT_STUN|CSB_BIT_MEZ))
|
||||
if (mob->appearanceData.iConditionBitFlag & (CSB_BIT_STUN|CSB_BIT_MEZ)) {
|
||||
mob->skillStyle = -1; // in this case we also reset the any outlying abilities the mob might be winding up.
|
||||
return;
|
||||
}
|
||||
|
||||
int distance = hypot(plr->x - mob->appearanceData.iX, plr->y - mob->appearanceData.iY);
|
||||
int mobRange = (int)mob->data["m_iAtkRange"] + (int)mob->data["m_iRadius"];
|
||||
@ -751,16 +750,11 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
||||
|
||||
void MobManager::step(CNServer *serv, time_t currTime) {
|
||||
for (auto& pair : Mobs) {
|
||||
|
||||
// skip chunks without players
|
||||
if (pair.second->playersInView == 0) //(!ChunkManager::inPopulatedChunks(pair.second->viewableChunks))
|
||||
continue;
|
||||
|
||||
if (pair.second->playersInView < 0)
|
||||
std::cout << "[WARN] Weird playerview value " << pair.second->playersInView << std::endl;
|
||||
|
||||
// skip mob movement and combat if disabled
|
||||
if (!simulateMobs && pair.second->state != MobState::DEAD
|
||||
// skip mob movement and combat if disabled or not in view
|
||||
if ((!simulateMobs || pair.second->playersInView == 0) && pair.second->state != MobState::DEAD
|
||||
&& pair.second->state != MobState::RETREAT)
|
||||
continue;
|
||||
|
||||
@ -1409,7 +1403,7 @@ void MobManager::followToCombat(Mob *mob) {
|
||||
}
|
||||
Mob* followerMob = Mobs[leadMob->groupMember[i]];
|
||||
|
||||
if (followerMob->state == MobState::COMBAT)
|
||||
if (followerMob->state != MobState::ROAMING) // only roaming mobs should transition to combat
|
||||
continue;
|
||||
|
||||
followerMob->target = mob->target;
|
||||
@ -1421,6 +1415,10 @@ void MobManager::followToCombat(Mob *mob) {
|
||||
followerMob->roamY = followerMob->appearanceData.iY;
|
||||
followerMob->roamZ = followerMob->appearanceData.iZ;
|
||||
}
|
||||
|
||||
if (leadMob->state != MobState::ROAMING)
|
||||
return;
|
||||
|
||||
leadMob->target = mob->target;
|
||||
leadMob->state = MobState::COMBAT;
|
||||
leadMob->nextMovement = getTime();
|
||||
@ -1433,6 +1431,12 @@ void MobManager::followToCombat(Mob *mob) {
|
||||
}
|
||||
|
||||
void MobManager::useAbilities(Mob *mob, time_t currTime) {
|
||||
/*
|
||||
* targetData approach
|
||||
* first integer is the count
|
||||
* second to fifth integers are IDs, these can be either player iID or mob's iID
|
||||
* whether the skill targets players or mobs is determined by the skill packet being fired
|
||||
*/
|
||||
Player *plr = PlayerManager::getPlayer(mob->target);
|
||||
|
||||
if (mob->skillStyle >= 0) { // corruption hit
|
||||
@ -1481,7 +1485,7 @@ void MobManager::useAbilities(Mob *mob, time_t currTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
int random = rand() % 100 * 15000;
|
||||
int random = rand() % 2000 * 1000;
|
||||
int prob1 = (int)mob->data["m_iActiveSkill1Prob"]; // active skill probability
|
||||
int prob2 = (int)mob->data["m_iCorruptionTypeProb"]; // corruption probability
|
||||
int prob3 = (int)mob->data["m_iMegaTypeProb"]; // eruption probability
|
||||
@ -1490,8 +1494,11 @@ void MobManager::useAbilities(Mob *mob, time_t currTime) {
|
||||
int skillID = (int)mob->data["m_iActiveSkill1"];
|
||||
std::vector<int> targetData = {1, plr->iID, 0, 0, 0};
|
||||
for (auto& pwr : MobPowers)
|
||||
if (pwr.skillType == NanoManager::SkillTable[skillID].skillType)
|
||||
if (pwr.skillType == NanoManager::SkillTable[skillID].skillType) {
|
||||
if (pwr.bitFlag != 0 && (plr->iConditionBitFlag & pwr.bitFlag))
|
||||
return; // prevent debuffing a player twice
|
||||
pwr.handle(mob, targetData, skillID, NanoManager::SkillTable[skillID].durationTime[0], NanoManager::SkillTable[skillID].powerIntensity[0]);
|
||||
}
|
||||
mob->nextAttack = currTime + (int)mob->data["m_iDelayTime"] * 100;
|
||||
return;
|
||||
}
|
||||
@ -1511,7 +1518,7 @@ void MobManager::useAbilities(Mob *mob, time_t currTime) {
|
||||
mob->skillStyle = rand() % 3;
|
||||
pkt.iStyle = mob->skillStyle;
|
||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_SKILL_CORRUPTION_READY, sizeof(sP_FE2CL_NPC_SKILL_CORRUPTION_READY));
|
||||
mob->nextAttack = currTime + 2000;
|
||||
mob->nextAttack = currTime + 1800;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1524,7 +1531,7 @@ void MobManager::useAbilities(Mob *mob, time_t currTime) {
|
||||
pkt.iValue2 = mob->hitY = plr->y;
|
||||
pkt.iValue3 = mob->hitZ = plr->z;
|
||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_SKILL_READY, sizeof(sP_FE2CL_NPC_SKILL_READY));
|
||||
mob->nextAttack = currTime + 2500;
|
||||
mob->nextAttack = currTime + 1800;
|
||||
mob->skillStyle = -2;
|
||||
return;
|
||||
}
|
||||
@ -1651,15 +1658,10 @@ bool doDamageNDebuff(Mob *mob, sSkillResult_Damage_N_Debuff *respdata, int i, in
|
||||
return false;
|
||||
}
|
||||
|
||||
int damage = duration;
|
||||
|
||||
if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE)
|
||||
damage = 0;
|
||||
|
||||
respdata[i].eCT = 1;
|
||||
respdata[i].iDamage = damage;
|
||||
respdata[i].iDamage = duration / 10;
|
||||
respdata[i].iID = plr->iID;
|
||||
respdata[i].iHP = plr->HP -= damage;
|
||||
respdata[i].iHP = plr->HP;
|
||||
respdata[i].iStamina = plr->Nanos[plr->activeNano].iStamina;
|
||||
if (plr->iConditionBitFlag & CSB_BIT_FREEDOM)
|
||||
respdata[i].bProtected = 1;
|
||||
|
@ -567,7 +567,7 @@ int NPCManager::eggBuffPlayer(CNSocket* sock, int skillId, int eggId) {
|
||||
|
||||
if (skillId == 183) {
|
||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Damage);
|
||||
} else if (skillId == 147) {
|
||||
} else if (skillId == 150) {
|
||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Heal_HP);
|
||||
} else {
|
||||
resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Buff);
|
||||
@ -588,7 +588,7 @@ int NPCManager::eggBuffPlayer(CNSocket* sock, int skillId, int eggId) {
|
||||
if (plr->HP < 0)
|
||||
plr->HP = 0;
|
||||
skill->iHP = plr->HP;
|
||||
} else if (skillId == 147) { // heal egg
|
||||
} else if (skillId == 150) { // heal egg
|
||||
sSkillResult_Heal_HP* skill = (sSkillResult_Heal_HP*)(respbuf + sizeof(sP_FE2CL_NPC_SKILL_HIT));
|
||||
memset(respbuf, 0, resplen);
|
||||
skill->eCT = 1;
|
||||
@ -651,6 +651,12 @@ void NPCManager::eggStep(CNServer* serv, time_t currTime) {
|
||||
plr->iConditionBitFlag &= ~CBFlag;
|
||||
resp.iConditionBitFlag = plr->iConditionBitFlag |= groupFlags | plr->iSelfConditionBitFlag;
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
|
||||
|
||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, resp2); // send a buff timeout to other players
|
||||
resp2.eCT = 1;
|
||||
resp2.iID = plr->iID;
|
||||
resp2.iConditionBitFlag = plr->iConditionBitFlag;
|
||||
PlayerManager::sendToViewable(sock, (void*)&resp2, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||
}
|
||||
}
|
||||
// remove buff from the map
|
||||
|
@ -287,6 +287,11 @@ void NanoManager::summonNano(CNSocket *sock, int slot, bool silent) {
|
||||
if (slot > 2 || slot < -1)
|
||||
return; // sanity check
|
||||
|
||||
int16_t nanoID = slot == -1 ? 0 : plr->equippedNanos[slot];
|
||||
|
||||
if (slot != -1 && plr->Nanos[nanoID].iSkillID == 0)
|
||||
return; // prevent powerless nanos from summoning
|
||||
|
||||
plr->nanoDrainRate = 0;
|
||||
int16_t skillID = plr->Nanos[plr->activeNano].iSkillID;
|
||||
|
||||
@ -299,14 +304,11 @@ void NanoManager::summonNano(CNSocket *sock, int slot, bool silent) {
|
||||
nanoUnbuff(sock, targetData, pwr.bitFlag, pwr.timeBuffID, 0,(SkillTable[skillID].targetType == 3));
|
||||
}
|
||||
|
||||
int16_t nanoID = slot == -1 ? 0 : plr->equippedNanos[slot];
|
||||
|
||||
if (nanoID > 36 || nanoID < 0)
|
||||
return; // sanity check
|
||||
|
||||
plr->activeNano = nanoID;
|
||||
sNano nano = plr->Nanos[nanoID];
|
||||
skillID = nano.iSkillID;
|
||||
skillID = plr->Nanos[nanoID].iSkillID;
|
||||
|
||||
// passive nano buffing
|
||||
if (SkillTable[skillID].drainType == 2) {
|
||||
@ -494,6 +496,11 @@ int NanoManager::nanoStyle(int nanoID) {
|
||||
return NanoTable[nanoID].style;
|
||||
}
|
||||
|
||||
/*
|
||||
* targetData approach
|
||||
* first integer is the count
|
||||
* second to fifth integers are IDs, these can be either player iID or mob's iID
|
||||
*/
|
||||
std::vector<int> NanoManager::findTargets(Player* plr, int skillID, CNPacketData* data) {
|
||||
std::vector<int> tD(5);
|
||||
|
||||
@ -564,10 +571,13 @@ bool doDebuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t target
|
||||
|
||||
respdata[i].eCT = 4;
|
||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag |= bitFlag;
|
||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
||||
|
||||
std::cout << (int)mob->appearanceData.iNPC_ID << " was debuffed" << std::endl;
|
||||
respdata[i].bProtected = 1;
|
||||
if (mob->skillStyle < 0 && mob->state != MobState::RETREAT) { // only debuff if the enemy is not retreating and not casting corruption
|
||||
mob->appearanceData.iConditionBitFlag |= bitFlag;
|
||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
||||
respdata[i].bProtected = 0;
|
||||
}
|
||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -620,15 +630,19 @@ bool doDamageNDebuff(CNSocket *sock, sSkillResult_Damage_N_Debuff *respdata, int
|
||||
|
||||
Mob* mob = MobManager::Mobs[targetID];
|
||||
|
||||
int damage = MobManager::hitMob(sock, mob, 0); // using amount for something else
|
||||
MobManager::hitMob(sock, mob, 0); // just to gain aggro
|
||||
|
||||
respdata[i].eCT = 4;
|
||||
respdata[i].iDamage = damage;
|
||||
respdata[i].iDamage = duration / 10;
|
||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
||||
respdata[i].iHP = mob->appearanceData.iHP;
|
||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag |= bitFlag;
|
||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
||||
std::cout << (int)mob->appearanceData.iNPC_ID << " was debuffed" << std::endl;
|
||||
respdata[i].bProtected = 1;
|
||||
if (mob->skillStyle < 0 && mob->state != MobState::RETREAT) { // only debuff if the enemy is not retreating and not casting corruption
|
||||
mob->appearanceData.iConditionBitFlag |= bitFlag;
|
||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
||||
respdata[i].bProtected = 0;
|
||||
}
|
||||
respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -665,8 +679,6 @@ bool doHeal(CNSocket *sock, sSkillResult_Heal_HP *respdata, int i, int32_t targe
|
||||
respdata[i].iHP = plr->HP;
|
||||
respdata[i].iHealHP = healedAmount;
|
||||
|
||||
std::cout << (int)plr->iID << " was healed" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -687,8 +699,6 @@ bool doDamage(CNSocket *sock, sSkillResult_Damage *respdata, int i, int32_t targ
|
||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
||||
respdata[i].iHP = mob->appearanceData.iHP;
|
||||
|
||||
std::cout << (int)mob->appearanceData.iNPC_ID << " was damaged" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -737,8 +747,6 @@ bool doLeech(CNSocket *sock, sSkillResult_Heal_HP *healdata, int i, int32_t targ
|
||||
damagedata->iID = mob->appearanceData.iNPC_ID;
|
||||
damagedata->iHP = mob->appearanceData.iHP;
|
||||
|
||||
std::cout << (int)mob->appearanceData.iNPC_ID << " was leeched" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user