mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-24 22:11:04 +00:00
[refactor] Mark all internal functions static
All packet handlers and helper functions that are only used in the source file they're declared in have been taken out of the namespaces in the corresponding header files, have been marked static, and have been reordered to avoid the need for declarations at the top of each source file. Each source file now contains a "using namespace" directive so that the static functions don't need to prefix the source file's symbols with their namespace. All redundant namespace prefixes found have been removed. An unused nano power resetting function in NanoManager has been removed.
This commit is contained in:
parent
04c56ce426
commit
cee09f6344
@ -55,6 +55,8 @@ namespace NanoManager {
|
||||
|
||||
void nanoUnbuff(CNSocket* sock, std::vector<int> targetData, int32_t bitFlag, int16_t timeBuffID, int16_t amount, bool groupPower);
|
||||
int applyBuff(CNSocket* sock, int skillID, int eTBU, int eTBT, int32_t groupFlags);
|
||||
|
||||
std::vector<int> findTargets(Player* plr, int skillID, CNPacketData* data = nullptr);
|
||||
}
|
||||
|
||||
namespace Combat {
|
||||
|
@ -12,18 +12,29 @@
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
void BuddyManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REQUEST_MAKE_BUDDY, requestBuddy);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIND_NAME_MAKE_BUDDY, reqBuddyByName);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ACCEPT_MAKE_BUDDY, reqAcceptBuddy);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIND_NAME_ACCEPT_BUDDY, reqFindNameBuddyAccept);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_GET_BUDDY_STATE, reqPktGetBuddyState);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_BUDDY_BLOCK, reqBuddyBlock);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_PC_BLOCK, reqPlayerBlock);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REMOVE_BUDDY, reqBuddyDelete);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_BUDDY_WARP, reqBuddyWarp);
|
||||
using namespace BuddyManager;
|
||||
|
||||
#pragma region Helper methods
|
||||
|
||||
static int getAvailableBuddySlot(Player* plr) {
|
||||
int slot = -1;
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (plr->buddyIDs[i] == 0)
|
||||
return i;
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
static bool playerHasBuddyWithID(Player* plr, int buddyID) {
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (plr->buddyIDs[i] == buddyID)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// Refresh buddy list
|
||||
void BuddyManager::refreshBuddyList(CNSocket* sock) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
@ -76,7 +87,7 @@ void BuddyManager::refreshBuddyList(CNSocket* sock) {
|
||||
}
|
||||
|
||||
// Buddy request
|
||||
void BuddyManager::requestBuddy(CNSocket* sock, CNPacketData* data) {
|
||||
static void requestBuddy(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_REQUEST_MAKE_BUDDY))
|
||||
return; // malformed packet
|
||||
|
||||
@ -117,7 +128,7 @@ void BuddyManager::requestBuddy(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Sending buddy request by player name
|
||||
void BuddyManager::reqBuddyByName(CNSocket* sock, CNPacketData* data) {
|
||||
static void reqBuddyByName(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_FIND_NAME_MAKE_BUDDY)) {
|
||||
return; // malformed packet
|
||||
}
|
||||
@ -144,7 +155,7 @@ void BuddyManager::reqBuddyByName(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Accepting buddy request
|
||||
void BuddyManager::reqAcceptBuddy(CNSocket* sock, CNPacketData* data) {
|
||||
static void reqAcceptBuddy(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_ACCEPT_MAKE_BUDDY))
|
||||
return; // malformed packet
|
||||
|
||||
@ -213,7 +224,7 @@ void BuddyManager::reqAcceptBuddy(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Accepting buddy request from the find name request
|
||||
void BuddyManager::reqFindNameBuddyAccept(CNSocket* sock, CNPacketData* data) {
|
||||
static void reqFindNameBuddyAccept(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_FIND_NAME_ACCEPT_BUDDY)) {
|
||||
return; // malformed packet
|
||||
}
|
||||
@ -284,7 +295,7 @@ void BuddyManager::reqFindNameBuddyAccept(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Getting buddy state
|
||||
void BuddyManager::reqPktGetBuddyState(CNSocket* sock, CNPacketData* data) {
|
||||
static void reqPktGetBuddyState(CNSocket* sock, CNPacketData* data) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
/*
|
||||
@ -307,7 +318,7 @@ void BuddyManager::reqPktGetBuddyState(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Blocking the buddy
|
||||
void BuddyManager::reqBuddyBlock(CNSocket* sock, CNPacketData* data) {
|
||||
static void reqBuddyBlock(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SET_BUDDY_BLOCK))
|
||||
return; // malformed packet
|
||||
|
||||
@ -353,7 +364,7 @@ void BuddyManager::reqBuddyBlock(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// block non-buddy
|
||||
void BuddyManager::reqPlayerBlock(CNSocket* sock, CNPacketData* data) {
|
||||
static void reqPlayerBlock(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SET_PC_BLOCK))
|
||||
return;
|
||||
|
||||
@ -381,7 +392,7 @@ void BuddyManager::reqPlayerBlock(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Deleting the buddy
|
||||
void BuddyManager::reqBuddyDelete(CNSocket* sock, CNPacketData* data) {
|
||||
static void reqBuddyDelete(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_REMOVE_BUDDY))
|
||||
return; // malformed packet
|
||||
|
||||
@ -431,7 +442,7 @@ void BuddyManager::reqBuddyDelete(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Warping to buddy
|
||||
void BuddyManager::reqBuddyWarp(CNSocket* sock, CNPacketData* data) {
|
||||
static void reqBuddyWarp(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_BUDDY_WARP))
|
||||
return; // malformed packet
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
@ -472,23 +483,14 @@ fail:
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_BUDDY_WARP_FAIL, sizeof(sP_FE2CL_REP_PC_BUDDY_WARP_FAIL));
|
||||
}
|
||||
|
||||
#pragma region Helper methods
|
||||
|
||||
int BuddyManager::getAvailableBuddySlot(Player* plr) {
|
||||
int slot = -1;
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (plr->buddyIDs[i] == 0)
|
||||
return i;
|
||||
}
|
||||
return slot;
|
||||
void BuddyManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REQUEST_MAKE_BUDDY, requestBuddy);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIND_NAME_MAKE_BUDDY, reqBuddyByName);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ACCEPT_MAKE_BUDDY, reqAcceptBuddy);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIND_NAME_ACCEPT_BUDDY, reqFindNameBuddyAccept);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_GET_BUDDY_STATE, reqPktGetBuddyState);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_BUDDY_BLOCK, reqBuddyBlock);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SET_PC_BLOCK, reqPlayerBlock);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REMOVE_BUDDY, reqBuddyDelete);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_BUDDY_WARP, reqBuddyWarp);
|
||||
}
|
||||
|
||||
bool BuddyManager::playerHasBuddyWithID(Player* plr, int buddyID) {
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if (plr->buddyIDs[i] == buddyID)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
@ -3,39 +3,11 @@
|
||||
#include "Player.hpp"
|
||||
#include "CNProtocol.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "CNShardServer.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include "CNProtocol.hpp"
|
||||
|
||||
namespace BuddyManager {
|
||||
void init();
|
||||
|
||||
// Buddy list
|
||||
void refreshBuddyList(CNSocket* sock);
|
||||
|
||||
// Buddy requests
|
||||
void requestBuddy(CNSocket* sock, CNPacketData* data);
|
||||
void reqBuddyByName(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
// Buddy accepting
|
||||
void reqAcceptBuddy(CNSocket* sock, CNPacketData* data);
|
||||
void reqFindNameBuddyAccept(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
// Getting buddy state
|
||||
void reqPktGetBuddyState(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
// Blocking/removing buddies
|
||||
void reqBuddyBlock(CNSocket* sock, CNPacketData* data);
|
||||
void reqPlayerBlock(CNSocket* sock, CNPacketData* data);
|
||||
void reqBuddyDelete(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
// Buddy warping
|
||||
void reqBuddyWarp(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
// helper methods
|
||||
|
||||
// Name checks
|
||||
int getAvailableBuddySlot(Player* plr);
|
||||
bool playerHasBuddyWithID(Player* plr, int buddyID);
|
||||
}
|
||||
|
@ -7,23 +7,9 @@
|
||||
|
||||
std::vector<std::string> ChatManager::dump;
|
||||
|
||||
void ChatManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_FREECHAT_MESSAGE, chatHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT, emoteHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_MENUCHAT_MESSAGE, menuChatHandler);
|
||||
using namespace ChatManager;
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE, buddyChatHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE, buddyMenuChatHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT, tradeChatHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE, groupChatHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE, groupMenuChatHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_ANNOUNCE, announcementHandler);
|
||||
}
|
||||
|
||||
void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void chatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -57,7 +43,7 @@ void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
PlayerManager::sendToViewable(sock, (void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC));
|
||||
}
|
||||
|
||||
void ChatManager::menuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void menuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -83,7 +69,7 @@ void ChatManager::menuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
PlayerManager::sendToViewable(sock, (void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC));
|
||||
}
|
||||
|
||||
void ChatManager::emoteHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void emoteHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
@ -113,7 +99,7 @@ void ChatManager::sendServerMessage(CNSocket* sock, std::string msg) {
|
||||
sock->sendPacket((void*)&motd, P_FE2CL_PC_MOTD_LOGIN, sizeof(sP_FE2CL_PC_MOTD_LOGIN));
|
||||
}
|
||||
|
||||
void ChatManager::announcementHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void announcementHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_GM_REQ_PC_ANNOUNCE))
|
||||
return; // ignore malformed packet
|
||||
|
||||
@ -151,7 +137,7 @@ void ChatManager::announcementHandler(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Buddy freechatting
|
||||
void ChatManager::buddyChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void buddyChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -171,7 +157,7 @@ void ChatManager::buddyChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
resp.iToPCUID = pkt->iBuddyPCUID;
|
||||
resp.iEmoteCode = pkt->iEmoteCode;
|
||||
|
||||
std::string fullChat = ChatManager::sanitizeText(U16toU8(pkt->szFreeChat));
|
||||
std::string fullChat = sanitizeText(U16toU8(pkt->szFreeChat));
|
||||
|
||||
if (fullChat.length() > 1 && fullChat[0] == CMD_PREFIX) { // PREFIX
|
||||
CustomCommands::runCmd(fullChat, sock);
|
||||
@ -183,7 +169,7 @@ void ChatManager::buddyChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
std::string logLine = "[BuddyChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
||||
std::cout << logLine << std::endl;
|
||||
ChatManager::dump.push_back(logLine);
|
||||
dump.push_back(logLine);
|
||||
|
||||
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
|
||||
|
||||
@ -192,7 +178,7 @@ void ChatManager::buddyChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Buddy menuchat
|
||||
void ChatManager::buddyMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void buddyMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -212,11 +198,11 @@ void ChatManager::buddyMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
resp.iToPCUID = pkt->iBuddyPCUID;
|
||||
resp.iEmoteCode = pkt->iEmoteCode;
|
||||
|
||||
std::string fullChat = ChatManager::sanitizeText(U16toU8(pkt->szFreeChat));
|
||||
std::string fullChat = sanitizeText(U16toU8(pkt->szFreeChat));
|
||||
std::string logLine = "[BuddyMenuChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
||||
|
||||
std::cout << logLine << std::endl;
|
||||
ChatManager::dump.push_back(logLine);
|
||||
dump.push_back(logLine);
|
||||
|
||||
U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat));
|
||||
|
||||
@ -224,7 +210,7 @@ void ChatManager::buddyMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_BUDDY_MENUCHAT_MESSAGE_SUCC)); // broadcast send to receiver
|
||||
}
|
||||
|
||||
void ChatManager::tradeChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void tradeChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT))
|
||||
return; // malformed packet
|
||||
sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT* pacdat = (sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT*)data->buf;
|
||||
@ -245,20 +231,20 @@ void ChatManager::tradeChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
resp.iID_Request = pacdat->iID_Request;
|
||||
resp.iID_From = pacdat->iID_From;
|
||||
resp.iID_To = pacdat->iID_To;
|
||||
std::string fullChat = ChatManager::sanitizeText(U16toU8(pacdat->szFreeChat));
|
||||
std::string fullChat = sanitizeText(U16toU8(pacdat->szFreeChat));
|
||||
U8toU16(fullChat, resp.szFreeChat, sizeof(resp.szFreeChat));
|
||||
|
||||
std::string logLine = "[TradeChat] " + PlayerManager::getPlayerName(plr) + " (to " + PlayerManager::getPlayerName(otherPlr) + "): " + fullChat;
|
||||
|
||||
std::cout << logLine << std::endl;
|
||||
ChatManager::dump.push_back(logLine);
|
||||
dump.push_back(logLine);
|
||||
|
||||
resp.iEmoteCode = pacdat->iEmoteCode;
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT));
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT));
|
||||
}
|
||||
|
||||
void ChatManager::groupChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void groupChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -269,7 +255,7 @@ void ChatManager::groupChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (otherPlr == nullptr)
|
||||
return;
|
||||
|
||||
std::string fullChat = ChatManager::sanitizeText(U16toU8(chat->szFreeChat));
|
||||
std::string fullChat = sanitizeText(U16toU8(chat->szFreeChat));
|
||||
|
||||
if (fullChat.length() > 1 && fullChat[0] == CMD_PREFIX) { // PREFIX
|
||||
CustomCommands::runCmd(fullChat, sock);
|
||||
@ -281,7 +267,7 @@ void ChatManager::groupChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
std::string logLine = "[GroupChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
||||
std::cout << logLine << std::endl;
|
||||
ChatManager::dump.push_back(logLine);
|
||||
dump.push_back(logLine);
|
||||
|
||||
// send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, resp);
|
||||
@ -293,7 +279,7 @@ void ChatManager::groupChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
GroupManager::sendToGroup(otherPlr, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC));
|
||||
}
|
||||
|
||||
void ChatManager::groupMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void groupMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -304,11 +290,11 @@ void ChatManager::groupMenuChatHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (otherPlr == nullptr)
|
||||
return;
|
||||
|
||||
std::string fullChat = ChatManager::sanitizeText(U16toU8(chat->szFreeChat));
|
||||
std::string fullChat = sanitizeText(U16toU8(chat->szFreeChat));
|
||||
std::string logLine = "[GroupMenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
|
||||
|
||||
std::cout << logLine << std::endl;
|
||||
ChatManager::dump.push_back(logLine);
|
||||
dump.push_back(logLine);
|
||||
|
||||
// send to client
|
||||
INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, resp);
|
||||
@ -343,3 +329,19 @@ std::string ChatManager::sanitizeText(std::string text, bool allowNewlines) {
|
||||
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
void ChatManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_FREECHAT_MESSAGE, chatHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_AVATAR_EMOTES_CHAT, emoteHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_MENUCHAT_MESSAGE, menuChatHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_FREECHAT_MESSAGE, buddyChatHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_BUDDY_MENUCHAT_MESSAGE, buddyMenuChatHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT, tradeChatHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE, groupChatHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE, groupMenuChatHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_GM_REQ_PC_ANNOUNCE, announcementHandler);
|
||||
}
|
||||
|
@ -8,19 +8,6 @@ namespace ChatManager {
|
||||
extern std::vector<std::string> dump;
|
||||
void init();
|
||||
|
||||
void chatHandler(CNSocket* sock, CNPacketData* data);
|
||||
void emoteHandler(CNSocket* sock, CNPacketData* data);
|
||||
void menuChatHandler(CNSocket* sock, CNPacketData* data);
|
||||
void announcementHandler(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void buddyChatHandler(CNSocket* sock, CNPacketData* data);
|
||||
void buddyMenuChatHandler(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void tradeChatHandler(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void groupChatHandler(CNSocket* sock, CNPacketData* data);
|
||||
void groupMenuChatHandler(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void sendServerMessage(CNSocket* sock, std::string msg); // uses MOTD
|
||||
std::string sanitizeText(std::string text, bool allowNewlines=false);
|
||||
}
|
||||
|
@ -4,11 +4,11 @@
|
||||
#include "settings.hpp"
|
||||
#include "Combat.hpp"
|
||||
|
||||
using namespace ChunkManager;
|
||||
|
||||
std::map<ChunkPos, Chunk*> ChunkManager::chunks;
|
||||
|
||||
void ChunkManager::init() {} // stubbed
|
||||
|
||||
void ChunkManager::newChunk(ChunkPos pos) {
|
||||
static void newChunk(ChunkPos pos) {
|
||||
if (chunkExists(pos)) {
|
||||
std::cout << "[WARN] Tried to create a chunk that already exists\n";
|
||||
return;
|
||||
@ -31,7 +31,7 @@ void ChunkManager::newChunk(ChunkPos pos) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkManager::deleteChunk(ChunkPos pos) {
|
||||
static void deleteChunk(ChunkPos pos) {
|
||||
if (!chunkExists(pos)) {
|
||||
std::cout << "[WARN] Tried to delete a chunk that doesn't exist\n";
|
||||
return;
|
||||
@ -53,78 +53,6 @@ void ChunkManager::deleteChunk(ChunkPos pos) {
|
||||
delete chunk; // free from memory
|
||||
}
|
||||
|
||||
void ChunkManager::updatePlayerChunk(CNSocket* sock, ChunkPos from, ChunkPos to) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// if the new chunk doesn't exist, make it first
|
||||
if (!ChunkManager::chunkExists(to))
|
||||
newChunk(to);
|
||||
|
||||
// move to other chunk's player set
|
||||
untrackPlayer(from, sock); // this will delete the chunk if it's empty
|
||||
trackPlayer(to, sock);
|
||||
|
||||
// calculate viewable chunks from both points
|
||||
std::set<Chunk*> oldViewables = getViewableChunks(from);
|
||||
std::set<Chunk*> newViewables = getViewableChunks(to);
|
||||
std::set<Chunk*> toExit, toEnter;
|
||||
|
||||
/*
|
||||
* Calculate diffs. This is done to prevent phasing on chunk borders.
|
||||
* toExit will contain old viewables - new viewables, so the player will only be exited in chunks that are out of sight.
|
||||
* toEnter contains the opposite: new viewables - old viewables, chunks where we previously weren't visible from before.
|
||||
*/
|
||||
std::set_difference(oldViewables.begin(), oldViewables.end(), newViewables.begin(), newViewables.end(),
|
||||
std::inserter(toExit, toExit.end())); // chunks we must be EXITed from (old - new)
|
||||
std::set_difference(newViewables.begin(), newViewables.end(), oldViewables.begin(), oldViewables.end(),
|
||||
std::inserter(toEnter, toEnter.end())); // chunks we must be ENTERed into (new - old)
|
||||
|
||||
// update views
|
||||
removePlayerFromChunks(toExit, sock);
|
||||
addPlayerToChunks(toEnter, sock);
|
||||
|
||||
plr->chunkPos = to; // update cached chunk position
|
||||
// updated cached viewable chunks
|
||||
plr->viewableChunks->clear();
|
||||
plr->viewableChunks->insert(newViewables.begin(), newViewables.end());
|
||||
}
|
||||
|
||||
void ChunkManager::updateNPCChunk(int32_t id, ChunkPos from, ChunkPos to) {
|
||||
BaseNPC* npc = NPCManager::NPCs[id];
|
||||
|
||||
// if the new chunk doesn't exist, make it first
|
||||
if (!ChunkManager::chunkExists(to))
|
||||
newChunk(to);
|
||||
|
||||
// move to other chunk's player set
|
||||
untrackNPC(from, id); // this will delete the chunk if it's empty
|
||||
trackNPC(to, id);
|
||||
|
||||
// calculate viewable chunks from both points
|
||||
std::set<Chunk*> oldViewables = getViewableChunks(from);
|
||||
std::set<Chunk*> newViewables = getViewableChunks(to);
|
||||
std::set<Chunk*> toExit, toEnter;
|
||||
|
||||
/*
|
||||
* Calculate diffs. This is done to prevent phasing on chunk borders.
|
||||
* toExit will contain old viewables - new viewables, so the player will only be exited in chunks that are out of sight.
|
||||
* toEnter contains the opposite: new viewables - old viewables, chunks where we previously weren't visible from before.
|
||||
*/
|
||||
std::set_difference(oldViewables.begin(), oldViewables.end(), newViewables.begin(), newViewables.end(),
|
||||
std::inserter(toExit, toExit.end())); // chunks we must be EXITed from (old - new)
|
||||
std::set_difference(newViewables.begin(), newViewables.end(), oldViewables.begin(), oldViewables.end(),
|
||||
std::inserter(toEnter, toEnter.end())); // chunks we must be ENTERed into (new - old)
|
||||
|
||||
// update views
|
||||
removeNPCFromChunks(toExit, id);
|
||||
addNPCToChunks(toEnter, id);
|
||||
|
||||
npc->chunkPos = to; // update cached chunk position
|
||||
// updated cached viewable chunks
|
||||
npc->viewableChunks->clear();
|
||||
npc->viewableChunks->insert(newViewables.begin(), newViewables.end());
|
||||
}
|
||||
|
||||
void ChunkManager::trackPlayer(ChunkPos chunkPos, CNSocket* sock) {
|
||||
if (!chunkExists(chunkPos))
|
||||
return; // shouldn't happen
|
||||
@ -371,7 +299,7 @@ void ChunkManager::removeNPCFromChunks(std::set<Chunk*> chnks, int32_t id) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkManager::emptyChunk(ChunkPos chunkPos) {
|
||||
static void emptyChunk(ChunkPos chunkPos) {
|
||||
if (!chunkExists(chunkPos)) {
|
||||
std::cout << "[WARN] Tried to empty chunk that doesn't exist\n";
|
||||
return; // chunk doesn't exist, we don't need to do anything
|
||||
@ -392,6 +320,78 @@ void ChunkManager::emptyChunk(ChunkPos chunkPos) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkManager::updatePlayerChunk(CNSocket* sock, ChunkPos from, ChunkPos to) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// if the new chunk doesn't exist, make it first
|
||||
if (!chunkExists(to))
|
||||
newChunk(to);
|
||||
|
||||
// move to other chunk's player set
|
||||
untrackPlayer(from, sock); // this will delete the chunk if it's empty
|
||||
trackPlayer(to, sock);
|
||||
|
||||
// calculate viewable chunks from both points
|
||||
std::set<Chunk*> oldViewables = getViewableChunks(from);
|
||||
std::set<Chunk*> newViewables = getViewableChunks(to);
|
||||
std::set<Chunk*> toExit, toEnter;
|
||||
|
||||
/*
|
||||
* Calculate diffs. This is done to prevent phasing on chunk borders.
|
||||
* toExit will contain old viewables - new viewables, so the player will only be exited in chunks that are out of sight.
|
||||
* toEnter contains the opposite: new viewables - old viewables, chunks where we previously weren't visible from before.
|
||||
*/
|
||||
std::set_difference(oldViewables.begin(), oldViewables.end(), newViewables.begin(), newViewables.end(),
|
||||
std::inserter(toExit, toExit.end())); // chunks we must be EXITed from (old - new)
|
||||
std::set_difference(newViewables.begin(), newViewables.end(), oldViewables.begin(), oldViewables.end(),
|
||||
std::inserter(toEnter, toEnter.end())); // chunks we must be ENTERed into (new - old)
|
||||
|
||||
// update views
|
||||
removePlayerFromChunks(toExit, sock);
|
||||
addPlayerToChunks(toEnter, sock);
|
||||
|
||||
plr->chunkPos = to; // update cached chunk position
|
||||
// updated cached viewable chunks
|
||||
plr->viewableChunks->clear();
|
||||
plr->viewableChunks->insert(newViewables.begin(), newViewables.end());
|
||||
}
|
||||
|
||||
void ChunkManager::updateNPCChunk(int32_t id, ChunkPos from, ChunkPos to) {
|
||||
BaseNPC* npc = NPCManager::NPCs[id];
|
||||
|
||||
// if the new chunk doesn't exist, make it first
|
||||
if (!chunkExists(to))
|
||||
newChunk(to);
|
||||
|
||||
// move to other chunk's player set
|
||||
untrackNPC(from, id); // this will delete the chunk if it's empty
|
||||
trackNPC(to, id);
|
||||
|
||||
// calculate viewable chunks from both points
|
||||
std::set<Chunk*> oldViewables = getViewableChunks(from);
|
||||
std::set<Chunk*> newViewables = getViewableChunks(to);
|
||||
std::set<Chunk*> toExit, toEnter;
|
||||
|
||||
/*
|
||||
* Calculate diffs. This is done to prevent phasing on chunk borders.
|
||||
* toExit will contain old viewables - new viewables, so the player will only be exited in chunks that are out of sight.
|
||||
* toEnter contains the opposite: new viewables - old viewables, chunks where we previously weren't visible from before.
|
||||
*/
|
||||
std::set_difference(oldViewables.begin(), oldViewables.end(), newViewables.begin(), newViewables.end(),
|
||||
std::inserter(toExit, toExit.end())); // chunks we must be EXITed from (old - new)
|
||||
std::set_difference(newViewables.begin(), newViewables.end(), oldViewables.begin(), oldViewables.end(),
|
||||
std::inserter(toEnter, toEnter.end())); // chunks we must be ENTERed into (new - old)
|
||||
|
||||
// update views
|
||||
removeNPCFromChunks(toExit, id);
|
||||
addNPCToChunks(toEnter, id);
|
||||
|
||||
npc->chunkPos = to; // update cached chunk position
|
||||
// updated cached viewable chunks
|
||||
npc->viewableChunks->clear();
|
||||
npc->viewableChunks->insert(newViewables.begin(), newViewables.end());
|
||||
}
|
||||
|
||||
bool ChunkManager::chunkExists(ChunkPos chunk) {
|
||||
return chunks.find(chunk) != chunks.end();
|
||||
}
|
||||
@ -424,10 +424,10 @@ std::set<Chunk*> ChunkManager::getViewableChunks(ChunkPos chunk) {
|
||||
/*
|
||||
* inefficient algorithm to get all chunks from a specific instance
|
||||
*/
|
||||
std::vector<ChunkPos> ChunkManager::getChunksInMap(uint64_t mapNum) {
|
||||
static std::vector<ChunkPos> getChunksInMap(uint64_t mapNum) {
|
||||
std::vector<ChunkPos> chnks;
|
||||
|
||||
for (auto it = ChunkManager::chunks.begin(); it != ChunkManager::chunks.end(); it++) {
|
||||
for (auto it = chunks.begin(); it != chunks.end(); it++) {
|
||||
if (std::get<2>(it->first) == mapNum) {
|
||||
chnks.push_back(it->first);
|
||||
}
|
||||
@ -451,8 +451,8 @@ bool ChunkManager::inPopulatedChunks(std::set<Chunk*>* chnks) {
|
||||
|
||||
void ChunkManager::createInstance(uint64_t instanceID) {
|
||||
|
||||
std::vector<ChunkPos> templateChunks = ChunkManager::getChunksInMap(MAPNUM(instanceID)); // base instance chunks
|
||||
if (ChunkManager::getChunksInMap(instanceID).size() == 0) { // only instantiate if the instance doesn't exist already
|
||||
std::vector<ChunkPos> templateChunks = getChunksInMap(MAPNUM(instanceID)); // base instance chunks
|
||||
if (getChunksInMap(instanceID).size() == 0) { // only instantiate if the instance doesn't exist already
|
||||
std::cout << "Creating instance " << instanceID << std::endl;
|
||||
for (ChunkPos &coords : templateChunks) {
|
||||
for (int npcID : chunks[coords]->NPCs) {
|
||||
@ -508,9 +508,9 @@ void ChunkManager::createInstance(uint64_t instanceID) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkManager::destroyInstance(uint64_t instanceID) {
|
||||
static void destroyInstance(uint64_t instanceID) {
|
||||
|
||||
std::vector<ChunkPos> instanceChunks = ChunkManager::getChunksInMap(instanceID);
|
||||
std::vector<ChunkPos> instanceChunks = getChunksInMap(instanceID);
|
||||
std::cout << "Deleting instance " << instanceID << " (" << instanceChunks.size() << " chunks)" << std::endl;
|
||||
for (ChunkPos& coords : instanceChunks) {
|
||||
emptyChunk(coords);
|
||||
|
@ -22,14 +22,8 @@ enum {
|
||||
};
|
||||
|
||||
namespace ChunkManager {
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
extern std::map<ChunkPos, Chunk*> chunks;
|
||||
|
||||
void newChunk(ChunkPos pos);
|
||||
void deleteChunk(ChunkPos pos);
|
||||
|
||||
void updatePlayerChunk(CNSocket* sock, ChunkPos from, ChunkPos to);
|
||||
void updateNPCChunk(int32_t id, ChunkPos from, ChunkPos to);
|
||||
|
||||
@ -44,13 +38,10 @@ namespace ChunkManager {
|
||||
void removeNPCFromChunks(std::set<Chunk*> chnks, int32_t id);
|
||||
|
||||
bool chunkExists(ChunkPos chunk);
|
||||
void emptyChunk(ChunkPos chunkPos);
|
||||
ChunkPos chunkPosAt(int posX, int posY, uint64_t instanceID);
|
||||
std::set<Chunk*> getViewableChunks(ChunkPos chunkPos);
|
||||
|
||||
std::vector<ChunkPos> getChunksInMap(uint64_t mapNum);
|
||||
bool inPopulatedChunks(std::set<Chunk*>* chnks);
|
||||
void createInstance(uint64_t);
|
||||
void destroyInstance(uint64_t);
|
||||
void destroyInstanceIfEmpty(uint64_t);
|
||||
}
|
||||
|
234
src/Combat.cpp
234
src/Combat.cpp
@ -11,25 +11,51 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Combat;
|
||||
|
||||
/// Player Id -> Bullet Id -> Bullet
|
||||
std::map<int32_t, std::map<int8_t, Bullet>> Combat::Bullets;
|
||||
|
||||
void Combat::init() {
|
||||
REGISTER_SHARD_TIMER(playerTick, 2000);
|
||||
static std::pair<int,int> getDamage(int attackPower, int defensePower, bool shouldCrit,
|
||||
bool batteryBoost, int attackerStyle,
|
||||
int defenderStyle, int difficulty) {
|
||||
std::pair<int,int> ret = {0, 1};
|
||||
if (attackPower + defensePower * 2 == 0)
|
||||
return ret;
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ATTACK_NPCs, pcAttackNpcs);
|
||||
// base calculation
|
||||
int damage = attackPower * attackPower / (attackPower + defensePower);
|
||||
damage = std::max(10 + attackPower / 10, damage - (defensePower - attackPower / 6) * difficulty / 100);
|
||||
damage = damage * (rand() % 40 + 80) / 100;
|
||||
|
||||
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);
|
||||
// Adaptium/Blastons/Cosmix
|
||||
if (attackerStyle != -1 && defenderStyle != -1 && attackerStyle != defenderStyle) {
|
||||
if (attackerStyle - defenderStyle == 2)
|
||||
defenderStyle += 3;
|
||||
if (defenderStyle - attackerStyle == 2)
|
||||
defenderStyle -= 3;
|
||||
if (attackerStyle < defenderStyle)
|
||||
damage = damage * 5 / 4;
|
||||
else
|
||||
damage = damage * 4 / 5;
|
||||
}
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GRENADE_STYLE_FIRE, grenadeFire);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ROCKET_STYLE_FIRE, rocketFire);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ROCKET_STYLE_HIT, projectileHit);
|
||||
// weapon boosts
|
||||
if (batteryBoost)
|
||||
damage = damage * 5 / 4;
|
||||
|
||||
ret.first = damage;
|
||||
ret.second = 1;
|
||||
|
||||
if (shouldCrit && rand() % 20 == 0) {
|
||||
ret.first *= 2; // critical hit
|
||||
ret.second = 2;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Combat::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
||||
static void pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
|
||||
sP_CL2FE_REQ_PC_ATTACK_NPCs* pkt = (sP_CL2FE_REQ_PC_ATTACK_NPCs*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
@ -271,7 +297,7 @@ void Combat::killMob(CNSocket *sock, Mob *mob) {
|
||||
}
|
||||
}
|
||||
|
||||
void Combat::combatBegin(CNSocket *sock, CNPacketData *data) {
|
||||
static void combatBegin(CNSocket *sock, CNPacketData *data) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
plr->inCombat = true;
|
||||
@ -286,7 +312,7 @@ void Combat::combatBegin(CNSocket *sock, CNPacketData *data) {
|
||||
PlayerManager::sendToViewable(sock, (void*)&resp, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
|
||||
}
|
||||
|
||||
void Combat::combatEnd(CNSocket *sock, CNPacketData *data) {
|
||||
static void combatEnd(CNSocket *sock, CNPacketData *data) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (plr != nullptr) {
|
||||
@ -295,7 +321,7 @@ void Combat::combatEnd(CNSocket *sock, CNPacketData *data) {
|
||||
}
|
||||
}
|
||||
|
||||
void Combat::dotDamageOnOff(CNSocket *sock, CNPacketData *data) {
|
||||
static void dotDamageOnOff(CNSocket *sock, CNPacketData *data) {
|
||||
sP_CL2FE_DOT_DAMAGE_ONOFF *pkt = (sP_CL2FE_DOT_DAMAGE_ONOFF*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
@ -312,7 +338,7 @@ void Combat::dotDamageOnOff(CNSocket *sock, CNPacketData *data) {
|
||||
sock->sendPacket((void*)&pkt1, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
|
||||
}
|
||||
|
||||
void Combat::dealGooDamage(CNSocket *sock, int amount) {
|
||||
static void dealGooDamage(CNSocket *sock, int amount) {
|
||||
size_t resplen = sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK) + sizeof(sSkillResult_DotDamage);
|
||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||
uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
|
||||
@ -358,46 +384,7 @@ void Combat::dealGooDamage(CNSocket *sock, int amount) {
|
||||
PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen);
|
||||
}
|
||||
|
||||
std::pair<int,int> Combat::getDamage(int attackPower, int defensePower, bool shouldCrit,
|
||||
bool batteryBoost, int attackerStyle,
|
||||
int defenderStyle, int difficulty) {
|
||||
std::pair<int,int> ret = {0, 1};
|
||||
if (attackPower + defensePower * 2 == 0)
|
||||
return ret;
|
||||
|
||||
// base calculation
|
||||
int damage = attackPower * attackPower / (attackPower + defensePower);
|
||||
damage = std::max(10 + attackPower / 10, damage - (defensePower - attackPower / 6) * difficulty / 100);
|
||||
damage = damage * (rand() % 40 + 80) / 100;
|
||||
|
||||
// Adaptium/Blastons/Cosmix
|
||||
if (attackerStyle != -1 && defenderStyle != -1 && attackerStyle != defenderStyle) {
|
||||
if (attackerStyle - defenderStyle == 2)
|
||||
defenderStyle += 3;
|
||||
if (defenderStyle - attackerStyle == 2)
|
||||
defenderStyle -= 3;
|
||||
if (attackerStyle < defenderStyle)
|
||||
damage = damage * 5 / 4;
|
||||
else
|
||||
damage = damage * 4 / 5;
|
||||
}
|
||||
|
||||
// weapon boosts
|
||||
if (batteryBoost)
|
||||
damage = damage * 5 / 4;
|
||||
|
||||
ret.first = damage;
|
||||
ret.second = 1;
|
||||
|
||||
if (shouldCrit && rand() % 20 == 0) {
|
||||
ret.first *= 2; // critical hit
|
||||
ret.second = 2;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Combat::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
||||
static void 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);
|
||||
|
||||
@ -514,65 +501,7 @@ void Combat::pcAttackChars(CNSocket *sock, CNPacketData *data) {
|
||||
PlayerManager::sendToViewable(sock, (void*)respbuf, P_FE2CL_PC_ATTACK_CHARs, resplen);
|
||||
}
|
||||
|
||||
void Combat::grenadeFire(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_PC_GRENADE_STYLE_FIRE* grenade = (sP_CL2FE_REQ_PC_GRENADE_STYLE_FIRE*)data->buf;
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC, resp);
|
||||
resp.iToX = grenade->iToX;
|
||||
resp.iToY = grenade->iToY;
|
||||
resp.iToZ = grenade->iToZ;
|
||||
|
||||
resp.iBulletID = addBullet(plr, true);
|
||||
resp.iBatteryW = plr->batteryW;
|
||||
|
||||
// 1 means grenade
|
||||
resp.Bullet.iID = 1;
|
||||
sock->sendPacket(&resp, P_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC, sizeof(sP_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC));
|
||||
|
||||
// send packet to nearby players
|
||||
INITSTRUCT(sP_FE2CL_PC_GRENADE_STYLE_FIRE, toOthers);
|
||||
toOthers.iPC_ID = plr->iID;
|
||||
toOthers.iToX = resp.iToX;
|
||||
toOthers.iToY = resp.iToY;
|
||||
toOthers.iToZ = resp.iToZ;
|
||||
toOthers.iBulletID = resp.iBulletID;
|
||||
toOthers.Bullet.iID = resp.Bullet.iID;
|
||||
|
||||
PlayerManager::sendToViewable(sock, &toOthers, P_FE2CL_PC_GRENADE_STYLE_FIRE, sizeof(sP_FE2CL_PC_GRENADE_STYLE_FIRE));
|
||||
}
|
||||
|
||||
void Combat::rocketFire(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_PC_ROCKET_STYLE_FIRE* rocket = (sP_CL2FE_REQ_PC_ROCKET_STYLE_FIRE*)data->buf;
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// We should be sending back rocket succ packet, but it doesn't work, and this one works
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC, resp);
|
||||
resp.iToX = rocket->iToX;
|
||||
resp.iToY = rocket->iToY;
|
||||
// rocket->iToZ is broken, this seems like a good height
|
||||
resp.iToZ = plr->z + 100;
|
||||
|
||||
resp.iBulletID = addBullet(plr, false);
|
||||
// we have to send it weapon id
|
||||
resp.Bullet.iID = plr->Equip[0].iID;
|
||||
resp.iBatteryW = plr->batteryW;
|
||||
|
||||
sock->sendPacket(&resp, P_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC, sizeof(sP_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC));
|
||||
|
||||
// send packet to nearby players
|
||||
INITSTRUCT(sP_FE2CL_PC_GRENADE_STYLE_FIRE, toOthers);
|
||||
toOthers.iPC_ID = plr->iID;
|
||||
toOthers.iToX = resp.iToX;
|
||||
toOthers.iToY = resp.iToY;
|
||||
toOthers.iToZ = resp.iToZ;
|
||||
toOthers.iBulletID = resp.iBulletID;
|
||||
toOthers.Bullet.iID = resp.Bullet.iID;
|
||||
|
||||
PlayerManager::sendToViewable(sock, &toOthers, P_FE2CL_PC_GRENADE_STYLE_FIRE, sizeof(sP_FE2CL_PC_GRENADE_STYLE_FIRE));
|
||||
}
|
||||
|
||||
int8_t Combat::addBullet(Player* plr, bool isGrenade) {
|
||||
static int8_t addBullet(Player* plr, bool isGrenade) {
|
||||
|
||||
int8_t findId = 0;
|
||||
if (Bullets.find(plr->iID) != Bullets.end()) {
|
||||
@ -605,7 +534,65 @@ int8_t Combat::addBullet(Player* plr, bool isGrenade) {
|
||||
return findId;
|
||||
}
|
||||
|
||||
void Combat::projectileHit(CNSocket* sock, CNPacketData* data) {
|
||||
static void grenadeFire(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_PC_GRENADE_STYLE_FIRE* grenade = (sP_CL2FE_REQ_PC_GRENADE_STYLE_FIRE*)data->buf;
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC, resp);
|
||||
resp.iToX = grenade->iToX;
|
||||
resp.iToY = grenade->iToY;
|
||||
resp.iToZ = grenade->iToZ;
|
||||
|
||||
resp.iBulletID = addBullet(plr, true);
|
||||
resp.iBatteryW = plr->batteryW;
|
||||
|
||||
// 1 means grenade
|
||||
resp.Bullet.iID = 1;
|
||||
sock->sendPacket(&resp, P_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC, sizeof(sP_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC));
|
||||
|
||||
// send packet to nearby players
|
||||
INITSTRUCT(sP_FE2CL_PC_GRENADE_STYLE_FIRE, toOthers);
|
||||
toOthers.iPC_ID = plr->iID;
|
||||
toOthers.iToX = resp.iToX;
|
||||
toOthers.iToY = resp.iToY;
|
||||
toOthers.iToZ = resp.iToZ;
|
||||
toOthers.iBulletID = resp.iBulletID;
|
||||
toOthers.Bullet.iID = resp.Bullet.iID;
|
||||
|
||||
PlayerManager::sendToViewable(sock, &toOthers, P_FE2CL_PC_GRENADE_STYLE_FIRE, sizeof(sP_FE2CL_PC_GRENADE_STYLE_FIRE));
|
||||
}
|
||||
|
||||
static void rocketFire(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_PC_ROCKET_STYLE_FIRE* rocket = (sP_CL2FE_REQ_PC_ROCKET_STYLE_FIRE*)data->buf;
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// We should be sending back rocket succ packet, but it doesn't work, and this one works
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC, resp);
|
||||
resp.iToX = rocket->iToX;
|
||||
resp.iToY = rocket->iToY;
|
||||
// rocket->iToZ is broken, this seems like a good height
|
||||
resp.iToZ = plr->z + 100;
|
||||
|
||||
resp.iBulletID = addBullet(plr, false);
|
||||
// we have to send it weapon id
|
||||
resp.Bullet.iID = plr->Equip[0].iID;
|
||||
resp.iBatteryW = plr->batteryW;
|
||||
|
||||
sock->sendPacket(&resp, P_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC, sizeof(sP_FE2CL_REP_PC_GRENADE_STYLE_FIRE_SUCC));
|
||||
|
||||
// send packet to nearby players
|
||||
INITSTRUCT(sP_FE2CL_PC_GRENADE_STYLE_FIRE, toOthers);
|
||||
toOthers.iPC_ID = plr->iID;
|
||||
toOthers.iToX = resp.iToX;
|
||||
toOthers.iToY = resp.iToY;
|
||||
toOthers.iToZ = resp.iToZ;
|
||||
toOthers.iBulletID = resp.iBulletID;
|
||||
toOthers.Bullet.iID = resp.Bullet.iID;
|
||||
|
||||
PlayerManager::sendToViewable(sock, &toOthers, P_FE2CL_PC_GRENADE_STYLE_FIRE, sizeof(sP_FE2CL_PC_GRENADE_STYLE_FIRE));
|
||||
}
|
||||
|
||||
static void projectileHit(CNSocket* sock, CNPacketData* data) {
|
||||
sP_CL2FE_REQ_PC_ROCKET_STYLE_HIT* pkt = (sP_CL2FE_REQ_PC_ROCKET_STYLE_HIT*)data->buf;
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
@ -699,7 +686,7 @@ void Combat::projectileHit(CNSocket* sock, CNPacketData* data) {
|
||||
Bullets[plr->iID].erase(resp->iBulletID);
|
||||
}
|
||||
|
||||
void Combat::playerTick(CNServer *serv, time_t currTime) {
|
||||
static void playerTick(CNServer *serv, time_t currTime) {
|
||||
static time_t lastHealTime = 0;
|
||||
|
||||
for (auto& pair : PlayerManager::players) {
|
||||
@ -780,3 +767,18 @@ void Combat::playerTick(CNServer *serv, time_t currTime) {
|
||||
if (currTime - lastHealTime >= 4000)
|
||||
lastHealTime = currTime;
|
||||
}
|
||||
|
||||
void Combat::init() {
|
||||
REGISTER_SHARD_TIMER(playerTick, 2000);
|
||||
|
||||
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);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ATTACK_CHARs, pcAttackChars);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GRENADE_STYLE_FIRE, grenadeFire);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ROCKET_STYLE_FIRE, rocketFire);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ROCKET_STYLE_HIT, projectileHit);
|
||||
}
|
||||
|
@ -23,25 +23,8 @@ namespace Combat {
|
||||
extern std::map<int32_t, std::map<int8_t, Bullet>> Bullets;
|
||||
|
||||
void init();
|
||||
void playerTick(CNServer*, time_t);
|
||||
|
||||
void pcAttackNpcs(CNSocket *sock, CNPacketData *data);
|
||||
void combatBegin(CNSocket *sock, CNPacketData *data);
|
||||
void combatEnd(CNSocket *sock, CNPacketData *data);
|
||||
void dotDamageOnOff(CNSocket *sock, CNPacketData *data);
|
||||
void dealGooDamage(CNSocket *sock, int amount);
|
||||
|
||||
void npcAttackPc(Mob *mob, time_t currTime);
|
||||
int hitMob(CNSocket *sock, Mob *mob, int damage);
|
||||
void killMob(CNSocket *sock, Mob *mob);
|
||||
|
||||
std::pair<int,int> lerp(int, int, int, int, int);
|
||||
std::pair<int,int> getDamage(int, int, bool, bool, int, int, int);
|
||||
|
||||
void pcAttackChars(CNSocket *sock, CNPacketData *data);
|
||||
void grenadeFire(CNSocket* sock, CNPacketData* data);
|
||||
void rocketFire(CNSocket* sock, CNPacketData* data);
|
||||
void projectileHit(CNSocket* sock, CNPacketData* data);
|
||||
/// returns bullet id
|
||||
int8_t addBullet(Player* plr, bool isGrenade);
|
||||
}
|
||||
|
@ -1,7 +1,18 @@
|
||||
#include "Email.hpp"
|
||||
|
||||
#include "CNProtocol.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "CNShardServer.hpp"
|
||||
|
||||
#include "db/Database.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "ItemManager.hpp"
|
||||
#include "ChatManager.hpp"
|
||||
|
||||
using namespace Email;
|
||||
|
||||
// New email notification
|
||||
void Email::emailUpdateCheck(CNSocket* sock, CNPacketData* data) {
|
||||
static void emailUpdateCheck(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_EMAIL_UPDATE_CHECK))
|
||||
return; // malformed packet
|
||||
|
||||
@ -11,7 +22,7 @@ void Email::emailUpdateCheck(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Retrieve page of emails
|
||||
void Email::emailReceivePageList(CNSocket* sock, CNPacketData* data) {
|
||||
static void emailReceivePageList(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_RECV_EMAIL_PAGE_LIST))
|
||||
return; // malformed packet
|
||||
|
||||
@ -41,7 +52,7 @@ void Email::emailReceivePageList(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Read individual email
|
||||
void Email::emailRead(CNSocket* sock, CNPacketData* data) {
|
||||
static void emailRead(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_READ_EMAIL))
|
||||
return; // malformed packet
|
||||
|
||||
@ -66,7 +77,7 @@ void Email::emailRead(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Retrieve attached taros from email
|
||||
void Email::emailReceiveTaros(CNSocket* sock, CNPacketData* data) {
|
||||
static void emailReceiveTaros(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_RECV_EMAIL_CANDY))
|
||||
return; // malformed packet
|
||||
|
||||
@ -89,7 +100,7 @@ void Email::emailReceiveTaros(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Retrieve individual attached item from email
|
||||
void Email::emailReceiveItemSingle(CNSocket* sock, CNPacketData* data) {
|
||||
static void emailReceiveItemSingle(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_RECV_EMAIL_ITEM))
|
||||
return; // malformed packet
|
||||
|
||||
@ -128,7 +139,7 @@ void Email::emailReceiveItemSingle(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Retrieve all attached items from email
|
||||
void Email::emailReceiveItemAll(CNSocket* sock, CNPacketData* data) {
|
||||
static void emailReceiveItemAll(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_RECV_EMAIL_ITEM_ALL))
|
||||
return; // malformed packet
|
||||
|
||||
@ -173,7 +184,7 @@ void Email::emailReceiveItemAll(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Delete an email
|
||||
void Email::emailDelete(CNSocket* sock, CNPacketData* data) {
|
||||
static void emailDelete(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_DELETE_EMAIL))
|
||||
return; // malformed packet
|
||||
|
||||
@ -190,7 +201,7 @@ void Email::emailDelete(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// Send an email
|
||||
void Email::emailSend(CNSocket* sock, CNPacketData* data) {
|
||||
static void emailSend(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_SEND_EMAIL))
|
||||
return; // malformed packet
|
||||
|
||||
|
@ -1,23 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "CNProtocol.hpp"
|
||||
#include "CNStructs.hpp"
|
||||
#include "CNShardServer.hpp"
|
||||
|
||||
#include "db/Database.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
#include "ItemManager.hpp"
|
||||
#include "ChatManager.hpp"
|
||||
|
||||
namespace Email {
|
||||
void init();
|
||||
|
||||
void emailUpdateCheck(CNSocket* sock, CNPacketData* data);
|
||||
void emailReceivePageList(CNSocket* sock, CNPacketData* data);
|
||||
void emailRead(CNSocket* sock, CNPacketData* data);
|
||||
void emailReceiveTaros(CNSocket* sock, CNPacketData* data);
|
||||
void emailReceiveItemSingle(CNSocket* sock, CNPacketData* data);
|
||||
void emailReceiveItemAll(CNSocket* sock, CNPacketData* data);
|
||||
void emailDelete(CNSocket* sock, CNPacketData* data);
|
||||
void emailSend(CNSocket* sock, CNPacketData* data);
|
||||
}
|
||||
|
@ -10,14 +10,9 @@
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
void GroupManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE, requestGroup);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE, refuseGroup);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_JOIN, joinGroup);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_LEAVE, leaveGroup);
|
||||
}
|
||||
using namespace GroupManager;
|
||||
|
||||
void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) {
|
||||
static void requestGroup(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GROUP_INVITE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -53,7 +48,7 @@ void GroupManager::requestGroup(CNSocket* sock, CNPacketData* data) {
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE, sizeof(sP_FE2CL_PC_GROUP_INVITE));
|
||||
}
|
||||
|
||||
void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) {
|
||||
static void refuseGroup(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GROUP_INVITE_REFUSE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -73,7 +68,7 @@ void GroupManager::refuseGroup(CNSocket* sock, CNPacketData* data) {
|
||||
otherSock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE_REFUSE, sizeof(sP_FE2CL_PC_GROUP_INVITE_REFUSE));
|
||||
}
|
||||
|
||||
void GroupManager::joinGroup(CNSocket* sock, CNPacketData* data) {
|
||||
static void joinGroup(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GROUP_JOIN))
|
||||
return; // malformed packet
|
||||
|
||||
@ -152,7 +147,7 @@ void GroupManager::joinGroup(CNSocket* sock, CNPacketData* data) {
|
||||
sendToGroup(otherPlr, (void*)&respbuf, P_FE2CL_PC_GROUP_JOIN, resplen);
|
||||
}
|
||||
|
||||
void GroupManager::leaveGroup(CNSocket* sock, CNPacketData* data) {
|
||||
static void leaveGroup(CNSocket* sock, CNPacketData* data) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
groupKickPlayer(plr);
|
||||
}
|
||||
@ -219,6 +214,20 @@ void GroupManager::groupTickInfo(Player* plr) {
|
||||
sendToGroup(plr, (void*)&respbuf, P_FE2CL_PC_GROUP_MEMBER_INFO, resplen);
|
||||
}
|
||||
|
||||
static void groupUnbuff(Player* plr) {
|
||||
for (int i = 0; i < plr->groupCnt; i++) {
|
||||
for (int n = 0; n < plr->groupCnt; n++) {
|
||||
if (i == n)
|
||||
continue;
|
||||
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]);
|
||||
CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[n]);
|
||||
|
||||
NanoManager::applyBuff(sock, otherPlr->Nanos[otherPlr->activeNano].iSkillID, 2, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GroupManager::groupKickPlayer(Player* plr) {
|
||||
// if you are the group leader, destroy your own group and kick everybody
|
||||
if (plr->iID == plr->iIDGroup) {
|
||||
@ -304,20 +313,6 @@ void GroupManager::groupKickPlayer(Player* plr) {
|
||||
sock->sendPacket((void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC));
|
||||
}
|
||||
|
||||
void GroupManager::groupUnbuff(Player* plr) {
|
||||
for (int i = 0; i < plr->groupCnt; i++) {
|
||||
for (int n = 0; n < plr->groupCnt; n++) {
|
||||
if (i == n)
|
||||
continue;
|
||||
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]);
|
||||
CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[n]);
|
||||
|
||||
NanoManager::applyBuff(sock, otherPlr->Nanos[otherPlr->activeNano].iSkillID, 2, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int GroupManager::getGroupFlags(Player* plr) {
|
||||
int bitFlag = 0;
|
||||
|
||||
@ -332,3 +327,10 @@ int GroupManager::getGroupFlags(Player* plr) {
|
||||
|
||||
return bitFlag;
|
||||
}
|
||||
|
||||
void GroupManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE, requestGroup);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE, refuseGroup);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_JOIN, joinGroup);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_LEAVE, leaveGroup);
|
||||
}
|
||||
|
@ -11,13 +11,8 @@
|
||||
namespace GroupManager {
|
||||
void init();
|
||||
|
||||
void requestGroup(CNSocket* sock, CNPacketData* data);
|
||||
void refuseGroup(CNSocket* sock, CNPacketData* data);
|
||||
void joinGroup(CNSocket* sock, CNPacketData* data);
|
||||
void leaveGroup(CNSocket* sock, CNPacketData* data);
|
||||
void sendToGroup(Player* plr, void* buf, uint32_t type, size_t size);
|
||||
void groupTickInfo(Player* plr);
|
||||
void groupKickPlayer(Player* plr);
|
||||
void groupUnbuff(Player* plr);
|
||||
int getGroupFlags(Player* plr);
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <string.h> // for memset()
|
||||
#include <assert.h>
|
||||
|
||||
using namespace ItemManager;
|
||||
|
||||
std::map<std::pair<int32_t, int32_t>, ItemManager::Item> ItemManager::ItemData;
|
||||
std::map<int32_t, CrocPotEntry> ItemManager::CrocPotTable;
|
||||
std::map<int32_t, std::vector<int>> ItemManager::RarityRatios;
|
||||
@ -25,9 +27,9 @@ std::map<int32_t, MobDrop> ItemManager::MobDrops;
|
||||
#ifdef ACADEMY
|
||||
std::map<int32_t, int32_t> ItemManager::NanoCapsules; // crate id -> nano id
|
||||
|
||||
void nanoCapsuleHandler(CNSocket* sock, int slot, sItemBase *chest) {
|
||||
static void nanoCapsuleHandler(CNSocket* sock, int slot, sItemBase *chest) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
int32_t nanoId = ItemManager::NanoCapsules[chest->iID];
|
||||
int32_t nanoId = NanoCapsules[chest->iID];
|
||||
|
||||
// chest opening acknowledgement packet
|
||||
INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp);
|
||||
@ -79,7 +81,93 @@ void nanoCapsuleHandler(CNSocket* sock, int slot, sItemBase *chest) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static int getRarity(Crate& crate, int itemSetId) {
|
||||
// find rarity ratio
|
||||
if (RarityRatios.find(crate.rarityRatioId) == RarityRatios.end()) {
|
||||
std::cout << "[WARN] Rarity Ratio " << crate.rarityRatioId << " not found!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<int> rarityRatio = RarityRatios[crate.rarityRatioId];
|
||||
|
||||
/*
|
||||
* First we have to check if specified item set contains items with all specified rarities,
|
||||
* and if not eliminate them from the draw
|
||||
* it is simpler to do here than to fix individually in the file
|
||||
*/
|
||||
|
||||
// remember that rarities start from 1!
|
||||
for (int i = 0; i < rarityRatio.size(); i++){
|
||||
if (CrateItems.find(std::make_pair(itemSetId, i+1)) == CrateItems.end())
|
||||
rarityRatio[i] = 0;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
for (int value : rarityRatio)
|
||||
total += value;
|
||||
|
||||
if (total == 0) {
|
||||
std::cout << "Item Set " << itemSetId << " has no items assigned?!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// now return a random rarity number
|
||||
int randomNum = rand() % total;
|
||||
int rarity = 0;
|
||||
int sum = 0;
|
||||
do {
|
||||
sum += rarityRatio[rarity];
|
||||
rarity++;
|
||||
} while (sum <= randomNum);
|
||||
|
||||
return rarity;
|
||||
}
|
||||
|
||||
static int getCrateItem(sItemBase& result, int itemSetId, int rarity, int playerGender) {
|
||||
auto key = std::make_pair(itemSetId, rarity);
|
||||
|
||||
if (CrateItems.find(key) == CrateItems.end()) {
|
||||
std::cout << "[WARN] Item Set ID " << itemSetId << " Rarity " << rarity << " does not exist" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// only take into account items that have correct gender
|
||||
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator> items;
|
||||
for (auto crateitem : CrateItems[key]) {
|
||||
int gender = crateitem->second.gender;
|
||||
// if gender is incorrect, exclude item
|
||||
if (gender != 0 && gender != playerGender)
|
||||
continue;
|
||||
items.push_back(crateitem);
|
||||
}
|
||||
|
||||
if (items.size() == 0) {
|
||||
std::cout << "[WARN] Set ID " << itemSetId << " Rarity " << rarity << " contains no valid items" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto item = items[rand() % items.size()];
|
||||
|
||||
result.iID = item->first.first;
|
||||
result.iType = item->first.second;
|
||||
result.iOpt = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getItemSetId(Crate& crate, int crateId) {
|
||||
int itemSetsCount = crate.itemSets.size();
|
||||
if (itemSetsCount == 0) {
|
||||
std::cout << "[WARN] Crate " << crateId << " has no item sets assigned?!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if crate points to multiple itemSets, choose a random one
|
||||
int itemSetIndex = rand() % itemSetsCount;
|
||||
return crate.itemSets[itemSetIndex];
|
||||
}
|
||||
|
||||
static void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_MOVE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
@ -100,20 +188,20 @@ void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
// get the fromItem
|
||||
sItemBase *fromItem;
|
||||
switch ((ItemManager::SlotType)itemmove->eFrom) {
|
||||
case ItemManager::SlotType::EQUIP:
|
||||
switch ((SlotType)itemmove->eFrom) {
|
||||
case SlotType::EQUIP:
|
||||
if (itemmove->iFromSlotNum >= AEQUIP_COUNT)
|
||||
return;
|
||||
|
||||
fromItem = &plr->Equip[itemmove->iFromSlotNum];
|
||||
break;
|
||||
case ItemManager::SlotType::INVENTORY:
|
||||
case SlotType::INVENTORY:
|
||||
if (itemmove->iFromSlotNum >= AINVEN_COUNT)
|
||||
return;
|
||||
|
||||
fromItem = &plr->Inven[itemmove->iFromSlotNum];
|
||||
break;
|
||||
case ItemManager::SlotType::BANK:
|
||||
case SlotType::BANK:
|
||||
if (itemmove->iFromSlotNum >= ABANK_COUNT)
|
||||
return;
|
||||
|
||||
@ -126,20 +214,20 @@ void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
// get the toItem
|
||||
sItemBase* toItem;
|
||||
switch ((ItemManager::SlotType)itemmove->eTo) {
|
||||
case ItemManager::SlotType::EQUIP:
|
||||
switch ((SlotType)itemmove->eTo) {
|
||||
case SlotType::EQUIP:
|
||||
if (itemmove->iToSlotNum >= AEQUIP_COUNT)
|
||||
return;
|
||||
|
||||
toItem = &plr->Equip[itemmove->iToSlotNum];
|
||||
break;
|
||||
case ItemManager::SlotType::INVENTORY:
|
||||
case SlotType::INVENTORY:
|
||||
if (itemmove->iToSlotNum >= AINVEN_COUNT)
|
||||
return;
|
||||
|
||||
toItem = &plr->Inven[itemmove->iToSlotNum];
|
||||
break;
|
||||
case ItemManager::SlotType::BANK:
|
||||
case SlotType::BANK:
|
||||
if (itemmove->iToSlotNum >= ABANK_COUNT)
|
||||
return;
|
||||
|
||||
@ -151,7 +239,7 @@ void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// if equipping an item, validate that it's of the correct type for the slot
|
||||
if ((ItemManager::SlotType)itemmove->eTo == ItemManager::SlotType::EQUIP) {
|
||||
if ((SlotType)itemmove->eTo == SlotType::EQUIP) {
|
||||
if (fromItem->iType == 10 && itemmove->iToSlotNum != 8)
|
||||
return; // vehicle in wrong slot
|
||||
else if (fromItem->iType != 10
|
||||
@ -169,8 +257,8 @@ void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
resp.FromSlotItem = *fromItem;
|
||||
|
||||
// swap/stack items in session
|
||||
ItemManager::Item* itemDat = ItemManager::getItemData(toItem->iID, toItem->iType);
|
||||
ItemManager::Item* itemDatFrom = ItemManager::getItemData(fromItem->iID, fromItem->iType);
|
||||
Item* itemDat = getItemData(toItem->iID, toItem->iType);
|
||||
Item* itemDatFrom = getItemData(fromItem->iID, fromItem->iType);
|
||||
if (itemDat != nullptr && itemDatFrom != nullptr && itemDat->stackSize > 1 && itemDat == itemDatFrom && fromItem->iOpt < itemDat->stackSize && toItem->iOpt < itemDat->stackSize) {
|
||||
// items are stackable, identical, and not maxed, so run stacking logic
|
||||
|
||||
@ -203,11 +291,11 @@ void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
|
||||
// send equip change to viewable players
|
||||
if (itemmove->eFrom == (int)ItemManager::SlotType::EQUIP || itemmove->eTo == (int)ItemManager::SlotType::EQUIP) {
|
||||
if (itemmove->eFrom == (int)SlotType::EQUIP || itemmove->eTo == (int)SlotType::EQUIP) {
|
||||
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, equipChange);
|
||||
|
||||
equipChange.iPC_ID = plr->iID;
|
||||
if (itemmove->eTo == (int)ItemManager::SlotType::EQUIP) {
|
||||
if (itemmove->eTo == (int)SlotType::EQUIP) {
|
||||
equipChange.iEquipSlotNum = itemmove->iToSlotNum;
|
||||
equipChange.EquipSlotItem = resp.FromSlotItem;
|
||||
} else {
|
||||
@ -223,14 +311,14 @@ void itemMoveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
PlayerManager::sendToViewable(sock, (void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
|
||||
|
||||
// set equipment stats serverside
|
||||
ItemManager::setItemStats(plr);
|
||||
setItemStats(plr);
|
||||
}
|
||||
|
||||
// send response
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_PC_ITEM_MOVE_SUCC, sizeof(sP_FE2CL_PC_ITEM_MOVE_SUCC));
|
||||
}
|
||||
|
||||
void itemDeleteHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void itemDeleteHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_ITEM_DELETE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
@ -250,7 +338,7 @@ void itemDeleteHandler(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_ITEM_DELETE_SUCC, sizeof(sP_FE2CL_REP_PC_ITEM_DELETE_SUCC));
|
||||
}
|
||||
|
||||
void itemUseHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void itemUseHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_USE))
|
||||
return; // ignore the malformed packet
|
||||
sP_CL2FE_REQ_ITEM_USE* request = (sP_CL2FE_REQ_ITEM_USE*)data->buf;
|
||||
@ -333,7 +421,7 @@ void itemUseHandler(CNSocket* sock, CNPacketData* data) {
|
||||
NPCManager::EggBuffs[key] = until;
|
||||
}
|
||||
|
||||
void itemBankOpenHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void itemBankOpenHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_BANK_OPEN))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
@ -348,7 +436,7 @@ void itemBankOpenHandler(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_BANK_OPEN_SUCC, sizeof(sP_FE2CL_REP_PC_BANK_OPEN_SUCC));
|
||||
}
|
||||
|
||||
void chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||
static void chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_ITEM_CHEST_OPEN))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
@ -370,7 +458,7 @@ void chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||
|
||||
#ifdef ACADEMY
|
||||
// check if chest isn't a nano capsule
|
||||
if (ItemManager::NanoCapsules.find(chest->iID) != ItemManager::NanoCapsules.end())
|
||||
if (NanoCapsules.find(chest->iID) != NanoCapsules.end())
|
||||
return nanoCapsuleHandler(sock, pkt->iSlotNum, chest);
|
||||
#endif
|
||||
|
||||
@ -406,24 +494,24 @@ void chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||
bool failing = false;
|
||||
|
||||
// find the crate
|
||||
if (ItemManager::Crates.find(chest->iID) == ItemManager::Crates.end()) {
|
||||
if (Crates.find(chest->iID) == Crates.end()) {
|
||||
std::cout << "[WARN] Crate " << chest->iID << " not found!" << std::endl;
|
||||
failing = true;
|
||||
}
|
||||
Crate& crate = ItemManager::Crates[chest->iID];
|
||||
Crate& crate = Crates[chest->iID];
|
||||
|
||||
if (!failing)
|
||||
itemSetId = ItemManager::getItemSetId(crate, chest->iID);
|
||||
itemSetId = getItemSetId(crate, chest->iID);
|
||||
if (itemSetId == -1)
|
||||
failing = true;
|
||||
|
||||
if (!failing)
|
||||
rarity = ItemManager::getRarity(crate, itemSetId);
|
||||
rarity = getRarity(crate, itemSetId);
|
||||
if (rarity == -1)
|
||||
failing = true;
|
||||
|
||||
if (!failing)
|
||||
ret = ItemManager::getCrateItem(item->sItem, itemSetId, rarity, plr->PCStyle.iGender);
|
||||
ret = getCrateItem(item->sItem, itemSetId, rarity, plr->PCStyle.iGender);
|
||||
if (ret == -1)
|
||||
failing = true;
|
||||
|
||||
@ -444,92 +532,6 @@ void chestOpenHandler(CNSocket *sock, CNPacketData *data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, sizeof(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC));
|
||||
}
|
||||
|
||||
int ItemManager::getItemSetId(Crate& crate, int crateId) {
|
||||
int itemSetsCount = crate.itemSets.size();
|
||||
if (itemSetsCount == 0) {
|
||||
std::cout << "[WARN] Crate " << crateId << " has no item sets assigned?!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if crate points to multiple itemSets, choose a random one
|
||||
int itemSetIndex = rand() % itemSetsCount;
|
||||
return crate.itemSets[itemSetIndex];
|
||||
}
|
||||
|
||||
int ItemManager::getRarity(Crate& crate, int itemSetId) {
|
||||
// find rarity ratio
|
||||
if (RarityRatios.find(crate.rarityRatioId) == RarityRatios.end()) {
|
||||
std::cout << "[WARN] Rarity Ratio " << crate.rarityRatioId << " not found!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<int> rarityRatio = RarityRatios[crate.rarityRatioId];
|
||||
|
||||
/*
|
||||
* First we have to check if specified item set contains items with all specified rarities,
|
||||
* and if not eliminate them from the draw
|
||||
* it is simpler to do here than to fix individually in the file
|
||||
*/
|
||||
|
||||
// remember that rarities start from 1!
|
||||
for (int i = 0; i < rarityRatio.size(); i++){
|
||||
if (CrateItems.find(std::make_pair(itemSetId, i+1)) == CrateItems.end())
|
||||
rarityRatio[i] = 0;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
for (int value : rarityRatio)
|
||||
total += value;
|
||||
|
||||
if (total == 0) {
|
||||
std::cout << "Item Set " << itemSetId << " has no items assigned?!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// now return a random rarity number
|
||||
int randomNum = rand() % total;
|
||||
int rarity = 0;
|
||||
int sum = 0;
|
||||
do {
|
||||
sum += rarityRatio[rarity];
|
||||
rarity++;
|
||||
} while (sum <= randomNum);
|
||||
|
||||
return rarity;
|
||||
}
|
||||
|
||||
int ItemManager::getCrateItem(sItemBase& result, int itemSetId, int rarity, int playerGender) {
|
||||
auto key = std::make_pair(itemSetId, rarity);
|
||||
|
||||
if (CrateItems.find(key) == CrateItems.end()) {
|
||||
std::cout << "[WARN] Item Set ID " << itemSetId << " Rarity " << rarity << " does not exist" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// only take into account items that have correct gender
|
||||
std::vector<std::map<std::pair<int32_t, int32_t>, Item>::iterator> items;
|
||||
for (auto crateitem : CrateItems[key]) {
|
||||
int gender = crateitem->second.gender;
|
||||
// if gender is incorrect, exclude item
|
||||
if (gender != 0 && gender != playerGender)
|
||||
continue;
|
||||
items.push_back(crateitem);
|
||||
}
|
||||
|
||||
if (items.size() == 0) {
|
||||
std::cout << "[WARN] Set ID " << itemSetId << " Rarity " << rarity << " contains no valid items" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto item = items[rand() % items.size()];
|
||||
|
||||
result.iID = item->first.first;
|
||||
result.iType = item->first.second;
|
||||
result.iOpt = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: use this in cleaned up ItemManager
|
||||
int ItemManager::findFreeSlot(Player *plr) {
|
||||
int i;
|
||||
@ -542,7 +544,7 @@ int ItemManager::findFreeSlot(Player *plr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ItemManager::Item* ItemManager::getItemData(int32_t id, int32_t type) {
|
||||
Item* ItemManager::getItemData(int32_t id, int32_t type) {
|
||||
if(ItemData.find(std::make_pair(id, type)) != ItemData.end())
|
||||
return &ItemData[std::make_pair(id, type)];
|
||||
return nullptr;
|
||||
@ -593,7 +595,7 @@ void ItemManager::setItemStats(Player* plr) {
|
||||
Item* itemStatsDat;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
itemStatsDat = ItemManager::getItemData(plr->Equip[i].iID, plr->Equip[i].iType);
|
||||
itemStatsDat = getItemData(plr->Equip[i].iID, plr->Equip[i].iType);
|
||||
if (itemStatsDat == nullptr) {
|
||||
std::cout << "[WARN] setItemStats(): getItemData() returned NULL" << std::endl;
|
||||
continue;
|
||||
@ -606,6 +608,7 @@ void ItemManager::setItemStats(Player* plr) {
|
||||
}
|
||||
|
||||
// HACK: work around the invisible weapon bug
|
||||
// TODO: I don't think this makes a difference at all? Check and remove, if necessary.
|
||||
void ItemManager::updateEquips(CNSocket* sock, Player* plr) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, resp);
|
||||
@ -618,6 +621,81 @@ void ItemManager::updateEquips(CNSocket* sock, Player* plr) {
|
||||
}
|
||||
}
|
||||
|
||||
static void getMobDrop(sItemBase *reward, MobDrop* drop, MobDropChance* chance, int rolled) {
|
||||
reward->iType = 9;
|
||||
reward->iOpt = 1;
|
||||
|
||||
int total = 0;
|
||||
for (int ratio : chance->cratesRatio)
|
||||
total += ratio;
|
||||
|
||||
// randomizing a crate
|
||||
int randomNum = rolled % total;
|
||||
int i = 0;
|
||||
int sum = 0;
|
||||
do {
|
||||
reward->iID = drop->crateIDs[i];
|
||||
sum += chance->cratesRatio[i];
|
||||
i++;
|
||||
}
|
||||
while (sum<=randomNum);
|
||||
}
|
||||
|
||||
static void giveEventDrop(CNSocket* sock, Player* player, int rolled) {
|
||||
// random drop chance
|
||||
if (rand() % 100 > settings::EVENTCRATECHANCE)
|
||||
return;
|
||||
|
||||
// no slot = no reward
|
||||
int slot = findFreeSlot(player);
|
||||
if (slot == -1)
|
||||
return;
|
||||
|
||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||
|
||||
uint8_t respbuf[resplen];
|
||||
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);
|
||||
|
||||
// leave everything here as it is
|
||||
reward->m_iCandy = player->money;
|
||||
reward->m_iFusionMatter = player->fusionmatter;
|
||||
reward->m_iBatteryN = player->batteryN;
|
||||
reward->m_iBatteryW = player->batteryW;
|
||||
reward->iFatigue = 100; // prevents warning message
|
||||
reward->iFatigue_Level = 1;
|
||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||
|
||||
// which crate to drop
|
||||
int crateId;
|
||||
switch (settings::EVENTMODE) {
|
||||
// knishmas
|
||||
case 1: crateId = 1187; break;
|
||||
// halloween
|
||||
case 2: crateId = 1181; break;
|
||||
// spring
|
||||
case 3: crateId = 1126; break;
|
||||
// what
|
||||
default:
|
||||
std::cout << "[WARN] Unknown event Id " << settings::EVENTMODE << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
item->sItem.iType = 9;
|
||||
item->sItem.iID = crateId;
|
||||
item->sItem.iOpt = 1;
|
||||
item->iSlotNum = slot;
|
||||
item->eIL = 1; // Inventory Location. 1 means player inventory.
|
||||
|
||||
// update player
|
||||
player->Inven[slot] = item->sItem;
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||
}
|
||||
|
||||
void ItemManager::giveMobDrop(CNSocket *sock, Mob* mob, int rolledBoosts, int rolledPotions,
|
||||
int rolledCrate, int rolledCrateType, int rolledEvent) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
@ -687,7 +765,7 @@ void ItemManager::giveMobDrop(CNSocket *sock, Mob* mob, int rolledBoosts, int ro
|
||||
reward->iFatigue_Level = 1;
|
||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||
|
||||
int slot = ItemManager::findFreeSlot(plr);
|
||||
int slot = findFreeSlot(plr);
|
||||
|
||||
bool awardDrop = false;
|
||||
MobDropChance *chance = nullptr;
|
||||
@ -722,81 +800,6 @@ void ItemManager::giveMobDrop(CNSocket *sock, Mob* mob, int rolledBoosts, int ro
|
||||
giveEventDrop(sock, plr, rolledEvent);
|
||||
}
|
||||
|
||||
void ItemManager::getMobDrop(sItemBase *reward, MobDrop* drop, MobDropChance* chance, int rolled) {
|
||||
reward->iType = 9;
|
||||
reward->iOpt = 1;
|
||||
|
||||
int total = 0;
|
||||
for (int ratio : chance->cratesRatio)
|
||||
total += ratio;
|
||||
|
||||
// randomizing a crate
|
||||
int randomNum = rolled % total;
|
||||
int i = 0;
|
||||
int sum = 0;
|
||||
do {
|
||||
reward->iID = drop->crateIDs[i];
|
||||
sum += chance->cratesRatio[i];
|
||||
i++;
|
||||
}
|
||||
while (sum<=randomNum);
|
||||
}
|
||||
|
||||
void ItemManager::giveEventDrop(CNSocket* sock, Player* player, int rolled) {
|
||||
// random drop chance
|
||||
if (rand() % 100 > settings::EVENTCRATECHANCE)
|
||||
return;
|
||||
|
||||
// no slot = no reward
|
||||
int slot = ItemManager::findFreeSlot(player);
|
||||
if (slot == -1)
|
||||
return;
|
||||
|
||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||
assert(resplen < CN_PACKET_BUFFER_SIZE - 8);
|
||||
|
||||
uint8_t respbuf[resplen];
|
||||
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);
|
||||
|
||||
// leave everything here as it is
|
||||
reward->m_iCandy = player->money;
|
||||
reward->m_iFusionMatter = player->fusionmatter;
|
||||
reward->m_iBatteryN = player->batteryN;
|
||||
reward->m_iBatteryW = player->batteryW;
|
||||
reward->iFatigue = 100; // prevents warning message
|
||||
reward->iFatigue_Level = 1;
|
||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||
|
||||
// which crate to drop
|
||||
int crateId;
|
||||
switch (settings::EVENTMODE) {
|
||||
// knishmas
|
||||
case 1: crateId = 1187; break;
|
||||
// halloween
|
||||
case 2: crateId = 1181; break;
|
||||
// spring
|
||||
case 3: crateId = 1126; break;
|
||||
// what
|
||||
default:
|
||||
std::cout << "[WARN] Unknown event Id " << settings::EVENTMODE << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
item->sItem.iType = 9;
|
||||
item->sItem.iID = crateId;
|
||||
item->sItem.iOpt = 1;
|
||||
item->iSlotNum = slot;
|
||||
item->eIL = 1; // Inventory Location. 1 means player inventory.
|
||||
|
||||
// update player
|
||||
player->Inven[slot] = item->sItem;
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||
}
|
||||
|
||||
void ItemManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler);
|
||||
|
@ -57,15 +57,8 @@ namespace ItemManager {
|
||||
|
||||
void init();
|
||||
|
||||
// crate opening logic with all helper functions
|
||||
int getItemSetId(Crate& crate, int crateId);
|
||||
int getRarity(Crate& crate, int itemSetId);
|
||||
int getCrateItem(sItemBase& reward, int itemSetId, int rarity, int playerGender);
|
||||
|
||||
// mob drops
|
||||
void giveMobDrop(CNSocket *sock, Mob *mob, int rolledBoosts, int rolledPotions, int rolledCrate, int rolledCrateType, int rolledEvent);
|
||||
void getMobDrop(sItemBase *reward, MobDrop *drop, MobDropChance *chance, int rolled);
|
||||
void giveEventDrop(CNSocket* sock, Player* player, int rolled);
|
||||
|
||||
int findFreeSlot(Player *plr);
|
||||
Item* getItemData(int32_t id, int32_t type);
|
||||
|
@ -7,292 +7,26 @@
|
||||
|
||||
#include "string.h"
|
||||
|
||||
using namespace MissionManager;
|
||||
|
||||
std::map<int32_t, Reward*> MissionManager::Rewards;
|
||||
std::map<int32_t, TaskData*> MissionManager::Tasks;
|
||||
nlohmann::json MissionManager::AvatarGrowth[37];
|
||||
|
||||
void MissionManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_START, taskStart);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_END, taskEnd);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID, setMission);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_STOP, quitMission);
|
||||
}
|
||||
|
||||
bool MissionManager::startTask(Player* plr, int TaskID) {
|
||||
if (MissionManager::Tasks.find(TaskID) == MissionManager::Tasks.end()) {
|
||||
std::cout << "[WARN] Player submitted unknown task!?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
TaskData& task = *MissionManager::Tasks[TaskID];
|
||||
|
||||
// client freaks out if nano mission isn't sent first after relogging, so it's easiest to set it here
|
||||
if (task["m_iSTNanoID"] != 0 && plr->tasks[0] != 0) {
|
||||
// lets move task0 to different spot
|
||||
int moveToSlot = 1;
|
||||
for (; moveToSlot < ACTIVE_MISSION_COUNT; moveToSlot++)
|
||||
if (plr->tasks[moveToSlot] == 0)
|
||||
break;
|
||||
|
||||
plr->tasks[moveToSlot] = plr->tasks[0];
|
||||
plr->tasks[0] = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
plr->RemainingNPCCount[moveToSlot][i] = plr->RemainingNPCCount[0][i];
|
||||
plr->RemainingNPCCount[0][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||
if (plr->tasks[i] == 0) {
|
||||
plr->tasks[i] = TaskID;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
plr->RemainingNPCCount[i][j] = (int)task["m_iCSUNumToKill"][j];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ACTIVE_MISSION_COUNT - 1 && plr->tasks[i] != TaskID) {
|
||||
std::cout << "[WARN] Player has more than 6 active missions!?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MissionManager::taskStart(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_START))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TASK_START* missionData = (sP_CL2FE_REQ_PC_TASK_START*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_START_SUCC, response);
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (!startTask(plr, missionData->iTaskNum)) {
|
||||
// TODO: TASK_FAIL?
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_START_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_START_SUCC));
|
||||
static void saveMission(Player* player, int missionId) {
|
||||
// sanity check missionID so we don't get exceptions
|
||||
if (missionId < 0 || missionId > 1023) {
|
||||
std::cout << "[WARN] Client submitted invalid missionId: " <<missionId<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
TaskData& task = *Tasks[missionData->iTaskNum];
|
||||
|
||||
// Give player their delivery items at the start, or reset them to 0 at the start.
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (task["m_iSTItemID"][i] != 0)
|
||||
dropQuestItem(sock, missionData->iTaskNum, task["m_iSTItemNumNeeded"][i], task["m_iSTItemID"][i], 0);
|
||||
std::cout << "Mission requested task: " << missionData->iTaskNum << std::endl;
|
||||
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));
|
||||
|
||||
// HACK: auto-succeed escort task
|
||||
if (task["m_iHTaskType"] == 6) {
|
||||
std::cout << "Skipping escort mission" << std::endl;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
|
||||
|
||||
endTask(sock, missionData->iTaskNum);
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
||||
}
|
||||
// Missions are stored in int64_t array
|
||||
int row = missionId / 64;
|
||||
int column = missionId % 64;
|
||||
player->aQuestFlag[row] |= (1ULL << column);
|
||||
}
|
||||
|
||||
void MissionManager::taskEnd(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_END))
|
||||
return; // malformed packet
|
||||
|
||||
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];
|
||||
if (task->task["m_iSTGrantTimer"] > 0) { // its a timed mission
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
/*
|
||||
* 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) {
|
||||
|
||||
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);
|
||||
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
|
||||
if (!endTask(sock, missionData->iTaskNum, missionData->iBox1Choice)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
||||
}
|
||||
|
||||
bool MissionManager::endTask(CNSocket *sock, int32_t taskNum, int choice) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (Tasks.find(taskNum) == Tasks.end())
|
||||
return false;
|
||||
|
||||
// ugly pointer/reference juggling for the sake of operator overloading...
|
||||
TaskData& task = *Tasks[taskNum];
|
||||
|
||||
// update player
|
||||
int i;
|
||||
for (i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||
if (plr->tasks[i] == taskNum) {
|
||||
plr->tasks[i] = 0;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
plr->RemainingNPCCount[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == ACTIVE_MISSION_COUNT - 1 && plr->tasks[i] != 0) {
|
||||
std::cout << "[WARN] Player completed non-active mission!?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// mission rewards
|
||||
if (Rewards.find(taskNum) != Rewards.end()) {
|
||||
if (giveMissionReward(sock, taskNum, choice) == -1)
|
||||
return false; // we don't want to send anything
|
||||
}
|
||||
// don't take away quest items if we haven't finished the quest
|
||||
|
||||
/*
|
||||
* Give (or take away) quest items
|
||||
*
|
||||
* Some mission tasks give the player a quest item upon completion.
|
||||
* This is distinct from quest item mob drops.
|
||||
* They can be identified by a counter in the task indicator (ie. 1/1 Gravity Decelerator).
|
||||
* The server is responsible for dropping the correct item.
|
||||
* Yes, this is pretty stupid.
|
||||
*
|
||||
* iSUInstancename is the number of items to give. It is usually negative at the end of
|
||||
* a mission, to clean up its quest items.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (task["m_iSUItem"][i] != 0)
|
||||
dropQuestItem(sock, taskNum, task["m_iSUInstancename"][i], task["m_iSUItem"][i], 0);
|
||||
|
||||
// if it's the last task
|
||||
if (task["m_iSUOutgoingTask"] == 0) {
|
||||
// save completed mission on player
|
||||
saveMission(plr, (int)(task["m_iHMissionID"])-1);
|
||||
|
||||
// if it's a nano mission, reward the nano.
|
||||
if (task["m_iSTNanoID"] != 0)
|
||||
NanoManager::addNano(sock, task["m_iSTNanoID"], 0, true);
|
||||
|
||||
// remove current mission
|
||||
plr->CurrentMissionID = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MissionManager::setMission(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID))
|
||||
return; // malformed packet
|
||||
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID* missionData = (sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, response);
|
||||
response.iCurrentMissionID = missionData->iCurrentMissionID;
|
||||
plr->CurrentMissionID = missionData->iCurrentMissionID;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, sizeof(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID));
|
||||
}
|
||||
|
||||
void MissionManager::quitMission(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_STOP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TASK_STOP* missionData = (sP_CL2FE_REQ_PC_TASK_STOP*)data->buf;
|
||||
quitTask(sock, missionData->iTaskNum, true);
|
||||
}
|
||||
|
||||
void MissionManager::quitTask(CNSocket* sock, int32_t taskNum, bool manual) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (Tasks.find(taskNum) == Tasks.end())
|
||||
return; // sanity check
|
||||
|
||||
// update player
|
||||
int i;
|
||||
for (i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||
if (plr->tasks[i] == taskNum) {
|
||||
plr->tasks[i] = 0;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
plr->RemainingNPCCount[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == ACTIVE_MISSION_COUNT - 1 && plr->tasks[i] != 0) {
|
||||
std::cout << "[WARN] Player quit non-active mission!?" << std::endl;
|
||||
}
|
||||
// remove current mission
|
||||
plr->CurrentMissionID = 0;
|
||||
|
||||
TaskData& task = *Tasks[taskNum];
|
||||
|
||||
// clean up quest items
|
||||
if (manual) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (task["m_iSUItem"][i] == 0 && task["m_iCSUItemID"][i] == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* It's ok to do this only server-side, because the server decides which
|
||||
* slot later items will be placed in.
|
||||
*/
|
||||
for (int j = 0; j < AQINVEN_COUNT; j++)
|
||||
if (plr->QInven[j].iID == task["m_iSUItem"][i] || plr->QInven[j].iID == task["m_iCSUItemID"][i] || plr->QInven[j].iID == task["m_iSTItemID"][i])
|
||||
memset(&plr->QInven[j], 0, sizeof(sItemBase));
|
||||
}
|
||||
} else {
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_FAIL, failResp);
|
||||
failResp.iErrorCode = 1;
|
||||
failResp.iTaskNum = taskNum;
|
||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_TASK_END_FAIL, sizeof(sP_FE2CL_REP_PC_TASK_END_FAIL));
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_STOP_SUCC, response);
|
||||
response.iTaskNum = taskNum;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_STOP_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_STOP_SUCC));
|
||||
}
|
||||
|
||||
int MissionManager::findQSlot(Player *plr, int id) {
|
||||
static int findQSlot(Player *plr, int id) {
|
||||
int i;
|
||||
|
||||
// two passes. we mustn't fail to find an existing stack.
|
||||
@ -309,7 +43,20 @@ int MissionManager::findQSlot(Player *plr, int id) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MissionManager::dropQuestItem(CNSocket *sock, int task, int count, int id, int mobid) {
|
||||
static bool isQuestItemFull(CNSocket* sock, int itemId, int itemCount) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
int slot = findQSlot(plr, itemId);
|
||||
if (slot == -1) {
|
||||
// this should never happen
|
||||
std::cout << "[WARN] Player has no room for quest item!?" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
return (itemCount == plr->QInven[slot].iOpt);
|
||||
}
|
||||
|
||||
static void dropQuestItem(CNSocket *sock, int task, int count, int id, int mobid) {
|
||||
std::cout << "Altered item id " << id << " by " << count << " for task id " << task << std::endl;
|
||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||
assert(resplen < CN_PACKET_BUFFER_SIZE);
|
||||
@ -364,7 +111,7 @@ void MissionManager::dropQuestItem(CNSocket *sock, int task, int count, int id,
|
||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||
}
|
||||
|
||||
int MissionManager::giveMissionReward(CNSocket *sock, int task, int choice) {
|
||||
static int giveMissionReward(CNSocket *sock, int task, int choice=0) {
|
||||
Reward *reward = Rewards[task];
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
@ -457,6 +204,280 @@ int MissionManager::giveMissionReward(CNSocket *sock, int task, int choice) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool endTask(CNSocket *sock, int32_t taskNum, int choice=0) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (Tasks.find(taskNum) == Tasks.end())
|
||||
return false;
|
||||
|
||||
// ugly pointer/reference juggling for the sake of operator overloading...
|
||||
TaskData& task = *Tasks[taskNum];
|
||||
|
||||
// update player
|
||||
int i;
|
||||
for (i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||
if (plr->tasks[i] == taskNum) {
|
||||
plr->tasks[i] = 0;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
plr->RemainingNPCCount[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == ACTIVE_MISSION_COUNT - 1 && plr->tasks[i] != 0) {
|
||||
std::cout << "[WARN] Player completed non-active mission!?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// mission rewards
|
||||
if (Rewards.find(taskNum) != Rewards.end()) {
|
||||
if (giveMissionReward(sock, taskNum, choice) == -1)
|
||||
return false; // we don't want to send anything
|
||||
}
|
||||
// don't take away quest items if we haven't finished the quest
|
||||
|
||||
/*
|
||||
* Give (or take away) quest items
|
||||
*
|
||||
* Some mission tasks give the player a quest item upon completion.
|
||||
* This is distinct from quest item mob drops.
|
||||
* They can be identified by a counter in the task indicator (ie. 1/1 Gravity Decelerator).
|
||||
* The server is responsible for dropping the correct item.
|
||||
* Yes, this is pretty stupid.
|
||||
*
|
||||
* iSUInstancename is the number of items to give. It is usually negative at the end of
|
||||
* a mission, to clean up its quest items.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (task["m_iSUItem"][i] != 0)
|
||||
dropQuestItem(sock, taskNum, task["m_iSUInstancename"][i], task["m_iSUItem"][i], 0);
|
||||
|
||||
// if it's the last task
|
||||
if (task["m_iSUOutgoingTask"] == 0) {
|
||||
// save completed mission on player
|
||||
saveMission(plr, (int)(task["m_iHMissionID"])-1);
|
||||
|
||||
// if it's a nano mission, reward the nano.
|
||||
if (task["m_iSTNanoID"] != 0)
|
||||
NanoManager::addNano(sock, task["m_iSTNanoID"], 0, true);
|
||||
|
||||
// remove current mission
|
||||
plr->CurrentMissionID = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MissionManager::startTask(Player* plr, int TaskID) {
|
||||
if (MissionManager::Tasks.find(TaskID) == MissionManager::Tasks.end()) {
|
||||
std::cout << "[WARN] Player submitted unknown task!?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
TaskData& task = *MissionManager::Tasks[TaskID];
|
||||
|
||||
// client freaks out if nano mission isn't sent first after relogging, so it's easiest to set it here
|
||||
if (task["m_iSTNanoID"] != 0 && plr->tasks[0] != 0) {
|
||||
// lets move task0 to different spot
|
||||
int moveToSlot = 1;
|
||||
for (; moveToSlot < ACTIVE_MISSION_COUNT; moveToSlot++)
|
||||
if (plr->tasks[moveToSlot] == 0)
|
||||
break;
|
||||
|
||||
plr->tasks[moveToSlot] = plr->tasks[0];
|
||||
plr->tasks[0] = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
plr->RemainingNPCCount[moveToSlot][i] = plr->RemainingNPCCount[0][i];
|
||||
plr->RemainingNPCCount[0][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||
if (plr->tasks[i] == 0) {
|
||||
plr->tasks[i] = TaskID;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
plr->RemainingNPCCount[i][j] = (int)task["m_iCSUNumToKill"][j];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ACTIVE_MISSION_COUNT - 1 && plr->tasks[i] != TaskID) {
|
||||
std::cout << "[WARN] Player has more than 6 active missions!?" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void taskStart(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_START))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TASK_START* missionData = (sP_CL2FE_REQ_PC_TASK_START*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_START_SUCC, response);
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (!startTask(plr, missionData->iTaskNum)) {
|
||||
// TODO: TASK_FAIL?
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_START_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_START_SUCC));
|
||||
return;
|
||||
}
|
||||
|
||||
TaskData& task = *Tasks[missionData->iTaskNum];
|
||||
|
||||
// Give player their delivery items at the start, or reset them to 0 at the start.
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (task["m_iSTItemID"][i] != 0)
|
||||
dropQuestItem(sock, missionData->iTaskNum, task["m_iSTItemNumNeeded"][i], task["m_iSTItemID"][i], 0);
|
||||
std::cout << "Mission requested task: " << missionData->iTaskNum << std::endl;
|
||||
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));
|
||||
|
||||
// HACK: auto-succeed escort task
|
||||
if (task["m_iHTaskType"] == 6) {
|
||||
std::cout << "Skipping escort mission" << std::endl;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response);
|
||||
|
||||
endTask(sock, missionData->iTaskNum);
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
||||
}
|
||||
}
|
||||
|
||||
static void taskEnd(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_END))
|
||||
return; // malformed packet
|
||||
|
||||
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];
|
||||
if (task->task["m_iSTGrantTimer"] > 0) { // its a timed mission
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
/*
|
||||
* 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) {
|
||||
|
||||
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);
|
||||
|
||||
response.iTaskNum = missionData->iTaskNum;
|
||||
|
||||
if (!endTask(sock, missionData->iTaskNum, missionData->iBox1Choice)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
||||
}
|
||||
|
||||
static void setMission(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID))
|
||||
return; // malformed packet
|
||||
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID* missionData = (sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, response);
|
||||
response.iCurrentMissionID = missionData->iCurrentMissionID;
|
||||
plr->CurrentMissionID = missionData->iCurrentMissionID;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, sizeof(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID));
|
||||
}
|
||||
|
||||
static void quitMission(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_STOP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_TASK_STOP* missionData = (sP_CL2FE_REQ_PC_TASK_STOP*)data->buf;
|
||||
quitTask(sock, missionData->iTaskNum, true);
|
||||
}
|
||||
|
||||
void MissionManager::quitTask(CNSocket* sock, int32_t taskNum, bool manual) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
if (Tasks.find(taskNum) == Tasks.end())
|
||||
return; // sanity check
|
||||
|
||||
// update player
|
||||
int i;
|
||||
for (i = 0; i < ACTIVE_MISSION_COUNT; i++) {
|
||||
if (plr->tasks[i] == taskNum) {
|
||||
plr->tasks[i] = 0;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
plr->RemainingNPCCount[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == ACTIVE_MISSION_COUNT - 1 && plr->tasks[i] != 0) {
|
||||
std::cout << "[WARN] Player quit non-active mission!?" << std::endl;
|
||||
}
|
||||
// remove current mission
|
||||
plr->CurrentMissionID = 0;
|
||||
|
||||
TaskData& task = *Tasks[taskNum];
|
||||
|
||||
// clean up quest items
|
||||
if (manual) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (task["m_iSUItem"][i] == 0 && task["m_iCSUItemID"][i] == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* It's ok to do this only server-side, because the server decides which
|
||||
* slot later items will be placed in.
|
||||
*/
|
||||
for (int j = 0; j < AQINVEN_COUNT; j++)
|
||||
if (plr->QInven[j].iID == task["m_iSUItem"][i] || plr->QInven[j].iID == task["m_iCSUItemID"][i] || plr->QInven[j].iID == task["m_iSTItemID"][i])
|
||||
memset(&plr->QInven[j], 0, sizeof(sItemBase));
|
||||
}
|
||||
} else {
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_FAIL, failResp);
|
||||
failResp.iErrorCode = 1;
|
||||
failResp.iTaskNum = taskNum;
|
||||
sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_TASK_END_FAIL, sizeof(sP_FE2CL_REP_PC_TASK_END_FAIL));
|
||||
}
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_STOP_SUCC, response);
|
||||
response.iTaskNum = taskNum;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_STOP_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_STOP_SUCC));
|
||||
}
|
||||
|
||||
void MissionManager::updateFusionMatter(CNSocket* sock, int fusion) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
@ -566,32 +587,6 @@ void MissionManager::mobKilled(CNSocket *sock, int mobid, int rolledQItem) {
|
||||
}
|
||||
}
|
||||
|
||||
void MissionManager::saveMission(Player* player, int missionId) {
|
||||
// sanity check missionID so we don't get exceptions
|
||||
if (missionId < 0 || missionId > 1023) {
|
||||
std::cout << "[WARN] Client submitted invalid missionId: " <<missionId<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Missions are stored in int64_t array
|
||||
int row = missionId / 64;
|
||||
int column = missionId % 64;
|
||||
player->aQuestFlag[row] |= (1ULL << column);
|
||||
}
|
||||
|
||||
bool MissionManager::isQuestItemFull(CNSocket* sock, int itemId, int itemCount) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
int slot = findQSlot(plr, itemId);
|
||||
if (slot == -1) {
|
||||
// this should never happen
|
||||
std::cout << "[WARN] Player has no room for quest item!?" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
return (itemCount == plr->QInven[slot].iOpt);
|
||||
}
|
||||
|
||||
void MissionManager::failInstancedMissions(CNSocket* sock) {
|
||||
// loop through all tasks; if the required instance is being left, "fail" the task
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
@ -610,3 +605,10 @@ void MissionManager::failInstancedMissions(CNSocket* sock) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MissionManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_START, taskStart);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_END, taskEnd);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID, setMission);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_STOP, quitMission);
|
||||
}
|
||||
|
@ -42,22 +42,12 @@ namespace MissionManager {
|
||||
void init();
|
||||
|
||||
bool startTask(Player* plr, int TaskID);
|
||||
void taskStart(CNSocket* sock, CNPacketData* data);
|
||||
void taskEnd(CNSocket* sock, CNPacketData* data);
|
||||
void setMission(CNSocket* sock, CNPacketData* data);
|
||||
void quitMission(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
int findQSlot(Player *plr, int id);
|
||||
void dropQuestItem(CNSocket *sock, int task, int count, int id, int mobid);
|
||||
// checks if player doesn't have n/n quest items
|
||||
bool isQuestItemFull(CNSocket* sock, int itemId, int itemCount);
|
||||
int giveMissionReward(CNSocket *sock, int task, int choice=0);
|
||||
void updateFusionMatter(CNSocket* sock, int fusion);
|
||||
|
||||
void mobKilled(CNSocket *sock, int mobid, int rolledQItem);
|
||||
|
||||
bool endTask(CNSocket *sock, int32_t taskNum, int choice=0);
|
||||
void saveMission(Player* player, int missionId);
|
||||
void quitTask(CNSocket* sock, int32_t taskNum, bool manual);
|
||||
|
||||
void failInstancedMissions(CNSocket* sock);
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <cmath>
|
||||
#include <limits.h>
|
||||
|
||||
using namespace MobAI;
|
||||
|
||||
std::map<int32_t, Mob*> MobAI::Mobs;
|
||||
static std::queue<int32_t> RemovalQueue;
|
||||
|
||||
@ -259,10 +261,10 @@ static void dealCorruption(Mob *mob, std::vector<int> targetData, int skillID, i
|
||||
if (plr->HP <= 0) {
|
||||
mob->target = nullptr;
|
||||
mob->state = MobState::RETREAT;
|
||||
if (!MobAI::aggroCheck(mob, getTime())) {
|
||||
MobAI::clearDebuff(mob);
|
||||
if (!aggroCheck(mob, getTime())) {
|
||||
clearDebuff(mob);
|
||||
if (mob->groupLeader != 0)
|
||||
MobAI::groupRetreat(mob);
|
||||
groupRetreat(mob);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -463,8 +465,8 @@ static void deadStep(Mob *mob, time_t currTime) {
|
||||
|
||||
// if mob is a group leader/follower, spawn where the group is.
|
||||
if (mob->groupLeader != 0) {
|
||||
if (MobAI::Mobs.find(mob->groupLeader) != MobAI::Mobs.end()) {
|
||||
Mob* leaderMob = MobAI::Mobs[mob->groupLeader];
|
||||
if (Mobs.find(mob->groupLeader) != Mobs.end()) {
|
||||
Mob* leaderMob = Mobs[mob->groupLeader];
|
||||
mob->appearanceData.iX = leaderMob->appearanceData.iX + mob->offsetX;
|
||||
mob->appearanceData.iY = leaderMob->appearanceData.iY + mob->offsetY;
|
||||
mob->appearanceData.iZ = leaderMob->appearanceData.iZ;
|
||||
@ -488,10 +490,10 @@ static void combatStep(Mob *mob, time_t currTime) {
|
||||
if (PlayerManager::players.find(mob->target) == PlayerManager::players.end()) {
|
||||
mob->target = nullptr;
|
||||
mob->state = MobState::RETREAT;
|
||||
if (!MobAI::aggroCheck(mob, currTime)) {
|
||||
MobAI::clearDebuff(mob);
|
||||
if (!aggroCheck(mob, currTime)) {
|
||||
clearDebuff(mob);
|
||||
if (mob->groupLeader != 0)
|
||||
MobAI::groupRetreat(mob);
|
||||
groupRetreat(mob);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -503,10 +505,10 @@ static void combatStep(Mob *mob, time_t currTime) {
|
||||
|| (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE)) {
|
||||
mob->target = nullptr;
|
||||
mob->state = MobState::RETREAT;
|
||||
if (!MobAI::aggroCheck(mob, currTime)) {
|
||||
MobAI::clearDebuff(mob);
|
||||
if (!aggroCheck(mob, currTime)) {
|
||||
clearDebuff(mob);
|
||||
if (mob->groupLeader != 0)
|
||||
MobAI::groupRetreat(mob);
|
||||
groupRetreat(mob);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -615,9 +617,9 @@ static void combatStep(Mob *mob, time_t currTime) {
|
||||
if (distance >= mob->data["m_iCombatRange"]) {
|
||||
mob->target = nullptr;
|
||||
mob->state = MobState::RETREAT;
|
||||
MobAI::clearDebuff(mob);
|
||||
clearDebuff(mob);
|
||||
if (mob->groupLeader != 0)
|
||||
MobAI::groupRetreat(mob);
|
||||
groupRetreat(mob);
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,7 +639,7 @@ static void roamingStep(Mob *mob, time_t currTime) {
|
||||
*/
|
||||
if (mob->state != MobState::DEAD && (mob->nextAttack == 0 || currTime >= mob->nextAttack)) {
|
||||
mob->nextAttack = currTime + 500;
|
||||
if (MobAI::aggroCheck(mob, currTime))
|
||||
if (aggroCheck(mob, currTime))
|
||||
return;
|
||||
}
|
||||
|
||||
@ -655,7 +657,7 @@ static void roamingStep(Mob *mob, time_t currTime) {
|
||||
*/
|
||||
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
|
||||
return;
|
||||
MobAI::incNextMovement(mob, currTime);
|
||||
incNextMovement(mob, currTime);
|
||||
|
||||
int xStart = mob->spawnX - mob->idleRange/2;
|
||||
int yStart = mob->spawnY - mob->idleRange/2;
|
||||
@ -702,13 +704,13 @@ static void roamingStep(Mob *mob, time_t currTime) {
|
||||
if (mob->groupMember[i] == 0)
|
||||
break;
|
||||
|
||||
if (MobAI::Mobs.find(mob->groupMember[i]) == MobAI::Mobs.end()) {
|
||||
if (Mobs.find(mob->groupMember[i]) == Mobs.end()) {
|
||||
std::cout << "[WARN] roamingStep: leader can't find a group member!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::queue<WarpLocation> queue2;
|
||||
Mob* followerMob = MobAI::Mobs[mob->groupMember[i]];
|
||||
Mob* followerMob = Mobs[mob->groupMember[i]];
|
||||
from = { followerMob->appearanceData.iX, followerMob->appearanceData.iY, followerMob->appearanceData.iZ };
|
||||
to = { farX + followerMob->offsetX, farY + followerMob->offsetY, followerMob->appearanceData.iZ };
|
||||
TransportManager::lerp(&queue2, from, to, speed);
|
||||
@ -758,17 +760,17 @@ static void retreatStep(Mob *mob, time_t currTime) {
|
||||
if (pwr.skillType == NanoManager::SkillTable[110].skillType)
|
||||
pwr.handle(mob, targetData, 110, NanoManager::SkillTable[110].durationTime[0], NanoManager::SkillTable[110].powerIntensity[0]);
|
||||
// clear outlying debuffs
|
||||
MobAI::clearDebuff(mob);
|
||||
clearDebuff(mob);
|
||||
}
|
||||
}
|
||||
|
||||
static void step(CNServer *serv, time_t currTime) {
|
||||
for (auto& pair : MobAI::Mobs) {
|
||||
for (auto& pair : Mobs) {
|
||||
if (pair.second->playersInView < 0)
|
||||
std::cout << "[WARN] Weird playerview value " << pair.second->playersInView << std::endl;
|
||||
|
||||
// skip mob movement and combat if disabled or not in view
|
||||
if ((!MobAI::simulateMobs || pair.second->playersInView == 0) && pair.second->state != MobState::DEAD
|
||||
if ((!simulateMobs || pair.second->playersInView == 0) && pair.second->state != MobState::DEAD
|
||||
&& pair.second->state != MobState::RETREAT)
|
||||
continue;
|
||||
|
||||
|
108
src/Monitor.cpp
108
src/Monitor.cpp
@ -12,59 +12,6 @@ static std::mutex sockLock; // guards socket list
|
||||
static std::list<SOCKET> sockets;
|
||||
static sockaddr_in address;
|
||||
|
||||
SOCKET Monitor::init() {
|
||||
listener = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (SOCKETERROR(listener)) {
|
||||
std::cout << "Failed to create monitor socket" << std::endl;
|
||||
printSocketError("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const char opt = 1;
|
||||
#else
|
||||
int opt = 1;
|
||||
#endif
|
||||
if (SOCKETERROR(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))) {
|
||||
std::cout << "Failed to set SO_REUSEADDR on monitor socket" << std::endl;
|
||||
printSocketError("setsockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(settings::MONITORPORT);
|
||||
|
||||
if (SOCKETERROR(bind(listener, (struct sockaddr*)&address, sizeof(address)))) {
|
||||
std::cout << "Failed to bind to monitor port" << std::endl;
|
||||
printSocketError("bind");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (SOCKETERROR(listen(listener, SOMAXCONN))) {
|
||||
std::cout << "Failed to listen on monitor port" << std::endl;
|
||||
printSocketError("listen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned long mode = 1;
|
||||
if (ioctlsocket(listener, FIONBIO, &mode) != 0) {
|
||||
#else
|
||||
if (fcntl(listener, F_SETFL, (fcntl(listener, F_GETFL, 0) | O_NONBLOCK)) != 0) {
|
||||
#endif
|
||||
std::cerr << "[FATAL] OpenFusion: fcntl failed" << std::endl;
|
||||
printSocketError("fcntl");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::cout << "Monitor listening on *:" << settings::MONITORPORT << std::endl;
|
||||
|
||||
REGISTER_SHARD_TIMER(tick, settings::MONITORINTERVAL);
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
||||
static bool transmit(std::list<SOCKET>::iterator& it, char *buff, int len) {
|
||||
int n = 0;
|
||||
int sock = *it;
|
||||
@ -92,7 +39,7 @@ static bool transmit(std::list<SOCKET>::iterator& it, char *buff, int len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Monitor::tick(CNServer *serv, time_t delta) {
|
||||
static void tick(CNServer *serv, time_t delta) {
|
||||
std::lock_guard<std::mutex> lock(sockLock);
|
||||
char buff[256];
|
||||
int n;
|
||||
@ -165,3 +112,56 @@ bool Monitor::acceptConnection(SOCKET fd, uint16_t revents) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SOCKET Monitor::init() {
|
||||
listener = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (SOCKETERROR(listener)) {
|
||||
std::cout << "Failed to create monitor socket" << std::endl;
|
||||
printSocketError("socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const char opt = 1;
|
||||
#else
|
||||
int opt = 1;
|
||||
#endif
|
||||
if (SOCKETERROR(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))) {
|
||||
std::cout << "Failed to set SO_REUSEADDR on monitor socket" << std::endl;
|
||||
printSocketError("setsockopt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(settings::MONITORPORT);
|
||||
|
||||
if (SOCKETERROR(bind(listener, (struct sockaddr*)&address, sizeof(address)))) {
|
||||
std::cout << "Failed to bind to monitor port" << std::endl;
|
||||
printSocketError("bind");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (SOCKETERROR(listen(listener, SOMAXCONN))) {
|
||||
std::cout << "Failed to listen on monitor port" << std::endl;
|
||||
printSocketError("listen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned long mode = 1;
|
||||
if (ioctlsocket(listener, FIONBIO, &mode) != 0) {
|
||||
#else
|
||||
if (fcntl(listener, F_SETFL, (fcntl(listener, F_GETFL, 0) | O_NONBLOCK)) != 0) {
|
||||
#endif
|
||||
std::cerr << "[FATAL] OpenFusion: fcntl failed" << std::endl;
|
||||
printSocketError("fcntl");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::cout << "Monitor listening on *:" << settings::MONITORPORT << std::endl;
|
||||
|
||||
REGISTER_SHARD_TIMER(tick, settings::MONITORINTERVAL);
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
@ -7,6 +7,5 @@
|
||||
|
||||
namespace Monitor {
|
||||
SOCKET init();
|
||||
void tick(CNServer *, time_t);
|
||||
bool acceptConnection(SOCKET, uint16_t);
|
||||
};
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#include "JSON.hpp"
|
||||
|
||||
using namespace NPCManager;
|
||||
|
||||
std::map<int32_t, BaseNPC*> NPCManager::NPCs;
|
||||
std::map<int32_t, WarpLocation> NPCManager::Warps;
|
||||
std::vector<WarpLocation> NPCManager::RespawnPoints;
|
||||
@ -30,8 +32,6 @@ std::unordered_map<int, EggType> NPCManager::EggTypes;
|
||||
std::unordered_map<int, Egg*> NPCManager::Eggs;
|
||||
nlohmann::json NPCManager::NPCData;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Initialized at the end of TableData::init().
|
||||
* This allows us to summon and kill mobs in arbitrary order without
|
||||
@ -39,18 +39,6 @@ nlohmann::json NPCManager::NPCData;
|
||||
*/
|
||||
int32_t NPCManager::nextId;
|
||||
|
||||
void NPCManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_NPC, npcWarpHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TIME_TO_GO_WARP, npcWarpTimeMachine);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_SUMMON, npcSummonHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_UNSUMMON, npcUnsummonHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_BARKER, npcBarkHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SHINY_PICKUP, eggPickup);
|
||||
|
||||
REGISTER_SHARD_TIMER(eggStep, 1000);
|
||||
}
|
||||
|
||||
void NPCManager::destroyNPC(int32_t id) {
|
||||
// sanity check
|
||||
if (NPCs.find(id) == NPCs.end()) {
|
||||
@ -109,7 +97,7 @@ void NPCManager::sendToViewable(BaseNPC *npc, void *buf, uint32_t type, size_t s
|
||||
}
|
||||
}
|
||||
|
||||
void NPCManager::npcBarkHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void npcBarkHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_BARKER))
|
||||
return; // malformed packet
|
||||
|
||||
@ -132,7 +120,7 @@ void NPCManager::npcBarkHandler(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_BARKER, sizeof(sP_FE2CL_REP_BARKER));
|
||||
}
|
||||
|
||||
void NPCManager::npcUnsummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void npcUnsummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NPC_UNSUMMON))
|
||||
return; // malformed packet
|
||||
|
||||
@ -169,7 +157,7 @@ BaseNPC *NPCManager::summonNPC(int x, int y, int z, uint64_t instance, int type,
|
||||
return npc;
|
||||
}
|
||||
|
||||
void NPCManager::npcSummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void npcSummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NPC_SUMMON))
|
||||
return; // malformed packet
|
||||
|
||||
@ -188,22 +176,7 @@ void NPCManager::npcSummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void NPCManager::npcWarpHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_WARP_USE_NPC))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_WARP_USE_NPC* warpNpc = (sP_CL2FE_REQ_PC_WARP_USE_NPC*)data->buf;
|
||||
handleWarp(sock, warpNpc->iWarpID);
|
||||
}
|
||||
|
||||
void NPCManager::npcWarpTimeMachine(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TIME_TO_GO_WARP))
|
||||
return; // malformed packet
|
||||
// this is just a warp request
|
||||
handleWarp(sock, 28);
|
||||
}
|
||||
|
||||
void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) {
|
||||
static void handleWarp(CNSocket* sock, int32_t warpId) {
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
// sanity check
|
||||
if (Warps.find(warpId) == Warps.end())
|
||||
@ -303,6 +276,21 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) {
|
||||
}
|
||||
}
|
||||
|
||||
static void npcWarpHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_WARP_USE_NPC))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_PC_WARP_USE_NPC* warpNpc = (sP_CL2FE_REQ_PC_WARP_USE_NPC*)data->buf;
|
||||
handleWarp(sock, warpNpc->iWarpID);
|
||||
}
|
||||
|
||||
static void npcWarpTimeMachine(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TIME_TO_GO_WARP))
|
||||
return; // malformed packet
|
||||
// this is just a warp request
|
||||
handleWarp(sock, 28);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to get NPC closest to coordinates in specified chunks
|
||||
*/
|
||||
@ -395,7 +383,7 @@ int NPCManager::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int durati
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NPCManager::eggStep(CNServer* serv, time_t currTime) {
|
||||
static void eggStep(CNServer* serv, time_t currTime) {
|
||||
// tick buffs
|
||||
time_t timeStamp = currTime;
|
||||
auto it = EggBuffs.begin();
|
||||
@ -457,7 +445,7 @@ void NPCManager::npcDataToEggData(sNPCAppearanceData* npc, sShinyAppearanceData*
|
||||
egg->iShiny_ID = npc->iNPC_ID;
|
||||
}
|
||||
|
||||
void NPCManager::eggPickup(CNSocket* sock, CNPacketData* data) {
|
||||
static void eggPickup(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_SHINY_PICKUP))
|
||||
return; // malformed packet
|
||||
|
||||
@ -565,6 +553,7 @@ void NPCManager::eggPickup(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move this to MobAI, possibly
|
||||
#pragma region NPCEvents
|
||||
|
||||
// summon right arm and stage 2 body
|
||||
@ -618,3 +607,15 @@ std::vector<NPCEvent> NPCManager::NPCEvents = {
|
||||
};
|
||||
|
||||
#pragma endregion NPCEvents
|
||||
|
||||
void NPCManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_NPC, npcWarpHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TIME_TO_GO_WARP, npcWarpTimeMachine);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_SUMMON, npcSummonHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_UNSUMMON, npcUnsummonHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_BARKER, npcBarkHandler);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_SHINY_PICKUP, eggPickup);
|
||||
|
||||
REGISTER_SHARD_TIMER(eggStep, 1000);
|
||||
}
|
||||
|
@ -69,20 +69,11 @@ namespace NPCManager {
|
||||
|
||||
void sendToViewable(BaseNPC* npc, void* buf, uint32_t type, size_t size);
|
||||
|
||||
void npcBarkHandler(CNSocket* sock, CNPacketData* data);
|
||||
void npcSummonHandler(CNSocket* sock, CNPacketData* data);
|
||||
void npcUnsummonHandler(CNSocket* sock, CNPacketData* data);
|
||||
void npcWarpHandler(CNSocket* sock, CNPacketData* data);
|
||||
void npcWarpTimeMachine(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void handleWarp(CNSocket* sock, int32_t warpId);
|
||||
BaseNPC *summonNPC(int x, int y, int z, uint64_t instance, int type, bool respawn=false, bool baseInstance=false);
|
||||
|
||||
BaseNPC* getNearestNPC(std::set<Chunk*>* chunks, int X, int Y, int Z);
|
||||
|
||||
/// returns -1 on fail
|
||||
int eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration);
|
||||
void eggStep(CNServer* serv, time_t currTime);
|
||||
void npcDataToEggData(sNPCAppearanceData* npc, sShinyAppearanceData* egg);
|
||||
void eggPickup(CNSocket* sock, CNPacketData* data);
|
||||
}
|
||||
|
@ -10,235 +10,11 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace NanoManager;
|
||||
|
||||
std::map<int32_t, NanoData> NanoManager::NanoTable;
|
||||
std::map<int32_t, NanoTuning> NanoManager::NanoTunings;
|
||||
|
||||
void NanoManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_EQUIP, nanoEquipHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_UNEQUIP, nanoUnEquipHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_NANO, nanoGMGiveHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_TUNE, nanoSkillSetHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_NANO_SKILL, nanoSkillSetGMHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_SKILL_USE, nanoSkillUseHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_RXCOM, nanoRecallRegisterHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_WARP_USE_RECALL, nanoRecallHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_CHARGE_NANO_STAMINA, nanoPotionHandler);
|
||||
}
|
||||
|
||||
void NanoManager::nanoEquipHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_EQUIP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_EQUIP* nano = (sP_CL2FE_REQ_NANO_EQUIP*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_EQUIP_SUCC, resp);
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity checks
|
||||
if (nano->iNanoSlotNum > 2 || nano->iNanoSlotNum < 0)
|
||||
return;
|
||||
|
||||
resp.iNanoID = nano->iNanoID;
|
||||
resp.iNanoSlotNum = nano->iNanoSlotNum;
|
||||
|
||||
// Update player
|
||||
plr->equippedNanos[nano->iNanoSlotNum] = nano->iNanoID;
|
||||
|
||||
// Unbuff gumballs
|
||||
int value1 = CSB_BIT_STIMPAKSLOT1 << nano->iNanoSlotNum;
|
||||
if (plr->iConditionBitFlag & value1) {
|
||||
int value2 = ECSB_STIMPAKSLOT1 + nano->iNanoSlotNum;
|
||||
INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt);
|
||||
pkt.eCSTB = value2; // eCharStatusTimeBuffID
|
||||
pkt.eTBU = 2; // eTimeBuffUpdate
|
||||
pkt.eTBT = 1; // eTimeBuffType 1 means nano
|
||||
pkt.iConditionBitFlag = plr->iConditionBitFlag &= ~value1;
|
||||
sock->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
|
||||
}
|
||||
|
||||
// unsummon nano if replaced
|
||||
if (plr->activeNano == plr->equippedNanos[nano->iNanoSlotNum])
|
||||
summonNano(sock, -1);
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_EQUIP_SUCC, sizeof(sP_FE2CL_REP_NANO_EQUIP_SUCC));
|
||||
}
|
||||
|
||||
void NanoManager::nanoUnEquipHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_UNEQUIP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_UNEQUIP* nano = (sP_CL2FE_REQ_NANO_UNEQUIP*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_UNEQUIP_SUCC, resp);
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity check
|
||||
if (nano->iNanoSlotNum > 2 || nano->iNanoSlotNum < 0)
|
||||
return;
|
||||
|
||||
resp.iNanoSlotNum = nano->iNanoSlotNum;
|
||||
|
||||
// unsummon nano if removed
|
||||
if (plr->equippedNanos[nano->iNanoSlotNum] == plr->activeNano)
|
||||
summonNano(sock, -1);
|
||||
|
||||
// update player
|
||||
plr->equippedNanos[nano->iNanoSlotNum] = 0;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_UNEQUIP_SUCC, sizeof(sP_FE2CL_REP_NANO_UNEQUIP_SUCC));
|
||||
}
|
||||
|
||||
void NanoManager::nanoGMGiveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_NANO))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
// Cmd: /nano <nanoID>
|
||||
sP_CL2FE_REQ_PC_GIVE_NANO* nano = (sP_CL2FE_REQ_PC_GIVE_NANO*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// Add nano to player
|
||||
addNano(sock, nano->iNanoID, 0);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << PlayerManager::getPlayerName(plr) << " requested to add nano id: " << nano->iNanoID << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_ACTIVE))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_ACTIVE* pkt = (sP_CL2FE_REQ_NANO_ACTIVE*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
summonNano(sock, pkt->iNanoSlotNum);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
int16_t nanoID = plr->activeNano;
|
||||
int16_t skillID = plr->Nanos[nanoID].iSkillID;
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl;
|
||||
)
|
||||
|
||||
std::vector<int> targetData = findTargets(plr, skillID, data);
|
||||
|
||||
int boost = 0;
|
||||
if (getNanoBoost(plr))
|
||||
boost = 1;
|
||||
|
||||
plr->Nanos[plr->activeNano].iStamina -= SkillTable[skillID].batteryUse[boost*3];
|
||||
if (plr->Nanos[plr->activeNano].iStamina < 0)
|
||||
plr->Nanos[plr->activeNano].iStamina = 0;
|
||||
|
||||
for (auto& pwr : NanoPowers)
|
||||
if (pwr.skillType == SkillTable[skillID].skillType)
|
||||
pwr.handle(sock, targetData, nanoID, skillID, SkillTable[skillID].durationTime[boost], SkillTable[skillID].powerIntensity[boost]);
|
||||
|
||||
if (plr->Nanos[plr->activeNano].iStamina < 0)
|
||||
summonNano(sock, -1);
|
||||
}
|
||||
|
||||
void NanoManager::nanoSkillSetHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_TUNE))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_TUNE* skill = (sP_CL2FE_REQ_NANO_TUNE*)data->buf;
|
||||
setNanoSkill(sock, skill);
|
||||
}
|
||||
|
||||
void NanoManager::nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_NANO_SKILL))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_TUNE* skillGM = (sP_CL2FE_REQ_NANO_TUNE*)data->buf;
|
||||
setNanoSkill(sock, skillGM);
|
||||
}
|
||||
|
||||
void NanoManager::nanoRecallRegisterHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_REGIST_RXCOM))
|
||||
return;
|
||||
|
||||
sP_CL2FE_REQ_REGIST_RXCOM* recallData = (sP_CL2FE_REQ_REGIST_RXCOM*)data->buf;
|
||||
|
||||
if (NPCManager::NPCs.find(recallData->iNPCID) == NPCManager::NPCs.end())
|
||||
return;
|
||||
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
BaseNPC *npc = NPCManager::NPCs[recallData->iNPCID];
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_REGIST_RXCOM, response);
|
||||
response.iMapNum = plr->recallInstance = (int32_t)npc->instanceID; // Never going to recall into a Fusion Lair
|
||||
response.iX = plr->recallX = npc->appearanceData.iX;
|
||||
response.iY = plr->recallY = npc->appearanceData.iY;
|
||||
response.iZ = plr->recallZ = npc->appearanceData.iZ;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_REGIST_RXCOM, sizeof(sP_FE2CL_REP_REGIST_RXCOM));
|
||||
}
|
||||
|
||||
void NanoManager::nanoRecallHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_WARP_USE_RECALL))
|
||||
return;
|
||||
|
||||
sP_CL2FE_REQ_WARP_USE_RECALL* recallData = (sP_CL2FE_REQ_WARP_USE_RECALL*)data->buf;
|
||||
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(recallData->iGroupMemberID);
|
||||
if (otherPlr == nullptr)
|
||||
return;
|
||||
|
||||
// ensure the group member is still in the same IZ
|
||||
if (otherPlr->instanceID != plr->instanceID)
|
||||
return;
|
||||
|
||||
// do not allow hypothetical recall points in lairs to mess with the respawn logic
|
||||
if (PLAYERID(plr->instanceID) != 0)
|
||||
return;
|
||||
|
||||
if ((int32_t)plr->instanceID == otherPlr->recallInstance)
|
||||
PlayerManager::sendPlayerTo(sock, otherPlr->recallX, otherPlr->recallY, otherPlr->recallZ, otherPlr->recallInstance);
|
||||
else {
|
||||
INITSTRUCT(sP_FE2CL_REP_WARP_USE_RECALL_FAIL, response)
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_WARP_USE_RECALL_FAIL, sizeof(sP_FE2CL_REP_WARP_USE_RECALL_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
void NanoManager::nanoPotionHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_CHARGE_NANO_STAMINA))
|
||||
return;
|
||||
|
||||
Player* player = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity checks
|
||||
if (player->activeNano == -1 || player->batteryN == 0)
|
||||
return;
|
||||
|
||||
sNano nano = player->Nanos[player->activeNano];
|
||||
int difference = 150 - nano.iStamina;
|
||||
if (player->batteryN < difference)
|
||||
difference = player->batteryN;
|
||||
|
||||
if (difference == 0)
|
||||
return;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_CHARGE_NANO_STAMINA, response);
|
||||
response.iNanoID = nano.iID;
|
||||
response.iNanoStamina = nano.iStamina + difference;
|
||||
response.iBatteryN = player->batteryN - difference;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_CHARGE_NANO_STAMINA, sizeof(sP_FE2CL_REP_CHARGE_NANO_STAMINA));
|
||||
// now update serverside
|
||||
player->batteryN -= difference;
|
||||
player->Nanos[nano.iID].iStamina += difference;
|
||||
|
||||
}
|
||||
|
||||
#pragma region Helper methods
|
||||
void NanoManager::addNano(CNSocket* sock, int16_t nanoID, int16_t slot, bool spendfm) {
|
||||
if (nanoID <= 0 || nanoID >= NANO_COUNT)
|
||||
@ -353,7 +129,7 @@ void NanoManager::summonNano(CNSocket *sock, int slot, bool silent) {
|
||||
PlayerManager::sendToViewable(sock, (void*)&pkt1, P_FE2CL_NANO_ACTIVE, sizeof(sP_FE2CL_NANO_ACTIVE));
|
||||
}
|
||||
|
||||
void NanoManager::setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill) {
|
||||
static void setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill) {
|
||||
if (skill->iNanoID >= NANO_COUNT)
|
||||
return;
|
||||
|
||||
@ -426,19 +202,6 @@ void NanoManager::setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill) {
|
||||
)
|
||||
}
|
||||
|
||||
void NanoManager::resetNanoSkill(CNSocket* sock, int16_t nanoID) {
|
||||
if (nanoID >= NANO_COUNT)
|
||||
return;
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
sNano nano = plr->Nanos[nanoID];
|
||||
|
||||
// 0 is reset
|
||||
nano.iSkillID = 0;
|
||||
plr->Nanos[nanoID] = nano;
|
||||
}
|
||||
|
||||
// 0=A 1=B 2=C -1=Not found
|
||||
int NanoManager::nanoStyle(int nanoID) {
|
||||
if (nanoID < 1 || nanoID >= (int)NanoTable.size())
|
||||
@ -454,3 +217,229 @@ bool NanoManager::getNanoBoost(Player* plr) {
|
||||
return false;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
static void nanoEquipHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_EQUIP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_EQUIP* nano = (sP_CL2FE_REQ_NANO_EQUIP*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_EQUIP_SUCC, resp);
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity checks
|
||||
if (nano->iNanoSlotNum > 2 || nano->iNanoSlotNum < 0)
|
||||
return;
|
||||
|
||||
resp.iNanoID = nano->iNanoID;
|
||||
resp.iNanoSlotNum = nano->iNanoSlotNum;
|
||||
|
||||
// Update player
|
||||
plr->equippedNanos[nano->iNanoSlotNum] = nano->iNanoID;
|
||||
|
||||
// Unbuff gumballs
|
||||
int value1 = CSB_BIT_STIMPAKSLOT1 << nano->iNanoSlotNum;
|
||||
if (plr->iConditionBitFlag & value1) {
|
||||
int value2 = ECSB_STIMPAKSLOT1 + nano->iNanoSlotNum;
|
||||
INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt);
|
||||
pkt.eCSTB = value2; // eCharStatusTimeBuffID
|
||||
pkt.eTBU = 2; // eTimeBuffUpdate
|
||||
pkt.eTBT = 1; // eTimeBuffType 1 means nano
|
||||
pkt.iConditionBitFlag = plr->iConditionBitFlag &= ~value1;
|
||||
sock->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE));
|
||||
}
|
||||
|
||||
// unsummon nano if replaced
|
||||
if (plr->activeNano == plr->equippedNanos[nano->iNanoSlotNum])
|
||||
summonNano(sock, -1);
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_EQUIP_SUCC, sizeof(sP_FE2CL_REP_NANO_EQUIP_SUCC));
|
||||
}
|
||||
|
||||
static void nanoUnEquipHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_UNEQUIP))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_UNEQUIP* nano = (sP_CL2FE_REQ_NANO_UNEQUIP*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_UNEQUIP_SUCC, resp);
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity check
|
||||
if (nano->iNanoSlotNum > 2 || nano->iNanoSlotNum < 0)
|
||||
return;
|
||||
|
||||
resp.iNanoSlotNum = nano->iNanoSlotNum;
|
||||
|
||||
// unsummon nano if removed
|
||||
if (plr->equippedNanos[nano->iNanoSlotNum] == plr->activeNano)
|
||||
summonNano(sock, -1);
|
||||
|
||||
// update player
|
||||
plr->equippedNanos[nano->iNanoSlotNum] = 0;
|
||||
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_UNEQUIP_SUCC, sizeof(sP_FE2CL_REP_NANO_UNEQUIP_SUCC));
|
||||
}
|
||||
|
||||
static void nanoGMGiveHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_NANO))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
// Cmd: /nano <nanoID>
|
||||
sP_CL2FE_REQ_PC_GIVE_NANO* nano = (sP_CL2FE_REQ_PC_GIVE_NANO*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
// Add nano to player
|
||||
addNano(sock, nano->iNanoID, 0);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << PlayerManager::getPlayerName(plr) << " requested to add nano id: " << nano->iNanoID << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
static void nanoSummonHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_ACTIVE))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_ACTIVE* pkt = (sP_CL2FE_REQ_NANO_ACTIVE*)data->buf;
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
summonNano(sock, pkt->iNanoSlotNum);
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl;
|
||||
)
|
||||
}
|
||||
|
||||
static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
int16_t nanoID = plr->activeNano;
|
||||
int16_t skillID = plr->Nanos[nanoID].iSkillID;
|
||||
|
||||
DEBUGLOG(
|
||||
std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl;
|
||||
)
|
||||
|
||||
std::vector<int> targetData = findTargets(plr, skillID, data);
|
||||
|
||||
int boost = 0;
|
||||
if (getNanoBoost(plr))
|
||||
boost = 1;
|
||||
|
||||
plr->Nanos[plr->activeNano].iStamina -= SkillTable[skillID].batteryUse[boost*3];
|
||||
if (plr->Nanos[plr->activeNano].iStamina < 0)
|
||||
plr->Nanos[plr->activeNano].iStamina = 0;
|
||||
|
||||
for (auto& pwr : NanoPowers)
|
||||
if (pwr.skillType == SkillTable[skillID].skillType)
|
||||
pwr.handle(sock, targetData, nanoID, skillID, SkillTable[skillID].durationTime[boost], SkillTable[skillID].powerIntensity[boost]);
|
||||
|
||||
if (plr->Nanos[plr->activeNano].iStamina < 0)
|
||||
summonNano(sock, -1);
|
||||
}
|
||||
|
||||
static void nanoSkillSetHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_NANO_TUNE))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_TUNE* skill = (sP_CL2FE_REQ_NANO_TUNE*)data->buf;
|
||||
setNanoSkill(sock, skill);
|
||||
}
|
||||
|
||||
static void nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_NANO_SKILL))
|
||||
return; // malformed packet
|
||||
|
||||
sP_CL2FE_REQ_NANO_TUNE* skillGM = (sP_CL2FE_REQ_NANO_TUNE*)data->buf;
|
||||
setNanoSkill(sock, skillGM);
|
||||
}
|
||||
|
||||
static void nanoRecallRegisterHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_REGIST_RXCOM))
|
||||
return;
|
||||
|
||||
sP_CL2FE_REQ_REGIST_RXCOM* recallData = (sP_CL2FE_REQ_REGIST_RXCOM*)data->buf;
|
||||
|
||||
if (NPCManager::NPCs.find(recallData->iNPCID) == NPCManager::NPCs.end())
|
||||
return;
|
||||
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
|
||||
BaseNPC *npc = NPCManager::NPCs[recallData->iNPCID];
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_REGIST_RXCOM, response);
|
||||
response.iMapNum = plr->recallInstance = (int32_t)npc->instanceID; // Never going to recall into a Fusion Lair
|
||||
response.iX = plr->recallX = npc->appearanceData.iX;
|
||||
response.iY = plr->recallY = npc->appearanceData.iY;
|
||||
response.iZ = plr->recallZ = npc->appearanceData.iZ;
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_REGIST_RXCOM, sizeof(sP_FE2CL_REP_REGIST_RXCOM));
|
||||
}
|
||||
|
||||
static void nanoRecallHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_WARP_USE_RECALL))
|
||||
return;
|
||||
|
||||
sP_CL2FE_REQ_WARP_USE_RECALL* recallData = (sP_CL2FE_REQ_WARP_USE_RECALL*)data->buf;
|
||||
|
||||
Player* plr = PlayerManager::getPlayer(sock);
|
||||
Player* otherPlr = PlayerManager::getPlayerFromID(recallData->iGroupMemberID);
|
||||
if (otherPlr == nullptr)
|
||||
return;
|
||||
|
||||
// ensure the group member is still in the same IZ
|
||||
if (otherPlr->instanceID != plr->instanceID)
|
||||
return;
|
||||
|
||||
// do not allow hypothetical recall points in lairs to mess with the respawn logic
|
||||
if (PLAYERID(plr->instanceID) != 0)
|
||||
return;
|
||||
|
||||
if ((int32_t)plr->instanceID == otherPlr->recallInstance)
|
||||
PlayerManager::sendPlayerTo(sock, otherPlr->recallX, otherPlr->recallY, otherPlr->recallZ, otherPlr->recallInstance);
|
||||
else {
|
||||
INITSTRUCT(sP_FE2CL_REP_WARP_USE_RECALL_FAIL, response)
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_WARP_USE_RECALL_FAIL, sizeof(sP_FE2CL_REP_WARP_USE_RECALL_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
static void nanoPotionHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_CHARGE_NANO_STAMINA))
|
||||
return;
|
||||
|
||||
Player* player = PlayerManager::getPlayer(sock);
|
||||
|
||||
// sanity checks
|
||||
if (player->activeNano == -1 || player->batteryN == 0)
|
||||
return;
|
||||
|
||||
sNano nano = player->Nanos[player->activeNano];
|
||||
int difference = 150 - nano.iStamina;
|
||||
if (player->batteryN < difference)
|
||||
difference = player->batteryN;
|
||||
|
||||
if (difference == 0)
|
||||
return;
|
||||
|
||||
INITSTRUCT(sP_FE2CL_REP_CHARGE_NANO_STAMINA, response);
|
||||
response.iNanoID = nano.iID;
|
||||
response.iNanoStamina = nano.iStamina + difference;
|
||||
response.iBatteryN = player->batteryN - difference;
|
||||
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_CHARGE_NANO_STAMINA, sizeof(sP_FE2CL_REP_CHARGE_NANO_STAMINA));
|
||||
// now update serverside
|
||||
player->batteryN -= difference;
|
||||
player->Nanos[nano.iID].iStamina += difference;
|
||||
|
||||
}
|
||||
|
||||
void NanoManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_EQUIP, nanoEquipHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_UNEQUIP, nanoUnEquipHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_NANO, nanoGMGiveHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_TUNE, nanoSkillSetHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_NANO_SKILL, nanoSkillSetGMHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_SKILL_USE, nanoSkillUseHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_RXCOM, nanoRecallRegisterHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_WARP_USE_RECALL, nanoRecallHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_CHARGE_NANO_STAMINA, nanoPotionHandler);
|
||||
}
|
||||
|
@ -20,23 +20,9 @@ namespace NanoManager {
|
||||
extern std::map<int32_t, NanoTuning> NanoTunings;
|
||||
void init();
|
||||
|
||||
void nanoSummonHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoEquipHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoUnEquipHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoGMGiveHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoSkillSetHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoRecallRegisterHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoRecallHandler(CNSocket* sock, CNPacketData* data);
|
||||
void nanoPotionHandler(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
// Helper methods
|
||||
void addNano(CNSocket* sock, int16_t nanoID, int16_t slot, bool spendfm=false);
|
||||
void summonNano(CNSocket* sock, int slot, bool silent = false);
|
||||
void setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill);
|
||||
void resetNanoSkill(CNSocket* sock, int16_t nanoID);
|
||||
int nanoStyle(int nanoID);
|
||||
std::vector<int> findTargets(Player* plr, int skillID, CNPacketData* data = nullptr);
|
||||
bool getNanoBoost(Player* plr);
|
||||
}
|
||||
|
@ -21,23 +21,11 @@
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
using namespace PlayerManager;
|
||||
|
||||
std::map<CNSocket*, Player*> PlayerManager::players;
|
||||
|
||||
void PlayerManager::init() {
|
||||
// register packet types
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ENTER, enterPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_LOADING_COMPLETE, loadPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REP_LIVE_CHECK, heartbeatPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_REGEN, revivePlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EXIT, exitGame);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH, setSpecialSwitchPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_ON, enterPlayerVehicle);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_OFF, exitPlayerVehicle);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_CHANGE_MENTOR, changePlayerGuide);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIRST_USE_FLAG_SET, setFirstUseFlag);
|
||||
}
|
||||
|
||||
void PlayerManager::addPlayer(CNSocket* key, Player plr) {
|
||||
static void addPlayer(CNSocket* key, Player plr) {
|
||||
Player *p = new Player();
|
||||
|
||||
memcpy(p, &plr, sizeof(Player));
|
||||
@ -174,7 +162,36 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z) {
|
||||
sendPlayerTo(sock, X, Y, Z, getPlayer(sock)->instanceID);
|
||||
}
|
||||
|
||||
void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
/*
|
||||
* Sends all nanos, from 0 to 58 (the contents of the Nanos array in PC_ENTER_SUCC are totally irrelevant).
|
||||
* The first Nano in the in-game nanobook is the Unstable Nano, which is Van Kleiss.
|
||||
* 0 (in plr->Nanos) is the null nano entry.
|
||||
* 58 is a "Coming Soon" duplicate entry for an actual Van Kleiss nano, identical to the Unstable Nano.
|
||||
* Nanos the player hasn't unlocked will (and should) be greyed out. Thus, all nanos should be accounted
|
||||
* for in these packets, even if the player hasn't unlocked them.
|
||||
*/
|
||||
static void sendNanoBookSubset(CNSocket *sock) {
|
||||
#ifdef ACADEMY
|
||||
Player *plr = getPlayer(sock);
|
||||
|
||||
int16_t id = 0;
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_BOOK_SUBSET, pkt);
|
||||
|
||||
pkt.PCUID = plr->iID;
|
||||
pkt.bookSize = NANO_COUNT;
|
||||
|
||||
while (id < NANO_COUNT) {
|
||||
pkt.elementOffset = id;
|
||||
|
||||
for (int i = id - pkt.elementOffset; id < NANO_COUNT && i < 10; id++, i = id - pkt.elementOffset)
|
||||
pkt.element[i] = plr->Nanos[id];
|
||||
|
||||
sock->sendPacket((void*)&pkt, P_FE2CL_REP_NANO_BOOK_SUBSET, sizeof(sP_FE2CL_REP_NANO_BOOK_SUBSET));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void enterPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_ENTER))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
@ -306,40 +323,11 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
// initial buddy sync
|
||||
BuddyManager::refreshBuddyList(sock);
|
||||
|
||||
for (auto& pair : PlayerManager::players)
|
||||
for (auto& pair : players)
|
||||
if (pair.second->notify)
|
||||
ChatManager::sendServerMessage(pair.first, "[ADMIN]" + getPlayerName(&plr) + " has joined.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends all nanos, from 0 to 58 (the contents of the Nanos array in PC_ENTER_SUCC are totally irrelevant).
|
||||
* The first Nano in the in-game nanobook is the Unstable Nano, which is Van Kleiss.
|
||||
* 0 (in plr->Nanos) is the null nano entry.
|
||||
* 58 is a "Coming Soon" duplicate entry for an actual Van Kleiss nano, identical to the Unstable Nano.
|
||||
* Nanos the player hasn't unlocked will (and should) be greyed out. Thus, all nanos should be accounted
|
||||
* for in these packets, even if the player hasn't unlocked them.
|
||||
*/
|
||||
void PlayerManager::sendNanoBookSubset(CNSocket *sock) {
|
||||
#ifdef ACADEMY
|
||||
Player *plr = getPlayer(sock);
|
||||
|
||||
int16_t id = 0;
|
||||
INITSTRUCT(sP_FE2CL_REP_NANO_BOOK_SUBSET, pkt);
|
||||
|
||||
pkt.PCUID = plr->iID;
|
||||
pkt.bookSize = NANO_COUNT;
|
||||
|
||||
while (id < NANO_COUNT) {
|
||||
pkt.elementOffset = id;
|
||||
|
||||
for (int i = id - pkt.elementOffset; id < NANO_COUNT && i < 10; id++, i = id - pkt.elementOffset)
|
||||
pkt.element[i] = plr->Nanos[id];
|
||||
|
||||
sock->sendPacket((void*)&pkt, P_FE2CL_REP_NANO_BOOK_SUBSET, sizeof(sP_FE2CL_REP_NANO_BOOK_SUBSET));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size) {
|
||||
Player* plr = getPlayer(sock);
|
||||
for (auto it = plr->viewableChunks->begin(); it != plr->viewableChunks->end(); it++) {
|
||||
@ -353,7 +341,7 @@ void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, siz
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::loadPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
static void loadPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_LOADING_COMPLETE))
|
||||
return; // ignore the malformed packet
|
||||
|
||||
@ -373,11 +361,11 @@ void PlayerManager::loadPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_LOADING_COMPLETE_SUCC, sizeof(sP_FE2CL_REP_PC_LOADING_COMPLETE_SUCC));
|
||||
}
|
||||
|
||||
void PlayerManager::heartbeatPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
static void heartbeatPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
getPlayer(sock)->lastHeartbeat = getTime();
|
||||
}
|
||||
|
||||
void PlayerManager::exitGame(CNSocket* sock, CNPacketData* data) {
|
||||
static void exitGame(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_EXIT))
|
||||
return;
|
||||
|
||||
@ -390,12 +378,27 @@ void PlayerManager::exitGame(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_EXIT_SUCC, sizeof(sP_FE2CL_REP_PC_EXIT_SUCC));
|
||||
}
|
||||
|
||||
void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
static WarpLocation* getRespawnPoint(Player *plr) {
|
||||
WarpLocation* best = nullptr;
|
||||
uint32_t curDist, bestDist = UINT32_MAX;
|
||||
|
||||
for (auto& targ : NPCManager::RespawnPoints) {
|
||||
curDist = sqrt(pow(plr->x - targ.x, 2) + pow(plr->y - targ.y, 2));
|
||||
if (curDist < bestDist && targ.instanceID == MAPNUM(plr->instanceID)) { // only mapNum needs to match
|
||||
best = &targ;
|
||||
bestDist = curDist;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
static void revivePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_REGEN))
|
||||
return;
|
||||
|
||||
Player *plr = PlayerManager::getPlayer(sock);
|
||||
WarpLocation* target = PlayerManager::getRespawnPoint(plr);
|
||||
Player *plr = getPlayer(sock);
|
||||
WarpLocation* target = getRespawnPoint(plr);
|
||||
|
||||
sP_CL2FE_REQ_PC_REGEN* reviveData = (sP_CL2FE_REQ_PC_REGEN*)data->buf;
|
||||
INITSTRUCT(sP_FE2CL_REP_PC_REGEN_SUCC, response);
|
||||
@ -466,7 +469,7 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
resp2.PCRegenDataForOtherPC.iHP = plr->HP;
|
||||
resp2.PCRegenDataForOtherPC.iAngle = plr->angle;
|
||||
|
||||
Player *otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||
Player *otherPlr = getPlayerFromID(plr->iIDGroup);
|
||||
if (otherPlr != nullptr) {
|
||||
int bitFlag = GroupManager::getGroupFlags(otherPlr);
|
||||
resp2.PCRegenDataForOtherPC.iConditionBitFlag = plr->iConditionBitFlag = plr->iSelfConditionBitFlag | bitFlag;
|
||||
@ -485,7 +488,7 @@ void PlayerManager::revivePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
updatePlayerPosition(sock, x, y, z, plr->instanceID, plr->angle);
|
||||
}
|
||||
|
||||
void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
static void enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
Player* plr = getPlayer(sock);
|
||||
|
||||
bool expired = plr->Equip[8].iTimeLimit < getTimestamp() && plr->Equip[8].iTimeLimit != 0;
|
||||
@ -514,7 +517,7 @@ void PlayerManager::enterPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
static void exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
Player* plr = getPlayer(sock);
|
||||
|
||||
if (plr->iPCState & 8) {
|
||||
@ -531,11 +534,11 @@ void PlayerManager::exitPlayerVehicle(CNSocket* sock, CNPacketData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerManager::setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
static void setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data) {
|
||||
BuiltinCommands::setSpecialState(sock, data);
|
||||
}
|
||||
|
||||
void PlayerManager::changePlayerGuide(CNSocket *sock, CNPacketData *data) {
|
||||
static void changePlayerGuide(CNSocket *sock, CNPacketData *data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_CHANGE_MENTOR))
|
||||
return;
|
||||
|
||||
@ -565,7 +568,7 @@ void PlayerManager::changePlayerGuide(CNSocket *sock, CNPacketData *data) {
|
||||
plr->mentor = pkt->iMentor;
|
||||
}
|
||||
|
||||
void PlayerManager::setFirstUseFlag(CNSocket* sock, CNPacketData* data) {
|
||||
static void setFirstUseFlag(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_FIRST_USE_FLAG_SET))
|
||||
return;
|
||||
|
||||
@ -609,24 +612,9 @@ std::string PlayerManager::getPlayerName(Player *plr, bool id) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
WarpLocation* PlayerManager::getRespawnPoint(Player *plr) {
|
||||
WarpLocation* best = nullptr;
|
||||
uint32_t curDist, bestDist = UINT32_MAX;
|
||||
|
||||
for (auto& targ : NPCManager::RespawnPoints) {
|
||||
curDist = sqrt(pow(plr->x - targ.x, 2) + pow(plr->y - targ.y, 2));
|
||||
if (curDist < bestDist && targ.instanceID == MAPNUM(plr->instanceID)) { // only mapNum needs to match
|
||||
best = &targ;
|
||||
bestDist = curDist;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
bool PlayerManager::isAccountInUse(int accountId) {
|
||||
std::map<CNSocket*, Player*>::iterator it;
|
||||
for (it = PlayerManager::players.begin(); it != PlayerManager::players.end(); it++) {
|
||||
for (it = players.begin(); it != players.end(); it++) {
|
||||
if (it->second->accountId == accountId)
|
||||
return true;
|
||||
}
|
||||
@ -698,3 +686,17 @@ CNSocket *PlayerManager::getSockFromAny(int by, int id, int uid, std::string fir
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void PlayerManager::init() {
|
||||
// register packet types
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ENTER, enterPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_LOADING_COMPLETE, loadPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REP_LIVE_CHECK, heartbeatPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_REGEN, revivePlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EXIT, exitGame);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_SPECIAL_STATE_SWITCH, setSpecialSwitchPlayer);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_ON, enterPlayerVehicle);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VEHICLE_OFF, exitPlayerVehicle);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_CHANGE_MENTOR, changePlayerGuide);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_FIRST_USE_FLAG_SET, setFirstUseFlag);
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ namespace PlayerManager {
|
||||
extern std::map<CNSocket*, Player*> players;
|
||||
void init();
|
||||
|
||||
void addPlayer(CNSocket* key, Player plr);
|
||||
void removePlayer(CNSocket* key);
|
||||
|
||||
void updatePlayerPosition(CNSocket* sock, int X, int Y, int Z, uint64_t I, int angle);
|
||||
@ -26,31 +25,13 @@ namespace PlayerManager {
|
||||
|
||||
void sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size);
|
||||
|
||||
void enterPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void loadPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void heartbeatPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void revivePlayer(CNSocket* sock, CNPacketData* data);
|
||||
void exitGame(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void setSpecialSwitchPlayer(CNSocket* sock, CNPacketData* data);
|
||||
void changePlayerGuide(CNSocket *sock, CNPacketData *data);
|
||||
|
||||
void enterPlayerVehicle(CNSocket* sock, CNPacketData* data);
|
||||
void exitPlayerVehicle(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
void setFirstUseFlag(CNSocket* sock, CNPacketData* data);
|
||||
|
||||
Player *getPlayer(CNSocket* key);
|
||||
std::string getPlayerName(Player *plr, bool id=true);
|
||||
WarpLocation* getRespawnPoint(Player *plr);
|
||||
|
||||
bool isAccountInUse(int accountId);
|
||||
void exitDuplicate(int accountId);
|
||||
void setSpecialState(CNSocket* sock, CNPacketData* data);
|
||||
Player *getPlayerFromID(int32_t iID);
|
||||
CNSocket *getSockFromID(int32_t iID);
|
||||
CNSocket *getSockFromName(std::string firstname, std::string lastname);
|
||||
CNSocket *getSockFromAny(int by, int id, int uid, std::string firstname, std::string lastname);
|
||||
|
||||
void sendNanoBookSubset(CNSocket *sock);
|
||||
}
|
||||
|
@ -7,18 +7,13 @@
|
||||
#include "db/Database.hpp"
|
||||
#include "NPCManager.hpp"
|
||||
|
||||
using namespace RacingManager;
|
||||
|
||||
std::map<int32_t, EPInfo> RacingManager::EPData;
|
||||
std::map<CNSocket*, EPRace> RacingManager::EPRaces;
|
||||
std::map<int32_t, std::pair<std::vector<int>, std::vector<int>>> RacingManager::EPRewards;
|
||||
|
||||
void RacingManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_START, racingStart);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_GET_RING, racingGetPod);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_CANCEL, racingCancel);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_END, racingEnd);
|
||||
}
|
||||
|
||||
void RacingManager::racingStart(CNSocket* sock, CNPacketData* data) {
|
||||
static void racingStart(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_EP_RACE_START))
|
||||
return; // malformed packet
|
||||
|
||||
@ -42,7 +37,7 @@ void RacingManager::racingStart(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_EP_RACE_START_SUCC, sizeof(sP_FE2CL_REP_EP_RACE_START_SUCC));
|
||||
}
|
||||
|
||||
void RacingManager::racingGetPod(CNSocket* sock, CNPacketData* data) {
|
||||
static void racingGetPod(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_EP_GET_RING))
|
||||
return; // malformed packet
|
||||
|
||||
@ -62,7 +57,7 @@ void RacingManager::racingGetPod(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_EP_GET_RING_SUCC, sizeof(sP_FE2CL_REP_EP_GET_RING_SUCC));
|
||||
}
|
||||
|
||||
void RacingManager::racingCancel(CNSocket* sock, CNPacketData* data) {
|
||||
static void racingCancel(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_EP_RACE_CANCEL))
|
||||
return; // malformed packet
|
||||
|
||||
@ -75,7 +70,7 @@ void RacingManager::racingCancel(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_EP_RACE_CANCEL_SUCC, sizeof(sP_FE2CL_REP_EP_RACE_CANCEL_SUCC));
|
||||
}
|
||||
|
||||
void RacingManager::racingEnd(CNSocket* sock, CNPacketData* data) {
|
||||
static void racingEnd(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_EP_RACE_END))
|
||||
return; // malformed packet
|
||||
|
||||
@ -165,3 +160,9 @@ void RacingManager::racingEnd(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_EP_RACE_END_SUCC, sizeof(sP_FE2CL_REP_EP_RACE_END_SUCC));
|
||||
}
|
||||
|
||||
void RacingManager::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_START, racingStart);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_GET_RING, racingGetPod);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_CANCEL, racingCancel);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_EP_RACE_END, racingEnd);
|
||||
}
|
||||
|
@ -17,9 +17,4 @@ namespace RacingManager {
|
||||
extern std::map<int32_t, std::pair<std::vector<int>, std::vector<int>>> EPRewards;
|
||||
|
||||
void init();
|
||||
|
||||
void racingStart(CNSocket* sock, CNPacketData* data);
|
||||
void racingGetPod(CNSocket* sock, CNPacketData* data);
|
||||
void racingCancel(CNSocket* sock, CNPacketData* data);
|
||||
void racingEnd(CNSocket* sock, CNPacketData* data);
|
||||
}
|
||||
|
1042
src/TableData.cpp
1042
src/TableData.cpp
File diff suppressed because it is too large
Load Diff
@ -13,13 +13,5 @@ namespace TableData {
|
||||
extern std::map<int32_t, BaseNPC*> RunningEggs;
|
||||
|
||||
void init();
|
||||
void cleanup();
|
||||
void loadGruntwork(int32_t*);
|
||||
void flush();
|
||||
|
||||
void loadPaths(int*);
|
||||
void loadDrops();
|
||||
void loadEggs(int32_t* nextId);
|
||||
void constructPathSkyway(nlohmann::json::iterator);
|
||||
void constructPathNPC(nlohmann::json::iterator, int id=0);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "Trading.hpp"
|
||||
#include "PlayerManager.hpp"
|
||||
|
||||
bool doTrade(Player* plr, Player* plr2) {
|
||||
using namespace Trading;
|
||||
|
||||
static bool doTrade(Player* plr, Player* plr2) {
|
||||
// init dummy inventories
|
||||
sItemBase plrInven[AINVEN_COUNT];
|
||||
sItemBase plr2Inven[AINVEN_COUNT];
|
||||
@ -429,4 +431,4 @@ void Trading::init() {
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER, tradeRegisterItem);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER, tradeUnregisterItem);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CASH_REGISTER, tradeRegisterCash);
|
||||
}
|
||||
}
|
||||
|
@ -10,20 +10,15 @@
|
||||
#include <unordered_map>
|
||||
#include <cmath>
|
||||
|
||||
using namespace TransportManager;
|
||||
|
||||
std::map<int32_t, TransportRoute> TransportManager::Routes;
|
||||
std::map<int32_t, TransportLocation> TransportManager::Locations;
|
||||
std::map<int32_t, std::queue<WarpLocation>> TransportManager::SkywayPaths;
|
||||
std::unordered_map<CNSocket*, std::queue<WarpLocation>> TransportManager::SkywayQueues;
|
||||
std::unordered_map<int32_t, std::queue<WarpLocation>> TransportManager::NPCQueues;
|
||||
|
||||
void TransportManager::init() {
|
||||
REGISTER_SHARD_TIMER(tickTransportationSystem, 1000);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION, transportWarpHandler);
|
||||
}
|
||||
|
||||
void TransportManager::transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void transportRegisterLocationHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION))
|
||||
return; // malformed packet
|
||||
|
||||
@ -99,7 +94,7 @@ void TransportManager::transportRegisterLocationHandler(CNSocket* sock, CNPacket
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC, sizeof(sP_FE2CL_REP_PC_REGIST_TRANSPORTATION_LOCATION_SUCC));
|
||||
}
|
||||
|
||||
void TransportManager::transportWarpHandler(CNSocket* sock, CNPacketData* data) {
|
||||
static void transportWarpHandler(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION))
|
||||
return; // malformed packet
|
||||
|
||||
@ -196,16 +191,11 @@ void TransportManager::testMssRoute(CNSocket *sock, std::vector<WarpLocation>* r
|
||||
SkywayQueues[sock] = path;
|
||||
}
|
||||
|
||||
void TransportManager::tickTransportationSystem(CNServer* serv, time_t currTime) {
|
||||
stepNPCPathing();
|
||||
stepSkywaySystem();
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through every socket that has broomstick points queued up, and advance to the next point.
|
||||
* If the player has disconnected or finished the route, clean up and remove them from the queue.
|
||||
*/
|
||||
void TransportManager::stepSkywaySystem() {
|
||||
static void stepSkywaySystem() {
|
||||
|
||||
// using an unordered map so we can remove finished players in one iteration
|
||||
std::unordered_map<CNSocket*, std::queue<WarpLocation>>::iterator it = SkywayQueues.begin();
|
||||
@ -254,7 +244,7 @@ void TransportManager::stepSkywaySystem() {
|
||||
}
|
||||
}
|
||||
|
||||
void TransportManager::stepNPCPathing() {
|
||||
static void stepNPCPathing() {
|
||||
|
||||
// all NPC pathing queues
|
||||
std::unordered_map<int32_t, std::queue<WarpLocation>>::iterator it = NPCQueues.begin();
|
||||
@ -334,6 +324,11 @@ void TransportManager::stepNPCPathing() {
|
||||
}
|
||||
}
|
||||
|
||||
static void tickTransportationSystem(CNServer* serv, time_t currTime) {
|
||||
stepNPCPathing();
|
||||
stepSkywaySystem();
|
||||
}
|
||||
|
||||
/*
|
||||
* Linearly interpolate between two points and insert the results into a queue.
|
||||
*/
|
||||
@ -355,3 +350,10 @@ void TransportManager::lerp(std::queue<WarpLocation>* queue, WarpLocation start,
|
||||
void TransportManager::lerp(std::queue<WarpLocation>* queue, WarpLocation start, WarpLocation end, int gapSize) {
|
||||
lerp(queue, start, end, gapSize, 1);
|
||||
}
|
||||
|
||||
void TransportManager::init() {
|
||||
REGISTER_SHARD_TIMER(tickTransportationSystem, 1000);
|
||||
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_REGIST_TRANSPORTATION_LOCATION, transportRegisterLocationHandler);
|
||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_TRANSPORTATION, transportWarpHandler);
|
||||
}
|
||||
|
@ -28,15 +28,8 @@ namespace TransportManager {
|
||||
|
||||
void init();
|
||||
|
||||
void transportRegisterLocationHandler(CNSocket*, CNPacketData*);
|
||||
void transportWarpHandler(CNSocket*, CNPacketData*);
|
||||
|
||||
void testMssRoute(CNSocket *sock, std::vector<WarpLocation>* route);
|
||||
|
||||
void tickTransportationSystem(CNServer*, time_t);
|
||||
void stepNPCPathing();
|
||||
void stepSkywaySystem();
|
||||
|
||||
void lerp(std::queue<WarpLocation>*, WarpLocation, WarpLocation, int, float);
|
||||
void lerp(std::queue<WarpLocation>*, WarpLocation, WarpLocation, int);
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "Vendor.hpp"
|
||||
|
||||
using namespace Vendor;
|
||||
|
||||
std::map<int32_t, std::vector<VendorListing>> Vendor::VendorTables;
|
||||
|
||||
void Vendor::vendorBuy(CNSocket* sock, CNPacketData* data) {
|
||||
static void vendorBuy(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY))
|
||||
return; // malformed packet
|
||||
|
||||
@ -57,7 +59,7 @@ void Vendor::vendorBuy(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_ITEM_BUY_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_ITEM_BUY_SUCC));
|
||||
}
|
||||
|
||||
void Vendor::vendorSell(CNSocket* sock, CNPacketData* data) {
|
||||
static void vendorSell(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_SELL))
|
||||
return; // malformed packet
|
||||
|
||||
@ -123,7 +125,7 @@ void Vendor::vendorSell(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_ITEM_SELL_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_ITEM_SELL_SUCC));
|
||||
}
|
||||
|
||||
void Vendor::vendorBuyback(CNSocket* sock, CNPacketData* data) {
|
||||
static void vendorBuyback(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_RESTORE_BUY))
|
||||
return; // malformed packet
|
||||
|
||||
@ -202,7 +204,7 @@ void Vendor::vendorBuyback(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_ITEM_RESTORE_BUY_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_ITEM_RESTORE_BUY_SUCC));
|
||||
}
|
||||
|
||||
void Vendor::vendorTable(CNSocket* sock, CNPacketData* data) {
|
||||
static void vendorTable(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_TABLE_UPDATE))
|
||||
return; // malformed packet
|
||||
|
||||
@ -234,7 +236,7 @@ void Vendor::vendorTable(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_SUCC));
|
||||
}
|
||||
|
||||
void Vendor::vendorStart(CNSocket* sock, CNPacketData* data) {
|
||||
static void vendorStart(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_START))
|
||||
return; // malformed packet
|
||||
|
||||
@ -247,7 +249,7 @@ void Vendor::vendorStart(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_START_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_START_SUCC));
|
||||
}
|
||||
|
||||
void Vendor::vendorBuyBattery(CNSocket* sock, CNPacketData* data) {
|
||||
static void vendorBuyBattery(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_BATTERY_BUY))
|
||||
return; // malformed packet
|
||||
|
||||
@ -284,7 +286,7 @@ void Vendor::vendorBuyBattery(CNSocket* sock, CNPacketData* data) {
|
||||
sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_BATTERY_BUY_SUCC));
|
||||
}
|
||||
|
||||
void vendorCombineItems(CNSocket* sock, CNPacketData* data) {
|
||||
static void vendorCombineItems(CNSocket* sock, CNPacketData* data) {
|
||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_ITEM_COMBINATION))
|
||||
return; // malformed packet
|
||||
|
||||
|
@ -15,11 +15,4 @@ namespace Vendor {
|
||||
extern std::map<int32_t, std::vector<VendorListing>> VendorTables;
|
||||
|
||||
void init();
|
||||
|
||||
void vendorStart(CNSocket* sock, CNPacketData* data);
|
||||
void vendorTable(CNSocket* sock, CNPacketData* data);
|
||||
void vendorBuy(CNSocket* sock, CNPacketData* data);
|
||||
void vendorSell(CNSocket* sock, CNPacketData* data);
|
||||
void vendorBuyback(CNSocket* sock, CNPacketData* data);
|
||||
void vendorBuyBattery(CNSocket* sock, CNPacketData* data);
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "BuddyManager.hpp"
|
||||
#include "db/Database.hpp"
|
||||
#include "TableData.hpp"
|
||||
#include "ChunkManager.hpp"
|
||||
#include "GroupManager.hpp"
|
||||
#include "Monitor.hpp"
|
||||
#include "RacingManager.hpp"
|
||||
|
Loading…
Reference in New Issue
Block a user