#include "common.h" #include "PseuWoW.h" #include #include "Channel.h" enum NotifyTypes { JOINED = 0x00, LEFT = 0x01, YOUJOINED = 0x02, YOULEFT = 0x03, WRONGPASS = 0x04, NOTON1 = 0x05, // Not on channel channel name. NOTMOD = 0x06, SETPASS = 0x07, CHANGEOWNER = 0x08, NOTON2 = 0x09, // Player %s is not on channel. NOTOWNER = 0x0A, WHOOWNER = 0x0B, MODECHANGE = 0x0C, ANNOUNCEON = 0x0D, ANNOUNCEOFF = 0x0E, MODERATED = 0x0F, UNMODERATED = 0x10, YOUCANTSPEAK = 0x11, KICKED = 0x12, YOUAREBANNED = 0x13, BANNED = 0x14, UNBANNED = 0x15, UNKNOWN1 = 0x16, // is not banned ALREADYON = 0x17, INVITED = 0x18, WRONGALLIANCE = 0x19, // target is in the wrong alliance for channel name UNKNOWN2 = 0x1A, // wrong alliance for channel name UNKNOWN3 = 0x1B, // invalid channel name ISNOTMODERATED = 0x1C, YOUINVITED = 0x1D, UNKNOWN4 = 0x1E, // %s has been banned. UNKNOWN5 = 0x1F, // The number of messages that can be sent to this channel is limited, please wait to send another message. UNKNOWN6 = 0x20 // You are in not the correct area for this channel. }; enum ChannelFlags { CHANNEL_FLAG_CUSTOM = 0x01, // 0x02 CHANNEL_FLAG_TRADE = 0x04, CHANNEL_FLAG_NOT_LFG = 0x08, CHANNEL_FLAG_GENERAL = 0x10, CHANNEL_FLAG_CITY = 0x20, CHANNEL_FLAG_LFG = 0x40, CHANNEL_FLAG_VOICE = 0x80 // General 0x18 = 0x10 | 0x08 // Trade 0x3C = 0x20 | 0x10 | 0x08 | 0x04 // LocalDefence 0x18 = 0x10 | 0x08 // GuildRecruitment 0x38 = 0x20 | 0x10 | 0x08 // LookingForGroup 0x50 = 0x40 | 0x10 }; enum ChannelMemberFlags { MEMBER_FLAG_NONE = 0x00, MEMBER_FLAG_OWNER = 0x01, MEMBER_FLAG_MODERATOR = 0x02, MEMBER_FLAG_VOICED = 0x04, MEMBER_FLAG_MUTED = 0x08, MEMBER_FLAG_CUSTOM = 0x10, MEMBER_FLAG_MIC_MUTED = 0x20, // 0x40 // 0x80 }; typedef std::map ChannelPlayerList; void Channel::Join(std::string channel, std::string password) { if (IsOnChannel(channel)) return; // Send join channel request WorldPacket worldPacket; worldPacket.SetOpcode(CMSG_JOIN_CHANNEL); worldPacket << (uint32)0; // new since 2.0.x, some channel ID? server answers us with that number later if channel joined worldPacket << (uint8)0; // unk worldPacket << (uint8)0; // unk, new since 2.2.x worldPacket << channel << password; _worldSession->SendWorldPacket(worldPacket); } void Channel::Leave(std::string channel) { for(std::vector::iterator i = channels.begin(); i != channels.end(); i++) { if (*i == channel) { // Send leave channel request WorldPacket worldPacket; worldPacket.SetOpcode(CMSG_LEAVE_CHANNEL); worldPacket << (uint32)0; // new since 2.0.x, maybe channel id worldPacket << channel; _worldSession->SendWorldPacket(worldPacket); return; } } log("Can't leave channel \"%s\": not joined",channel.c_str()); } void Channel::Say(std::string channel, std::string text, uint32 lang) { _worldSession->SendChatMessage(CHAT_MSG_CHANNEL, lang, text, channel); } bool Channel::IsOnChannel(std::string channel) { for(std::vector::iterator i = channels.begin(); i != channels.end(); i++) { if (*i == channel) { return true; } } return false; } void Channel::HandleNotifyOpcode(WorldPacket &packet) { uint8 code; uint64 guid; std::string channel, name; packet >> code >> channel; switch (code) { // Player joined channel you are on case JOINED: packet >> guid; if(guid) { name = _worldSession->GetOrRequestPlayerName(guid); if (name.empty()) { _worldSession->_DelayWorldPacket(packet,_worldSession->GetLagMS() * 1.2f); return; } } log("%s joined channel %s",name.c_str(),channel.c_str()); break; // Player leaved channel you are on case LEFT: packet >> guid; if(guid) { name = _worldSession->GetOrRequestPlayerName(guid); if (name.empty()) { _worldSession->_DelayWorldPacket(packet,_worldSession->GetLagMS() * 1.2f); return; } } log("%s left channel %s", name.c_str(), channel.c_str()); break; // You joined channel successfully case YOUJOINED: log("Joined channel %s", channel.c_str()); channels.push_back(channel); break; // You leaved channel successfully case YOULEFT: for(std::vector::iterator i = channels.begin(); i != channels.end(); i++) { if(*i == channel) { channels.erase(i); break; } } log("Left channel %s", channel.c_str()); break; // Wrong password while trying to join channel case WRONGPASS: log("Could not join channel %s (Wrong password)", channel.c_str()); break; // Not on channel while trying to write to channel etc. case NOTON1: log("You are not on channel %s", channel.c_str()); break; } // TODO: Even more channel notices to handle /* printf("Channel notice not handled! Code: %d - Channel name: %s\nData:\n", code, channel.c_str()); packet.textlike(); printf("\n"); */ } void Channel::RequestList(std::string ch) { if(!IsOnChannel(ch)) logdebug("Requesting list of not joined channel '%s'",ch.c_str()); WorldPacket wp; wp.SetOpcode(CMSG_CHANNEL_LIST); wp << ch; _worldSession->SendWorldPacket(wp); } void Channel::HandleListRequest(WorldPacket& recvPacket) { ChannelPlayerList cpl; uint8 unk; uint32 size; uint64 guid; uint8 mode, flags; // mode: player flags; flags: channel flags std::string name; recvPacket >> unk >> name >> flags >> size; for(uint32 i = 0; i < size; i++) { recvPacket >> guid >> mode; // all player names in this packet must be known before if(_worldSession->GetOrRequestPlayerName(guid).empty()) { _worldSession->_DelayWorldPacket(recvPacket, _worldSession->GetLagMS() * 1.2f); return; } cpl[guid] = mode; } // store list of GUIDs in: @ChannelList - see below DefList *l = _worldSession->GetInstance()->GetScripts()->lists.Get("@ChannelList"); l->clear(); std::string pname; bool muted,mod; logcustom(0,WHITE,"Player channel list, %u players:",size); for(ChannelPlayerList::iterator i = cpl.begin(); i != cpl.end(); i++) { pname = _worldSession->GetOrRequestPlayerName(i->first); // all names should be known now mode = i->second; if(pname.empty()) pname = ""; muted = mode & MEMBER_FLAG_MUTED; mod = mode & MEMBER_FLAG_MODERATOR; while(pname.length()<12) pname += " "; // for better formatting logcustom(0,WHITE,"%s ["I64FMT"] %s %s",pname.c_str(),i->first,muted?"(muted)":"",mod?"(moderator)":""); // DefScript binding l->push_back(DefScriptTools::toString(guid)); } }