mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
1474 lines
43 KiB
C++
1474 lines
43 KiB
C++
/* EQEMu: Everquest Server Emulator
|
|
Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
are required to give you total support for your newly bought product;
|
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "../common/servertalk.h"
|
|
#include "../common/string_util.h"
|
|
|
|
#include "client.h"
|
|
#include "entity.h"
|
|
#include "guild_mgr.h"
|
|
#include "worldserver.h"
|
|
#include "zonedb.h"
|
|
|
|
ZoneGuildManager guild_mgr;
|
|
GuildBankManager *GuildBanks;
|
|
|
|
extern WorldServer worldserver;
|
|
extern volatile bool ZoneLoaded;
|
|
|
|
void ZoneGuildManager::SendGuildRefresh(uint32 guild_id, bool name, bool motd, bool rank, bool relation) {
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds, "Sending guild refresh for %d to world, changes: name=%d, motd=%d, rank=d, relation=%d", guild_id, name, motd, rank, relation);
|
|
ServerPacket* pack = new ServerPacket(ServerOP_RefreshGuild, sizeof(ServerGuildRefresh_Struct));
|
|
ServerGuildRefresh_Struct *s = (ServerGuildRefresh_Struct *) pack->pBuffer;
|
|
s->guild_id = guild_id;
|
|
s->name_change = name;
|
|
s->motd_change = motd;
|
|
s->rank_change = rank;
|
|
s->relation_change = relation;
|
|
worldserver.SendPacket(pack);
|
|
safe_delete(pack);
|
|
}
|
|
|
|
void ZoneGuildManager::SendCharRefresh(uint32 old_guild_id, uint32 guild_id, uint32 charid) {
|
|
if(guild_id == 0) {
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds, "Guild lookup for char %d when sending char refresh.", charid);
|
|
|
|
CharGuildInfo gci;
|
|
if(!GetCharInfo(charid, gci)) {
|
|
guild_id = GUILD_NONE;
|
|
} else {
|
|
guild_id = gci.guild_id;
|
|
}
|
|
}
|
|
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds, "Sending char refresh for %d from guild %d to world", charid, guild_id);
|
|
|
|
ServerPacket* pack = new ServerPacket(ServerOP_GuildCharRefresh, sizeof(ServerGuildCharRefresh_Struct));
|
|
ServerGuildCharRefresh_Struct *s = (ServerGuildCharRefresh_Struct *) pack->pBuffer;
|
|
s->guild_id = guild_id;
|
|
s->old_guild_id = old_guild_id;
|
|
s->char_id = charid;
|
|
worldserver.SendPacket(pack);
|
|
safe_delete(pack);
|
|
}
|
|
|
|
void ZoneGuildManager::SendRankUpdate(uint32 CharID)
|
|
{
|
|
CharGuildInfo gci;
|
|
|
|
if(!GetCharInfo(CharID, gci))
|
|
return;
|
|
|
|
ServerPacket* pack = new ServerPacket(ServerOP_GuildRankUpdate, sizeof(ServerGuildRankUpdate_Struct));
|
|
|
|
ServerGuildRankUpdate_Struct *sgrus = (ServerGuildRankUpdate_Struct*)pack->pBuffer;
|
|
|
|
sgrus->GuildID = gci.guild_id;
|
|
strn0cpy(sgrus->MemberName, gci.char_name.c_str(), sizeof(sgrus->MemberName));
|
|
sgrus->Rank = gci.rank;
|
|
sgrus->Banker = gci.banker + (gci.alt * 2);
|
|
|
|
worldserver.SendPacket(pack);
|
|
|
|
safe_delete(pack);
|
|
}
|
|
|
|
void ZoneGuildManager::SendGuildDelete(uint32 guild_id) {
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds, "Sending guild delete for guild %d to world", guild_id);
|
|
ServerPacket* pack = new ServerPacket(ServerOP_DeleteGuild, sizeof(ServerGuildID_Struct));
|
|
ServerGuildID_Struct *s = (ServerGuildID_Struct *) pack->pBuffer;
|
|
s->guild_id = guild_id;
|
|
worldserver.SendPacket(pack);
|
|
safe_delete(pack);
|
|
}
|
|
|
|
//makes a guild member list packet (internal format), returns ownership of the buffer.
|
|
uint8 *ZoneGuildManager::MakeGuildMembers(uint32 guild_id, const char *prefix_name, uint32 &length) {
|
|
uint8 *retbuffer;
|
|
|
|
//hack because we dont have the "remove from guild" packet right now.
|
|
if(guild_id == GUILD_NONE) {
|
|
length = sizeof(Internal_GuildMembers_Struct);
|
|
retbuffer = new uint8[length];
|
|
Internal_GuildMembers_Struct *gms = (Internal_GuildMembers_Struct *) retbuffer;
|
|
strcpy(gms->player_name, prefix_name);
|
|
gms->count = 0;
|
|
gms->name_length = 0;
|
|
gms->note_length = 0;
|
|
return(retbuffer);
|
|
}
|
|
|
|
std::vector<CharGuildInfo *> members;
|
|
if(!GetEntireGuild(guild_id, members))
|
|
return(nullptr);
|
|
|
|
//figure out the actual packet length.
|
|
uint32 fixed_length = sizeof(Internal_GuildMembers_Struct) + members.size()*sizeof(Internal_GuildMemberEntry_Struct);
|
|
std::vector<CharGuildInfo *>::iterator cur, end;
|
|
CharGuildInfo *ci;
|
|
cur = members.begin();
|
|
end = members.end();
|
|
uint32 name_len = 0;
|
|
uint32 note_len = 0;
|
|
for(; cur != end; ++cur) {
|
|
ci = *cur;
|
|
name_len += ci->char_name.length();
|
|
note_len += ci->public_note.length();
|
|
}
|
|
|
|
//calc total length.
|
|
length = fixed_length + name_len + note_len + members.size()*2; //string data + null terminators
|
|
|
|
//make our nice buffer
|
|
retbuffer = new uint8[length];
|
|
|
|
Internal_GuildMembers_Struct *gms = (Internal_GuildMembers_Struct *) retbuffer;
|
|
|
|
//fill in the global header
|
|
strcpy(gms->player_name, prefix_name);
|
|
gms->count = members.size();
|
|
gms->name_length = name_len;
|
|
gms->note_length = note_len;
|
|
|
|
char *name_buf = (char *) ( retbuffer + fixed_length );
|
|
char *note_buf = (char *) ( name_buf + name_len + members.size() );
|
|
|
|
//fill in each member's entry.
|
|
Internal_GuildMemberEntry_Struct *e = gms->member;
|
|
|
|
cur = members.begin();
|
|
end = members.end();
|
|
for(; cur != end; ++cur) {
|
|
ci = *cur;
|
|
|
|
//the order we set things here must match the struct
|
|
|
|
//nice helper macro
|
|
#define SlideStructString(field, str) \
|
|
strcpy(field, str.c_str()); \
|
|
field += str.length() + 1
|
|
#define PutField(field) \
|
|
e->field = ci->field
|
|
|
|
SlideStructString( name_buf, ci->char_name );
|
|
PutField(level);
|
|
e->banker = ci->banker + (ci->alt * 2); // low bit is banker flag, next bit is 'alt' flag.
|
|
PutField(class_);
|
|
PutField(rank);
|
|
PutField(time_last_on);
|
|
PutField(tribute_enable);
|
|
PutField(total_tribute);
|
|
PutField(last_tribute);
|
|
SlideStructString( note_buf, ci->public_note );
|
|
e->zoneinstance = 0;
|
|
e->zone_id = 0; // Flag them as offline (zoneid 0) as world will update us with their online status afterwards.
|
|
#undef SlideStructString
|
|
#undef PutFieldN
|
|
|
|
delete *cur;
|
|
|
|
e++;
|
|
}
|
|
|
|
return(retbuffer);
|
|
}
|
|
|
|
void ZoneGuildManager::ListGuilds(Client *c) const {
|
|
c->Message(0, "Listing guilds on the server:");
|
|
char leadername[64];
|
|
std::map<uint32, GuildInfo *>::const_iterator cur, end;
|
|
cur = m_guilds.begin();
|
|
end = m_guilds.end();
|
|
int r = 0;
|
|
for(; cur != end; ++cur) {
|
|
leadername[0] = '\0';
|
|
database.GetCharName(cur->second->leader_char_id, leadername);
|
|
if (leadername[0] == '\0')
|
|
c->Message(0, " Guild #%i <%s>", cur->first, cur->second->name.c_str());
|
|
else
|
|
c->Message(0, " Guild #%i <%s> Leader: %s", cur->first, cur->second->name.c_str(), leadername);
|
|
r++;
|
|
}
|
|
c->Message(0, "%i guilds listed.", r);
|
|
}
|
|
|
|
|
|
void ZoneGuildManager::DescribeGuild(Client *c, uint32 guild_id) const {
|
|
std::map<uint32, GuildInfo *>::const_iterator res;
|
|
res = m_guilds.find(guild_id);
|
|
if(res == m_guilds.end()) {
|
|
c->Message(0, "Guild %d not found.", guild_id);
|
|
return;
|
|
}
|
|
|
|
const GuildInfo *info = res->second;
|
|
|
|
c->Message(0, "Guild info DB# %i <%s>", guild_id, info->name.c_str());
|
|
|
|
char leadername[64];
|
|
database.GetCharName(info->leader_char_id, leadername);
|
|
c->Message(0, "Guild Leader: %s", leadername);
|
|
|
|
char permbuffer[256];
|
|
uint8 i;
|
|
for (i = 0; i <= GUILD_MAX_RANK; i++) {
|
|
char *permptr = permbuffer;
|
|
uint8 r;
|
|
for(r = 0; r < _MaxGuildAction; r++)
|
|
permptr += sprintf(permptr, " %s: %c", GuildActionNames[r], info->ranks[i].permissions[r]?'Y':'N');
|
|
|
|
c->Message(0, "Rank %i: %s", i, info->ranks[i].name.c_str());
|
|
c->Message(0, "Permissions: %s", permbuffer);
|
|
}
|
|
|
|
}
|
|
|
|
//in theory, we could get a pile of unused entries in this array, but only if
|
|
//we had a malicious client sending controlled packets, plus its like 10 bytes per entry.
|
|
void ZoneGuildManager::RecordInvite(uint32 char_id, uint32 guild_id, uint8 rank) {
|
|
m_inviteQueue[char_id] = std::pair<uint32, uint8>(guild_id, rank);
|
|
}
|
|
|
|
bool ZoneGuildManager::VerifyAndClearInvite(uint32 char_id, uint32 guild_id, uint8 rank) {
|
|
std::map<uint32, std::pair<uint32, uint8> >::iterator res;
|
|
res = m_inviteQueue.find(char_id);
|
|
if(res == m_inviteQueue.end())
|
|
return(false); //no entry...
|
|
bool valid = false;
|
|
if(res->second.first == guild_id && res->second.second == rank) {
|
|
valid = true;
|
|
}
|
|
m_inviteQueue.erase(res);
|
|
return(valid);
|
|
}
|
|
|
|
void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) {
|
|
switch(pack->opcode) {
|
|
case ServerOP_RefreshGuild: {
|
|
if(pack->size != sizeof(ServerGuildRefresh_Struct)) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Received ServerOP_RefreshGuild of incorrect size %d, expected %d", pack->size, sizeof(ServerGuildRefresh_Struct));
|
|
return;
|
|
}
|
|
ServerGuildRefresh_Struct *s = (ServerGuildRefresh_Struct *) pack->pBuffer;
|
|
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds, "Received guild refresh from world for %d, changes: name=%d, motd=%d, rank=%d, relation=%d", s->guild_id, s->name_change, s->motd_change, s->rank_change, s->relation_change);
|
|
|
|
//reload all the guild details from the database.
|
|
RefreshGuild(s->guild_id);
|
|
|
|
if(s->motd_change) {
|
|
//resend guild MOTD to all guild members in this zone.
|
|
entity_list.SendGuildMOTD(s->guild_id);
|
|
}
|
|
|
|
if(s->name_change) {
|
|
//until we figure out the guild update packet, we resend the whole guild list.
|
|
entity_list.SendGuildList();
|
|
}
|
|
|
|
if(s->rank_change) {
|
|
//we need to send spawn appearance packets for all members of this guild in the zone, to everybody.
|
|
entity_list.SendGuildSpawnAppearance(s->guild_id);
|
|
}
|
|
|
|
if(s->relation_change) {
|
|
//unknown until we implement guild relations.
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ServerOP_GuildCharRefresh: {
|
|
if(pack->size != sizeof(ServerGuildCharRefresh_Struct)) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Received ServerOP_RefreshGuild of incorrect size %d, expected %d", pack->size, sizeof(ServerGuildCharRefresh_Struct));
|
|
return;
|
|
}
|
|
ServerGuildCharRefresh_Struct *s = (ServerGuildCharRefresh_Struct *) pack->pBuffer;
|
|
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds, "Received guild member refresh from world for char %d from guild %d", s->char_id, s->guild_id);
|
|
|
|
Client *c = entity_list.GetClientByCharID(s->char_id);
|
|
|
|
if(c != nullptr) {
|
|
//this reloads the char's guild info from the database and sends appearance updates
|
|
c->RefreshGuildInfo();
|
|
}
|
|
|
|
//it would be nice if we had the packet to send just a one-person update
|
|
if(s->guild_id == GUILD_NONE) {
|
|
if(c != nullptr)
|
|
c->SendGuildMembers(); //only need to update this player's list (trying to clear it)
|
|
} else {
|
|
entity_list.SendGuildMembers(s->guild_id); //even send GUILD_NONE (empty)
|
|
}
|
|
|
|
if(s->old_guild_id != 0 && s->old_guild_id != GUILD_NONE && s->old_guild_id != s->guild_id)
|
|
entity_list.SendGuildMembers(s->old_guild_id);
|
|
else if(c != nullptr && s->guild_id != GUILD_NONE) {
|
|
//char is in zone, and has changed into a new guild, send MOTD.
|
|
c->SendGuildMOTD();
|
|
if(c->GetClientVersion() >= EQClientRoF)
|
|
{
|
|
c->SendGuildRanks();
|
|
}
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
case ServerOP_GuildRankUpdate:
|
|
{
|
|
if(ZoneLoaded)
|
|
{
|
|
if(pack->size != sizeof(ServerGuildRankUpdate_Struct))
|
|
{
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Received ServerOP_RankUpdate of incorrect size %d, expected %d",
|
|
pack->size, sizeof(ServerGuildRankUpdate_Struct));
|
|
|
|
return;
|
|
}
|
|
|
|
ServerGuildRankUpdate_Struct *sgrus = (ServerGuildRankUpdate_Struct*)pack->pBuffer;
|
|
|
|
EQApplicationPacket *outapp = new EQApplicationPacket(OP_SetGuildRank, sizeof(GuildSetRank_Struct));
|
|
|
|
GuildSetRank_Struct *gsrs = (GuildSetRank_Struct*)outapp->pBuffer;
|
|
|
|
gsrs->Rank = sgrus->Rank;
|
|
strn0cpy(gsrs->MemberName, sgrus->MemberName, sizeof(gsrs->MemberName));
|
|
gsrs->Banker = sgrus->Banker;
|
|
|
|
entity_list.QueueClientsGuild(nullptr, outapp, false, sgrus->GuildID);
|
|
|
|
safe_delete(outapp);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ServerOP_DeleteGuild: {
|
|
if(pack->size != sizeof(ServerGuildID_Struct)) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Received ServerOP_DeleteGuild of incorrect size %d, expected %d", pack->size, sizeof(ServerGuildID_Struct));
|
|
return;
|
|
}
|
|
ServerGuildID_Struct *s = (ServerGuildID_Struct *) pack->pBuffer;
|
|
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds, "Received guild delete from world for guild %d", s->guild_id);
|
|
|
|
//clear all the guild tags.
|
|
entity_list.RefreshAllGuildInfo(s->guild_id);
|
|
|
|
//remove the guild data from the local guild manager
|
|
guild_mgr.LocalDeleteGuild(s->guild_id);
|
|
|
|
//if we stop forcing guild list to send on guild create, we need to do this:
|
|
//in the case that we delete a guild and add a new one.
|
|
//entity_list.SendGuildList();
|
|
|
|
break;
|
|
}
|
|
|
|
case ServerOP_GuildMemberUpdate:
|
|
{
|
|
ServerGuildMemberUpdate_Struct *sgmus = (ServerGuildMemberUpdate_Struct*)pack->pBuffer;
|
|
|
|
if(ZoneLoaded)
|
|
{
|
|
EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct));
|
|
|
|
GuildMemberUpdate_Struct *gmus = (GuildMemberUpdate_Struct*)outapp->pBuffer;
|
|
|
|
gmus->GuildID = sgmus->GuildID;
|
|
strn0cpy(gmus->MemberName, sgmus->MemberName, sizeof(gmus->MemberName));
|
|
gmus->ZoneID = sgmus->ZoneID;
|
|
gmus->InstanceID = 0; // I don't think we care what Instance they are in, for the Guild Management Window.
|
|
gmus->LastSeen = sgmus->LastSeen;
|
|
|
|
entity_list.QueueClientsGuild(nullptr, outapp, false, sgmus->GuildID);
|
|
|
|
safe_delete(outapp);
|
|
}
|
|
break;
|
|
}
|
|
case ServerOP_OnlineGuildMembersResponse:
|
|
if (ZoneLoaded)
|
|
{
|
|
char *Buffer = (char *)pack->pBuffer;
|
|
|
|
uint32 FromID = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
|
|
uint32 Count = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
|
|
Client *c = entity_list.GetClientByCharID(FromID);
|
|
|
|
if (!c || !c->IsInAGuild())
|
|
{
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds,"Invalid Client or not in guild. ID=%i", FromID);
|
|
break;
|
|
}
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds,"Processing ServerOP_OnlineGuildMembersResponse");
|
|
EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct));
|
|
GuildMemberUpdate_Struct *gmus = (GuildMemberUpdate_Struct*)outapp->pBuffer;
|
|
char Name[64];
|
|
gmus->LastSeen = time(nullptr);
|
|
gmus->InstanceID = 0;
|
|
gmus->GuildID = c->GuildID();
|
|
for (int i=0;i<Count;i++)
|
|
{
|
|
// Just make the packet once and swap out name/zone and send
|
|
VARSTRUCT_DECODE_STRING(Name, Buffer);
|
|
strn0cpy(gmus->MemberName, Name, sizeof(gmus->MemberName));
|
|
gmus->ZoneID = VARSTRUCT_DECODE_TYPE(uint32, Buffer);
|
|
Log.Out(EQEmuLogSys::Detail, EQEmuLogSys::Guilds,"Sending OP_GuildMemberUpdate to %i. Name=%s ZoneID=%i",FromID,Name,gmus->ZoneID);
|
|
c->QueuePacket(outapp);
|
|
}
|
|
safe_delete(outapp);
|
|
|
|
}
|
|
break;
|
|
|
|
case ServerOP_LFGuildUpdate:
|
|
{
|
|
if(ZoneLoaded)
|
|
{
|
|
char GuildName[33];
|
|
char Comments[257];
|
|
uint32 FromLevel, ToLevel, Classes, AACount, TimeZone, TimePosted, Toggle;
|
|
|
|
pack->ReadString(GuildName);
|
|
pack->ReadString(Comments);
|
|
FromLevel = pack->ReadUInt32();
|
|
ToLevel = pack->ReadUInt32();
|
|
Classes = pack->ReadUInt32();
|
|
AACount = pack->ReadUInt32();
|
|
TimeZone = pack->ReadUInt32();
|
|
TimePosted = pack->ReadUInt32();
|
|
Toggle = pack->ReadUInt32();
|
|
|
|
uint32 GuildID = GetGuildIDByName(GuildName);
|
|
|
|
if(GuildID == GUILD_NONE)
|
|
break;
|
|
|
|
EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, sizeof(LFGuild_GuildToggle_Struct));
|
|
|
|
LFGuild_GuildToggle_Struct *gts = (LFGuild_GuildToggle_Struct *)outapp->pBuffer;
|
|
gts->Command = 1;
|
|
strcpy(gts->Comment, Comments);
|
|
gts->FromLevel = FromLevel;
|
|
gts->ToLevel = ToLevel;
|
|
gts->Classes = Classes;
|
|
gts->AACount = AACount;
|
|
gts->TimeZone = TimeZone;
|
|
gts->Toggle = Toggle;
|
|
gts->TimePosted = TimePosted;
|
|
gts->Name[0] = 0;
|
|
entity_list.QueueClientsGuild(nullptr, outapp, false, GuildID);
|
|
safe_delete(outapp);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ZoneGuildManager::SendGuildMemberUpdateToWorld(const char *MemberName, uint32 GuildID, uint16 ZoneID, uint32 LastSeen)
|
|
{
|
|
ServerPacket* pack = new ServerPacket(ServerOP_GuildMemberUpdate, sizeof(ServerGuildMemberUpdate_Struct));
|
|
|
|
ServerGuildMemberUpdate_Struct *sgmus = (ServerGuildMemberUpdate_Struct*)pack->pBuffer;
|
|
sgmus->GuildID = GuildID;
|
|
strn0cpy(sgmus->MemberName, MemberName, sizeof(sgmus->MemberName));
|
|
sgmus->ZoneID = ZoneID;
|
|
sgmus->LastSeen = LastSeen;
|
|
worldserver.SendPacket(pack);
|
|
|
|
safe_delete(pack);
|
|
}
|
|
|
|
void ZoneGuildManager::RequestOnlineGuildMembers(uint32 FromID, uint32 GuildID)
|
|
{
|
|
ServerPacket* pack = new ServerPacket(ServerOP_RequestOnlineGuildMembers, sizeof(ServerRequestOnlineGuildMembers_Struct));
|
|
ServerRequestOnlineGuildMembers_Struct *srogm = (ServerRequestOnlineGuildMembers_Struct*)pack->pBuffer;
|
|
|
|
srogm->FromID = FromID;
|
|
srogm->GuildID = GuildID;
|
|
worldserver.SendPacket(pack);
|
|
|
|
safe_delete(pack);
|
|
}
|
|
|
|
void ZoneGuildManager::ProcessApproval()
|
|
{
|
|
LinkedListIterator<GuildApproval*> iterator(list);
|
|
|
|
iterator.Reset();
|
|
while(iterator.MoreElements())
|
|
{
|
|
if(!iterator.GetData()->ProcessApproval())
|
|
iterator.RemoveCurrent();
|
|
iterator.Advance();
|
|
}
|
|
}
|
|
|
|
void ZoneGuildManager::AddGuildApproval(const char* guildname,Client* owner)
|
|
{
|
|
GuildApproval* tmp = new GuildApproval(guildname,owner,GetFreeID());
|
|
list.Insert(tmp);
|
|
}
|
|
|
|
void ZoneGuildManager::AddMemberApproval(uint32 refid,Client* name)
|
|
{
|
|
GuildApproval* tmp = FindGuildByIDApproval(refid);
|
|
if(tmp != 0)
|
|
{
|
|
if(!tmp->AddMemberApproval(name))
|
|
name->Message(0,"Unable to add to list.");
|
|
else
|
|
{
|
|
name->Message(0,"Added to list.");
|
|
}
|
|
}
|
|
else
|
|
name->Message(0,"Unable to find guild reference id.");
|
|
}
|
|
|
|
ZoneGuildManager::~ZoneGuildManager()
|
|
{
|
|
ClearGuilds();
|
|
}
|
|
|
|
void ZoneGuildManager::ClearGuildsApproval()
|
|
{
|
|
list.Clear();
|
|
}
|
|
|
|
GuildApproval* ZoneGuildManager::FindGuildByIDApproval(uint32 refid)
|
|
{
|
|
LinkedListIterator<GuildApproval*> iterator(list);
|
|
|
|
iterator.Reset();
|
|
while(iterator.MoreElements())
|
|
{
|
|
if(iterator.GetData()->GetID() == refid)
|
|
return iterator.GetData();
|
|
iterator.Advance();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
GuildApproval* ZoneGuildManager::FindGuildByOwnerApproval(Client* owner)
|
|
{
|
|
LinkedListIterator<GuildApproval*> iterator(list);
|
|
|
|
iterator.Reset();
|
|
while(iterator.MoreElements())
|
|
{
|
|
if(iterator.GetData()->GetOwner() == owner)
|
|
return iterator.GetData();
|
|
iterator.Advance();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
GuildBankManager::~GuildBankManager()
|
|
{
|
|
std::list<GuildBank*>::iterator Iterator = Banks.begin();
|
|
|
|
while(Iterator != Banks.end())
|
|
{
|
|
safe_delete(*Iterator);
|
|
|
|
++Iterator;
|
|
}
|
|
}
|
|
|
|
bool GuildBankManager::Load(uint32 guildID)
|
|
{
|
|
|
|
std::string query = StringFormat("SELECT `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `whofor` "
|
|
"FROM `guild_bank` WHERE `guildid` = %i", guildID);
|
|
auto results = database.QueryDatabase(query);
|
|
if(!results.Success()) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Error Loading guild bank: %s, %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return false;
|
|
}
|
|
|
|
GuildBank *bank = new GuildBank;
|
|
|
|
bank->GuildID = guildID;
|
|
|
|
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
|
bank->Items.MainArea[i].ItemID = 0;
|
|
|
|
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
|
|
bank->Items.DepositArea[i].ItemID = 0;
|
|
|
|
char donator[64], whoFor[64];
|
|
|
|
for (auto row = results.begin(); row != results.end(); ++row)
|
|
{
|
|
int area = atoi(row[0]);
|
|
int slot = atoi(row[1]);
|
|
int itemID = atoi(row[2]);
|
|
int qty = atoi(row[3]);
|
|
|
|
if(row[4])
|
|
strn0cpy(donator, row[4], sizeof(donator));
|
|
else
|
|
donator[0] = '\0';
|
|
|
|
int permissions = atoi(row[5]);
|
|
|
|
if(row[6])
|
|
strn0cpy(whoFor, row[6], sizeof(whoFor));
|
|
else
|
|
whoFor[0] = '\0';
|
|
|
|
if(slot < 0)
|
|
continue;
|
|
|
|
GuildBankItem *itemSection = nullptr;
|
|
|
|
if (area == GuildBankMainArea && slot < GUILD_BANK_MAIN_AREA_SIZE)
|
|
itemSection = bank->Items.MainArea;
|
|
else if (area != GuildBankMainArea && slot < GUILD_BANK_DEPOSIT_AREA_SIZE)
|
|
itemSection = bank->Items.DepositArea;
|
|
else
|
|
continue;
|
|
|
|
itemSection[slot].ItemID = itemID;
|
|
itemSection[slot].Quantity = qty;
|
|
|
|
strn0cpy(itemSection[slot].Donator, donator, sizeof(donator));
|
|
|
|
itemSection[slot].Permissions = permissions;
|
|
|
|
strn0cpy(itemSection[slot].WhoFor, whoFor, sizeof(whoFor));
|
|
}
|
|
|
|
Banks.push_back(bank);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GuildBankManager::IsLoaded(uint32 GuildID)
|
|
{
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
|
|
|
return (Iterator != Banks.end());
|
|
}
|
|
|
|
void GuildBankManager::SendGuildBank(Client *c)
|
|
{
|
|
if(!c || !c->IsInAGuild())
|
|
return;
|
|
|
|
if(!IsLoaded(c->GuildID()))
|
|
Load(c->GuildID());
|
|
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(c->GuildID());
|
|
|
|
if(Iterator == Banks.end())
|
|
{
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Unable to find guild bank for guild ID %i", c->GuildID());
|
|
|
|
return;
|
|
}
|
|
|
|
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
|
|
{
|
|
if((*Iterator)->Items.DepositArea[i].ItemID > 0)
|
|
{
|
|
const Item_Struct *Item = database.GetItem((*Iterator)->Items.DepositArea[i].ItemID);
|
|
|
|
if(!Item)
|
|
continue;
|
|
|
|
EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct));
|
|
|
|
GuildBankItemUpdate_Struct *gbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer;
|
|
|
|
if(!Item->Stackable)
|
|
gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, 1,
|
|
(*Iterator)->Items.DepositArea[i].Permissions, 0, 0);
|
|
else
|
|
{
|
|
if((*Iterator)->Items.DepositArea[i].Quantity == Item->StackSize)
|
|
gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon,
|
|
(*Iterator)->Items.DepositArea[i].Quantity, (*Iterator)->Items.DepositArea[i].Permissions, 0, 0);
|
|
else
|
|
gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon,
|
|
(*Iterator)->Items.DepositArea[i].Quantity, (*Iterator)->Items.DepositArea[i].Permissions, 1, 0);
|
|
}
|
|
|
|
strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName));
|
|
|
|
strn0cpy(gbius->Donator, (*Iterator)->Items.DepositArea[i].Donator, sizeof(gbius->Donator));
|
|
|
|
strn0cpy(gbius->WhoFor, (*Iterator)->Items.DepositArea[i].WhoFor, sizeof(gbius->WhoFor));
|
|
|
|
c->FastQueuePacket(&outapp);
|
|
}
|
|
}
|
|
|
|
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
|
{
|
|
if((*Iterator)->Items.MainArea[i].ItemID > 0)
|
|
{
|
|
const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[i].ItemID);
|
|
|
|
if(!Item)
|
|
continue;
|
|
|
|
bool Useable = Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass());
|
|
|
|
EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct));
|
|
|
|
GuildBankItemUpdate_Struct *gbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer;
|
|
|
|
if(!Item->Stackable)
|
|
gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, 1,
|
|
(*Iterator)->Items.MainArea[i].Permissions, 0, Useable);
|
|
else
|
|
{
|
|
if((*Iterator)->Items.MainArea[i].Quantity == Item->StackSize)
|
|
gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
|
(*Iterator)->Items.MainArea[i].Quantity, (*Iterator)->Items.MainArea[i].Permissions, 0, Useable);
|
|
else
|
|
gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
|
(*Iterator)->Items.MainArea[i].Quantity, (*Iterator)->Items.MainArea[i].Permissions, 1, Useable);
|
|
}
|
|
|
|
strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName));
|
|
|
|
strn0cpy(gbius->Donator, (*Iterator)->Items.MainArea[i].Donator, sizeof(gbius->Donator));
|
|
|
|
strn0cpy(gbius->WhoFor, (*Iterator)->Items.MainArea[i].WhoFor, sizeof(gbius->WhoFor));
|
|
|
|
c->FastQueuePacket(&outapp);
|
|
}
|
|
}
|
|
}
|
|
bool GuildBankManager::IsAreaFull(uint32 GuildID, uint16 Area)
|
|
{
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
|
|
|
if(Iterator == Banks.end())
|
|
return true;
|
|
|
|
GuildBankItem* BankArea = nullptr;
|
|
|
|
int AreaSize = 0;
|
|
|
|
if(Area == GuildBankMainArea)
|
|
{
|
|
BankArea = &(*Iterator)->Items.MainArea[0];
|
|
|
|
AreaSize = GUILD_BANK_MAIN_AREA_SIZE;
|
|
}
|
|
else
|
|
{
|
|
BankArea = &(*Iterator)->Items.DepositArea[0];
|
|
|
|
AreaSize = GUILD_BANK_DEPOSIT_AREA_SIZE;
|
|
}
|
|
|
|
for(int i = 0; i < AreaSize; ++i)
|
|
if(BankArea[i].ItemID == 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GuildBankManager::AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32 QtyOrCharges, const char *Donator, uint8 Permissions, const char *WhoFor)
|
|
{
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
|
|
|
if(Iterator == Banks.end())
|
|
{
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Unable to find guild bank for guild ID %i", GuildID);
|
|
|
|
return false;
|
|
}
|
|
|
|
GuildBankItem* BankArea = nullptr;
|
|
|
|
int AreaSize = 0;
|
|
|
|
if(Area == GuildBankMainArea)
|
|
{
|
|
BankArea = &(*Iterator)->Items.MainArea[0];
|
|
|
|
AreaSize = GUILD_BANK_MAIN_AREA_SIZE;
|
|
}
|
|
else
|
|
{
|
|
BankArea = &(*Iterator)->Items.DepositArea[0];
|
|
|
|
AreaSize = GUILD_BANK_DEPOSIT_AREA_SIZE;
|
|
}
|
|
|
|
int Slot = -1;
|
|
|
|
for(int i = 0; i < AreaSize; ++i)
|
|
{
|
|
if(BankArea[i].ItemID == 0)
|
|
{
|
|
BankArea[i].ItemID = ItemID;
|
|
|
|
BankArea[i].Quantity = QtyOrCharges;
|
|
|
|
strn0cpy(BankArea[i].Donator, Donator, sizeof(BankArea[i].Donator));
|
|
|
|
BankArea[i].Permissions = Permissions;
|
|
|
|
strn0cpy(BankArea[i].WhoFor, WhoFor, sizeof(BankArea[i].WhoFor));
|
|
|
|
Slot = i;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(Slot < 0)
|
|
{
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "No space to add item to the guild bank.");
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string query = StringFormat("INSERT INTO `guild_bank` "
|
|
"(`guildid`, `area`, `slot`, `itemid`, `qty`, `donator`, `permissions`, `WhoFor`) "
|
|
"VALUES (%i, %i, %i, %i, %i, '%s', %i, '%s')",
|
|
GuildID, Area, Slot, ItemID, QtyOrCharges, Donator, Permissions, WhoFor);
|
|
auto results = database.QueryDatabase(query);
|
|
if(!results.Success()) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Insert Error: %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return false;
|
|
}
|
|
|
|
const Item_Struct *Item = database.GetItem(ItemID);
|
|
|
|
GuildBankItemUpdate_Struct gbius;
|
|
|
|
if(!Item->Stackable)
|
|
gbius.Init(GuildBankItemUpdate, 1, Slot, Area, 1, ItemID, Item->Icon, Item->Stackable ? QtyOrCharges : 1, Permissions, 0, 0);
|
|
else
|
|
{
|
|
if(QtyOrCharges == Item->StackSize)
|
|
gbius.Init(GuildBankItemUpdate, 1, Slot, Area, 1, ItemID, Item->Icon, Item->Stackable ? QtyOrCharges : 1, Permissions, 0, 0);
|
|
else
|
|
gbius.Init(GuildBankItemUpdate, 1, Slot, Area, 1, ItemID, Item->Icon, Item->Stackable ? QtyOrCharges : 1, Permissions, 1, 0);
|
|
}
|
|
|
|
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
|
|
|
strn0cpy(gbius.Donator, Donator, sizeof(gbius.Donator));
|
|
|
|
strn0cpy(gbius.WhoFor, WhoFor, sizeof(gbius.WhoFor));
|
|
|
|
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
|
|
|
return true;
|
|
}
|
|
|
|
int GuildBankManager::Promote(uint32 guildID, int slotID)
|
|
{
|
|
if((slotID < 0) || (slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)))
|
|
return -1;
|
|
|
|
auto iter = GetGuildBank(guildID);
|
|
|
|
if(iter == Banks.end())
|
|
return -1;
|
|
|
|
if((*iter)->Items.DepositArea[slotID].ItemID == 0)
|
|
return -1;
|
|
|
|
int mainSlot = -1;
|
|
|
|
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
|
if((*iter)->Items.MainArea[i].ItemID == 0) {
|
|
mainSlot = i;
|
|
break;
|
|
}
|
|
|
|
if(mainSlot == -1)
|
|
return -1;
|
|
|
|
(*iter)->Items.MainArea[mainSlot].ItemID = (*iter)->Items.DepositArea[slotID].ItemID;
|
|
(*iter)->Items.MainArea[mainSlot].Quantity = (*iter)->Items.DepositArea[slotID].Quantity;
|
|
(*iter)->Items.MainArea[mainSlot].Permissions = (*iter)->Items.DepositArea[slotID].Permissions;
|
|
|
|
strn0cpy((*iter)->Items.MainArea[mainSlot].Donator, (*iter)->Items.DepositArea[slotID].Donator, sizeof((*iter)->Items.MainArea[mainSlot].Donator));
|
|
strn0cpy((*iter)->Items.MainArea[mainSlot].WhoFor, (*iter)->Items.DepositArea[slotID].WhoFor, sizeof((*iter)->Items.MainArea[mainSlot].WhoFor));
|
|
|
|
std::string query = StringFormat("UPDATE `guild_bank` SET `area` = 1, `slot` = %i "
|
|
"WHERE `guildid` = %i AND `area` = 0 AND `slot` = %i "
|
|
"LIMIT 1", mainSlot, guildID, slotID);
|
|
auto results = database.QueryDatabase(query);
|
|
if (!results.Success()) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "error promoting item: %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return -1;
|
|
}
|
|
|
|
(*iter)->Items.DepositArea[slotID].ItemID = 0;
|
|
|
|
const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[mainSlot].ItemID);
|
|
|
|
GuildBankItemUpdate_Struct gbius;
|
|
|
|
if(!Item->Stackable)
|
|
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, 0, 0, 0);
|
|
else
|
|
{
|
|
if((*iter)->Items.MainArea[mainSlot].Quantity == Item->StackSize)
|
|
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
|
(*iter)->Items.MainArea[mainSlot].Quantity, 0, 0, 0);
|
|
else
|
|
gbius.Init(GuildBankItemUpdate, 1, mainSlot, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
|
(*iter)->Items.MainArea[mainSlot].Quantity, 0, 1, 0);
|
|
}
|
|
|
|
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
|
|
|
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
|
|
|
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankDepositArea, 0, 0, 0, 0, 0, 0, 0);
|
|
|
|
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
|
|
|
return mainSlot;
|
|
}
|
|
|
|
void GuildBankManager::SetPermissions(uint32 guildID, uint16 slotID, uint32 permissions, const char *memberName)
|
|
{
|
|
if((slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)))
|
|
return;
|
|
|
|
auto iter = GetGuildBank(guildID);
|
|
|
|
if(iter == Banks.end())
|
|
return;
|
|
|
|
if((*iter)->Items.MainArea[slotID].ItemID == 0)
|
|
return;
|
|
|
|
std::string query = StringFormat("UPDATE `guild_bank` SET `permissions` = %i, `whofor` = '%s' "
|
|
"WHERE `guildid` = %i AND `area` = 1 AND `slot` = %i LIMIT 1",
|
|
permissions, memberName, guildID, slotID);
|
|
auto results = database.QueryDatabase(query);
|
|
if(!results.Success())
|
|
{
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "error changing permissions: %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return;
|
|
}
|
|
|
|
(*iter)->Items.MainArea[slotID].Permissions = permissions;
|
|
|
|
if(permissions == GuildBankSingleMember)
|
|
strn0cpy((*iter)->Items.MainArea[slotID].WhoFor, memberName, sizeof((*iter)->Items.MainArea[slotID].WhoFor));
|
|
else
|
|
(*iter)->Items.MainArea[slotID].WhoFor[0] = '\0';
|
|
|
|
const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[slotID].ItemID);
|
|
|
|
GuildBankItemUpdate_Struct gbius;
|
|
|
|
if(!Item->Stackable)
|
|
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, (*iter)->Items.MainArea[slotID].Permissions, 0, 0);
|
|
else
|
|
{
|
|
if((*iter)->Items.MainArea[slotID].Quantity == Item->StackSize)
|
|
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
|
(*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 0, 0);
|
|
else
|
|
gbius.Init(GuildBankItemUpdate, 1, slotID, GuildBankMainArea, 1, Item->ID, Item->Icon,
|
|
(*iter)->Items.MainArea[slotID].Quantity, (*iter)->Items.MainArea[slotID].Permissions, 1, 0);
|
|
}
|
|
|
|
|
|
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
|
|
|
strn0cpy(gbius.WhoFor, (*iter)->Items.MainArea[slotID].WhoFor, sizeof(gbius.WhoFor));
|
|
|
|
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
|
}
|
|
|
|
ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity)
|
|
{
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
|
|
|
if(Iterator == Banks.end())
|
|
return nullptr;
|
|
|
|
GuildBankItem* BankArea = nullptr;
|
|
|
|
ItemInst* inst = nullptr;
|
|
|
|
if(Area == GuildBankDepositArea)
|
|
{
|
|
if((SlotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1)))
|
|
return nullptr;
|
|
|
|
inst = database.CreateItem((*Iterator)->Items.DepositArea[SlotID].ItemID);
|
|
|
|
if(!inst)
|
|
return nullptr;
|
|
|
|
BankArea = &(*Iterator)->Items.DepositArea[0];
|
|
}
|
|
else
|
|
{
|
|
|
|
if((SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)))
|
|
return nullptr;
|
|
|
|
inst = database.CreateItem((*Iterator)->Items.MainArea[SlotID].ItemID);
|
|
|
|
if(!inst)
|
|
return nullptr;
|
|
|
|
BankArea = &(*Iterator)->Items.MainArea[0];
|
|
}
|
|
|
|
if(!inst->IsStackable())
|
|
inst->SetCharges(BankArea[SlotID].Quantity);
|
|
else
|
|
{
|
|
if(Quantity <= BankArea[SlotID].Quantity)
|
|
inst->SetCharges(Quantity);
|
|
else
|
|
inst->SetCharges(BankArea[SlotID].Quantity);
|
|
}
|
|
|
|
return inst;
|
|
}
|
|
|
|
bool GuildBankManager::HasItem(uint32 GuildID, uint32 ItemID)
|
|
{
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
|
|
|
if(Iterator == Banks.end())
|
|
return false;
|
|
|
|
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i)
|
|
if((*Iterator)->Items.MainArea[i].ItemID == ItemID)
|
|
return true;
|
|
|
|
for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i)
|
|
if((*Iterator)->Items.DepositArea[i].ItemID == ItemID)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
std::list<GuildBank*>::iterator GuildBankManager::GetGuildBank(uint32 GuildID)
|
|
{
|
|
std::list<GuildBank*>::iterator Iterator = Banks.begin();
|
|
|
|
while(Iterator != Banks.end())
|
|
{
|
|
if((*Iterator)->GuildID == GuildID)
|
|
break;
|
|
|
|
++Iterator;
|
|
}
|
|
|
|
return Iterator;
|
|
}
|
|
|
|
bool GuildBankManager::DeleteItem(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
|
|
{
|
|
auto iter = GetGuildBank(guildID);
|
|
|
|
if(iter == Banks.end())
|
|
return false;
|
|
|
|
GuildBankItem* BankArea = nullptr;
|
|
|
|
if(area == GuildBankMainArea)
|
|
{
|
|
if(slotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
|
|
return false;
|
|
|
|
BankArea = &(*iter)->Items.MainArea[0];
|
|
} else {
|
|
if(slotID > (GUILD_BANK_DEPOSIT_AREA_SIZE - 1))
|
|
return false;
|
|
|
|
BankArea = &(*iter)->Items.DepositArea[0];
|
|
}
|
|
|
|
bool deleted = true;
|
|
|
|
const Item_Struct *Item = database.GetItem(BankArea[slotID].ItemID);
|
|
|
|
if(!Item->Stackable || (quantity >= BankArea[slotID].Quantity)) {
|
|
std::string query = StringFormat("DELETE FROM `guild_bank` WHERE `guildid` = %i "
|
|
"AND `area` = %i AND `slot` = %i LIMIT 1",
|
|
guildID, area, slotID);
|
|
auto results = database.QueryDatabase(query);
|
|
if(!results.Success()) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Delete item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return false;
|
|
}
|
|
|
|
BankArea[slotID].ItemID = 0;
|
|
|
|
} else {
|
|
std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i WHERE `guildid` = %i "
|
|
"AND `area` = %i AND `slot` = %i LIMIT 1",
|
|
BankArea[slotID].Quantity - quantity, guildID, area, slotID);
|
|
auto results = database.QueryDatabase(query);
|
|
if(!results.Success()) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Update item failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return false;
|
|
}
|
|
|
|
BankArea[slotID].Quantity -= quantity;
|
|
|
|
deleted = false;
|
|
}
|
|
|
|
GuildBankItemUpdate_Struct gbius;
|
|
|
|
if(!deleted)
|
|
{
|
|
gbius.Init(GuildBankItemUpdate, 1, slotID, area, 1, Item->ID, Item->Icon, BankArea[slotID].Quantity, BankArea[slotID].Permissions, 1, 0);
|
|
|
|
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
|
|
|
strn0cpy(gbius.WhoFor, BankArea[slotID].WhoFor, sizeof(gbius.WhoFor));
|
|
}
|
|
else
|
|
gbius.Init(GuildBankItemUpdate, 1, slotID, area, 0, 0, 0, 0, 0, 0, 0);
|
|
|
|
entity_list.QueueClientsGuildBankItemUpdate(&gbius, guildID);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool GuildBankManager::MergeStacks(uint32 GuildID, uint16 SlotID)
|
|
{
|
|
if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
|
|
return false;
|
|
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
|
|
|
if(Iterator == Banks.end())
|
|
return false;
|
|
|
|
GuildBankItem* BankArea = &(*Iterator)->Items.MainArea[0];
|
|
|
|
if(BankArea[SlotID].ItemID == 0)
|
|
return false;
|
|
|
|
const Item_Struct *Item = database.GetItem(BankArea[SlotID].ItemID);
|
|
|
|
if(!Item->Stackable)
|
|
return false;
|
|
|
|
uint32 ItemID = BankArea[SlotID].ItemID;
|
|
|
|
for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE - 1; ++i)
|
|
{
|
|
if(BankArea[i].ItemID != ItemID)
|
|
continue;
|
|
|
|
if(BankArea[i].Quantity == Item->StackSize)
|
|
continue;
|
|
|
|
bool Merged = false;
|
|
|
|
for(int j = i + 1; j < GUILD_BANK_MAIN_AREA_SIZE; ++j)
|
|
{
|
|
if(BankArea[j].ItemID != ItemID)
|
|
continue;
|
|
|
|
if(BankArea[j].Permissions != BankArea[i].Permissions)
|
|
continue;
|
|
|
|
if(BankArea[i].Permissions == 1)
|
|
if(strncmp(BankArea[i].WhoFor, BankArea[j].WhoFor, sizeof(BankArea[i].WhoFor)))
|
|
continue;
|
|
|
|
if((BankArea[i].Quantity + BankArea[j].Quantity) <= Item->StackSize)
|
|
{
|
|
BankArea[i].Quantity += BankArea[j].Quantity;
|
|
|
|
DeleteItem(GuildID, GuildBankMainArea, j, BankArea[j].Quantity);
|
|
|
|
Merged = true;
|
|
|
|
if(BankArea[i].Quantity == Item->StackSize)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
uint32 QuantityToMove = Item->StackSize - BankArea[i].Quantity;
|
|
|
|
DeleteItem(GuildID, GuildBankMainArea, j, QuantityToMove);
|
|
|
|
BankArea[i].Quantity = Item->StackSize;
|
|
|
|
Merged = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(Merged)
|
|
{
|
|
UpdateItemQuantity(GuildID, GuildBankMainArea, i, BankArea[i].Quantity);
|
|
|
|
GuildBankItemUpdate_Struct gbius;
|
|
|
|
if(BankArea[i].Quantity == Item->StackSize)
|
|
gbius.Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, ItemID, Item->Icon, BankArea[i].Quantity, BankArea[i].Permissions, 0, 0);
|
|
else
|
|
gbius.Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, ItemID, Item->Icon, BankArea[i].Quantity, BankArea[i].Permissions, 1, 0);
|
|
|
|
strn0cpy(gbius.ItemName, Item->Name, sizeof(gbius.ItemName));
|
|
|
|
strn0cpy(gbius.WhoFor, BankArea[i].WhoFor, sizeof(gbius.WhoFor));
|
|
|
|
entity_list.QueueClientsGuildBankItemUpdate(&gbius, GuildID);
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GuildBankManager::SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity)
|
|
{
|
|
if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
|
|
return false;
|
|
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
|
|
|
if(Iterator == Banks.end())
|
|
return false;
|
|
|
|
if(IsAreaFull(GuildID, GuildBankMainArea))
|
|
return false;
|
|
|
|
GuildBankItem* BankArea = &(*Iterator)->Items.MainArea[0];
|
|
|
|
if(BankArea[SlotID].ItemID == 0)
|
|
return false;
|
|
|
|
if(BankArea[SlotID].Quantity <= Quantity || Quantity == 0)
|
|
return false;
|
|
|
|
const Item_Struct *Item = database.GetItem(BankArea[SlotID].ItemID);
|
|
|
|
if(!Item->Stackable)
|
|
return false;
|
|
|
|
AddItem(GuildID, GuildBankMainArea, BankArea[SlotID].ItemID, Quantity, "", BankArea[SlotID].Permissions, BankArea[SlotID].WhoFor);
|
|
|
|
DeleteItem(GuildID, GuildBankMainArea, SlotID, Quantity);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GuildBankManager::UpdateItemQuantity(uint32 guildID, uint16 area, uint16 slotID, uint32 quantity)
|
|
{
|
|
// Helper method for MergeStacks. Assuming all passed parameters are valid.
|
|
//
|
|
std::string query = StringFormat("UPDATE `guild_bank` SET `qty` = %i "
|
|
"WHERE `guildid` = %i AND `area` = %i "
|
|
"AND `slot` = %i LIMIT 1",
|
|
quantity, guildID, area, slotID);
|
|
auto results = database.QueryDatabase(query);
|
|
if(!results.Success()) {
|
|
Log.Out(EQEmuLogSys::General, EQEmuLogSys::Error, "Update item quantity failed. %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
bool GuildBankManager::AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 SlotID, const char *Name)
|
|
{
|
|
// Is a none-Guild Banker allowed to withdraw the item at this slot ?
|
|
// This is really here for anti-hacking measures, as the client should not request an item it does not have permission to withdraw.
|
|
//
|
|
if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1))
|
|
return false;
|
|
|
|
std::list<GuildBank*>::iterator Iterator = GetGuildBank(GuildID);
|
|
|
|
if(Iterator == Banks.end())
|
|
return false;
|
|
|
|
if(Area != GuildBankMainArea)
|
|
return false;
|
|
|
|
uint8 Permissions = (*Iterator)->Items.MainArea[SlotID].Permissions;
|
|
|
|
if(Permissions == GuildBankBankerOnly)
|
|
return false;
|
|
|
|
if(Permissions != GuildBankSingleMember) // Public or Public-If-Useable (should really check if item is useable)
|
|
return true;
|
|
|
|
if(!strncmp((*Iterator)->Items.MainArea[SlotID].WhoFor, Name, sizeof((*Iterator)->Items.MainArea[SlotID].WhoFor)))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/*================== GUILD APPROVAL ========================*/
|
|
|
|
bool GuildApproval::ProcessApproval()
|
|
{
|
|
if(owner && owner->GuildID() != 0)
|
|
{
|
|
owner->Message(10,"You are already in a guild! Guild request deleted.");
|
|
return false;
|
|
}
|
|
if(deletion_timer->Check() || !owner)
|
|
{
|
|
if(owner)
|
|
owner->Message(0,"You took too long! Your guild request has been deleted.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
GuildApproval::GuildApproval(const char* guildname, Client* owner,uint32 id)
|
|
{
|
|
database.GetVariable("GuildCreation", founders, 3);
|
|
uint8 tmp = atoi(founders);
|
|
deletion_timer = new Timer(1800000);
|
|
strcpy(guild,guildname);
|
|
this->owner = owner;
|
|
this->refid = id;
|
|
if(owner)
|
|
owner->Message(0,"You can now start getting your guild approved, tell your %i members to #guildapprove %i, you have 30 minutes to create your guild.",tmp,GetID());
|
|
for(int i=0;i<tmp;i++)
|
|
members[i] = 0;
|
|
}
|
|
|
|
GuildApproval::~GuildApproval()
|
|
{
|
|
safe_delete(deletion_timer);
|
|
}
|
|
|
|
bool GuildApproval::AddMemberApproval(Client* addition)
|
|
{
|
|
database.GetVariable("GuildCreation", founders, 3);
|
|
uint8 tmp = atoi(founders);
|
|
for(int i=0;i<tmp;i++)
|
|
{
|
|
if(members[i] && members[i] == addition)
|
|
return false;
|
|
}
|
|
|
|
for(int i=0;i<tmp;i++)
|
|
{
|
|
if(!members[i])
|
|
{
|
|
members[i] = addition;
|
|
int z=0;
|
|
for(int i=0;i<tmp;i++)
|
|
{
|
|
if(members[i])
|
|
z++;
|
|
}
|
|
if(z==tmp)
|
|
GuildApproved();
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void GuildApproval::ApprovedMembers(Client* requestee)
|
|
{
|
|
database.GetVariable("GuildCreation", founders, 3);
|
|
uint8 tmp = atoi(founders);
|
|
for(int i=0;i<tmp;i++)
|
|
{
|
|
if(members[i])
|
|
requestee->Message(0,"%i: %s",i,members[i]->GetName());
|
|
}
|
|
}
|
|
|
|
void GuildApproval::GuildApproved()
|
|
{
|
|
char petitext[PBUFFER] = "A new guild was founded! Guildname: ";
|
|
char gmembers[MBUFFER] = " ";
|
|
|
|
if(!owner)
|
|
return;
|
|
database.GetVariable("GuildCreation", founders, 3);
|
|
uint8 tmp = atoi(founders);
|
|
uint32 tmpeq = guild_mgr.CreateGuild(guild, owner->CharacterID());
|
|
guild_mgr.SetGuild(owner->CharacterID(),tmpeq,2);
|
|
owner->SendAppearancePacket(AT_GuildID,true,false);
|
|
for(int i=0;i<tmp;i++)
|
|
{
|
|
if(members[i])
|
|
{
|
|
owner->Message(0, "%s",members[i]->GetName());
|
|
owner->Message(0, "%i",members[i]->CharacterID());
|
|
guild_mgr.SetGuild(members[i]->CharacterID(),tmpeq,0);
|
|
size_t len = MBUFFER - strlen(gmembers)+1;
|
|
strncat(gmembers," ",len);
|
|
strncat(gmembers,members[i]->GetName(),len);
|
|
}
|
|
}
|
|
size_t len = PBUFFER - strlen(petitext)+1;
|
|
strncat(petitext,guild,len);
|
|
strncat(petitext," Leader: ",len);
|
|
strncat(petitext,owner->CastToClient()->GetName(),len);
|
|
strncat(petitext," Members:",len);
|
|
strncat(petitext,gmembers,len);
|
|
Petition* pet = new Petition(owner->CastToClient()->CharacterID());
|
|
pet->SetAName(owner->CastToClient()->AccountName());
|
|
pet->SetClass(owner->CastToClient()->GetClass());
|
|
pet->SetLevel(owner->CastToClient()->GetLevel());
|
|
pet->SetCName(owner->CastToClient()->GetName());
|
|
pet->SetRace(owner->CastToClient()->GetRace());
|
|
pet->SetLastGM("");
|
|
pet->SetCName(owner->CastToClient()->GetName()); //aza77 is this really 2 times needed ??
|
|
pet->SetPetitionText(petitext);
|
|
pet->SetZone(zone->GetZoneID());
|
|
pet->SetUrgency(0);
|
|
petition_list.AddPetition(pet);
|
|
database.InsertPetitionToDB(pet);
|
|
petition_list.UpdateGMQueue();
|
|
petition_list.UpdateZoneListQueue();
|
|
worldserver.SendEmoteMessage(0, 0, 80, 15, "%s has made a petition. #%i", owner->CastToClient()->GetName(), pet->GetID());
|
|
ServerPacket* pack = new ServerPacket;
|
|
pack->opcode = ServerOP_RefreshGuild;
|
|
pack->size = tmp;
|
|
pack->pBuffer = new uchar[pack->size];
|
|
memcpy(pack->pBuffer, &tmpeq, 4);
|
|
worldserver.SendPacket(pack);
|
|
safe_delete(pack);
|
|
owner->Message(0, "Your guild was created.");
|
|
owner = 0;
|
|
}
|
|
|