Merge remote-tracking branch 'remotes/origin/master' into blob_conversion

Conflicts:
	changelog.txt
	common/database.cpp
	world/client.cpp
	world/zoneserver.cpp
	zone/command.cpp
This commit is contained in:
akkadius 2014-09-21 02:32:31 -05:00
commit ad29fa9cfa
22 changed files with 271 additions and 172 deletions

View File

@ -1,6 +1,6 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 09/21/2014 ==
== 09/21/2014 ==
Akkadius: Player Profile Blob to Database Conversion
- Summary: HUGE difference in database speeds reads/writes and 1:10 datasize difference
- The new character storage engine unlike the character_ table before, is able to properly index data and make use of
@ -94,6 +94,24 @@ Akkadius: Player Profile Blob to Database Conversion
WHERE `table_name` LIKE 'character_%'
ORDER BY DATA DESC;
== 09/20/2014 ==
demonstar55: Fix crash in SendEnterWorld on illegally long names
demonstar55: The client only lets you enter 15 characters for your name (UF at least)
demonstar55: Add rule Spells:SHDProcIDOffByOne for pre-UF spell file, set to true, UF+ set to false
KLS: #suspend and #ban now have required messages to record the reason for the ban/suspension.
== 09/19/2014 ==
demonstar55: Added Client::Tell_StringID (used in tell queue messages)
demonstar55: Tell queues (and offline) messages now show correctly
demonstar55: Fix starting with capital check
== 09/18/2014==
demonstar55: Implement tell queues
Currently set to a limit of 20 by default (World:TellQueueSize) I was unable to hit the limit on live though (100+)
The required SQL nukes the old tell queue table, which may or may not be in your DB
Optional SQL adds the rule to the DB to allow easy of change
Note: this does not play well with multiple sessions with the same name on (crash and relog and have multiple sessions) but normal tells don't play well either
== 09/16/2014 ==
demonstar55: Implement spell formula 137 (BER AA Desperation)
Uleat (NateDog): Fix for LoadBuffs() crash when a spell with a non-persistent Illusion effect was loaded.

View File

@ -770,10 +770,20 @@ uint32 Database::GetCharacterID(const char *name) {
the name "name" or zero if no character with that name was found
Zero will also be returned if there is a database error.
*/
uint32 Database::GetAccountIDByChar(const char* charname) {
uint32 accountId = 0;
std::string query = StringFormat("SELECT `account_id`, `id` FROM `character_data` WHERE `name` = '%s' LIMIT 1", charname);
auto results = QueryDatabase(query);
uint32 Database::GetAccountIDByChar(const char* charname, uint32* oCharID) {
std::string query = StringFormat("SELECT account_id, id FROM character_ WHERE name='%s'", EscapeString(charname).c_str());
auto results = QueryDatabase(query);
if (!results.Success())
{
std::cerr << "Error in GetAccountIDByChar query '" << query << "' " << results.ErrorMessage() << std::endl;
return 0;
}
if (results.RowCount() != 1)
return 0;
auto row = results.begin();
if (row[0]){ accountId = atoi(row[0]); }
return accountId;
@ -2244,7 +2254,7 @@ bool Database::CheckNameFilter(const char* name, bool surname)
else
{
// the minimum 4 is enforced by the client too
if(!name || strlen(name) < 4 || strlen(name) > 64)
if(!name || strlen(name) < 4 || strlen(name) > 15)
{
return false;
}

View File

@ -10,7 +10,7 @@ MySQLRequestResult::MySQLRequestResult()
MySQLRequestResult::MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected, uint32 rowCount, uint32 columnCount, uint32 lastInsertedID, uint32 errorNumber, char *errorBuffer)
: m_CurrentRow(result), m_OneBeyondRow()
{
m_Result = result;
m_Result = result;
m_RowsAffected = rowsAffected;
m_RowCount = rowCount;
m_ColumnCount = columnCount;
@ -22,12 +22,12 @@ MySQLRequestResult::MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected, u
m_ColumnLengths = nullptr;
m_Fields = nullptr;
if (errorBuffer != nullptr)
m_Success = true;
if (errorBuffer != nullptr)
m_Success = false;
m_Success = true;
m_ErrorNumber = errorNumber;
m_ErrorBuffer = errorBuffer;
m_ErrorNumber = errorNumber;
m_ErrorBuffer = errorBuffer;
}
void MySQLRequestResult::FreeInternals()

View File

@ -171,6 +171,7 @@ RULE_INT ( World, PVPSettings, 0) // Sets the PVP settings for the server, 1 = R
RULE_BOOL (World, IsGMPetitionWindowEnabled, false)
RULE_INT (World, FVNoDropFlag, 0) // Sets the Firiona Vie settings on the client. If set to 2, the flag will be set for GMs only, allowing trading of no-drop items.
RULE_BOOL (World, IPLimitDisconnectAll, false)
RULE_INT (World, TellQueueSize, 20)
RULE_CATEGORY_END()
RULE_CATEGORY( Zone )
@ -320,6 +321,7 @@ RULE_INT ( Spells, AI_PursueDetrimentalChance, 90) // Chance while chasing targe
RULE_INT ( Spells, AI_IdleNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random)
RULE_INT ( Spells, AI_IdleNoSpellMaxRecast, 2000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random)
RULE_INT ( Spells, AI_IdleBeneficialChance, 100) // Chance while idle to do a beneficial spell on self or others.
RULE_BOOL ( Spells, SHDProcIDOffByOne, true) // pre June 2009 SHD spell procs were off by 1, they stopped doing this in June 2009 (so UF+ spell files need this false)
RULE_CATEGORY_END()

View File

@ -83,6 +83,7 @@
#define ServerOP_QGlobalUpdate 0x0063
#define ServerOP_QGlobalDelete 0x0064
#define ServerOP_DepopPlayerCorpse 0x0065
#define ServerOP_RequestTellQueue 0x0066 // client asks for it's tell queues
#define ServerOP_RaidAdd 0x0100 //in use
#define ServerOP_RaidRemove 0x0101 //in use
@ -348,6 +349,7 @@ struct ServerChannelMessage_Struct {
uint16 chan_num;
uint32 guilddbid;
uint16 language;
uint8 queued; // 0 = not queued, 1 = queued, 2 = queue full, 3 = offline
char message[0];
};
@ -1250,6 +1252,10 @@ struct ReloadWorld_Struct{
uint32 Option;
};
struct ServerRequestTellQueue_Struct {
char name[64];
};
#pragma pack()
#endif

View File

@ -0,0 +1 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'World:TellQueueSize', '20', 'Maximum tell queue size.');

View File

@ -0,0 +1 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:SHDProcIDOffByOne', 'true', 'SHD procs are off by 1. Set true for pre-UF spell files, false for UF+.');

View File

@ -0,0 +1 @@
DROP TABLE `tellque`;

View File

@ -0,0 +1 @@
ALTER TABLE `account` ADD COLUMN `ban_reason` TEXT NULL DEFAULT NULL AFTER `expansion`, ADD COLUMN `suspend_reason` TEXT NULL DEFAULT NULL AFTER `ban_reason`;

View File

@ -126,8 +126,9 @@ void Client::SendLogServer()
safe_delete(outapp);
}
void Client::SendEnterWorld(std::string name) {
char char_name[32]= { 0 };
void Client::SendEnterWorld(std::string name)
{
char char_name[64] = { 0 };
if (pZoning && database.GetLiveChar(GetAccountID(), char_name)) {
if(database.GetAccountIDByChar(char_name) != GetAccountID()) {
eqs->Close();
@ -468,7 +469,8 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app) {
return true;
}
bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app) {
bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app)
{
if (GetAccountID() == 0) {
clog(WORLD__CLIENT_ERR,"Name approval request with no logged in account");
return false;
@ -478,7 +480,7 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app) {
uchar race = app->pBuffer[64];
uchar clas = app->pBuffer[68];
clog(WORLD__CLIENT,"Name approval request. Name=%s, race=%s, class=%s",char_name,GetRaceName(race),GetEQClassName(clas));
clog(WORLD__CLIENT, "Name approval request. Name=%s, race=%s, class=%s", char_name, GetRaceName(race), GetEQClassName(clas));
EQApplicationPacket *outapp;
outapp = new EQApplicationPacket;
@ -495,9 +497,8 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app) {
QueuePacket(outapp);
safe_delete(outapp);
if(!valid) {
if (!valid)
memset(char_name, 0, sizeof(char_name));
}
return true;
}

View File

@ -93,6 +93,7 @@ ClientListEntry::~ClientListEntry() {
Camp(); // updates zoneserver's numplayers
client_list.RemoveCLEReferances(this);
}
tell_queue.clear();
}
void ClientListEntry::SetChar(uint32 iCharID, const char* iCharName) {
@ -233,6 +234,7 @@ void ClientListEntry::ClearVars(bool iAll) {
pLFG = 0;
gm = 0;
pClientVersion = 0;
tell_queue.clear();
}
void ClientListEntry::Camp(ZoneServer* iZS) {
@ -295,3 +297,21 @@ bool ClientListEntry::CheckAuth(uint32 id, const char* iKey, uint32 ip) {
return false;
}
void ClientListEntry::ProcessTellQueue()
{
if (!Server())
return;
ServerPacket *pack;
auto it = tell_queue.begin();
while (it != tell_queue.end()) {
pack = new ServerPacket(ServerOP_ChannelMessage, sizeof(ServerChannelMessage_Struct) + strlen((*it)->message) + 1);
memcpy(pack->pBuffer, *it, pack->size);
pack->Deflate();
Server()->SendPacket(pack);
safe_delete(pack);
it = tell_queue.erase(it);
}
return;
}

View File

@ -5,6 +5,8 @@
#include "../common/md5.h"
//#include "../common/eq_packet_structs.h"
#include "../common/servertalk.h"
#include "../common/rulesys.h"
#include <vector>
#define CLE_Status_Never -1
@ -80,6 +82,11 @@ public:
inline const char* GetLFGComments() const { return pLFGComments; }
inline uint8 GetClientVersion() { return pClientVersion; }
inline bool TellQueueFull() const { return tell_queue.size() >= RuleI(World, TellQueueSize); }
inline bool TellQueueEmpty() const { return tell_queue.empty(); }
inline void PushToTellQueue(ServerChannelMessage_Struct *scm) { tell_queue.push_back(scm); }
void ProcessTellQueue();
private:
void ClearVars(bool iAll = false);
@ -120,6 +127,9 @@ private:
uint8 pLFGToLevel;
bool pLFGMatchFilter;
char pLFGComments[64];
// Tell Queue -- really a vector :D
std::vector<ServerChannelMessage_Struct *> tell_queue;
};
#endif /*CLIENTENTRY_H_*/

View File

@ -437,45 +437,48 @@ bool ZoneServer::Process() {
Console* con = 0;
con = console_list.FindByAccountName(&scm->deliverto[1]);
if (((!con) || (!con->SendChannelMessage(scm))) && (!scm->noreply))
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "%s is not online at this time.", scm->to);
break;
}
ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
if (cle == 0 || cle->Online() < CLE_Status_Zoning || (cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
if (!scm->noreply)
zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
}
else if (cle->Online() == CLE_Status_Zoning) {
if (!scm->noreply)
{
// time_t rawtime;
// struct tm * timeinfo;
// time ( &rawtime );
// timeinfo = localtime ( &rawtime );
// char *telldate=asctime(timeinfo);
//
// std::string query = StringFormat("SELECT name FROM `character_data` WHERE name = '%s'",scm->deliverto);
// auto results = database.QueryDatabase(query);
// if (!results.Success())
// break;
//
// if (results.RowCount() == 0) {
// zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
// break;
// }
//
// query = StringFormat("INSERT INTO tellque "
// "(Date, Receiver, Sender, Message) "
// "VALUES('%s', '%s', '%s', '%s')",
// telldate, scm->deliverto, scm->from, scm->message);
// results = database.QueryDatabase(query);
// if (results.Success())
// zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "Your message has been added to the %s's que.", scm->to);
// else
// zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
if (cle == 0 || cle->Online() < CLE_Status_Zoning ||
(cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from);
if (!sender)
break;
scm->noreply = true;
scm->queued = 3; // offline
strcpy(scm->deliverto, scm->from);
// ideally this would be trimming off the message too, oh well
sender->Server()->SendPacket(pack);
}
} else if (cle->Online() == CLE_Status_Zoning) {
if (!scm->noreply) {
ClientListEntry* sender = client_list.FindCharacter(scm->from);
if (cle->TellQueueFull()) {
if (!sender)
break;
scm->noreply = true;
scm->queued = 2; // queue full
strcpy(scm->deliverto, scm->from);
sender->Server()->SendPacket(pack);
} else {
size_t struct_size = sizeof(ServerChannelMessage_Struct) + strlen(scm->message) + 1;
ServerChannelMessage_Struct *temp = (ServerChannelMessage_Struct *) new uchar[struct_size];
memset(temp, 0, struct_size); // just in case, was seeing some corrupt messages, but it shouldn't happen
memcpy(temp, scm, struct_size);
temp->noreply = true;
cle->PushToTellQueue(temp); // deallocation is handled in processing or deconstructor
if (!sender)
break;
scm->noreply = true;
scm->queued = 1; // queued
strcpy(scm->deliverto, scm->from);
sender->Server()->SendPacket(pack);
}
}
// zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
}
else if (cle->Server() == 0) {
if (!scm->noreply)
@ -1285,6 +1288,16 @@ bool ZoneServer::Process() {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_RequestTellQueue:
{
ServerRequestTellQueue_Struct* rtq = (ServerRequestTellQueue_Struct*) pack->pBuffer;
ClientListEntry *cle = client_list.FindCharacter(rtq->name);
if (!cle || cle->TellQueueEmpty())
break;
cle->ProcessTellQueue();
break;
}
default:
{
zlog(WORLD__ZONE_ERR,"Unknown ServerOPcode from zone 0x%04x, size %d",pack->opcode,pack->size);

View File

@ -3077,6 +3077,14 @@ void Client::FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType fil
safe_delete(outapp);
}
void Client::Tell_StringID(uint32 string_id, const char *who, const char *message)
{
char string_id_str[10];
snprintf(string_id_str, 10, "%d", string_id);
Message_StringID(MT_TellEcho, TELL_QUEUED_MESSAGE, who, string_id_str, message);
}
void Client::SetTint(int16 in_slot, uint32 color) {
Color_Struct new_color;
new_color.color = color;

View File

@ -254,6 +254,7 @@ public:
const char *message5 = nullptr, const char *message6 = nullptr,
const char *message7 = nullptr, const char *message8 = nullptr,
const char *message9 = nullptr);
void Tell_StringID(uint32 string_id, const char *who, const char *message);
void SendBazaarResults(uint32 trader_id,uint32 class_,uint32 race,uint32 stat,uint32 slot,uint32 type,char name[64],uint32 minprice,uint32 maxprice);
void SendTraderItem(uint32 item_id,uint16 quantity);
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);

View File

@ -9696,6 +9696,8 @@ void Client::CompleteConnect() {
}
entity_list.RefreshClientXTargets(this);
worldserver.RequestTellQueue(GetName());
}
void Client::Handle_OP_KeyRing(const EQApplicationPacket *app)

View File

@ -331,8 +331,6 @@ int command_init(void) {
command_add("guilds",nullptr,0,command_guild) ||
command_add("zonestatus","- Show connected zoneservers, synonymous with /servers",150,command_zonestatus) ||
command_add("manaburn","- Use AA Wizard class skill manaburn on target",10,command_manaburn) ||
command_add("viewmessage","[id] - View messages in your tell queue",100,command_viewmessage) ||
command_add("viewmessages",nullptr,0,command_viewmessage) ||
command_add("doanim","[animnum] [type] - Send an EmoteAnim for you or your target",50,command_doanim) ||
command_add("randomfeatures","- Temporarily randomizes the Facial Features of your target",80,command_randomfeatures) ||
command_add("rf",nullptr,80,command_randomfeatures) ||
@ -5191,53 +5189,6 @@ void command_manaburn(Client *c, const Seperator *sep)
}
}
void command_viewmessage(Client *c, const Seperator *sep)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if(sep->arg[1][0]==0)
{
if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT id,date,receiver,sender,message from tellque where receiver='%s'",c->GetName()), errbuf, &result))
{
if (mysql_num_rows(result)>0)
{
c->Message(0,"You have messages waiting for you to view.");
c->Message(0,"Type #Viewmessage <Message ID> to view the message.");
c->Message(0," ID , Message Sent Date, Message Sender");
while ((row = mysql_fetch_row(result)))
c->Message(0,"ID: %s Sent Date: %s Sender: %s ",row[0],row[1],row[3]);
}
else
c->Message(0,"You have no new messages");
mysql_free_result(result);
}
safe_delete_array(query);
}
else
{
if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT id,date,receiver,sender,message from tellque where id=%s",sep->argplus[1]), errbuf, &result))
{
if (mysql_num_rows(result)==1)
{
row = mysql_fetch_row(result);
mysql_free_result(result);
if (strcasecmp((const char *) c->GetName(), (const char *) row[2]) == 0)
{
c->Message(15,"ID: %s,Sent Date: %s,Sender: %s,Message: %s",row[0],row[1],row[3],row[4]);
database.RunQuery(query, MakeAnyLenString(&query, "Delete from tellque where id=%s",row[0]), errbuf);
}
else
c->Message(13,"Invalid Message Number, check the number and try again.");
}
else
c->Message(13,"Invalid Message Number, check the number and try again.");
}
safe_delete_array(query);
}
}
void command_doanim(Client *c, const Seperator *sep)
{
if (!sep->IsNumber(1))
@ -6204,36 +6155,49 @@ void command_stun(Client *c, const Seperator *sep)
c->Message(0, "Usage: #stun [duration]");
}
void command_ban(Client *c, const Seperator *sep)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if(sep->arg[1][0] == 0)
if(sep->arg[1][0] == 0 || sep->arg[2][0] == 0)
{
c->Message(0, "Usage: #ban [charname]");
c->Message(0, "Usage: #ban <charname> <message>");
}
else
{
database.RunQuery(query, MakeAnyLenString(&query, "SELECT account_id from `character_data` where name = '%s'", sep->arg[1]), errbuf, &result);
if(query)
{
safe_delete_array(query);
auto account_id = database.GetAccountIDByChar(sep->arg[1]);
std::string message;
int i = 2;
while(1) {
if(sep->arg[i][0] == 0) {
break;
}
if(message.length() > 0) {
message.push_back(' ');
}
message += sep->arg[i];
++i;
}
if(mysql_num_rows(result))
{
row = mysql_fetch_row(result);
database.RunQuery(query, MakeAnyLenString(&query, "UPDATE account set status = -2 where id = %i", atoi(row[0])), errbuf, 0);
c->Message(13,"Account number %i with the character %s has been banned.", atoi(row[0]), sep->arg[1]);
if(message.length() == 0) {
c->Message(0, "Usage: #ban <charname> <message>");
return;
}
ServerPacket* pack = new ServerPacket(ServerOP_FlagUpdate, 6);
*((uint32*) pack->pBuffer) = atoi(row[0]);
*((int16*) &pack->pBuffer[4]) = -2;
worldserver.SendPacket(pack);
safe_delete(pack);
if(account_id > 0)
{
database.RunQuery(query, MakeAnyLenString(&query, "UPDATE account set status = -2, ban_reason = '%s' where id = %i", EscapeString(message).c_str(), account_id), errbuf, 0);
c->Message(13, "Account number %i with the character %s has been banned with message: \"%s\"", account_id, sep->arg[1], message.c_str());
ServerPacket pack(ServerOP_FlagUpdate, 6);
*((uint32*)&pack.pBuffer[0]) = account_id;
*((int16*)&pack.pBuffer[4]) = -2;
worldserver.SendPacket(&pack);
Client *client = nullptr;
client = entity_list.GetClientByName(sep->arg[1]);
@ -6243,25 +6207,20 @@ void command_ban(Client *c, const Seperator *sep)
}
else
{
ServerPacket* pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct));
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer;
ServerPacket pack(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct));
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*)pack.pBuffer;
strcpy(skp->adminname, c->GetName());
strcpy(skp->name, sep->arg[1]);
skp->adminrank = c->Admin();
worldserver.SendPacket(pack);
safe_delete(pack);
worldserver.SendPacket(&pack);
}
mysql_free_result(result);
}
else
{
c->Message(13,"Character does not exist.");
}
if(query)
{
safe_delete_array(query);
c->Message(13, "Character does not exist.");
}
safe_delete_array(query);
}
}
@ -6271,7 +6230,7 @@ void command_suspend(Client *c, const Seperator *sep)
char *query = nullptr;
if((sep->arg[1][0] == 0) || (sep->arg[2][0] == 0))
c->Message(0, "Usage: #suspend <charname> <days> (Specify 0 days to lift the suspension immediately)");
c->Message(0, "Usage: #suspend <charname> <days>(Specify 0 days to lift the suspension immediately) <message>");
else
{
int Duration = atoi(sep->arg[2]);
@ -6279,22 +6238,40 @@ void command_suspend(Client *c, const Seperator *sep)
if(Duration < 0)
Duration = 0;
char *EscName = new char[strlen(sep->arg[1]) * 2 + 1];
std::string message;
if(Duration > 0) {
int i = 3;
while(1) {
if(sep->arg[i][0] == 0) {
break;
}
database.DoEscapeString(EscName, sep->arg[1], strlen(sep->arg[1]));
if(message.length() > 0) {
message.push_back(' ');
}
message += sep->arg[i];
++i;
}
if(message.length() == 0) {
c->Message(0, "Usage: #suspend <charname> <days>(Specify 0 days to lift the suspension immediately) <message>");
return;
}
}
int AccountID;
if((AccountID = database.GetAccountIDByChar(EscName)) > 0)
if((AccountID = database.GetAccountIDByChar(sep->arg[1])) > 0)
{
database.RunQuery(query, MakeAnyLenString(&query, "UPDATE `account` SET `suspendeduntil` = DATE_ADD(NOW(), INTERVAL %i DAY)"
" WHERE `id` = %i", Duration, AccountID), errbuf, 0);
database.RunQuery(query, MakeAnyLenString(&query, "UPDATE `account` SET `suspendeduntil` = DATE_ADD(NOW(), INTERVAL %i DAY), "
"suspend_reason = '%s' WHERE `id` = %i", Duration, EscapeString(message).c_str(), AccountID), errbuf, 0);
if(Duration)
c->Message(13,"Account number %i with the character %s has been temporarily suspended for %i day(s).", AccountID, sep->arg[1],
Duration);
c->Message(13, "Account number %i with the character %s has been temporarily suspended for %i day(s) with the message: \"%s\"", AccountID, sep->arg[1],
Duration, message.c_str());
else
c->Message(13,"Account number %i with the character %s is no longer suspended.", AccountID, sep->arg[1]);
c->Message(13, "Account number %i with the character %s is no longer suspended.", AccountID, sep->arg[1]);
safe_delete_array(query);
@ -6304,22 +6281,20 @@ void command_suspend(Client *c, const Seperator *sep)
BannedClient->WorldKick();
else
{
ServerPacket* pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct));
ServerKickPlayer_Struct* sks = (ServerKickPlayer_Struct*) pack->pBuffer;
ServerPacket pack(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct));
ServerKickPlayer_Struct* sks = (ServerKickPlayer_Struct*)pack.pBuffer;
strn0cpy(sks->adminname, c->GetName(), sizeof(sks->adminname));
strn0cpy(sks->name, sep->arg[1], sizeof(sks->name));
sks->adminrank = c->Admin();
worldserver.SendPacket(pack);
safe_delete(pack);
worldserver.SendPacket(&pack);
}
} else
c->Message(13,"Character does not exist.");
safe_delete_array(EscName);
}
else {
c->Message(13, "Character does not exist.");
}
}
}

View File

@ -215,7 +215,6 @@ void command_guild(Client *c, const Seperator *sep);
bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value);
void command_zonestatus(Client *c, const Seperator *sep);
void command_manaburn(Client *c, const Seperator *sep);
void command_viewmessage(Client *c, const Seperator *sep);
void command_doanim(Client *c, const Seperator *sep);
void command_randomfeatures(Client *c, const Seperator *sep);
void command_face(Client *c, const Seperator *sep);

View File

@ -5598,28 +5598,29 @@ void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id)
}
//for some stupid reason SK procs return theirs one base off...
uint16 Mob::GetProcID(uint16 spell_id, uint8 effect_index) {
uint16 Mob::GetProcID(uint16 spell_id, uint8 effect_index)
{
if (!RuleB(Spells, SHDProcIDOffByOne)) // UF+ spell files
return spells[spell_id].base[effect_index];
// We should actually just be checking if the mob is SHD, but to not force
// custom servers to create new spells, we will still do this
bool sk = false;
bool other = false;
for(int x = 0; x < 16; x++)
{
if(x == 4){
if(spells[spell_id].classes[4] < 255)
for (int x = 0; x < 16; x++) {
if (x == 4) {
if (spells[spell_id].classes[4] < 255)
sk = true;
}
else{
if(spells[spell_id].classes[x] < 255)
} else {
if (spells[spell_id].classes[x] < 255)
other = true;
}
}
if(sk && !other)
{
return(spells[spell_id].base[effect_index] + 1);
}
else{
return(spells[spell_id].base[effect_index]);
}
if (sk && !other)
return spells[spell_id].base[effect_index] + 1;
else
return spells[spell_id].base[effect_index];
}
bool Mob::TryDivineSave()

View File

@ -249,6 +249,8 @@
#define PLAYER_CHARMED 1461 //You lose control of yourself!
#define TRADER_BUSY 1468 //That Trader is currently with a customer. Please wait until their transaction is finished.
#define SENSE_CORPSE_DIRECTION 1563 //You sense a corpse in this direction.
#define QUEUED_TELL 2458 //[queued]
#define QUEUE_TELL_FULL 2459 //[zoing and queue is full]
#define SUSPEND_MINION_UNSUSPEND 3267 //%1 tells you, 'I live again...'
#define SUSPEND_MINION_SUSPEND 3268 //%1 tells you, 'By your command, master.'
#define ONLY_SUMMONED_PETS 3269 //3269 This effect only works with summoned pets.
@ -269,6 +271,8 @@
#define CORPSEDRAG_STOP 4066 //You stop dragging the corpse.
#define TARGET_TOO_CLOSE 4602 //You are too close to your target. Get farther away.
#define WHOALL_NO_RESULTS 5029 //There are no players in EverQuest that match those who filters.
#define TELL_QUEUED_MESSAGE 5045 //You told %1 '%T2. %3'
#define TOLD_NOT_ONLINE 5046 //%1 is not online at this time.
#define PETITION_NO_DELETE 5053 //You do not have a petition in the queue.
#define PETITION_DELETED 5054 //Your petition was successfully deleted.
#define GAIN_RAIDEXP 5085 //You gained raid experience!

View File

@ -168,18 +168,24 @@ void WorldServer::Process() {
break;
}
case ServerOP_ChannelMessage: {
if (!ZoneLoaded) break;
if (!ZoneLoaded)
break;
ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer;
if (scm->deliverto[0] == 0) {
entity_list.ChannelMessageFromWorld(scm->from, scm->to, scm->chan_num, scm->guilddbid, scm->language, scm->message);
}
else {
Client* client;
client = entity_list.GetClientByName(scm->deliverto);
if (client != 0) {
} else {
Client* client = entity_list.GetClientByName(scm->deliverto);
if (client) {
if (client->Connected()) {
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->message);
if (!scm->noreply && scm->chan_num!=2) { //dont echo on group chat
if (scm->queued == 1) // tell was queued
client->Tell_StringID(QUEUED_TELL, scm->to, scm->message);
else if (scm->queued == 2) // tell queue was full
client->Tell_StringID(QUEUE_TELL_FULL, scm->to, scm->message);
else if (scm->queued == 3) // person was offline
client->Message_StringID(MT_TellEcho, TOLD_NOT_ONLINE, scm->to);
else // normal stuff
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->message);
if (!scm->noreply && scm->chan_num != 2) { //dont echo on group chat
// if it's a tell, echo back so it shows up
scm->noreply = true;
scm->chan_num = 14;
@ -1874,6 +1880,7 @@ bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_nu
scm->chan_num = chan_num;
scm->guilddbid = guilddbid;
scm->language = language;
scm->queued = 0;
strcpy(scm->message, buffer);
pack->Deflate();
@ -2198,3 +2205,19 @@ void WorldServer::HandleLFPMatches(ServerPacket *pack) {
safe_delete(outapp);
}
}
void WorldServer::RequestTellQueue(const char *who)
{
if (!who)
return;
ServerPacket* pack = new ServerPacket(ServerOP_RequestTellQueue, sizeof(ServerRequestTellQueue_Struct));
ServerRequestTellQueue_Struct* rtq = (ServerRequestTellQueue_Struct*) pack->pBuffer;
strn0cpy(rtq->name, who, sizeof(rtq->name));
SendPacket(pack);
safe_delete(pack);
return;
}

View File

@ -57,6 +57,8 @@ public:
void HandleLFGMatches(ServerPacket *pack);
void HandleLFPMatches(ServerPacket *pack);
void RequestTellQueue(const char *who);
private:
virtual void OnConnected();