knightonline/server/GameServer/Knights.cpp

396 lines
9.1 KiB
C++

#include "stdafx.h"
#include "Knights.h"
#include "DBAgent.h"
using std::string;
CKnights::CKnights()
{
m_sIndex = 0;
m_byFlag = ClanTypeNone;
m_byNation = 0;
m_byGrade = 5;
m_byRanking = 0;
m_sMembers = 1;
memset(&m_Image, 0, sizeof(m_Image));
m_nMoney = 0;
m_sDomination = 0;
m_nPoints = 0;
m_nClanPointFund = 0;
m_sCape = -1;
m_sAlliance = 0;
m_sMarkLen = 0;
m_sMarkVersion = 0;
m_bCapeR = m_bCapeG = m_bCapeB = 0;
m_sClanPointMethod = 0;
}
void CKnights::OnLogin(CUser *pUser)
{
Packet result, result2;
string Name = "", myName = pUser->GetName();
STRTOUPPER(myName);
// Set the active session for this user
foreach_array (i, m_arKnightsUser)
{
_KNIGHTS_USER * p = &m_arKnightsUser[i];
if (!p->byUsed)
continue;
Name = p->strUserName;
STRTOUPPER(Name);
if(Name != myName)
continue;
p->pSession = pUser;
pUser->m_pKnightsUser = p;
break;
}
// Send login notice
// TODO: Shift this to SERVER_RESOURCE
std::string buffer = string_format("%s is online.", pUser->GetName().c_str());
ChatPacket::Construct(&result, KNIGHTS_CHAT, &buffer);
Send(&result);
// Construct the clan notice packet to send to the logged in player
if (!m_strClanNotice.empty())
{
ConstructClanNoticePacket(&result);
pUser->Send(&result);
}
if(m_sAlliance != 0)
{
std::string buffer2 = string_format("%s is online.", pUser->GetName().c_str());
ChatPacket::Construct(&result2, ALLIANCE_CHAT, &buffer2);
g_pMain->Send_KnightsAlliance(GetAllianceID(), &result2);
}
}
void CKnights::ConstructClanNoticePacket(Packet *result)
{
result->Initialize(WIZ_NOTICE);
result->DByte();
*result << uint8(4) // type
<< uint8(1) // total blocks
<< m_strName // header
<< m_strClanNotice;
}
/**
* @brief Updates this clan's notice with clanNotice
* and informs logged in clan members.
*
* @param clanNotice The clan notice.
*/
void CKnights::UpdateClanNotice(std::string & clanNotice)
{
if (clanNotice.length() > MAX_CLAN_NOTICE_LENGTH || clanNotice.size() == 0)
return;
Packet result;
// Update the stored clan notice
m_strClanNotice = clanNotice;
// Construct the update notice packet to inform players the clan notice has changed
std::string updateNotice = string_format("%s updated the clan notice.", m_strChief.c_str());
ChatPacket::Construct(&result, KNIGHTS_CHAT, &updateNotice);
Send(&result);
// Construct the new clan notice packet
ConstructClanNoticePacket(&result);
Send(&result);
// Tell the database to update the clan notice.
result.Initialize(WIZ_CHAT);
result << uint8(CLAN_NOTICE) << GetID() << clanNotice;
g_pMain->AddDatabaseRequest(result);
}
/**
* @brief Sends a request to update the clan's fund in the database.
*/
void CKnights::UpdateClanFund()
{
Packet result(WIZ_KNIGHTS_PROCESS, uint8(KNIGHTS_UPDATE_FUND));
result << GetID() << uint32(m_nClanPointFund);
g_pMain->AddDatabaseRequest(result);
}
void CKnights::OnLogout(CUser *pUser)
{
// Unset the active session for this user
if (pUser->m_pKnightsUser != nullptr)
{
pUser->m_pKnightsUser->m_lastLogin = UNIXTIME;
pUser->m_pKnightsUser->m_lastLogined = uint32(UNIXTIME);
pUser->m_pKnightsUser->pSession = nullptr;
pUser->m_pKnightsUser = nullptr;
}
Packet logoutNotice;
// TODO: Shift this to SERVER_RESOURCE
std::string buffer = string_format("%s is offline.", pUser->GetName().c_str());
ChatPacket::Construct(&logoutNotice, KNIGHTS_CHAT, &buffer);
Send(&logoutNotice);
Packet result2;
if(m_sAlliance != 0)
{
std::string buffer2 = string_format("%s is offline.", pUser->GetName().c_str());
ChatPacket::Construct(&result2, ALLIANCE_CHAT, &buffer2);
g_pMain->Send_KnightsAlliance(GetAllianceID(), &result2);
}
}
bool CKnights::AddUser(std::string & strUserID)
{
for (int i = 0; i < MAX_CLAN_USERS; i++)
{
_KNIGHTS_USER * p = &m_arKnightsUser[i];
if (p->byUsed)
continue;
p->byUsed = 1;
p->strUserName = strUserID;
p->pSession = g_pMain->GetUserPtr(strUserID, TYPE_CHARACTER);
if (p->pSession != nullptr)
{
p->pSession->m_pKnightsUser = p;
p->m_sFame = p->pSession->m_bFame;
p->m_bLevel = p->pSession->GetLevel();
p->m_sClass = p->pSession->GetClass();
}
if(p->pSession == nullptr)
g_DBAgent.GetClanUserData(GetID(),m_arKnightsUser[i]);
return true;
}
return false;
}
bool CKnights::AddUser(CUser *pUser)
{
if (pUser == nullptr
|| !AddUser(pUser->GetName()))
return false;
pUser->SetClanID(m_sIndex);
pUser->m_bFame = TRAINEE;
return true;
}
/**
* @brief Removes the specified user from the clan array.
*
* @param strUserID Identifier for the user.
*
* @return .
*/
bool CKnights::RemoveUser(std::string & strUserID)
{
string Name;
STRTOUPPER(strUserID);
for (int i = 0; i < MAX_CLAN_USERS; i++)
{
_KNIGHTS_USER * p = &m_arKnightsUser[i];
if (p->byUsed == 0)
continue;
Name = p->strUserName;
STRTOUPPER(Name);
if(Name != strUserID)
continue;
// If they're not logged in (note: logged in users being removed have their NP refunded in the other handler)
// but they've donated NP, ensure they're refunded for the next time they login.
if (p->nDonatedNP > 0)
RefundDonatedNP(p->nDonatedNP, p->pSession, p->strUserName.c_str());
p->Initialise();
return true;
}
return false;
}
/**
* @brief Removes the specified user from this clan.
*
* @param pUser The user.
*/
bool CKnights::RemoveUser(CUser *pUser)
{
if (pUser == nullptr)
//|| pUser->m_pKnightsUser == nullptr)
return false;
uint32 nDonatedNP = 0;
if( pUser->m_pKnightsUser != nullptr )
nDonatedNP = pUser->m_pKnightsUser->nDonatedNP;
if (nDonatedNP > 0)
RefundDonatedNP(nDonatedNP, pUser);
pUser->SetClanID(0);
pUser->m_bFame = 0;
if( pUser->m_pKnightsUser != nullptr )
pUser->m_pKnightsUser->Initialise();
pUser->m_pKnightsUser = nullptr;
if (!pUser->isClanLeader())
pUser->SendClanUserStatusUpdate();
return true;
}
/**
* @brief Refunds 30% of the user's donated NP.
* If the user has the item "CONT Recovery", refund ALL of the user's
* donated NP.
*
* @param nDonatedNP The donated NP.
* @param pUser The user's session, when refunding the user in-game.
* Set to nullptr to indicate the use of the character's name
* and consequently a database update instead.
* @param strUserID Logged out character's name.
* Used to refund logged out characters' national points
* when pUser is set to nullptr.
*/
void CKnights::RefundDonatedNP(uint32 nDonatedNP, CUser * pUser /*= nullptr*/, const char * strUserID /*= nullptr*/)
{
// Refund 30% of NP unless the user has the item "CONT Recovery".
// In this case, ALL of the donated NP will be refunded.
if (pUser != nullptr)
{
if (pUser->CheckExistItem(ITEM_CONT_RECOVERY))
pUser->RobItem(ITEM_CONT_RECOVERY);
else
nDonatedNP = (nDonatedNP * 30) / 100;
}
else
nDonatedNP = (nDonatedNP * 30) / 100;
// Remove the refunded NP from the clan fund
if(m_nClanPointFund > nDonatedNP)
m_nClanPointFund -= nDonatedNP;
else
m_nClanPointFund = 0;
// If the player's logged in, just adjust their national points in-game.
if (pUser != nullptr)
{
pUser->m_iLoyalty += nDonatedNP;
pUser->SendLoyaltyChange(0);
return;
}
// For logged out players, we must update the player's national points in the database.
Packet result(WIZ_KNIGHTS_PROCESS, uint8(KNIGHTS_REFUND_POINTS));
result << strUserID << nDonatedNP;
g_pMain->AddDatabaseRequest(result);
}
void CKnights::SendToRegion(Packet *pkt)
{
foreach_array (i, m_arKnightsUser)
{
_KNIGHTS_USER *p = &m_arKnightsUser[i];
if (p->byUsed && p->pSession != nullptr
&& p->pSession->GetClanID() == m_sIndex)
p->pSession->SendToRegion(pkt);
}
}
void CKnights::Disband(CUser *pLeader /*= nullptr*/)
{
std::string clanNotice;
g_pMain->GetServerResource(m_byFlag == ClanTypeTraining ? IDS_CLAN_DESTROY : IDS_KNIGHTS_DESTROY,
&clanNotice, m_strName.c_str());
SendChat(clanNotice.c_str());
foreach_array (i, m_arKnightsUser)
{
_KNIGHTS_USER *p = &m_arKnightsUser[i];
if (!p->byUsed)
continue;
// If the user's logged in, handle the player data removal in-game.
// It will be saved to the database when they log out.
if (p->pSession != nullptr)
RemoveUser(p->pSession);
else
RemoveUser(p->strUserName);
}
g_pMain->m_KnightsArray.DeleteData(m_sIndex);
Packet result(WIZ_KNIGHTS_PROCESS, uint8(KNIGHTS_DESTROY));
result << uint8(1);
pLeader->Send(&result);
}
void CKnights::SendUpdate()
{
CKnights *aKnights = g_pMain->GetClanPtr(GetAllianceID());
Packet result(WIZ_KNIGHTS_PROCESS, uint8(KNIGHTS_UPDATE));
result << GetID() << m_byFlag << GetCapeID(aKnights);
Send(&result);
}
void CKnights::SendChat(const char * format, ...)
{
char buffer[128];
va_list ap;
va_start(ap, format);
vsnprintf(buffer, 128, format, ap);
va_end(ap);
Packet result;
ChatPacket::Construct(&result, KNIGHTS_CHAT, buffer);
Send(&result);
}
void CKnights::SendChatAlliance(const char * format, ...)
{
char buffer[128];
va_list ap;
va_start(ap, format);
vsnprintf(buffer, 128, format, ap);
va_end(ap);
Packet result;
ChatPacket::Construct(&result, ALLIANCE_CHAT, buffer);
Send(&result);
}
void CKnights::Send(Packet *pkt)
{
foreach_array (i, m_arKnightsUser)
{
_KNIGHTS_USER *p = &m_arKnightsUser[i];
if (p->byUsed && p->pSession != nullptr)
p->pSession->Send(pkt);
}
}
CKnights::~CKnights()
{
}