[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:
dongresource 2021-03-16 22:06:10 +01:00
parent 04c56ce426
commit cee09f6344
36 changed files with 1808 additions and 1957 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -7,6 +7,5 @@
namespace Monitor {
SOCKET init();
void tick(CNServer *, time_t);
bool acceptConnection(SOCKET, uint16_t);
};

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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"