/* * guildmanager.cpp * * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * 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; 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 #include #include #include #include #include #include "client.h" #include "clients.h" #include "util/serverconsole.h" #include "util/psstring.h" #include "util/psxmlparser.h" #include "util/eventmanager.h" #include "util/psdatabase.h" // Database #include "gem.h" #include "playergroup.h" #include "guildmanager.h" #include "cachemanager.h" #include "util/pserror.h" #include "util/log.h" #include "util/psconst.h" #include "globals.h" #include "psserver.h" #include "bulkobjects/pscharacter.h" #include "bulkobjects/pscharacterloader.h" #include "bulkobjects/pssectorinfo.h" #include "bulkobjects/psaccountinfo.h" #include "chatmanager.h" #include "netmanager.h" class PendingGuildInvite : public PendingInvite { public: int guildID; PendingGuildInvite(Client *inviter, Client *invitee, const char *question, int guildID) : PendingInvite( inviter, invitee, true, question,"Accept","Decline", "You have asked %s to join your guild.", "%s has invited you to join a guild.", "%s has joined your guild.", "You have joined the guild.", "%s has declined your invitation.", "You have declined %s's invitation.", psQuestionMessage::generalConfirm) { this->guildID = guildID; }; virtual ~PendingGuildInvite() {} void HandleAnswer(const csString & answer); }; /** * This invitation isn't really an invitation. It is used when somebody tries to invite a player that is already * member of a guild and this guild is secret. We cannot tell the inviter that the player is already in a guild. * We must keep this information secret. So we send invitation that explains the situation to the * secret member and that cannot be accepted. In this way, his membership in secret guild won't be revealed. */ class PendingSecretGuildMemberInvite : public PendingInvite { public: PendingSecretGuildMemberInvite(Client *inviter, Client *invitee, const char *question, int guildID) : PendingInvite( inviter, invitee, true, question,"Decline","", "You have asked %s to join your guild.", "%s has invited you to join a guild. You are already member of a secret guild so you cannot accept this offer.", "", "", "%s has declined your invitation.", "You have declined %s's invitation.", psQuestionMessage::secretGuildNotify) { cannotAccept = true; }; }; /** A structure to hold the clients that are pending on guild war challenges. */ class PendingGuildWarInvite : public PendingInvite { public: PendingGuildWarInvite(Client *inviter, Client *invitee, const char *question) : PendingInvite( inviter, invitee, true, question,"Accept","Decline", "You have challenged %s to a guild war.", "%s has challenged you to a guild war.", "%s has accepted your challenge.", "You have accepted %s's challenge.", "%s has declined your challenge.", "You have declined %s's challenge.", psQuestionMessage::generalConfirm) { } virtual ~PendingGuildWarInvite() {} virtual void HandleAnswer(const csString & answer); }; class psGuildCheckEvent : public psGameEvent { protected: int guildid; GuildManager *guildmanager; public: psGuildCheckEvent(int guild_id, GuildManager *gm) : psGameEvent(0,GUILD_KICK_GRACE *60*1000,"psGuildCheckEvent") { guildid = guild_id; guildmanager = gm; } void Trigger() { guildmanager->RequirementsDeadline(guildid); } }; /** * Returns guild of 'client'. * If he is not in a guild, NULL is returned and text message "You are not in a guild." is sent to the client */ psGuildInfo * GetClientGuild(Client * client) { psGuildInfo * guild = client->GetActor()->GetGuild(); if (!guild) { psSystemMessage newmsg(client->GetClientNum(),MSG_ERROR,"You are not in a guild."); newmsg.SendMessage(); return NULL; } return guild; } GuildManager::GuildManager(ClientConnectionSet *cs, ChatManager *chat) { clients = cs; chatserver = chat; // Needed to GUILDSAY things. xml = csPtr(new csTinyDocumentSystem); CS_ASSERT( xml ); psserver->GetEventManager()->Subscribe(this,MSGTYPE_GUILDCMD,REQUIRE_READY_CLIENT); psserver->GetEventManager()->Subscribe(this,MSGTYPE_GUIGUILD,REQUIRE_READY_CLIENT); psserver->GetEventManager()->Subscribe(this,MSGTYPE_GUILDMOTDSET,REQUIRE_ANY_CLIENT); } GuildManager::~GuildManager() { size_t i; for (i=0; i < notifySubscr.Length(); i++) delete notifySubscr[i]; notifySubscr.DeleteAll(); psserver->GetEventManager()->Unsubscribe(this,MSGTYPE_GUILDCMD); psserver->GetEventManager()->Unsubscribe(this,MSGTYPE_GUIGUILD); psserver->GetEventManager()->Unsubscribe(this,MSGTYPE_GUILDMOTDSET); } void GuildManager::HandleMessage(MsgEntry *me,Client *client) { switch (me->GetType()) { case MSGTYPE_GUILDCMD: { psGuildCmdMessage msg(me); if (!msg.valid) { psserver->SendSystemError(me->clientnum, "Command not supported by server yet."); Error2("Failed to parse psGuildCmdMessage from client %u.",me->clientnum); return; } HandleCmdMessage(msg,client); break; } case MSGTYPE_GUIGUILD: { psGUIGuildMessage msg(me); if (!msg.valid) { Error2("Failed to parse psGUIGuildMessage from client %u.",me->clientnum); return; } HandleGUIMessage(msg,client); break; } case MSGTYPE_GUILDMOTDSET: { psGuildMOTDSetMessage msg(me); if (!msg.valid) { Error2("Failed to parse psGuildMOTDSetMessage from client %u.",me->clientnum); } HandleMOTDSet(msg,client); } } } void GuildManager::HandleCmdMessage(psGuildCmdMessage& msg, Client* client ) { int clientnum = client->GetClientNum(); if (msg.command == "/newguild") { CreateGuild(msg,client); } else if (msg.command == "/endguild") { EndGuild(msg,client); } else if (msg.command == "/guildname") { ChangeGuildName(msg,client); } else if (msg.command == "/guildinvite") { Invite(msg,client); } else if (msg.command == "/guildremove") { Remove(msg,client); } else if (msg.command == "/guildlevel") { Rename(msg,client); } else if (msg.command == "/guildpromote") { Promote(msg,client); } else if (msg.command == "/guildmembers") { ListMembers(msg,client); } else if (msg.command == "/guildsecret") { Secret(msg, client); } else if (msg.command == "/guildweb") { Web(msg, client); } else if (msg.command == "/guildmotd") { MOTD(msg,client); } else if (msg.command == "/guildwar") { GuildWar(msg,client); } else if (msg.command == "/guildyield") { GuildYield(msg,client); } else if (msg.command == "/guildpoints") { SendGuildPoints(msg,client); } else if (msg.command == "/newalliance") { NewAlliance(msg,client); } else if (msg.command == "/allianceinvite") { AllianceInvite(msg,client); } else if (msg.command == "/allianceremove") { AllianceRemove(msg,client); } else if (msg.command == "/allianceleave") { AllianceLeave(msg,client); } else if (msg.command == "/allianceleader") { AllianceLeader(msg,client); } else if (msg.command == "/endalliance") { EndAlliance(msg,client); } else { psserver->SendSystemError(clientnum,"Command not supported by server yet."); } } void GuildManager::HandleGUIMessage(psGUIGuildMessage& msg,Client *client) { csRef doc = xml->CreateDocument(); const char* error = doc->Parse( msg.commandData); if ( error ) { Error2("Error in XML: %s", error ); return; } switch(msg.command) { case psGUIGuildMessage::SUBSCRIBE_GUILD_DATA: HandleSubscribeGuildData(client, doc->GetRoot()); break; case psGUIGuildMessage::UNSUBSCRIBE_GUILD_DATA: UnsubscribeGuildData(client); break; case psGUIGuildMessage::SET_ONLINE: HandleSetOnline(client, doc->GetRoot()); break; case psGUIGuildMessage::SET_LEVEL_RIGHT: HandleSetLevelRight(client, doc->GetRoot()); break; case psGUIGuildMessage::SET_MEMBER_POINTS: HandleSetMemberPoints(client, doc->GetRoot()); break; case psGUIGuildMessage::SET_MEMBER_PUBLIC_NOTES: HandleSetMemberNotes(client, doc->GetRoot(), true); break; case psGUIGuildMessage::SET_MEMBER_PRIVATE_NOTES: HandleSetMemberNotes(client, doc->GetRoot(), false); break; } } void GuildManager::HandleMOTDSet(psGuildMOTDSetMessage& msg,Client *client) { if (CheckClientRights(client,RIGHTS_EDIT_GUILD,"You don't have permission to change settings of your guild.")) { psGuildInfo *gi = client->GetActor()->GetGuild(); gi->SetMOTD(msg.guildmotd); //Send notify to all guild members psSystemMessage newmsg(client->GetClientNum(), MSG_INFO, "Guild message of the day updated"); psserver->GetEventManager()->Broadcast(newmsg.msg,NetBase::BC_GUILD,gi->id); } } /** Returns guild level of character connected as 'client' (zero if he has no level) */ int GuildManager::GetClientLevel(Client * client) { psGuildLevel * level; level = client->GetActor()->GetGuildLevel(); if (level != NULL) return level->level; else return 0; } /** Checks if 'client' has priviledge 'priv' in his guild. */ bool GuildManager::CheckClientRights(Client * client, GUILD_PRIVILEGE priv) { psGuildLevel * level; level = client->GetActor()->GetGuildLevel(); if (level == NULL) return false; if (level->HasRights(priv)) return true; else return false; } /** Checks if 'client' has priviledge 'priv' in his guild. * If not, he is sent 'denialMsg'. */ bool GuildManager::CheckClientRights(Client * client, GUILD_PRIVILEGE priv, const char * denialMsg) { if (CheckClientRights(client, priv)) return true; else { psserver->SendSystemError(client->GetClientNum(),denialMsg); return false; } } bool RetrieveOnlineOnly(iDocumentNode * root) { csRef topNode = root->GetNode("r"); if (!topNode) return true; csString onlineOnly = topNode->GetAttributeValue("onlineonly"); return (onlineOnly == "yes"); } void GuildManager::HandleSubscribeGuildData(Client *client,iDocumentNode * root) { int clientnum = client->GetClientNum(); psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) { psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::NOT_IN_GUILD,""); cmd.SendMessage(); return; } // check if already subscribed GuildNotifySubscription * subscr = FindNotifySubscr(client); if (subscr != NULL) return; subscr = new GuildNotifySubscription(guild->id, client->GetClientNum(), RetrieveOnlineOnly(root)); notifySubscr.Push(subscr); SendGuildData(client); SendLevelData(client); SendMemberData(client, subscr->onlineOnly); SendAllianceData(client); } void GuildManager::UnsubscribeGuildData(Client *client) { GuildNotifySubscription * subscr = FindNotifySubscr(client); if (subscr == NULL) return; delete subscr; notifySubscr.Delete(subscr); } void GuildManager::HandleSetOnline(Client *client,iDocumentNode * root) { GuildNotifySubscription * subscr = FindNotifySubscr(client); if (subscr != NULL) { subscr->onlineOnly = RetrieveOnlineOnly(root); SendMemberData(client, subscr->onlineOnly); } } void GuildManager::SendNotifications(int guild, int msg) { Client * client; size_t i; for (i=0; i < notifySubscr.Length(); i++) if (notifySubscr[i]->guild == guild) { client = clients->Find( notifySubscr[i]->clientnum ); if (!client) continue; psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) { Error2("Error - character %s is not in any guild but it has guild notifications subscribed", client->GetName()); continue; } psUpdatePlayerGuildMessage update( client->GetClientNum(), client->GetActor()->GetEntity()->GetID(), guild->GetName() ); if (guild->IsSecret()) // If this is a secret guild, we should only broadcast to members psserver->GetEventManager()->Broadcast( update.msg, NetBase::BC_GUILD, guild->id ); else psserver->GetEventManager()->Broadcast( update.msg, NetBase::BC_EVERYONE ); switch (msg) { case psGUIGuildMessage::GUILD_DATA: SendGuildData(client); break; case psGUIGuildMessage::LEVEL_DATA: SendLevelData(client); break; case psGUIGuildMessage::MEMBER_DATA: SendMemberData(client, notifySubscr[i]->onlineOnly); break; case psGUIGuildMessage::ALLIANCE_DATA: SendAllianceData(client); break; } } } void GuildManager::SendAllianceNotifications(psGuildAlliance * alliance) { int memberNum; for (memberNum=0; memberNum < (int)alliance->GetMemberCount(); memberNum++) SendNotifications(alliance->GetMember(memberNum)->id, psGUIGuildMessage::ALLIANCE_DATA); } void GuildManager::SendNoAllianceNotifications(psGuildAlliance * alliance) { int memberNum; for (memberNum=0; memberNum < (int)alliance->GetMemberCount(); memberNum++) { SendNoAllianceNotifications(alliance->GetMember(memberNum)); } } void GuildManager::SendNoAllianceNotifications(psGuildInfo * guild) { size_t notifNum; for (notifNum=0; notifNum < notifySubscr.Length(); notifNum++) if (notifySubscr[notifNum]->guild == guild->id) { Client * client = clients->Find( notifySubscr[notifNum]->clientnum ); if (client != NULL) { psGUIGuildMessage cmd(client->GetClientNum(),psGUIGuildMessage::ALLIANCE_DATA,""); cmd.SendMessage(); } } } GuildNotifySubscription * GuildManager::FindNotifySubscr(Client * client) { int clientnum; size_t i; clientnum = client->GetClientNum(); for (i=0; i < notifySubscr.Length(); i++) if (notifySubscr[i]->clientnum == clientnum) return notifySubscr[i]; return NULL; } void GuildManager::HandleSetLevelRight(Client * client, iDocumentNode* root) { csRef topNode = root->GetNode("l"); if (!topNode) { Error1("Error in XML: Can't find node l"); return; } int level = topNode->GetAttributeValueAsInt("level"); csString privilege = topNode->GetAttributeValue("privilege"); csString state = topNode->GetAttributeValue("state"); psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) { psserver->SendSystemError(client->GetClientNum(),"You are not in a guild."); return; } if ( ! IsLeader(client)) { if ( ! CheckClientRights(client, RIGHTS_EDIT_LEVEL, "You do not have the rights to edit priviledges in your guild.")) return; if ( GetClientLevel(client) <= level ) { psserver->SendSystemError(client->GetClientNum(),"You do not have the rights to edit priviledges of this level in your guild."); return; } } GUILD_PRIVILEGE right; if (privilege == "view_chat") { right = RIGHTS_VIEW_CHAT; } else if (privilege == "chat") { right = RIGHTS_CHAT; } else if (privilege == "invite") { right = RIGHTS_INVITE; } else if (privilege == "remove") { right = RIGHTS_REMOVE; } else if (privilege == "promote") { right = RIGHTS_PROMOTE; } else if (privilege == "edit_level") { right = RIGHTS_EDIT_LEVEL; } else if (privilege == "edit_points") { right = RIGHTS_EDIT_POINTS; } else if (privilege == "edit_guild") { right = RIGHTS_EDIT_GUILD; } else if (privilege == "edit_public") { right = RIGHTS_EDIT_PUBLIC; } else if (privilege == "edit_private") { right = RIGHTS_EDIT_PRIVATE; } else { Error2("Unkown privilege %s",privilege.GetData()); return; } if (guild->SetPrivilege(level,right,state=="on")) { psGuildLevel *lev = guild->FindLevel(level); if (lev != NULL) psserver->SendSystemInfo(client->GetClientNum(),"Privilege %s for level %s was turned %s", privilege.GetData(),lev->title.GetData(),state.GetData()); } SendNotifications(guild->id, psGUIGuildMessage::LEVEL_DATA); } void GuildManager::HandleSetMemberPoints(Client *client,iDocumentNode * root) { csRef topNode = root->GetNode("p"); if (topNode == NULL) return; unsigned int char_id = topNode->GetAttributeValueAsInt("char_id"); int points = topNode->GetAttributeValueAsInt("points"); psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) return; psGuildMember * member = guild->FindMember(char_id); if (member == NULL) return; if ( ! IsLeader(client)) { if ( !CheckClientRights(client, RIGHTS_EDIT_POINTS, "You do not have the rights to edit points in your guild.")) return; if (GetClientLevel(client) <= member->guildlevel->level ) { psserver->SendSystemError(client->GetClientNum(),"You do not have the rights to edit points of this member."); return; } } guild->SetMemberPoints(member, points); SendNotifications(guild->id, psGUIGuildMessage::MEMBER_DATA); } void GuildManager::HandleSetMemberNotes(Client *client,iDocumentNode * root, bool isPublic) { csRef topNode = root->GetNode("n"); if (topNode == NULL) return; int char_id = topNode->GetAttributeValueAsInt("char_id"); csString notes = topNode->GetAttributeValue("notes"); psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) return; psGuildMember * member = guild->FindMember(char_id); if (member == NULL) return; if (isPublic) { if ( ! IsLeader(client)) { if ( !CheckClientRights(client, RIGHTS_EDIT_PUBLIC) || ( GetClientLevel(client) < member->guildlevel->level ) ) { psserver->SendSystemError(client->GetClientNum(),"You do not have the rights to edit public notes of this member."); return; } } } else { if ( !CheckClientRights(client, RIGHTS_EDIT_PRIVATE) ) { psserver->SendSystemError(client->GetClientNum(),"You do not have the rights to edit private notes."); return; } if (client->GetPlayerID() != char_id)// if this is not my info notes = member->private_notes + notes+ "\n";// append the notes to the end } guild->SetMemberNotes(member, notes, isPublic); SendNotifications(guild->id, psGUIGuildMessage::MEMBER_DATA); } const char * DeNULL(const char * str) { return (str == NULL) ? "" : str; } void GuildManager::SendGuildData(Client *client) { int clientnum = client->GetClientNum(); psString open; psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) return; csString escpxml_guild = EscpXML(guild->GetName()); csString escpxml_webpage = EscpXML(guild->web_page); open.AppendFmt("", escpxml_guild.GetData(), guild->IsSecret()?"yes":"no", escpxml_webpage.GetData()); psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::GUILD_DATA,open); cmd.SendMessage(); } const char * BoolToText(bool b) { return b ? "true" : "false"; } void GuildManager::SendLevelData(Client *client) { int clientnum = client->GetClientNum(); psString open; psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) return; open.Append(""); csArray::Iterator lIter = guild->levels.GetIterator(); while (lIter.HasNext()) { open.Append(""); psGuildLevel* level = lIter.Next(); csString escpxml = EscpXML(level->title); open.AppendFmt("",escpxml.GetData()); open.AppendFmt("<level text=\"%d\"/>",level->level); open.AppendFmt("<view_chat down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_VIEW_CHAT))); open.AppendFmt("<chat down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_CHAT))); open.AppendFmt("<invite down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_INVITE))); open.AppendFmt("<remove down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_REMOVE))); open.AppendFmt("<promote down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_PROMOTE))); open.AppendFmt("<edit_level down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_LEVEL))); open.AppendFmt("<edit_points down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_POINTS))); open.AppendFmt("<edit_guild down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_GUILD))); open.AppendFmt("<edit_public down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_PUBLIC))); open.AppendFmt("<edit_private down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_PRIVATE))); open.Append("</l>"); } open.Append("</levellist>"); psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::LEVEL_DATA,open); cmd.SendMessage(); } void GuildManager::SendMemberData(Client *client,bool onlineOnly) { int clientnum = client->GetClientNum(); csString online, lastOnline; psString sectorName; psSectorInfo * sector = NULL; psString open; psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) return; psGuildLevel * level = client->GetCharacterData()->GetGuildLevel(); if (level == NULL) return; // Member list open.Append("<memberlist>"); csArray<psGuildMember*>::Iterator mIter = guild->members.GetIterator(); while (mIter.HasNext()) { sectorName.Clear(); psGuildMember* member = mIter.Next(); Client * memberClient = clients->FindPlayer(member->char_id); if (memberClient != NULL) { online = "yes"; psCharacter* character = memberClient->GetCharacterData(); if(character) { sector = character->location.loc_sector; lastOnline = character->GetLastLoginTime(); lastOnline.Truncate(16); } if (sector != NULL) sectorName = sector->name; } else { online = "no"; lastOnline = ""; //The guild member can be NOT online, in this case we have to query the db directly Result result(db->Select("SELECT last_login FROM characters WHERE id = '%d'",member->char_id)); if (result.Count() > 0) { lastOnline = result[0][0]; lastOnline.Truncate(16); // cut date+time string to date only } } //account = CacheManager::GetSingleton().GetAccountInfoByCharID(member->char_id); /*if (account != NULL) { lastOnline = account->lastlogintime; lastOnline.Truncate(16); // cut date+time string to date only delete account; } else Error2("Could not find account info for player %s !", member->name.GetData());*/ if (online=="yes" || !onlineOnly) { open.Append("<m>"); csString escpxml = EscpXML(member->name); open.AppendFmt("<name text=\"%s\"/>",escpxml.GetData()); escpxml = EscpXML(member->guildlevel->title); open.AppendFmt("<level text=\"%s\"/>",escpxml.GetData()); open.AppendFmt("<online text=\"%s\"/>",online.GetData()); open.AppendFmt("<sector text=\"%s\"/>",sectorName.EscapeXML()); open.AppendFmt("<lastonline text=\"%s\"/>",lastOnline.GetData()); open.AppendFmt("<points text=\"%d\"/>",member->guild_points); open.Append("</m>"); } } open.Append("</memberlist>"); // Information about members that is not in the member listbox open.Append("<memberinfo>"); csArray<psGuildMember*>::Iterator mIter2 = guild->members.GetIterator(); while (mIter2.HasNext()) { psGuildMember* member = mIter2.Next(); csString escpxml_name = EscpXML(member->name); csString escpxml_publicnotes = EscpXML(member->public_notes); csString escpxml_privatenotes; if (client->GetPlayerID() == member->char_id)//only show private notes to yourself escpxml_privatenotes = EscpXML(member->private_notes); else escpxml_privatenotes = ""; open.AppendFmt("<m char_id=\"%i\" name=\"%s\" public=\"%s\" private=\"%s\" points=\"%i\" level=\"%i\"/>", member->char_id, escpxml_name.GetData(), escpxml_publicnotes.GetData(), escpxml_privatenotes.GetData(), member->guild_points, member->guildlevel->level); } open.Append("</memberinfo>"); open.AppendFmt("<playerinfo char_id=\"%i\"/>", client->GetPlayerID()); psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::MEMBER_DATA,open); cmd.SendMessage(); } csString GuildManager::MakeAllianceMemberXML(psGuildInfo * member, bool allianceLeader) { psString xml; csString name, isLeader, leaderName, online; psGuildMember * leader; name = member->name; if (allianceLeader) isLeader = "leader"; else isLeader = ""; leader = member->FindLeader(); if (leader != NULL) { leaderName = leader->name; if (clients->FindPlayer(leader->char_id) != NULL) online = "yes"; else online = "no"; } csString escpxml_name = EscpXML(name); csString escpxml_isleader = EscpXML(isLeader); csString escpxml_leadername = EscpXML(leaderName); xml.AppendFmt("<member name=\"%s\" isleader=\"%s\" leadername=\"%s\" online=\"%s\"/>", escpxml_name.GetData(), escpxml_isleader.GetData(), escpxml_leadername.GetData(), online.GetData()); return xml; } void GuildManager::SendAllianceData(Client *client) { int clientnum = client->GetClientNum(); psGuildAlliance * alliance; psString xml; int memberNum; psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) return; if (guild->alliance != 0) { alliance = CacheManager::GetSingleton().FindAlliance(guild->alliance); if (alliance == NULL) return; csString escpxml = EscpXML(alliance->GetName()); xml.AppendFmt("<alliance IamLeader=\"%i\" name=\"%s\">", guild==alliance->GetLeader(), escpxml.GetData()); for (memberNum=0; memberNum < (int)alliance->GetMemberCount(); memberNum++) { psGuildInfo * member = alliance->GetMember(memberNum); xml += MakeAllianceMemberXML(member, member == alliance->GetLeader()); } } else xml.Append("<alliance IamLeader=\"0\">"); xml.Append("</alliance>"); psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::ALLIANCE_DATA,xml); cmd.SendMessage(); } void GuildManager::CheckMinimumRequirements(psGuildInfo *guild, gemActor *notify) { int clientid=0; if (!guild->MeetsMinimumRequirements()) { printf("*****************************************************************************\n" "Guild %s has %d members and will be deleted in %d minutes.\n" "*****************************************************************************\n", (const char *)guild->name, guild->members.Length(), GUILD_KICK_GRACE ); if (!notify) // If not auto-notifying the leader, find the leader if online { if (guild->FindLeader() && guild->FindLeader()->actor && guild->FindLeader()->actor->GetActor()) clientid = guild->FindLeader()->actor->GetActor()->GetClientID(); } else clientid = notify->GetClientID(); if (clientid) psserver->SendSystemInfo(clientid, "You have %d minutes to meet guild minimum requirements " "(%d+ members) or your guild will be disbanded.", GUILD_KICK_GRACE, GUILD_MIN_MEMBERS ); psGuildCheckEvent *event = new psGuildCheckEvent(guild->id, this); psserver->GetEventManager()->Push(event); } else { // guild ok. do nothing } } void GuildManager::RequirementsDeadline(int guild_id) { psGuildInfo *guild = CacheManager::GetSingleton().FindGuild(guild_id); if (!guild) return; if (!guild->MeetsMinimumRequirements()) { printf("Removing guild <%s> for failure to meet minimum requirements.\n",guild->GetName().GetDataSafe() ); EndGuild(guild,0); } } void GuildManager::CreateGuild(psGuildCmdMessage& msg,Client *client) { int clientnum = client->GetClientNum(); // check if the player is already in a guild if (client->GetCharacterData()->GetGuild() != NULL) { psserver->SendSystemError(clientnum,"You are already in a guild."); return; } if (msg.guildname.Length()==0) { psserver->SendSystemError(clientnum,"Please specify a guild name."); return; } if (msg.guildname.Length()<5) { psserver->SendSystemError(clientnum,"Guild name must be at least five characters."); return; } if (msg.guildname.Length() > 25) { psserver->SendSystemError(clientnum,"Guild name must be at under 25 characters."); return; } if(!FilterGuildName(msg.guildname)) { psserver->SendSystemError(clientnum,"Guild name contains invaild characters (A-Z,a-z and space is allowed)."); return; } psCharacter *chardata=client->GetCharacterData(); if (chardata==NULL) { Error2("Guild creation attempted by character '%s' with no character data!",client->GetName()); psserver->SendSystemError(clientnum,"An internal server error occcured (could not find your character data)."); return; } if (CacheManager::GetSingleton().FindGuild(msg.guildname)) { psserver->SendSystemError(clientnum,"A guild already exists with that name."); return; } if (chardata->Money().GetTotal() < GUILD_FEE) { psserver->SendSystemError(clientnum,"It costs %d trias to create a guild.",GUILD_FEE); return; } if (!CacheManager::GetSingleton().CreateGuild(msg.guildname, client) ) { psserver->SendSystemError(clientnum, db->GetLastError()); return; } else { psserver->SendSystemInfo(clientnum,"Guild '%s' created. You have been charged %d tria.", (const char *)msg.guildname, GUILD_FEE); } // Charge the price now chardata->SetMoney(chardata->Money() - GUILD_FEE); // subscribe client to updates of his guild psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) return; GuildNotifySubscription * subscr = new GuildNotifySubscription(guild->id, client->GetClientNum(), true); notifySubscr.Push(subscr); // send client data about guild - this will open GuildWindow for him SendGuildData(client); SendLevelData(client); SendMemberData(client, false); SendAllianceData(client); // Update the player's label psUpdatePlayerGuildMessage update(client->GetClientNum(), client->GetActor()->GetEntity()->GetID(), guild->GetName()); update.Multicast(client->GetActor()->GetMulticastClients(),0,0 ); // Now kick off guild minimum requirement timer CheckMinimumRequirements(guild,client->GetActor() ); } void GuildManager::EndGuild(psGuildCmdMessage& msg,Client *client) { int clientnum = client->GetClientNum(); psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) { psserver->SendSystemError(clientnum,"You are not in a guild."); return; } if (!(const char *)msg.guildname || msg.guildname=="" ) { psserver->SendSystemError(clientnum,"Guild name must be specified for confirmation purposes."); return; } if ( ! IsLeader(client)) if ( ! CheckClientRights(client, RIGHTS_EDIT_GUILD, "You do not have the rights to disband your guild.")) return; if (!guild->GetName().CompareNoCase(msg.guildname)) { psserver->SendSystemError(clientnum,"The guild name you specified did not match the guild you are in. The guild was not disbanded."); return; } EndGuild(guild,clientnum); } void GuildManager::EndGuild(psGuildInfo *guild,int clientnum) { if (!guild->RemoveGuild() ) { psserver->SendSystemError(clientnum,db->GetLastError()); return; } if (clientnum) psserver->SendSystemInfo(clientnum, "Guild has been disbanded."); UnsubscribeWholeGuild(guild); Client *p; ClientIterator i(*clients); for (p = i.First(); p; p = i.Next()) { if (p->GetActor() && (p->GetActor()->GetGuild() == guild)) { psUpdatePlayerGuildMessage update(p->GetClientNum(), p->GetActor()->GetEntity()->GetID(), ""); update.Multicast(p->GetActor()->GetMulticastClients(),0,0 ); psserver->SendSystemInfo(p->GetClientNum(),"Your guild has been disbanded."); guild->Disconnect(p->GetActor()->GetCharacterData()); } } CacheManager::GetSingleton().RemoveGuild(guild); } void GuildManager::UnsubscribeWholeGuild(psGuildInfo * guild) { size_t subscrNum=0; while (subscrNum < notifySubscr.Length()) { if (notifySubscr[subscrNum]->guild == guild->id) { Client * member = clients->Find( notifySubscr[subscrNum]->clientnum ); if (member != NULL) { psGUIGuildMessage msg(member->GetClientNum(), psGUIGuildMessage::CLOSE_WINDOW, "<x/>"); msg.SendMessage(); } delete notifySubscr[subscrNum]; notifySubscr.Delete(notifySubscr[subscrNum]); } else subscrNum++; } } void GuildManager::ChangeGuildName(psGuildCmdMessage& msg,Client *client) { int clientnum = client->GetClientNum(); psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (guild == NULL) { psserver->SendSystemError(clientnum,"You are not in a guild."); return; } if (!(const char *)msg.guildname || msg.guildname=="" ) { psserver->SendSystemError(clientnum,"New guild name must be specified."); return; } if ( ! IsLeader(client)) if (!CheckClientRights(client, RIGHTS_EDIT_GUILD, "You do not have the rights to edit the name of your guild.")) return; if (msg.guildname.Length()<5) { psserver->SendSystemError(clientnum,"Guild name must be at least five characters."); return; } if (msg.guildname.Length() > 25) { psserver->SendSystemError(clientnum,"Guild name must be at under 25 characters."); return; } if(!FilterGuildName(msg.guildname)) { psserver->SendSystemError(clientnum,"Guild name contains invalid characters (A-Z,a-z and space is allowed)."); return; } if(CacheManager::GetSingleton().FindGuild(msg.guildname)) { psserver->SendSystemError(clientnum,"A guild already exists with that name"); return; } if (guild->SetName(msg.guildname)) { psserver->SendSystemInfo(clientnum,"Your guild name has been changed to: %s",msg.guildname.GetData()); } SendNotifications(guild->id, psGUIGuildMessage::GUILD_DATA); } void GuildManager::Invite(psGuildCmdMessage& msg,Client *client) { csString playerName; int clientnum = client->GetClientNum(); playerName = NormalizeCharacterName(msg.player); psGuildInfo * guild = client->GetCharacterData()->GetGuild(); if (!guild) { psserver->SendSystemError(clientnum,"You have to be in a guild to invite someone."); return; } if ( ! IsLeader(client)) if ( ! CheckClientRights(client, RIGHTS_INVITE, "You do not have the rights to invite players into your guild.")) return; // invited player must be online when invited Client *invitee = clients->Find(playerName); if (!invitee) { psserver->SendSystemError(clientnum,"%s is not online right now.", (const char*) msg.player); return; } if (invitee == client) { psserver->SendSystemError(clientnum,"You can't invite yourself.", invitee->GetName()); return; } bool inviteeIsAlreadyInSecretGuild = false; psGuildInfo * inviteeGuild = invitee->GetCharacterData()->GetGuild(); if (inviteeGuild != NULL) { if (!inviteeGuild->IsSecret() ) { psserver->SendSystemError(clientnum, "That player is already a member of a guild."); return; } else inviteeIsAlreadyInSecretGuild = true; } PendingInvite *pnew; csString invitation; invitation.Format("You have been invited to join the %s. Click Accept to join this guild.",client->GetActor()->GetGuild()->name.GetData() ); if (inviteeIsAlreadyInSecretGuild) pnew = new PendingSecretGuildMemberInvite(client,invitee,invitation,guild->id); else pnew = new PendingGuildInvite(client,invitee,invitation,guild->id); // Track who is invited where, to verify confirmations psserver->questionmanager->SendQuestion(pnew); } void PendingGuildInvite::HandleAnswer(const csString & answer) { Client * client = psserver->GetConnections()->Find(clientnum); if (!client || client->GetCharacterData()->GetGuild() != NULL) return; PendingInvite::HandleAnswer(answer); if (answer == "yes") psserver->guildmanager->HandleJoinGuild(this); } void GuildManager::HandleJoinGuild(PendingGuildInvite *invite) { Client * inviteeClient = clients->Find(invite->clientnum); if (inviteeClient == NULL) return; psGuildInfo * guild = CacheManager::GetSingleton().FindGuild(invite->guildID); if (guild == NULL) return; if ( !guild->AddNewMember(inviteeClient->GetActor()->GetCharacterData() ) ) { psserver->SendSystemError(invite->inviterClientNum, "Error joining guild! (%s)", db->GetLastError()); Error2("Error joining guild! (%s)",db->GetLastError() ); return; } csString text; text.Format("Player %s has joined the guild!",invite->inviteeName.GetData() ); psChatMessage guildmsg(invite->inviterClientNum,"System",text,CHAT_GUILD, false); chatserver->SendGuild(inviteeClient->GetCharacterData()->GetCharName(), guild, guildmsg); SendNotifications(guild->id, psGUIGuildMessage::MEMBER_DATA); if (!guild->IsSecret())// update guild labels { psUpdatePlayerGuildMessage update( inviteeClient->GetClientNum(), inviteeClient->GetActor()->GetEntity()->GetID(), guild->GetName() ); psserver->GetEventManager()->Broadcast(update.msg,NetBase::BC_EVERYONE); } // forward new motd csString tip(""); csString motdMsg(psserver->GetMOTD()); csString guildMOTD(guild->GetMOTD()); csString guildName(guild->GetName()); psMOTDMessage motd(inviteeClient->GetClientNum(),tip,motdMsg,guildMOTD,guildName); motd.SendMessage(); } void GuildManager::Remove(psGuildCmdMessage& msg,Client *client) { Client * targetClient; csString name; int clientnum = client->GetClientNum(); psGuildInfo *gi = client->GetActor()->GetGuild(); if (!gi) { psserver->SendSystemError(clientnum,"You are not in a guild."); return; } if ( msg.player.Length() ) name = NormalizeCharacterName(msg.player); else name = client->GetName(); // Find the named player in guild psGuildMember *target = gi->FindMember(name); if (!target) { psserver->SendSystemError(clientnum,"That player is not member of your guild."); return; } // Verify rights if the player is removing someone else from the guild if (client->GetPlayerID() != (int)target->char_id ) { if ( ! IsLeader(client)) { if ( !CheckClientRights(client, RIGHTS_REMOVE, "You do not have rights to remove someone from your guild.")) return; if (GetClientLevel(client) <= target->guildlevel->level) { psserver->SendSystemError(clientnum,"You can't remove players of same or higher level."); return; } } targetClient = clients->Find(target->name); } else targetClient = client; if (target->guildlevel->level == MAX_GUILD_LEVEL) { psserver->SendSystemError(clientnum,"The leader cannot simply leave his guild. He must appoint a new leader first."); return; } gi->RemoveMember(target); if (targetClient != NULL) { psserver->SendSystemInfo(targetClient->GetClientNum(),"You have been removed from your guild."); UnsubscribeGuildData(targetClient); // forward blank MOTD to remove old csString blank(""); csString motdMsg(psserver->GetMOTD()); psMOTDMessage motd(targetClient->GetClientNum(),blank,motdMsg,blank,blank); motd.SendMessage(); } csString text; text.Format("Player %s has left the guild.", (const char *)msg.player ); psChatMessage guildmsg(0,"System",text,CHAT_GUILD, false); chatserver->SendGuild("server", gi, guildmsg); SendNotifications(gi->id, psGUIGuildMessage::MEMBER_DATA); // Now kick off guild minimum requirement timer CheckMinimumRequirements(gi,NULL); } /** * Called when player issues /guildlevel command * * Syntax: * /guildlevel <level> <levelname> * or * /guildlevel (this will show all current level names) */ void GuildManager::Rename(psGuildCmdMessage& msg,Client *client) { int clientnum = client->GetClientNum(); psGuildInfo *gi = client->GetActor()->GetGuild(); if (!gi) { psserver->SendSystemError(clientnum,"You are not in a guild."); return; } // checks if levelnumber has been specified if (msg.level <= 0 || msg.level > 9) { psserver->SendSystemInfo(clientnum,"Your guild has these titles defined:"); for (size_t i=0; i<gi->levels.Length(); i++) { psserver->SendSystemInfo(clientnum,"%i: %s",gi->levels[i]->level,gi->levels[i]->title.GetData() ); } return; } if ( ! IsLeader(client)) if ( ! CheckClientRights(client, RIGHTS_EDIT_LEVEL, "You do not have the rights to rename levels of your guild.")) return; // checks if levelname has been specified if (! (const char *)msg.levelname) { psserver->SendSystemError(clientnum,"You must specify the name after the level to rename a guild level."); return; } if(!FilterGuildName(msg.levelname)) { psserver->SendSystemError(clientnum,"Level name contains invaild characters (A-Z,a-z and space is allowed)."); return; } if (msg.levelname.Length()<3) { psserver->SendSystemError(clientnum,"Guild level name must be at least three characters."); return; } if (msg.levelname.Length() > 25) { psserver->SendSystemError(clientnum,"Guild level name must be at under 25 characters."); return; } if (!gi->RenameLevel(msg.level,msg.levelname)) { psserver->SendSystemError(clientnum,"SQL Error: %s",db->GetLastError()); return; } psserver->SendSystemInfo(clientnum,"Guild level rename was successful."); csString text; text.Format("Guild level %d is now called: %s", msg.level, (const char *)msg.levelname ); psChatMessage guildmsg(clientnum,"System",text,CHAT_GUILD, false); if (guildmsg.valid) chatserver->SendGuild(client->GetCharacterData()->GetCharName(), gi, guildmsg); SendNotifications(gi->id, psGUIGuildMessage::LEVEL_DATA); } void GuildManager::Promote(psGuildCmdMessage& msg,Client *client) { int clientnum = client->GetClientNum(); psGuildInfo *guild = client->GetActor()->GetGuild(); if (!guild) { psserver->SendSystemError(clientnum,"You are not in a guild."); return; } if (! (const char *)msg.player) { psserver->SendSystemError(clientnum,"You must specify the player to promote someone."); return; } if (msg.level <= 0 || msg.level > 9) { psserver->SendSystemError(clientnum,"You must specify a level between 1 and 9 to promote someone."); return; } psGuildMember *target = guild->FindMember(msg.player); if (!target) { psserver->SendSystemError(clientnum,"Player %s is not a member of your guild.",(const char *)msg.player); return; } if (target->guildlevel->level == MAX_GUILD_LEVEL) { psserver->SendSystemError(clientnum,"You can't just put leader to lower level. You must promote someone else to his place."); return; } if ( ! IsLeader(client)) { if ( ! CheckClientRights(client, RIGHTS_PROMOTE, "You do not have the rights in your guild to promote someone.")) return; if (GetClientLevel(client) <= target->guildlevel->level) { psserver->SendSystemError(clientnum,"You can't promote players of higher or equal level.",(const char *)msg.player); return; } if (GetClientLevel(client) <= msg.level) { psserver->SendSystemError(clientnum,"You can't promote players to higher or equal level.",(const char *)msg.player); return; } } if (!guild->UpdateMemberLevel(target,msg.level)) { psserver->SendSystemError(clientnum,"SQL Error: %s",db->GetLastError()); return; } // If we just promoted someone to highest level, we must also demote the current leader // (i.e. the player who did this action). if (msg.level == MAX_GUILD_LEVEL) { psGuildMember *clientMembership = guild->FindMember(client->GetPlayerID()); if (!clientMembership) { psserver->SendSystemError(clientnum,"Internal error: membership of player not found."); return; } if (!guild->UpdateMemberLevel(clientMembership, MAX_GUILD_LEVEL-1)) { psserver->SendSystemError(clientnum,"SQL Error: %s",db->GetLastError()); return; } } psserver->SendSystemInfo(clientnum,"Promotion successful."); csString text; text.Format("%s has been promoted to '%s'", (const char *)msg.player, target->guildlevel->title.GetData() ); psChatMessage guildmsg(clientnum,"System",text,CHAT_GUILD, false); if (guildmsg.valid) chatserver->SendGuild(client->GetCharacterData()->GetCharName(), guild, guildmsg); SendNotifications(guild->id, psGUIGuildMessage::MEMBER_DATA); } /** Sends list of guild members of given level as text messages to client */ void ListMembersOfLevel(psGuildInfo * guild, int clientnum, int level) { psGuildMember * member; for (size_t i=0; i < guild->members.Length(); i++) { member = guild->members[i]; if (member->guildlevel->level == level) psserver->SendSystemInfo(clientnum,"%s: %s", member->name.GetData(), member->guildlevel->title.GetData() ); } } void GuildManager::ListMembers(psGuildCmdMessage& msg,Client *client) { int clientnum = client->GetClientNum(); psGuildInfo *guild = client->GetActor()->GetGuild(); if (guild == NULL) { psserver->SendSystemError(clientnum,"You are not in a guild."); return; } if (!msg.level) for (int i=9; i>0; i--) ListMembersOfLevel(guild, clientnum, i); else ListMembersOfLevel(guild, clientnum, msg.level); } void GuildManager::Secret(psGuildCmdMessage &msg, Client *client) { int clientnum = client->GetClientNum(); psGuildInfo *guild = client->GetActor()->GetGuild(); if (!guild) { psserver->SendSystemError(clientnum, "You are not in a guild."); return; } // If the player doesn't provide an argument, just report the current // status of the secrecy flag. if (msg.secret == "") { psserver->SendSystemInfo(clientnum, "Your guild's secrecy setting is: %s", (client->GetActor()->GetGuild()->IsSecret() ? "ON" : "OFF")); return; } if ( ! IsLeader(client)) if ( ! CheckClientRights(client, RIGHTS_EDIT_GUILD, "You do not have rights to change secrecy of your guild.")) return; // Change the argument to lowercase to get a case-insensitive match. msg.secret.Downcase(); // Check for invalid arguments. if (msg.secret != "on" && msg.secret != "off") { psserver->SendSystemError(clientnum, "Unrecognized /guildsecret argument \"%s\". Choose \"on\" or \"off\".", msg.secret.GetData()); return; } bool new_secrecy_value = (msg.secret == "on"); // Only update the database if the value is really being changed. if (new_secrecy_value != guild->IsSecret() ) { if (!guild->SetSecret(new_secrecy_value)) { psserver->SendSystemError(clientnum, "SQL Error: %s", db->GetLastError()); return; } } // Report the new value to the player. psserver->SendSystemInfo(clientnum, "Your guild's secrecy setting is now: %s", (new_secrecy_value ? "ON" : "OFF")); SendNotifications(guild->id, psGUIGuildMessage::GUILD_DATA); // If secrecy is on send a message to all others clearing guild name // else send a message to all others to show the guild name. if ( new_secrecy_value == true ) { // Turn label off for everybody psUpdatePlayerGuildMessage update( clientnum, client->GetActor()->GetEntity()->GetID(), ""); psserver->GetEventManager()->Broadcast(update.msg,NetBase::BC_EVERYONE); // Update guild members with the label psUpdatePlayerGuildMessage update2( clientnum, client->GetActor()->GetEntity()->GetID(), guild->GetName() ); psserver->GetEventManager()->Broadcast(update2.msg,NetBase::BC_GUILD,guild->id); } else { // turn label on for everybody psUpdatePlayerGuildMessage update( clientnum, client->GetActor()->GetEntity()->GetID(), guild->GetName() ); psserver->GetEventManager()->Broadcast(update.msg,NetBase::BC_EVERYONE); } } void GuildManager::Web(psGuildCmdMessage &msg, Client *client) { int clientnum = client->GetClientNum(); psGuildInfo *guild = client->GetActor()->GetGuild(); if (!guild) { psserver->SendSystemError(clientnum,"You are not in a guild."); return; } if ( ! IsLeader(client)) if ( ! CheckClientRights(client, RIGHTS_EDIT_GUILD, "You do not have rights to change web page of your guild.")) return; if (!msg.web_page.Length()) { psserver->SendSystemError(clientnum,"You did not specify anything as your url."); return; } // Only update the database if the value is really being changed. if (msg.web_page != guild->web_page ) { if (!guild->SetWebPage(msg.web_page)) { psserver->SendSystemError(clientnum, "Setting of web page failed"); return; } } // Report the new value to the player. psserver->SendSystemInfo(clientnum, "Your guild's web page url is now: %s", guild->web_page.GetData()); SendNotifications(guild->id, psGUIGuildMessage::GUILD_DATA); } bool GuildManager::IsLeader(Client * client) { return GetClientLevel(client) == MAX_GUILD_LEVEL; } void GuildManager::MOTD(psGuildCmdMessage &msg, Client *client) { int clientnum = client->GetClientNum(); psGuildInfo *guild = client->GetActor()->GetGuild(); if (!guild) { psSystemMessage newmsg(clientnum,MSG_ERROR,"You are not in a guild."); newmsg.SendMessage(); return; } if (msg.motd == "") { psserver->SendSystemInfo(clientnum, "Guild Message Of The Day: %s", (client->GetActor()->GetGuild()->GetMOTD())); return; } if ( ! IsLeader(client)) if ( ! CheckClientRights(client, RIGHTS_EDIT_PUBLIC, "You do not have rights to change the message of the day in your guild.")) return; //All fine, let's change it already guild->SetMOTD(msg.motd); //Send notify to all guild members psSystemMessage newmsg(clientnum, MSG_INFO, "Guild message of the day updated"); psserver->GetEventManager()->Broadcast(newmsg.msg,NetBase::BC_GUILD,guild->id); SendNotifications(guild->id, psGUIGuildMessage::GUILD_DATA); } void GuildManager::GuildWar(psGuildCmdMessage &msg, Client *client) { int clientnum = client->GetClientNum(); // Check target dead gemObject *target = client->GetTargetObject(); if (!target) { psserver->SendSystemError(clientnum,"You don't have another player targeted."); return; } if (!target->IsAlive()) { psserver->SendSystemError(clientnum, "You can't challenge a dead person"); return; } Client * targetClient = psserver->GetNetManager()->GetClient(target->GetClientID()); if (!targetClient) { psserver->SendSystemError(clientnum, "You can challenge other players only"); return; } if (targetClient == client) { psserver->SendSystemError(clientnum,"You can't begin war with yourself.", targetClient->GetName()); return; } gemActor *wartarget = targetClient->GetActor(); // Check for pre-existing war with this person psGuildInfo *attackguild = GetClientGuild(client); if (attackguild == NULL) return; psGuildInfo *targetguild = wartarget->GetGuild(); if (!targetguild) { psserver->SendSystemError(clientnum, "This player is not in a guild"); return; } if (attackguild->FindLeader()->actor != client->GetActor()->GetCharacterData() ) { psserver->SendSystemError(clientnum, "You are not guild leader"); return; } // Check to see if it can find a leader. If no leader is found then the guild is in a bad // state and needs to be fixed by an admin. if ( targetguild->FindLeader() == NULL ) { psserver->SendSystemError(clientnum, "The guild %s has no leader. Please inform PlaneShift admins", targetguild->GetName().GetData() ); return; } if (targetguild->FindLeader()->actor != wartarget->GetCharacterData() ) { psserver->SendSystemError(clientnum, "This player is not guild leader"); return; } if (attackguild->IsGuildWarActive(targetguild)) { psserver->SendSystemError(clientnum,"You are already in a guild war with your target."); return; } // Challenge csString question; question.Format("%s has challenged your guild to a war! Click on Accept to allow the war or Reject to ignore it.", client->GetName() ); PendingGuildWarInvite *invite = new PendingGuildWarInvite(client, targetClient, question); psserver->questionmanager->SendQuestion(invite); } void GuildManager::AcceptWar(PendingGuildWarInvite *invite) { Client * inviteeClient = clients->Find(invite->clientnum); Client * inviterClient = clients->Find(invite->inviterClientNum); if (!inviteeClient || !inviterClient) return; psGuildInfo *attackguild = inviterClient->GetActor()->GetGuild(); psGuildInfo *targetguild = inviteeClient->GetActor()->GetGuild(); if (!attackguild || !targetguild) return; attackguild->AddGuildWar(targetguild); targetguild->AddGuildWar(attackguild); psSystemMessage sys(0,MSG_INFO,"%s and %s have started a guild war!", attackguild->GetName().GetData(), targetguild->GetName().GetData() ); psserver->GetEventManager()->Broadcast(sys.msg,NetBase::BC_GUILD,attackguild->id); psserver->GetEventManager()->Broadcast(sys.msg,NetBase::BC_GUILD,targetguild->id); } void PendingGuildWarInvite::HandleAnswer(const csString & answer) { Client * client = psserver->GetConnections()->Find(inviterClientNum); if (!client) return; psGuildInfo *attackguild = GetClientGuild(client); if (!attackguild) return; Client * targetClient = psserver->GetConnections()->Find(clientnum); if (!targetClient) return; psGuildInfo *targetguild = GetClientGuild(targetClient); if (!targetguild) return; if (attackguild->IsGuildWarActive(targetguild)) return; PendingInvite::HandleAnswer(answer); if (answer == "yes") psserver->guildmanager->AcceptWar(this); } void GuildManager::GuildYield(psGuildCmdMessage &msg, Client *client) { int clientnum = client->GetClientNum(); int winnerid = client->GetTargetClientID(); if (!winnerid) { psserver->SendSystemError(client->GetClientNum(),"You don't have another player targeted."); return; } psGuildInfo *loserguild = client->GetActor()->GetGuild(); if (!loserguild) { psserver->SendSystemError(clientnum, "You are not in a guild"); return; } if (loserguild->FindLeader()->actor != client->GetActor()->GetCharacterData() ) { psserver->SendSystemError(clientnum, "You are not guild leader"); return; } if ( client->GetTargetObject() == NULL ) { psserver->SendSystemError(clientnum, "You must target the leader of the guild."); return; } gemActor *target = client->GetTargetObject()->GetActorPtr(); if (!target) return; psGuildInfo *winnerguild = target->GetGuild(); if (!winnerguild) { psserver->SendSystemError(clientnum, "Your target is not in a guild"); return; } if (!loserguild->IsGuildWarActive(winnerguild)) { psserver->SendSystemError(clientnum,"You are not in a guild war with your target."); return; } // Remove the duel from both sides. loserguild->RemoveGuildWar(winnerguild); winnerguild->RemoveGuildWar(loserguild); // TODO: Stop all fights in progress. //client->GetActor()->SetMode(PSCHARACTER_MODE_PEACE); // Award guild karma points (33% of lower-ranked guild's points) float delta = loserguild->karma_points; if (winnerguild->karma_points < delta) delta = winnerguild->karma_points; delta /= 3; if (!(int)delta) delta=1; csString str; str.Format("%1.0f karma points from %s awarded to %s.", delta,loserguild->GetName().GetData(),winnerguild->GetName().GetData() ); CPrintf(CON_DEBUG, str); psSystemMessage sys(0,MSG_INFO,str); psserver->GetEventManager()->Broadcast(sys.msg,NetBase::BC_GUILD,loserguild->id); psserver->GetEventManager()->Broadcast(sys.msg,NetBase::BC_GUILD,winnerguild->id); loserguild->karma_points -= (int)delta; winnerguild->karma_points += (int)delta; if (delta) { db->Command("update guilds set karma_points=%1.0f where id=%d", loserguild->karma_points, loserguild->id); db->Command("update guilds set karma_points=%1.0f where id=%d", winnerguild->karma_points, winnerguild->id); } } /****************************************************************************** * * Handlers of alliance management network messages * ******************************************************************************/ class PendingAllianceInvite : public PendingInvite { public: int allianceID; PendingAllianceInvite(Client *inviter, Client *invitee, const char *question, int allianceID) : PendingInvite( inviter, invitee, true, question,"Accept","Decline", "You have asked %s to join your alliance.", "%s has invited you to join an alliance.", "%s has joined your alliance.", "You have joined the alliance.", "%s has declined your invitation.", "You have declined %s's invitation.", psQuestionMessage::generalConfirm) { this->allianceID = allianceID; } void HandleAnswer(const csString & answer) { Client * client = psserver->GetConnections()->Find(clientnum); if (!client) return; psGuildInfo * guild = GetClientGuild(client); if (!guild) return; if (guild->GetAllianceID() != 0) return; PendingInvite::HandleAnswer(answer); if (answer != "yes") return; Client * inviteeClient = psserver->GetConnections()->Find(clientnum); if (inviteeClient == NULL) return; psGuildInfo * inviteeGuild = GetClientGuild(inviteeClient); if (inviteeGuild == NULL) return; psGuildAlliance * alliance = CacheManager::GetSingleton().FindAlliance(allianceID); if (alliance == NULL) return; alliance->AddNewMember(inviteeGuild); psserver->GetGuildManager()->SendAllianceNotifications(alliance); } }; /** Does common checks needed for most alliance operations. * If one of the checks fails, then the user is sent text description of the problem. * * Parameter 'checkLeaderGuild' says if we should check that player's guild is leader in the alliance. * * This function also returns pointers to player's guild and alliance as a secondary product. */ bool GuildManager::CheckAllianceOperation(Client * client, bool checkLeaderGuild, psGuildInfo * & guild, psGuildAlliance * & alliance) { int clientnum = client->GetClientNum(); guild = NULL; alliance = NULL; guild = GetClientGuild(client); if (guild == NULL) return false; if (guild->alliance == 0) { psserver->SendSystemError(clientnum,"You guild is not in an alliance."); return false; } if (GetClientLevel(client) != MAX_GUILD_LEVEL) { psserver->SendSystemError(clientnum,"You are not guild leader."); return false; } alliance = CacheManager::GetSingleton().FindAlliance(guild->alliance); if (alliance == NULL) { psserver->SendSystemError(clientnum,"Internal error - alliance %d not found.", guild->alliance); return false; } if (checkLeaderGuild && alliance->GetLeader() != guild) { psserver->SendSystemError(clientnum,"Your guild is not alliance leader."); return false; } return true; } void GuildManager::NewAlliance(psGuildCmdMessage &msg, Client *client) { int clientnum = client->GetClientNum(); psGuildInfo * guild = GetClientGuild(client); if (guild == NULL) return; if (GetClientLevel(client) != MAX_GUILD_LEVEL) { psserver->SendSystemError(clientnum,"You are not guild leader."); return; } if (guild->alliance != 0) { psserver->SendSystemError(clientnum,"Your guild is already member of an alliance."); return; } if (msg.alliancename.Length()==0) { psserver->SendSystemError(clientnum,"Please specify name of the alliance."); return; } if (CacheManager::GetSingleton().CreateAlliance(msg.alliancename, guild, client)) psserver->SendSystemInfo(clientnum, "Alliance \"%s\" was created.", msg.alliancename.GetData()); else psserver->SendSystemInfo(clientnum, "Alliance creation failed: %s", psGuildAlliance::lastError.GetData()); psGuildAlliance * alliance = CacheManager::GetSingleton().FindAlliance(guild->alliance); if (alliance != NULL) SendAllianceNotifications(alliance); } void GuildManager::AllianceInvite(psGuildCmdMessage &msg, Client *client) { psGuildInfo * guild; psGuildAlliance * alliance; csString inviteeName; int clientnum = client->GetClientNum(); if ( ! CheckAllianceOperation(client, true, guild, alliance)) return; if (msg.player.Length()==0) { psserver->SendSystemError(clientnum,"Please specify name of guild leader to be invited."); return; } inviteeName = NormalizeCharacterName(msg.player); Client * inviteeClient = clients->Find(inviteeName); if (inviteeClient == NULL) { psserver->SendSystemError(clientnum,"\"%s\" is not online right now.", inviteeName.GetData()); return; } if (inviteeClient == client) { psserver->SendSystemError(clientnum,"You can't invite yourself.", inviteeName.GetData()); return; } psGuildInfo * inviteeGuild = GetClientGuild(inviteeClient); if (inviteeGuild == NULL) { psserver->SendSystemError(clientnum,"Player \"%s\" is not member of any guild.", inviteeName.GetData()); return; } if (alliance->CheckMembership(inviteeGuild)) { psserver->SendSystemError(clientnum,"They are already members of your alliance."); return; } if (inviteeGuild->GetAllianceID() != 0) { psserver->SendSystemError(clientnum,"%s is already a member of an alliance.", inviteeName.GetData()); return; } if (GetClientLevel(inviteeClient) != MAX_GUILD_LEVEL) { psserver->SendSystemError(clientnum,"Player \"%s\" is not guild leader.", inviteeName.GetData()); return; } csString invitation; invitation.Format("You have been invited to join the %s alliance. Click Accept to join this alliance.",alliance->GetName().GetData() ); PendingAllianceInvite *pnew = new PendingAllianceInvite(client, inviteeClient, invitation, alliance->GetID()); psserver->questionmanager->SendQuestion(pnew); } void GuildManager::AllianceRemove(psGuildCmdMessage &msg, Client *client) { psGuildInfo * guild; psGuildAlliance * alliance; int clientnum = client->GetClientNum(); if ( ! CheckAllianceOperation(client, false, guild, alliance)) return; if (msg.guildname.Length()==0) { psserver->SendSystemError(clientnum,"Please specify name of the guild to be removed from alliance."); return; } psGuildInfo * removedGuild = CacheManager::GetSingleton().FindGuild(msg.guildname); if (removedGuild == NULL) { psserver->SendSystemError(clientnum,"No such guild exists."); return; } RemoveMemberFromAlliance(client, guild, alliance, removedGuild); } void GuildManager::AllianceLeave(psGuildCmdMessage &msg, Client *client) { psGuildInfo * guild; psGuildAlliance * alliance; if ( ! CheckAllianceOperation(client, false, guild, alliance)) return; RemoveMemberFromAlliance(client, guild, alliance, guild); } void GuildManager::RemoveMemberFromAlliance(Client * client, psGuildInfo * guild, psGuildAlliance * alliance, psGuildInfo * removedGuild) { int clientnum = client->GetClientNum(); if (removedGuild == alliance->GetLeader()) { psserver->SendSystemError(clientnum,"Alliance leader cannot leave. Choose another leader first."); return; } // if one guild removes another one (and not just itself), it must be alliance leader if (guild != removedGuild) if (alliance->GetLeader() != guild) { psserver->SendSystemError(clientnum,"Your guild must be alliance leader to be able to remove other guilds."); return; } if (alliance->RemoveMember(removedGuild)) psserver->SendSystemInfo(clientnum,"Guild \"%s\" was removed from alliance.", removedGuild->name.GetData()); else psserver->SendSystemInfo(clientnum,"Failed to remove guild from alliance: %s", psGuildAlliance::lastError.GetData()); SendNoAllianceNotifications(removedGuild); SendAllianceNotifications(alliance); } void GuildManager::AllianceLeader(psGuildCmdMessage &msg, Client *client) { psGuildInfo * guild; psGuildAlliance * alliance; int clientnum = client->GetClientNum(); if ( ! CheckAllianceOperation(client, true, guild, alliance)) return; if (msg.guildname.Length()==0) { psserver->SendSystemError(clientnum,"Please specify name of the guild to be new alliance leader."); return; } psGuildInfo * newLeader = CacheManager::GetSingleton().FindGuild(msg.guildname); if (newLeader == NULL) { psserver->SendSystemError(clientnum,"No such guild exists."); return; } if (guild == newLeader) { psserver->SendSystemError(clientnum,"You must specify other guild than your own."); return; } if ( ! alliance->CheckMembership(newLeader)) { psserver->SendSystemError(clientnum,"This guild is not member of your alliance !"); return; } if (alliance->SetLeader(newLeader)) psserver->SendSystemInfo(clientnum,"Alliance leadership was transfered to %s.", newLeader->name.GetData()); else psserver->SendSystemInfo(clientnum,"Failed to transfer alliance leadership: %s.", psGuildAlliance::lastError.GetData()); SendAllianceNotifications(alliance); } void GuildManager::EndAlliance(psGuildCmdMessage &msg, Client *client) { psGuildInfo * guild; psGuildAlliance * alliance; int clientnum = client->GetClientNum(); if ( ! CheckAllianceOperation(client, true, guild, alliance)) return; SendNoAllianceNotifications(alliance); if (CacheManager::GetSingleton().RemoveAlliance(alliance)) psserver->SendSystemInfo(clientnum,"Alliance was disbanded."); else psserver->SendSystemInfo(clientnum,"Failed to disband alliance: %s.", psGuildAlliance::lastError.GetData()); } bool GuildManager::FilterGuildName(const char* name) { if (name == NULL) return false; size_t len = strlen(name); if ( (strspn(name,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ") != len) ) return false; if ((strspn(((const char*)name)+1, (const char*)"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ") != len - 1)) return false; return true; } void GuildManager::SendGuildPoints(psGuildCmdMessage& msg,Client *client) { psGuildInfo* guild = NULL; if(msg.guildname.Length() == 0) guild = CacheManager::GetSingleton().FindGuild(client->GetGuildID()); else guild = CacheManager::GetSingleton().FindGuild(msg.guildname); if(!guild) { csString error; error = "Couldn't find the guild " + msg.guildname; error += "you specified"; psserver->SendSystemError(client->GetClientNum(),error); return; } csString info; info.Format("The guild %s has %d karma points",guild->GetName().GetData(),guild->karma_points); psserver->SendSystemInfo(client->GetClientNum(),info); } void GuildManager::ResendGuildData(int id) { SendNotifications(id, psGUIGuildMessage::GUILD_DATA); }