mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-05 06:50:04 +00:00
Implemented GM SpecialState Handling
Co-authored-by: dongresource <dongresource@protonmail.com>
This commit is contained in:
parent
c9be0e5402
commit
efb3df7133
@ -25,6 +25,7 @@ void MobManager::init() {
|
||||
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);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ATTACK_CHARs, pcAttackChars);
|
||||
}
|
||||
|
||||
void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
||||
@ -212,8 +213,11 @@ void MobManager::killMob(CNSocket *sock, Mob *mob) {
|
||||
mob->appearanceData.iConditionBitFlag = 0;
|
||||
mob->killedTime = getTime(); // XXX: maybe introduce a shard-global time for each step?
|
||||
|
||||
// check for the edge case where hitting the mob did not aggro it
|
||||
if (sock != nullptr) {
|
||||
giveReward(sock);
|
||||
MissionManager::mobKilled(sock, mob->appearanceData.iNPCType);
|
||||
}
|
||||
|
||||
mob->despawned = false;
|
||||
}
|
||||
@ -620,3 +624,92 @@ std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
||||
sP_CL2FE_REQ_PC_ATTACK_CHARs* pkt = (sP_CL2FE_REQ_PC_ATTACK_CHARs*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// Unlike the attack mob packet, attacking players packet has an 8-byte trail (Instead of 4 bytes).
|
||||
if (!validInVarPacket(sizeof(sP_CL2FE_REQ_PC_ATTACK_CHARs), pkt->iTargetCnt, sizeof(int32_t) * 2, data->size)) {
|
||||
std::cout << "[WARN] bad sP_CL2FE_REQ_PC_ATTACK_CHARs packet size\n";
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_PC_ATTACK_CHARs));
|
||||
|
||||
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_ATTACK_CHARs_SUCC), pkt->iTargetCnt, sizeof(sAttackResult))) {
|
||||
std::cout << "[WARN] bad sP_FE2CL_PC_ATTACK_CHARs_SUCC packet size\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize response struct
|
||||
size_t resplen = sizeof(sP_FE2CL_PC_ATTACK_CHARs_SUCC) + pkt->iTargetCnt * sizeof(sAttackResult);
|
||||
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
||||
|
||||
memset(respbuf, 0, resplen);
|
||||
|
||||
sP_FE2CL_PC_ATTACK_CHARs_SUCC *resp = (sP_FE2CL_PC_ATTACK_CHARs_SUCC*)respbuf;
|
||||
sAttackResult *respdata = (sAttackResult*)(respbuf+sizeof(sP_FE2CL_PC_ATTACK_CHARs_SUCC));
|
||||
|
||||
resp->iTargetCnt = pkt->iTargetCnt;
|
||||
|
||||
for (int i = 0; i < pkt->iTargetCnt; i++) {
|
||||
if (pktdata[i*2+1] == 1) { // eCT == 1; attack player
|
||||
Player *target = nullptr;
|
||||
|
||||
for (auto& pair : PlayerManager::players) {
|
||||
if (pair.second.plr->iID == pktdata[i*2]) {
|
||||
target = pair.second.plr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == nullptr) {
|
||||
// you shall not pass
|
||||
std::cout << "[WARN] pcAttackChars: player ID not found" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
target->HP -= 100;
|
||||
|
||||
respdata[i].eCT = pktdata[i*2+1];
|
||||
respdata[i].iID = target->iID;
|
||||
respdata[i].iDamage = 100;
|
||||
respdata[i].iHP = target->HP;
|
||||
respdata[i].iHitFlag = 2; // 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
|
||||
std::cout << "[WARN] pcAttackNpcs: mob ID not found" << std::endl;
|
||||
return;
|
||||
}
|
||||
Mob *mob = Mobs[pktdata[i*2]];
|
||||
|
||||
std::pair<int,int> damage;
|
||||
|
||||
if (pkt->iTargetCnt > 1)
|
||||
damage = getDamage(plr->groupDamage, (int)mob->data["m_iProtection"], true, (int)mob->data["m_iNpcLevel"]);
|
||||
else
|
||||
damage = getDamage(plr->pointDamage, (int)mob->data["m_iProtection"], true, (int)mob->data["m_iNpcLevel"]);
|
||||
|
||||
damage.first = hitMob(sock, mob, damage.first);
|
||||
|
||||
respdata[i].eCT = pktdata[i*2+1];
|
||||
respdata[i].iID = mob->appearanceData.iNPC_ID;
|
||||
respdata[i].iDamage = damage.first;
|
||||
respdata[i].iHP = mob->appearanceData.iHP;
|
||||
respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade
|
||||
}
|
||||
}
|
||||
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_PC_ATTACK_CHARs_SUCC, resplen);
|
||||
|
||||
// a bit of a hack: these are the same size, so we can reuse the response packet
|
||||
assert(sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC) == sizeof(sP_FE2CL_PC_ATTACK_CHARs));
|
||||
sP_FE2CL_PC_ATTACK_CHARs *resp1 = (sP_FE2CL_PC_ATTACK_CHARs*)respbuf;
|
||||
|
||||
resp1->iPC_ID = plr->iID;
|
||||
|
||||
// send to other players
|
||||
PlayerManager::sendToViewable(sock, (void*)respbuf, P_FE2CL_PC_ATTACK_CHARs, resplen);
|
||||
}
|
||||
|
@ -105,4 +105,6 @@ namespace MobManager {
|
||||
void giveReward(CNSocket *sock);
|
||||
std::pair<int,int> lerp(int, int, int, int, int);
|
||||
std::pair<int,int> getDamage(int, int, bool, int);
|
||||
|
||||
void pcAttackChars(CNSocket *sock, CNPacketData *data);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ struct Player {
|
||||
int32_t iWarpLocationFlag;
|
||||
int64_t aSkywayLocationFlag[2];
|
||||
int32_t iConditionBitFlag;
|
||||
int8_t iSpecialState;
|
||||
|
||||
int x, y, z, angle;
|
||||
sItemBase Equip[AEQUIP_COUNT];
|
||||
|
@ -35,6 +35,7 @@ void PlayerManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_REGEN, PlayerManager::revivePlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EXIT, PlayerManager::exitGame);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH, PlayerManager::setSpecialSwitchPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH, PlayerManager::setGMSpecialSwitchPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_ON, PlayerManager::enterPlayerVehicle);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_OFF, PlayerManager::exitPlayerVehicle);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_CHANGE_MENTOR, PlayerManager::changePlayerGuide);
|
||||
@ -152,6 +153,7 @@ void PlayerManager::addPlayerToChunks(std::vector<Chunk*> chunks, CNSocket* sock
|
||||
newPlayer.PCAppearanceData.PCStyle = plr->PCStyle;
|
||||
newPlayer.PCAppearanceData.Nano = plr->Nanos[plr->activeNano];
|
||||
newPlayer.PCAppearanceData.iPCState = plr->iPCState;
|
||||
newPlayer.PCAppearanceData.iSpecialState = plr->iSpecialState;
|
||||
memcpy(newPlayer.PCAppearanceData.ItemEquip, plr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
||||
|
||||
otherSock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
|
||||
@ -166,6 +168,7 @@ void PlayerManager::addPlayerToChunks(std::vector<Chunk*> chunks, CNSocket* sock
|
||||
newPlayer.PCAppearanceData.PCStyle = otherPlr->PCStyle;
|
||||
newPlayer.PCAppearanceData.Nano = otherPlr->Nanos[otherPlr->activeNano];
|
||||
newPlayer.PCAppearanceData.iPCState = otherPlr->iPCState;
|
||||
newPlayer.PCAppearanceData.iSpecialState = otherPlr->iSpecialState;
|
||||
memcpy(newPlayer.PCAppearanceData.ItemEquip, otherPlr->Equip, sizeof(sItemBase) * AEQUIP_COUNT);
|
||||
|
||||
sock->sendPacket((void*)&newPlayer, P_FE2CL_PC_NEW, sizeof(sP_FE2CL_PC_NEW));
|
||||
@ -811,12 +814,15 @@ void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH* specialData = (sP_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, response);
|
||||
setSpecialState(sock, data);
|
||||
}
|
||||
|
||||
response.iPC_ID = specialData->iPC_ID;
|
||||
response.iReqSpecialStateFlag = specialData->iSpecialStateFlag;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC));
|
||||
void PlayerManager::setGMSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
if (getPlayer(sock)->accountLevel > 30)
|
||||
return;
|
||||
|
||||
setSpecialState(sock, data);
|
||||
}
|
||||
|
||||
void PlayerManager::changePlayerGuide(CNSocket *sock, CNPacketData *data) {
|
||||
@ -893,4 +899,24 @@ void PlayerManager::exitDuplicate(int accountId) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::setSpecialState(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
Player *plr = getPlayer(sock);
|
||||
|
||||
sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH* setData = (sP_CL2FE_GM_REQ_PC_SPECIAL_STATE_SWITCH*)data->buf;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_PC_SPECIAL_STATE_CHANGE, response);
|
||||
|
||||
plr->iSpecialState ^= setData->iSpecialStateFlag;
|
||||
|
||||
response.iPC_ID = setData->iPC_ID;
|
||||
response.iReqSpecialStateFlag = setData->iSpecialStateFlag;
|
||||
response.iSpecialState = plr->iSpecialState;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC, sizeof(sP_FE2CL_REP_PC_SPECIAL_STATE_SWITCH_SUCC));
|
||||
sendToViewable(sock, (void*)&response, P_FE2CL_PC_SPECIAL_STATE_CHANGE, sizeof(sP_FE2CL_PC_SPECIAL_STATE_CHANGE));
|
||||
}
|
||||
#pragma endregion
|
||||
|
@ -54,6 +54,7 @@ namespace PlayerManager {
|
||||
void exitGame(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void setGMSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void changePlayerGuide(CNSocket *sock, CNPacketData *data);
|
||||
|
||||
void enterPlayerVehicle(CNSocket* sock, CNPacketData* data);
|
||||
@ -64,4 +65,5 @@ namespace PlayerManager {
|
||||
|
||||
bool isAccountInUse(int accountId);
|
||||
void exitDuplicate(int accountId);
|
||||
void setSpecialState(CNSocket* sock, CNPacketData* data);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user