mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-04 22:40:05 +00:00
Implement two more mission types + tweaks & fixes
* Weapons will consume your batteries fully. * Nerfed enemy damage at lower levels. * Further reworked drain, uses a static variable as a timer (lastDrainTime) * resendMobHP has been repurposed to drainMobHP. * Players heal faster after a sizable cooldown. * Nano type advantage is more noticeable during combat. Implemented two more mission types + Tweaks * Item delivery quests now work. * Timed missions now work. * All escort missions (type 6) are skipped. * /minfo now also prints the terminator npc. * Weapon battery consumption tweaked * Fixed indentations. * Heal nanos have better output (25% -> 35%) * Damage formula had a slight tweak. * Bugfixed weapon equipping. * Other tweaks
This commit is contained in:
parent
177c5f0f17
commit
c8497a4856
@ -411,6 +411,7 @@ void minfoCommand(std::string full, std::vector<std::string>& args, CNSocket* so
|
|||||||
ChatManager::sendServerMessage(sock, "[MINFO] Current task ID: " + std::to_string(plr->tasks[i]));
|
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 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 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++)
|
for (int j = 0; j < 3; j++)
|
||||||
if ((int)(task["m_iCSUEnemyID"][j]) != 0)
|
if ((int)(task["m_iCSUEnemyID"][j]) != 0)
|
||||||
|
@ -29,12 +29,12 @@ void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) {
|
|||||||
Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_To);
|
Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_To);
|
||||||
|
|
||||||
if (plr == nullptr || otherPlr == nullptr)
|
if (plr == nullptr || otherPlr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup);
|
otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup);
|
||||||
|
|
||||||
if (otherPlr == nullptr)
|
if (otherPlr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// fail if the group is full or the other player is already in a group
|
// fail if the group is full or the other player is already in a group
|
||||||
if (plr->groupCnt >= 4 || otherPlr->groupCnt > 1) {
|
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);
|
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) {
|
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;
|
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)
|
if (otherSock == nullptr)
|
||||||
return;
|
return;
|
||||||
@ -69,13 +69,13 @@ void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) {
|
|||||||
Player* plr = PlayerManager::getPlayer(sock);
|
Player* plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
if (plr == nullptr)
|
if (plr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_PC_GROUP_INVITE_REFUSE, resp);
|
INITSTRUCT(sP_FE2CL_PC_GROUP_INVITE_REFUSE, resp);
|
||||||
|
|
||||||
resp.iID_To = plr->iID;
|
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) {
|
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);
|
Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_From);
|
||||||
|
|
||||||
if (plr == nullptr || otherPlr == nullptr)
|
if (plr == nullptr || otherPlr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup);
|
otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup);
|
||||||
|
|
||||||
if (otherPlr == nullptr)
|
if (otherPlr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// fail if the group is full or the other player is already in a group
|
// 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) {
|
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);
|
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||||
|
|
||||||
if (plr == nullptr || otherPlr == nullptr)
|
if (plr == nullptr || otherPlr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// send to client
|
// send to client
|
||||||
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, resp);
|
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) {
|
void GroupManager::menuChatGroup(CNSocket* sock, CNPacketData* data) {
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE))
|
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;
|
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* plr = PlayerManager::getPlayer(sock);
|
||||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||||
|
|
||||||
if (plr == nullptr || otherPlr == nullptr)
|
if (plr == nullptr || otherPlr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// send to client
|
// send to client
|
||||||
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, resp);
|
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);
|
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||||
|
|
||||||
if (otherPlr == nullptr)
|
if (otherPlr == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_LEAVE), otherPlr->groupCnt - 1, sizeof(sPCGroupMemberInfo))) {
|
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";
|
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);
|
CNSocket* sock = PlayerManager::getSockFromID(plr->iID);
|
||||||
|
|
||||||
if (sock == nullptr)
|
if (sock == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1);
|
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));
|
sock->sendPacket((void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC));
|
||||||
|
@ -140,12 +140,12 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, equipChange);
|
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, equipChange);
|
||||||
|
|
||||||
equipChange.iPC_ID = plr.plr->iID;
|
equipChange.iPC_ID = plr.plr->iID;
|
||||||
if (itemmove->eFrom == (int)SlotType::EQUIP) {
|
if (itemmove->eTo == (int)SlotType::EQUIP) {
|
||||||
equipChange.iEquipSlotNum = itemmove->iFromSlotNum;
|
|
||||||
equipChange.EquipSlotItem = resp.ToSlotItem;
|
|
||||||
} else {
|
|
||||||
equipChange.iEquipSlotNum = itemmove->iToSlotNum;
|
equipChange.iEquipSlotNum = itemmove->iToSlotNum;
|
||||||
equipChange.EquipSlotItem = resp.FromSlotItem;
|
equipChange.EquipSlotItem = resp.FromSlotItem;
|
||||||
|
} else {
|
||||||
|
equipChange.iEquipSlotNum = itemmove->iFromSlotNum;
|
||||||
|
equipChange.EquipSlotItem = resp.ToSlotItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unequip vehicle if equip slot 8 is 0
|
// unequip vehicle if equip slot 8 is 0
|
||||||
|
@ -77,20 +77,27 @@ void MissionManager::taskStart(CNSocket* sock, CNPacketData* data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TaskData& task = *Tasks[missionData->iTaskNum];
|
||||||
|
|
||||||
response.iTaskNum = 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));
|
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
|
// HACK: auto-succeed escort task
|
||||||
// TODO: maybe check for iTaskType == 6 and skip all escort missions?
|
if (task["m_iHTaskType"] == 6) {
|
||||||
if (missionData->iTaskNum == 576) {
|
|
||||||
std::cout << "Sending Eduardo success packet" << std::endl;
|
std::cout << "Sending Eduardo success packet" << std::endl;
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
|
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
|
||||||
|
|
||||||
endTask(sock, 576);
|
endTask(sock, missionData->iTaskNum);
|
||||||
response.iTaskNum = 576;
|
response.iTaskNum = missionData->iTaskNum;
|
||||||
|
|
||||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
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) {
|
void MissionManager::taskEnd(CNSocket* sock, CNPacketData* data) {
|
||||||
@ -98,6 +105,25 @@ void MissionManager::taskEnd(CNSocket* sock, CNPacketData* data) {
|
|||||||
return; // malformed packet
|
return; // malformed packet
|
||||||
|
|
||||||
sP_CL2FE_REQ_PC_TASK_END* missionData = (sP_CL2FE_REQ_PC_TASK_END*)data->buf;
|
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);
|
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
|
||||||
|
|
||||||
response.iTaskNum = missionData->iTaskNum;
|
response.iTaskNum = missionData->iTaskNum;
|
||||||
|
@ -85,11 +85,12 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
|||||||
damage.first = plr->pointDamage;
|
damage.first = plr->pointDamage;
|
||||||
|
|
||||||
int difficulty = (int)mob->data["m_iNpcLevel"];
|
int difficulty = (int)mob->data["m_iNpcLevel"];
|
||||||
|
damage = getDamage(damage.first, (int)mob->data["m_iProtection"], true, (plr->batteryW > 6 + difficulty), NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
|
||||||
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 >= 6 + difficulty)
|
||||||
if (plr->batteryW >= 11 + difficulty)
|
plr->batteryW -= 6 + difficulty;
|
||||||
plr->batteryW -= 11 + difficulty;
|
else
|
||||||
|
plr->batteryW = 0;
|
||||||
|
|
||||||
damage.first = hitMob(sock, mob, damage.first);
|
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;
|
sP_FE2CL_NPC_ATTACK_PCs *pkt = (sP_FE2CL_NPC_ATTACK_PCs*)respbuf;
|
||||||
sAttackResult *atk = (sAttackResult*)(respbuf + sizeof(sP_FE2CL_NPC_ATTACK_PCs));
|
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;
|
plr->HP -= damage.first;
|
||||||
|
|
||||||
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
|
pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||||
@ -329,16 +330,16 @@ int MobManager::hitMob(CNSocket *sock, Mob *mob, int damage) {
|
|||||||
|
|
||||||
mob->appearanceData.iHP -= damage;
|
mob->appearanceData.iHP -= damage;
|
||||||
|
|
||||||
// wake up sleeping monster
|
// wake up sleeping monster
|
||||||
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_MEZ) {
|
if (mob->appearanceData.iConditionBitFlag & CSB_BIT_MEZ) {
|
||||||
mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ;
|
mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ;
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1);
|
||||||
pkt1.eCT = 2;
|
pkt1.eCT = 2;
|
||||||
pkt1.iID = mob->appearanceData.iNPC_ID;
|
pkt1.iID = mob->appearanceData.iNPC_ID;
|
||||||
pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag;
|
||||||
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mob->appearanceData.iHP <= 0)
|
if (mob->appearanceData.iHP <= 0)
|
||||||
killMob(mob->target, mob);
|
killMob(mob->target, mob);
|
||||||
@ -492,7 +493,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
|
|||||||
// movement logic
|
// movement logic
|
||||||
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
||||||
return;
|
return;
|
||||||
mob->nextMovement = currTime + 399;
|
mob->nextMovement = currTime + 400;
|
||||||
if (currTime >= mob->nextAttack)
|
if (currTime >= mob->nextAttack)
|
||||||
mob->nextAttack = 0;
|
mob->nextAttack = 0;
|
||||||
|
|
||||||
@ -598,7 +599,7 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) {
|
|||||||
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mob->nextMovement = currTime + 399;
|
mob->nextMovement = currTime + 400;
|
||||||
|
|
||||||
// distance between spawn point and current location
|
// distance between spawn point and current location
|
||||||
int distance = hypot(mob->appearanceData.iX - mob->roamX, mob->appearanceData.iY - mob->roamY);
|
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.iNPC_ID = mob->appearanceData.iNPC_ID;
|
||||||
pkt.iSpeed = (int)mob->data["m_iRunSpeed"] * 2;
|
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.iToX = mob->appearanceData.iX = targ.first;
|
||||||
pkt.iToY = mob->appearanceData.iY = targ.second;
|
pkt.iToY = mob->appearanceData.iY = targ.second;
|
||||||
pkt.iToZ = mob->appearanceData.iZ;
|
pkt.iToZ = mob->appearanceData.iZ = mob->spawnZ;
|
||||||
|
|
||||||
// notify all nearby players
|
// notify all nearby players
|
||||||
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
|
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->killedTime = 0;
|
||||||
mob->nextAttack = 0;
|
mob->nextAttack = 0;
|
||||||
mob->appearanceData.iConditionBitFlag = 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) {
|
void MobManager::step(CNServer *serv, time_t currTime) {
|
||||||
|
static time_t lastDrainTime = 0;
|
||||||
|
|
||||||
for (auto& pair : Mobs) {
|
for (auto& pair : Mobs) {
|
||||||
int x = pair.second->appearanceData.iX;
|
int x = pair.second->appearanceData.iX;
|
||||||
int y = pair.second->appearanceData.iY;
|
int y = pair.second->appearanceData.iY;
|
||||||
@ -644,9 +646,8 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// drain
|
// drain
|
||||||
if (pair.second->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) {
|
if (currTime - lastDrainTime >= 600 && pair.second->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) {
|
||||||
pair.second->appearanceData.iHP -= pair.second->maxHealth / 50; // lose 10% every second
|
drainMobHP(pair.second, pair.second->maxHealth * 3 / 50); // lose 10% every second
|
||||||
// TODO: Make this send a damage packet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unbuffing
|
// unbuffing
|
||||||
@ -692,6 +693,9 @@ void MobManager::step(CNServer *serv, time_t currTime) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currTime - lastDrainTime >= 600)
|
||||||
|
lastDrainTime = currTime;
|
||||||
|
|
||||||
// deallocate all NPCs queued for removal
|
// deallocate all NPCs queued for removal
|
||||||
while (RemovalQueue.size() > 0) {
|
while (RemovalQueue.size() > 0) {
|
||||||
@ -752,8 +756,10 @@ void MobManager::combatBegin(CNSocket *sock, CNPacketData *data) {
|
|||||||
void MobManager::combatEnd(CNSocket *sock, CNPacketData *data) {
|
void MobManager::combatEnd(CNSocket *sock, CNPacketData *data) {
|
||||||
Player *plr = PlayerManager::getPlayer(sock);
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
if (plr != nullptr)
|
if (plr != nullptr) {
|
||||||
plr->inCombat = false;
|
plr->inCombat = false;
|
||||||
|
plr->healCooldown = 4000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobManager::dotDamageOnOff(CNSocket *sock, CNPacketData *data) {
|
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);
|
dealGooDamage(sock, PC_MAXHEALTH(plr->level) * 3 / 20);
|
||||||
|
|
||||||
// heal
|
// heal
|
||||||
if (currTime - lastHealTime >= 6000 && !plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) {
|
if (currTime - lastHealTime >= 4000 && !plr->inCombat && plr->HP < PC_MAXHEALTH(plr->level)) {
|
||||||
plr->HP += PC_MAXHEALTH(plr->level) / 5;
|
if (currTime - lastHealTime - plr->healCooldown >= 4000) {
|
||||||
if (plr->HP > PC_MAXHEALTH(plr->level))
|
plr->HP += PC_MAXHEALTH(plr->level) / 5;
|
||||||
plr->HP = PC_MAXHEALTH(plr->level);
|
if (plr->HP > PC_MAXHEALTH(plr->level))
|
||||||
transmit = true;
|
plr->HP = PC_MAXHEALTH(plr->level);
|
||||||
|
transmit = true;
|
||||||
|
} else
|
||||||
|
plr->healCooldown -= 4000;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
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 this was a heal tick, update the counter outside of the loop
|
||||||
if (currTime - lastHealTime >= 6000)
|
if (currTime - lastHealTime >= 4000)
|
||||||
lastHealTime = currTime;
|
lastHealTime = currTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -907,15 +916,15 @@ std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool
|
|||||||
|
|
||||||
// base calculation
|
// base calculation
|
||||||
int damage = attackPower * attackPower / (attackPower + defensePower);
|
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;
|
damage = damage * (rand() % 40 + 80) / 100;
|
||||||
|
|
||||||
// Adaptium/Blastons/Cosmix
|
// Adaptium/Blastons/Cosmix
|
||||||
if (attackerStyle != -1 && defenderStyle != -1 && attackerStyle != defenderStyle) {
|
if (attackerStyle != -1 && defenderStyle != -1 && attackerStyle != defenderStyle) {
|
||||||
if (attackerStyle < defenderStyle || attackerStyle - defenderStyle == 2)
|
if (attackerStyle < defenderStyle || attackerStyle - defenderStyle == 2)
|
||||||
damage = damage * 5 / 4;
|
damage = damage * 3 / 2;
|
||||||
else
|
else
|
||||||
damage = damage * 4 / 5;
|
damage = damage * 2 / 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// weapon boosts
|
// weapon boosts
|
||||||
@ -988,10 +997,12 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
|||||||
else
|
else
|
||||||
damage.first = plr->pointDamage;
|
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)
|
if (plr->batteryW >= 6 + plr->level)
|
||||||
plr->batteryW -= 12;
|
plr->batteryW -= 6 + plr->level;
|
||||||
|
else
|
||||||
|
plr->batteryW = 0;
|
||||||
|
|
||||||
target->HP -= damage.first;
|
target->HP -= damage.first;
|
||||||
|
|
||||||
@ -1017,11 +1028,13 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
|||||||
|
|
||||||
int difficulty = (int)mob->data["m_iNpcLevel"];
|
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);
|
NanoManager::nanoStyle(plr->activeNano), (int)mob->data["m_iNpcStyle"], difficulty);
|
||||||
|
|
||||||
if (plr->batteryW >= 11 + difficulty)
|
if (plr->batteryW >= 6 + difficulty)
|
||||||
plr->batteryW -= 11 + difficulty;
|
plr->batteryW -= 6 + difficulty;
|
||||||
|
else
|
||||||
|
plr->batteryW = 0;
|
||||||
|
|
||||||
damage.first = hitMob(sock, mob, damage.first);
|
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);
|
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::drainMobHP(Mob *mob, int amount) {
|
||||||
void MobManager::resendMobHP(Mob *mob) {
|
size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_Damage);
|
||||||
size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_Heal_HP);
|
|
||||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||||
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
||||||
|
|
||||||
memset(respbuf, 0, resplen);
|
memset(respbuf, 0, resplen);
|
||||||
|
|
||||||
sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf;
|
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->iID = mob->appearanceData.iNPC_ID;
|
||||||
pkt->eCT = 4; // mob
|
pkt->eCT = 4; // mob
|
||||||
pkt->iTB_ID = ECSB_HEAL; // sSkillResult_Heal_HP
|
pkt->iTB_ID = ECSB_BOUNDINGBALL;
|
||||||
|
|
||||||
heal->eCT = 4;
|
drain->eCT = 4;
|
||||||
heal->iID = mob->appearanceData.iNPC_ID;
|
drain->iID = mob->appearanceData.iNPC_ID;
|
||||||
heal->iHealHP = 0;
|
drain->iDamage = amount;
|
||||||
heal->iHP = mob->appearanceData.iHP;
|
drain->iHP = mob->appearanceData.iHP -= amount;
|
||||||
|
|
||||||
NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
|
NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ namespace MobManager {
|
|||||||
std::pair<int,int> getDamage(int, int, bool, bool, int, int, int);
|
std::pair<int,int> getDamage(int, int, bool, bool, int, int, int);
|
||||||
|
|
||||||
void pcAttackChars(CNSocket *sock, CNPacketData *data);
|
void pcAttackChars(CNSocket *sock, CNPacketData *data);
|
||||||
void resendMobHP(Mob *mob);
|
void drainMobHP(Mob *mob, int amount);
|
||||||
void incNextMovement(Mob *mob, time_t currTime=0);
|
void incNextMovement(Mob *mob, time_t currTime=0);
|
||||||
bool aggroCheck(Mob *mob, time_t currTime);
|
bool aggroCheck(Mob *mob, time_t currTime);
|
||||||
}
|
}
|
||||||
|
@ -608,13 +608,6 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) {
|
|||||||
if (otherPlr == nullptr || sockTo == nullptr)
|
if (otherPlr == nullptr || sockTo == nullptr)
|
||||||
continue;
|
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);
|
PlayerManager::sendPlayerTo(sockTo, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -672,8 +672,8 @@ void activePower(CNSocket *sock, CNPacketData *data,
|
|||||||
// active nano power dispatch table
|
// active nano power dispatch table
|
||||||
std::vector<ActivePower> ActivePowers = {
|
std::vector<ActivePower> ActivePowers = {
|
||||||
ActivePower(StunPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_STUN, CSB_BIT_STUN, 2250),
|
ActivePower(StunPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_STUN, CSB_BIT_STUN, 2250),
|
||||||
ActivePower(HealPowers, activePower<sSkillResult_Heal_HP, doHeal>, EST_HEAL_HP, CSB_BIT_NONE, 25),
|
ActivePower(HealPowers, activePower<sSkillResult_Heal_HP, doHeal>, EST_HEAL_HP, CSB_BIT_NONE, 35),
|
||||||
ActivePower(GroupHealPowers, activePower<sSkillResult_Heal_HP, doGroupHeal, GHEAL>,EST_HEAL_HP, CSB_BIT_NONE, 15),
|
ActivePower(GroupHealPowers, activePower<sSkillResult_Heal_HP, doGroupHeal, GHEAL>,EST_HEAL_HP, CSB_BIT_NONE, 20),
|
||||||
// TODO: Recall
|
// TODO: Recall
|
||||||
ActivePower(DrainPowers, activePower<sSkillResult_Buff, doBuff>, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 3000),
|
ActivePower(DrainPowers, activePower<sSkillResult_Buff, doBuff>, EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, 3000),
|
||||||
ActivePower(SnarePowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SNARE, CSB_BIT_DN_MOVE_SPEED, 4500),
|
ActivePower(SnarePowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, EST_SNARE, CSB_BIT_DN_MOVE_SPEED, 4500),
|
||||||
|
@ -50,6 +50,7 @@ struct Player {
|
|||||||
|
|
||||||
bool inCombat;
|
bool inCombat;
|
||||||
bool passiveNanoOut;
|
bool passiveNanoOut;
|
||||||
|
int healCooldown;
|
||||||
|
|
||||||
int pointDamage;
|
int pointDamage;
|
||||||
int groupDamage;
|
int groupDamage;
|
||||||
|
@ -280,7 +280,6 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z) {
|
|||||||
plrv.currentChunks.clear();
|
plrv.currentChunks.clear();
|
||||||
plrv.chunkPos = std::make_tuple(0, 0, plrv.plr->instanceID);
|
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));
|
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) {
|
void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
|
||||||
|
Loading…
Reference in New Issue
Block a user