2020-09-16 19:46:15 +00:00
|
|
|
#include "MobManager.hpp"
|
2020-08-27 20:16:52 +00:00
|
|
|
#include "PlayerManager.hpp"
|
|
|
|
#include "NPCManager.hpp"
|
2020-08-28 16:25:03 +00:00
|
|
|
#include "ItemManager.hpp"
|
2020-09-10 16:40:38 +00:00
|
|
|
#include "MissionManager.hpp"
|
2020-08-27 20:16:52 +00:00
|
|
|
|
2020-08-28 16:25:03 +00:00
|
|
|
#include <assert.h>
|
2020-08-27 20:16:52 +00:00
|
|
|
|
2020-09-16 19:46:15 +00:00
|
|
|
void MobManager::init() {
|
2020-08-27 20:16:52 +00:00
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ATTACK_NPCs, pcAttackNpcs);
|
|
|
|
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_COMBAT_BEGIN, combatBegin);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_COMBAT_END, combatEnd);
|
|
|
|
REGISTER_SHARD_PACKET(P_CL2FE_DOT_DAMAGE_ONOFF, dotDamageOnOff);
|
|
|
|
}
|
|
|
|
|
2020-09-16 19:46:15 +00:00
|
|
|
void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
2020-08-27 20:16:52 +00:00
|
|
|
sP_CL2FE_REQ_PC_ATTACK_NPCs* pkt = (sP_CL2FE_REQ_PC_ATTACK_NPCs*)data->buf;
|
2020-08-28 20:01:49 +00:00
|
|
|
Player *plr = PlayerManager::getPlayer(sock);
|
2020-08-27 20:16:52 +00:00
|
|
|
|
2020-08-28 14:09:26 +00:00
|
|
|
// sanity check
|
|
|
|
if (!validInVarPacket(sizeof(sP_CL2FE_REQ_PC_ATTACK_NPCs), pkt->iNPCCnt, sizeof(int32_t), data->size)) {
|
|
|
|
std::cout << "[WARN] bad sP_CL2FE_REQ_PC_ATTACK_NPCs packet size\n";
|
2020-08-27 20:16:52 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-08-28 14:09:26 +00:00
|
|
|
|
2020-08-27 20:16:52 +00:00
|
|
|
int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_PC_ATTACK_NPCs));
|
|
|
|
|
2020-08-28 14:09:26 +00:00
|
|
|
/*
|
|
|
|
* Due to the possibility of multiplication overflow (and regular buffer overflow),
|
2020-08-28 19:42:00 +00:00
|
|
|
* both incoming and outgoing variable-length packets must be validated, at least if
|
|
|
|
* the number of trailing structs isn't well known (ie. it's from the client).
|
2020-08-28 14:09:26 +00:00
|
|
|
*/
|
|
|
|
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC), pkt->iNPCCnt, sizeof(sAttackResult))) {
|
2020-08-28 16:25:03 +00:00
|
|
|
std::cout << "[WARN] bad sP_FE2CL_PC_ATTACK_NPCs_SUCC packet size\n";
|
2020-08-28 14:09:26 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-08-27 20:16:52 +00:00
|
|
|
|
|
|
|
// initialize response struct
|
|
|
|
size_t resplen = sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC) + pkt->iNPCCnt * sizeof(sAttackResult);
|
2020-09-09 19:08:31 +00:00
|
|
|
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
2020-08-28 14:09:26 +00:00
|
|
|
|
2020-08-27 20:16:52 +00:00
|
|
|
memset(respbuf, 0, resplen);
|
2020-08-28 14:09:26 +00:00
|
|
|
|
2020-08-27 20:16:52 +00:00
|
|
|
sP_FE2CL_PC_ATTACK_NPCs_SUCC *resp = (sP_FE2CL_PC_ATTACK_NPCs_SUCC*)respbuf;
|
|
|
|
sAttackResult *respdata = (sAttackResult*)(respbuf+sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC));
|
|
|
|
|
|
|
|
resp->iNPCCnt = pkt->iNPCCnt;
|
|
|
|
|
|
|
|
for (int i = 0; i < pkt->iNPCCnt; i++) {
|
|
|
|
if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) {
|
|
|
|
// not sure how to best handle this
|
|
|
|
std::cout << "[WARN] pcAttackNpcs: mob ID not found" << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
BaseNPC& mob = NPCManager::NPCs[pktdata[i]];
|
|
|
|
|
|
|
|
mob.appearanceData.iHP -= 100;
|
|
|
|
|
2020-09-09 19:08:31 +00:00
|
|
|
if (mob.appearanceData.iHP <= 0) {
|
2020-08-27 20:16:52 +00:00
|
|
|
giveReward(sock);
|
2020-09-10 16:40:38 +00:00
|
|
|
MissionManager::mobKilled(sock, mob.appearanceData.iNPCType);
|
2020-09-09 19:08:31 +00:00
|
|
|
// TODO: despawn mobs when they die
|
|
|
|
}
|
2020-08-27 20:16:52 +00:00
|
|
|
|
|
|
|
respdata[i].iID = mob.appearanceData.iNPC_ID;
|
|
|
|
respdata[i].iDamage = 100;
|
|
|
|
respdata[i].iHP = mob.appearanceData.iHP;
|
2020-09-09 19:08:31 +00:00
|
|
|
respdata[i].iHitFlag = 2; // hitscan, not a rocket or a grenade
|
2020-08-27 20:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sock->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs_SUCC, resplen);
|
2020-08-28 20:01:49 +00:00
|
|
|
|
2020-09-09 19:08:31 +00:00
|
|
|
// a bit of a hack: these are the same size, so we can reuse the response packet
|
2020-08-28 20:01:49 +00:00
|
|
|
assert(sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC) == sizeof(sP_FE2CL_PC_ATTACK_NPCs));
|
|
|
|
sP_FE2CL_PC_ATTACK_NPCs *resp1 = (sP_FE2CL_PC_ATTACK_NPCs*)respbuf;
|
|
|
|
|
|
|
|
resp1->iPC_ID = plr->iID;
|
|
|
|
|
|
|
|
// send to other players
|
2020-09-09 19:08:31 +00:00
|
|
|
for (CNSocket *s : PlayerManager::players[sock].viewable)
|
2020-08-28 20:01:49 +00:00
|
|
|
s->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_NPCs, resplen);
|
2020-08-27 20:16:52 +00:00
|
|
|
}
|
|
|
|
|
2020-09-16 19:46:15 +00:00
|
|
|
void MobManager::combatBegin(CNSocket *sock, CNPacketData *data) {} // stub
|
|
|
|
void MobManager::combatEnd(CNSocket *sock, CNPacketData *data) {} // stub
|
|
|
|
void MobManager::dotDamageOnOff(CNSocket *sock, CNPacketData *data) {} // stub
|
2020-08-27 20:16:52 +00:00
|
|
|
|
2020-09-16 19:46:15 +00:00
|
|
|
void MobManager::giveReward(CNSocket *sock) {
|
2020-08-27 20:16:52 +00:00
|
|
|
Player *plr = PlayerManager::getPlayer(sock);
|
|
|
|
|
2020-08-28 16:25:03 +00:00
|
|
|
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
2020-09-08 01:01:47 +00:00
|
|
|
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
2020-08-28 16:25:03 +00:00
|
|
|
// 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_REP_REWARD_ITEM *reward = (sP_FE2CL_REP_REWARD_ITEM *)respbuf;
|
|
|
|
sItemReward *item = (sItemReward *)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
|
|
|
|
|
|
|
// don't forget to zero the buffer!
|
|
|
|
memset(respbuf, 0, resplen);
|
|
|
|
|
2020-08-27 20:16:52 +00:00
|
|
|
// update player
|
|
|
|
plr->money += 50;
|
|
|
|
plr->fusionmatter += 70;
|
|
|
|
|
2020-08-28 16:25:03 +00:00
|
|
|
// simple rewards
|
|
|
|
reward->m_iCandy = plr->money;
|
|
|
|
reward->m_iFusionMatter = plr->fusionmatter;
|
|
|
|
reward->iFatigue = 100; // prevents warning message
|
|
|
|
reward->iFatigue_Level = 1;
|
|
|
|
reward->iItemCnt = 1; // remember to update resplen if you change this
|
|
|
|
|
|
|
|
int slot = ItemManager::findFreeSlot(plr);
|
|
|
|
if (slot == -1) {
|
|
|
|
// no room for an item, but you still get FM and taros
|
2020-09-09 19:08:31 +00:00
|
|
|
reward->iItemCnt = 0;
|
2020-08-28 16:25:03 +00:00
|
|
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
|
|
|
} else {
|
|
|
|
// item reward
|
|
|
|
item->sItem.iType = 9;
|
|
|
|
item->sItem.iID = 1;
|
|
|
|
item->iSlotNum = slot;
|
|
|
|
item->eIL = 1; // Inventory Location. 1 means player inventory.
|
|
|
|
|
|
|
|
// update player
|
|
|
|
plr->Inven[slot] = item->sItem;
|
|
|
|
|
|
|
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
|
|
|
}
|
2020-08-27 20:16:52 +00:00
|
|
|
}
|