mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 18:52:22 +00:00
Implemented per-client character creation limits
This commit is contained in:
+73
-65
@@ -16,6 +16,7 @@
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/clientversions.h"
|
||||
#include "../common/random.h"
|
||||
#include "../common/shareddb.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "worlddb.h"
|
||||
@@ -161,32 +162,34 @@ void Client::SendCharInfo() {
|
||||
cle->SetOnline(CLE_Status_CharSelect);
|
||||
}
|
||||
|
||||
if (m_ClientVersionBit & BIT_RoFAndLater)
|
||||
{
|
||||
// Can make max char per account into a rule - New to VoA
|
||||
SendMaxCharCreate(10);
|
||||
if (m_ClientVersionBit & BIT_RoFAndLater) {
|
||||
SendMaxCharCreate();
|
||||
SendMembership();
|
||||
SendMembershipSettings();
|
||||
}
|
||||
|
||||
seencharsel = true;
|
||||
|
||||
|
||||
// Send OP_SendCharInfo
|
||||
auto outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
|
||||
CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer;
|
||||
EQApplicationPacket *outapp = nullptr;
|
||||
database.GetCharSelectInfo(GetAccountID(), &outapp, m_ClientVersionBit);
|
||||
|
||||
database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit);
|
||||
|
||||
QueuePacket(outapp);
|
||||
if (outapp) {
|
||||
QueuePacket(outapp);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::General, Logs::World_Server, "[Error] Database did not return an OP_SendCharInfo packet for account %u", GetAccountID());
|
||||
}
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::SendMaxCharCreate(int max_chars) {
|
||||
void Client::SendMaxCharCreate() {
|
||||
auto outapp = new EQApplicationPacket(OP_SendMaxCharacters, sizeof(MaxCharacters_Struct));
|
||||
MaxCharacters_Struct* mc = (MaxCharacters_Struct*)outapp->pBuffer;
|
||||
|
||||
mc->max_chars = max_chars;
|
||||
mc->max_chars = EQLimits::CharacterCreationLimit(m_ClientVersion);
|
||||
if (mc->max_chars > EmuConstants::CHARACTER_CREATION_LIMIT)
|
||||
mc->max_chars = EmuConstants::CHARACTER_CREATION_LIMIT;
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
@@ -716,66 +719,71 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!pZoning && ew->return_home && !ew->tutorial) {
|
||||
auto cs = new CharacterSelect_Struct;
|
||||
memset(cs, 0, sizeof(CharacterSelect_Struct));
|
||||
database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit);
|
||||
bool home_enabled = false;
|
||||
// This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above)
|
||||
if (!pZoning) {
|
||||
size_t character_limit = EQLimits::CharacterCreationLimit(eqs->GetClientVersion());
|
||||
if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT) { character_limit = EmuConstants::CHARACTER_CREATION_LIMIT; }
|
||||
if (eqs->GetClientVersion() == ClientVersion::Titanium) { character_limit = 8; }
|
||||
|
||||
for(int x = 0; x < 10; ++x)
|
||||
{
|
||||
if(strcasecmp(cs->Name[x], char_name) == 0)
|
||||
{
|
||||
if(cs->GoHome[x] == 1)
|
||||
{
|
||||
home_enabled = true;
|
||||
break;
|
||||
std::string tgh_query = StringFormat(
|
||||
"SELECT "
|
||||
"`id`, "
|
||||
"name, "
|
||||
"`level`, "
|
||||
"last_login, "
|
||||
"FROM "
|
||||
"character_data "
|
||||
"WHERE `account_id` = %i ORDER BY `name` LIMIT %u", GetAccountID(), character_limit);
|
||||
auto tgh_results = database.QueryDatabase(tgh_query);
|
||||
|
||||
/* Check GoHome */
|
||||
if (ew->return_home && !ew->tutorial) {
|
||||
bool home_enabled = false;
|
||||
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||
if (strcasecmp(row[1], char_name) == 0) {
|
||||
if (RuleB(World, EnableTutorialButton) && ((uint8)atoi(row[2]) <= RuleI(World, MaxLevelForTutorial))) {
|
||||
home_enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
safe_delete(cs);
|
||||
|
||||
if(home_enabled) {
|
||||
zoneID = database.MoveCharacterToBind(charid,4);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go home before they're able...",char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) {
|
||||
auto cs = new CharacterSelect_Struct;
|
||||
memset(cs, 0, sizeof(CharacterSelect_Struct));
|
||||
database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit);
|
||||
bool tutorial_enabled = false;
|
||||
|
||||
for(int x = 0; x < 10; ++x)
|
||||
{
|
||||
if(strcasecmp(cs->Name[x], char_name) == 0)
|
||||
{
|
||||
if(cs->Tutorial[x] == 1)
|
||||
{
|
||||
tutorial_enabled = true;
|
||||
break;
|
||||
}
|
||||
if (home_enabled) {
|
||||
zoneID = database.MoveCharacterToBind(charid, 4);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go home before they're able...", char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
safe_delete(cs);
|
||||
|
||||
if(tutorial_enabled)
|
||||
{
|
||||
zoneID = RuleI(World, TutorialZoneID);
|
||||
database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go to tutorial but are not allowed...",char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
/* Check Tutorial*/
|
||||
if (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial)) {
|
||||
bool tutorial_enabled = false;
|
||||
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||
if (strcasecmp(row[1], char_name) == 0) {
|
||||
if (RuleB(World, EnableReturnHomeButton)) {
|
||||
int now = time(nullptr);
|
||||
if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) {
|
||||
tutorial_enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tutorial_enabled) {
|
||||
zoneID = RuleI(World, TutorialZoneID);
|
||||
database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go to tutorial but are not allowed...", char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user