Exemple #1
0
User& Battle::OnUserAdded( User& user )
{
		user = IBattle::OnUserAdded( user );
		if ( &user == &GetMe() )
		{
			 m_timer = new wxTimer(this,TIMER_ID);
			 m_timer->Start( TIMER_INTERVAL );
		}
    user.SetBattle( this );
    user.BattleStatus().isfromdemo = false;

    if ( IsFounderMe() )
    {
        if ( CheckBan( user ) ) return user;

        if ( ( &user != &GetMe() ) && !user.BattleStatus().IsBot() && ( m_opts.rankneeded > UserStatus::RANK_1 ) && ( user.GetStatus().rank < m_opts.rankneeded ))
        {
					DoAction( _T("Rank limit autospec: ") + user.GetNick() );
					ForceSpectator( user, true );
        }

        m_ah.OnUserAdded( user );
        if ( !user.BattleStatus().IsBot() && sett().GetBattleLastAutoAnnounceDescription() ) DoAction( m_opts.description );
    }
    // any code here may be skipped if the user was autokicked
    return user;
}
Exemple #2
0
User& IBattle::OnUserAdded( User& user )
{
	UserList::AddUser( user );
	UserBattleStatus& bs = user.BattleStatus();
	bs.spectator = false;
	bs.ready = false;
	bs.sync = SYNC_UNKNOWN;
	if ( !bs.IsBot() && IsFounderMe() && GetBattleType() == BT_Played ) {
		bs.team = GetFreeTeam( &user == &GetMe() );
		bs.ally = GetFreeAlly( &user == &GetMe() );
		bs.colour = GetFreeColour( user );
	}
	if ( IsFounderMe() && ( ( bs.pos.x < 0 ) || ( bs.pos.y < 0 ) ) ) {
		UserPosition& pos = bs.pos;
		pos = GetFreePosition();
		UserPositionChanged( user );
	}
	if ( !bs.spectator ) {
		PlayerJoinedAlly( bs.ally );
		PlayerJoinedTeam( bs.team );
	}
	if ( bs.spectator && IsFounderMe() ) m_opts.spectators++;
	if ( !bs.spectator && !bs.IsBot() ) {
		if ( bs.ready ) m_players_ready++;
		if ( bs.sync) m_players_sync++;
		if ( !bs.ready || !bs.sync ) m_ready_up_map[user.GetNick()] = time(0);
		if ( bs.ready && bs.sync ) m_players_ok++;
	}
	return user;
}
Exemple #3
0
void Battle::FixColours()
{
    if ( !IsFounderMe() )return;
    std::vector<wxColour> &palette = GetFixColoursPalette( m_teams_sizes.size() + 1 );
    std::vector<int> palette_use( palette.size(), 0 );

    wxColour my_col = GetMe().BattleStatus().colour; // Never changes color of founder (me) :-)
    int my_diff = 0;
    int my_col_i = GetClosestFixColour( my_col, palette_use,my_diff );
    palette_use[my_col_i]++;
    std::set<int> parsed_teams;

    for ( user_map_t::size_type i = 0; i < GetNumUsers(); i++ )
    {
        User &user=GetUser(i);
        if ( &user == &GetMe() ) continue; // skip founder ( yourself )
        UserBattleStatus& status = user.BattleStatus();
        if ( status.spectator ) continue;
        if ( parsed_teams.find( status.team ) != parsed_teams.end() ) continue; // skip duplicates
        parsed_teams.insert( status.team );

        wxColour &user_col=status.colour;
        int user_col_i=GetClosestFixColour(user_col,palette_use, 60);
        palette_use[user_col_i]++;
				for ( user_map_t::size_type j = 0; j < GetNumUsers(); j++ )
				{
					User &usr=GetUser(j);
					if ( usr.BattleStatus().team == status.team )
					{
						 ForceColour( usr, palette[user_col_i]);
					}
				}
    }
}
Exemple #4
0
bool CNetManager::close_server(Game_Logic::Game_Interface& gm_interface)
{
    CCLOG("CNetManager::close_server");
    GetMe()->Release();
    GetMe()->connect_state_ = 0;
    GetMe()->show_ = false;
    return true;
}
void Battle::ShouldAutoUnspec()
{
	if ( m_auto_unspec && !IsLocked() && GetMe().BattleStatus().spectator )
	{
		if ( GetNumActivePlayers() < m_opts.maxplayers )
		{
			ForceSpectator(GetMe(),false);
		}
	}
}
void Battle::OnUserBattleStatusUpdated( User &user, UserBattleStatus status )
{
    if ( IsFounderMe() )
    {
			if ( ( &user != &GetMe() ) && !status.IsBot() && ( m_opts.rankneeded != UserStatus::RANK_1 ) && !status.spectator )
			{
				if ( m_opts.rankneeded > UserStatus::RANK_1 && user.GetStatus().rank < m_opts.rankneeded )
				{
					DoAction( _T("Rank limit autospec: ") + user.GetNick() );
					ForceSpectator( user, true );
				}
				else if ( m_opts.rankneeded < UserStatus::RANK_1 && user.GetStatus().rank > ( -m_opts.rankneeded - 1 ) )
				{
					DoAction( _T("Rank limit autospec: ") + user.GetNick() );
					ForceSpectator( user, true );
				}
			}
			UserBattleStatus previousstatus = user.BattleStatus();
			if ( m_opts.lockexternalbalancechanges )
			{
				if ( previousstatus.team != status.team )
				{
					 ForceTeam( user, previousstatus.team );
					 status.team = previousstatus.team;
				}
				if ( previousstatus.ally != status.ally )
				{
					ForceAlly( user, previousstatus.ally );
					status.ally = previousstatus.ally;
				}
			}
    }
		IBattle::OnUserBattleStatusUpdated( user, status );
    if ( status.handicap != 0 )
    {
		UiEvents::GetUiEventSender( UiEvents::OnBattleActionEvent ).SendEvent(
				UiEvents::OnBattleActionData( wxString(_T(" ")) , ( _T("Warning: user ") + user.GetNick() + _T(" got bonus ") ) << status.handicap )
			);
    }
		if ( IsFounderMe() )
		{
			if ( ShouldAutoStart() )
			{
				if ( sett().GetBattleLastAutoStartState() )
				{
					if ( !spring().IsRunning() ) StartHostedBattle();
				}
			}
		}
	if ( !GetMe().BattleStatus().spectator ) SetAutoUnspec(false); // we don't need auto unspec anymore
	ShouldAutoUnspec();
#ifndef SL_QT_MODE
	ui().OnUserBattleStatus( *this, user );
#endif
}
Exemple #7
0
void Battle::StartSpring()
{
	if ( UserExists( GetMe().GetNick() ) && !GetMe().Status().in_game )
	{
		GetMe().BattleStatus().ready = false;
		SendMyBattleStatus();
		GetMe().Status().in_game = spring().Run( *this );
		GetMe().SendMyUserStatus();
	}
	ui().OnBattleStarted( *this );
}
Exemple #8
0
bool CNetManager::connetect_to_game_server(Game_Logic::Game_Interface& gm_interface)
{
	CCLog("---------------------CNetManager::connetect_to_game_server11111111111");
   GetMe()->Initial(NULL);
    vector<uint64> para;
    gm_interface.get_para(para);
    if( para.size() <= 0 )
        return false;
    int port = (int)para[0];
	CCLog("---------------------CNetManager::connetect_to_game_server2222222222222222222");
    string ip = gm_interface.get_keyword();
	return 0 == GetMe()->real_connect(ip.data(), port) ? true : false;
}
Exemple #9
0
void Battle::StartSpring()
{
	if ( UserExists( GetMe().GetNick() ) && !GetMe().Status().in_game )
	{
		GetMe().BattleStatus().ready = false;
		SendMyBattleStatus();
		// set m_generating_script, this will make the script.txt writer realize we're just clients even if using a relayhost
		m_generating_script = true;
		GetMe().Status().in_game = spring().Run( *this );
		m_generating_script = false;
		GetMe().SendMyUserStatus();
	}
	ui().OnBattleStarted( *this );
}
VOID CActionSystem::QuestLogItem_Update(VOID)
{
	GetMe()->CleanInvalidAction();
	_MISSION_INFO* misInfo = NULL;
	
	//创建新的物品
	for(INT i=0; i < MAX_CHAR_MISSION_NUM; i++)
	{
		const _OWN_MISSION * OwnMission = CUIDataPool::GetMe()->GetMySelfDetailAttrib()->GetMission(i);

		if(!OwnMission)	continue;

		INT scriptId = OwnMission->m_idScript;

		misInfo = &(GetMissionInfo(scriptId));
		if((!misInfo) || (!misInfo->m_bFill)) continue;
		INT max = (INT)misInfo->m_vecQuestRewardItem.size();
		for(INT j=0; j< max; j++)
		{			
			//取得物品
			_MISSION_INFO::QuestRewardItem misItem = misInfo->m_vecQuestRewardItem[j];
			if(		misItem.pItemData->m_nType == MISSION_BONUS_TYPE_ITEM 
				||	misItem.pItemData->m_nType == MISSION_BONUS_TYPE_ITEM_RAND
				||	misItem.pItemData->m_nType == MISSION_BONUS_TYPE_ITEM_RADIO )
			{
				tObject_Item* pItem = misItem.pItemImpl;
				if(!pItem) continue;
				UpdateAction_FromItem(pItem);
			}
		}
	}
	return;
}
Exemple #11
0
bool CNetManager::connetect_to_gate(Game_Logic::Game_Interface& gm_interface)
{
    GetMe()->Initial(NULL);
    vector<uint64> para;
    gm_interface.get_para(para);
    if( para.size() <= 0 )
        return false;
    int port = (int)para[0];

    string ip = gm_interface.get_keyword();

    //CCLOG("connect to gate %s  %d", ip.data(), port);

    return 0 == GetMe()->real_connect(ip.data(), port) ? true : false;
   
}
Exemple #12
0
void Battle::ShouldAutoUnspec()
{
	if ( m_auto_unspec && !IsLocked() && GetMe().BattleStatus().spectator )
	{
		unsigned int numplayers = 0;
		std::map<int, int> allysizes = GetAllySizes();
		for ( std::map<int, int>::const_iterator itor = allysizes.begin(); itor != allysizes.end(); ++itor )
		{
			numplayers += itor->second;
		}
		if ( numplayers < m_auto_unspec_num_players )
		{
			ForceSpectator(GetMe(),false);
		}
	}
}
Exemple #13
0
		void TeleportTo(Vector3* position)
		{
			IPlayer* me = GetMe();
			if (!me) return;

			Player* playerMe = me->GetPlayer();
			if (!playerMe) return;

			IActor* actorMe = me->vfptr->GetActorInterface(me);
			if (!actorMe) return;

			IUE4Actor* ue4actor = playerMe->baseclass_0.m_target;
			if (!ue4actor) return;

			World* GameWorld = GetWorldObject();
			if (!GameWorld) return;

			//auto const logMsg = boost::str(boost::format("TeleportTo(%.2f,%.2f,%.2f)")
			//	% position->x % position->y % position->z);
			//Chat(logMsg);

			Rotation rot{ 0, 0, 0 };
			ue4actor->vfptr->GetRotation(ue4actor, &rot);
			GameWorld->vfptr->SendRespawnEvent(GameWorld, me->GetPlayer(), position, &rot);
			ue4actor->vfptr->LocalRespawn(ue4actor, position, &rot);
		}
Exemple #14
0
void IBattle::OnSelfLeftBattle()
{
	GetMe().BattleStatus().spectator = false; // always reset back yourself to player when rejoining
	if ( m_timer ) m_timer->Stop();
	delete m_timer;
	m_timer = 0;
    m_is_self_in = false;
	for( size_t j = 0; j < GetNumUsers(); ++j  )
	{
		User& u = GetUser( j );
		if ( u.GetBattleStatus().IsBot() )
		{
			OnUserRemoved( u );
			ui().OnUserLeftBattle( *this, u, true );
			j--;
		}
	}
    ClearStartRects();
    m_teams_sizes.clear();
    m_ally_sizes.clear();
    m_players_ready = 0;
    m_players_sync = 0;
	m_players_ok = 0;
	usync().UnSetCurrentMod(); //left battle
}
VOID CActionSystem::UserBag_Update(VOID)
{
	//清空已经不存在的Action
	GetMe()->CleanInvalidAction();

	for(INT i=0; i<MAX_BAG_SIZE; i++)
	{
		//取得物品
		tObject_Item*	pItem = CDataPool::GetMe()->UserBag_GetItem(i);
		if(pItem)
		{
			//设置新的物品数据
			GetMe()->UpdateAction_FromItem(pItem);
		}
	}
}
Exemple #16
0
void IBattle::OnUserRemoved( User& user )
{
	UserBattleStatus& bs = user.BattleStatus();
	if ( !bs.spectator ) {
		PlayerLeftTeam( bs.team );
		PlayerLeftAlly( bs.ally );
	}
	if ( !bs.spectator && !bs.IsBot() ) {
		if ( bs.ready ) m_players_ready--;
		if ( bs.sync ) m_players_sync--;
		if ( bs.ready && bs.sync ) m_players_ok--;
	}
	if ( IsFounderMe() && bs.spectator ) {
		m_opts.spectators--;
		SendHostInfo( HI_Spectators );
	}
	if ( &user == &GetMe() ) {
		OnSelfLeftBattle();
	}
	UserList::RemoveUser( user.GetNick() );
	if ( !bs.IsBot() )
		user.SetBattle( 0 );
	else {
		UserVecIter itor = m_internal_bot_list.find( user.GetNick());
		if ( itor != m_internal_bot_list.end() ) {
			m_internal_bot_list.erase( itor );
		}
	}
}
// 通过数据池中的数据, 创建出来装备action item
VOID CActionSystem::OtherPlayerEquip_Update(VOID)
{
	//清空已经不存在的Action
	GetMe()->CleanInvalidAction();

	// 装备点的最大个数.
	for(INT i=0; i<HEQUIP_NUMBER; i++)
	{
		//取得玩家身上的装备
		tObject_Item*	pItem = CDataPool::GetMe()->OtherPlayerEquip_GetItem((HUMAN_EQUIP)i);
		if(pItem)
		{
			//创建新的装备的action item
			GetMe()->UpdateAction_FromItem(pItem);
		}
	}
}
VOID CActionSystem::CleanInvalidAction(BOOL bForceCleanItemBox)
{
	register std::map< INT, CActionItem* >::iterator it;
	for(it=GetMe()->m_mapAllAction.begin(); it!=GetMe()->m_mapAllAction.end();)
	{
		std::map< INT, CActionItem* >::iterator itNext = it;
		itNext++;

		CActionItem* pActionItem = it->second;
		VOID* pImpl = pActionItem->GetImpl();
		if(!pImpl) 
		{
			//销毁
			EraseActionItem(it->second);
		}

		it = itNext;
	}
}
VOID CActionSystem::_OnSkillActive(const EVENT* pEvent, UINT dwOwnerData)
{
	//取得技能id
	INT idSkill = atoi(pEvent->vArg[0].c_str());
	//技能Action
	CActionItem_Skill* pSkillItem = (CActionItem_Skill*)GetMe()->GetAction(idSkill);
	if(!pSkillItem) return;

	//检查是否是能够自动进行的技能
	pSkillItem->AutoKeepOn();
}
Exemple #20
0
void Battle::OnRequestBattleStatus()
{
    UserBattleStatus& bs = m_serv.GetMe().BattleStatus();
    bs.team = GetFreeTeam( true );
    bs.ally = GetFreeAlly( true );
    bs.spectator = false;
    bs.colour = sett().GetBattleLastColour();
    // theres some highly annoying bug with color changes on player join/leave.
    if ( !bs.colour.IsOk() ) bs.colour = GetFreeColour( GetMe() );

    SendMyBattleStatus();
}
Exemple #21
0
//! @brief Output a message said in the channel.
//!
//! @param who nick of the person who said something.
//! @param message the message to be outputted.
void ChatPanel::Said( const wxString& who, const wxString& message )
{
	wxString me = GetMe().GetNick();
	wxColour col;
	bool req_user = false;
	if ( who.Upper() == me.Upper() )
  {
		col = sett().GetChatColorMine();
	} else
	{
    // change the image of the tab to show new events
    SetIconHighlight( highlight_say );
    if ( m_type == CPT_User ) req_user = true;
    //process logic for custom word highlights
    if ( ContainsWordToHighlight( message ) )
    {
        req_user = sett().GetRequestAttOnHighlight();
        col = sett().GetChatColorHighlight();
    }
    else
        col = sett().GetChatColorNormal();
  }

	if ( ( who == _T( "MelBot" ) || who == _T( "[BOT]tizbacbridgebot" ) )
            && message.StartsWith( _T( "<" ) ) && message.Find( _T( ">" ) ) != wxNOT_FOUND )
    {
		wxString who2;
		wxString message2;
		who2 = message.BeforeFirst( '>' ).AfterFirst( '<' );
		if ( who != _T( "[BOT]tizbacbridgebot" ) ) who2 += _T( "@IRC" );
		//don't highlight if i'm talking from irc to channel
		if ( who2.Upper().BeforeLast(_T('@')) == me.Upper() )
		{
		    req_user = false;
		    col = sett().GetChatColorNormal();
		}
		message2 = message.AfterFirst( '>' );
		OutputLine( _T( " <" ) + who2 + _T( "> " ) + message2, col, sett().GetChatFont() );
	} else {
		OutputLine( _T( " <" ) + who + _T( "> " ) + message, col, sett().GetChatFont() );
	}


	if ( req_user ) {
		bool inactive = ui().GetActiveChatPanel() != this  || !wxTheApp->IsActive() ;
		ui().mw().RequestUserAttention();
		if ( inactive )
			UiEvents::GetNotificationEventSender().SendEvent(
					UiEvents::NotficationData( UiEvents::PrivateMessage,
											   wxString::Format( _T("%s:\n%s"), who.c_str(), message.Left(50).c_str() ) ) );
	}
}
VOID CActionSystem::ItemBox_Update(VOID)
{
	GetMe()->CleanInvalidAction();
	//创建新的物品
	for(INT i=0; i<MAX_BOXITEM_NUMBER; i++)
	{
		//取得物品
		tObject_Item* pItem = CDataPool::GetMe()->ItemBox_GetItem(i);
		if(!pItem) continue;

		UpdateAction_FromItem(pItem);
	}
}
Exemple #23
0
bool IBattle::IsEveryoneReady() const
{
	for ( unsigned int i = 0; i < GetNumPlayers(); i++ ) {
		User& usr = GetUser( i );
		UserBattleStatus& status = usr.BattleStatus();
		if ( status.IsBot() ) continue;
		if ( status.spectator ) continue;
		if ( &usr == &GetMe() ) continue;
		if ( !status.ready ) return false;
		if ( !status.sync ) return false;
	}
	return true;
}
// 任务物品提交界面的更新
VOID CActionSystem::UserMission_Update(VOID)
{
	//清空已经不存在的Action
	GetMe()->CleanInvalidAction();
	for(INT i=0; i<MISSION_BOX_SIZE; i++)
	{
		//取得物品
		tObject_Item*	pItem = CDataPool::GetMe()->MissionBox_GetItem(i);
		if(pItem)
		{
			//设置新的物品数据
			UpdateAction_FromItem(pItem);
		}
	}
}
VOID CActionSystem::Booth_Update(VOID)
{
	GetMe()->CleanInvalidAction();

	//创建新的物品
	for(INT i=0; i<MAX_BOOTH_NUMBER; i++)
	{
		//取得物品
		tObject_Item* pItem = CDataPool::GetMe()->Booth_GetItem(i);
		if(!pItem) continue;

		GetMe()->UpdateAction_FromItem(pItem);
	}

	//回购商品刷新
	for(INT i=0; i<MAX_BOOTH_SOLD_NUMBER ; i++)
	{
		//取得物品
		tObject_Item* pItem = CDataPool::GetMe()->Booth_GetSoldItem(i);
		if(!pItem) continue;

		GetMe()->UpdateAction_FromItem(pItem);
	}
}
Exemple #26
0
void Battle::StartHostedBattle()
{
	if ( UserExists( GetMe().GetNick() ) )
	{
		if ( IsFounderMe() )
		{
			if ( sett().GetBattleLastAutoControlState() )
			{
				FixTeamIDs( (IBattle::BalanceType)sett().GetFixIDMethod(), sett().GetFixIDClans(), sett().GetFixIDStrongClans(), sett().GetFixIDGrouping() );
				Autobalance( (IBattle::BalanceType)sett().GetBalanceMethod(), sett().GetBalanceClans(), sett().GetBalanceStrongClans(), sett().GetBalanceGrouping() );
				FixColours();
			}
			if ( IsProxy() )
			{
				if ( UserExists( GetProxy()) && !GetUser(GetProxy()).Status().in_game )
				{
					// DON'T set m_generating_script here, it will trick the script generating code to think we're the host
					wxString hostscript = spring().WriteScriptTxt( *this );
					try
					{
						wxString path = TowxString(SlPaths::GetDataDir()) + _T("relayhost_script.txt");
						if ( !wxFile::Access( path, wxFile::write ) ) {
								wxLogError( _T("Access denied to script.txt.") );
						}

						wxFile f( path, wxFile::write );
						f.Write( hostscript );
						f.Close();

					} catch (...) {}
					m_serv.SendScriptToProxy( hostscript );
				}
			}
			if( GetAutoLockOnStart() )
			{
				SetIsLocked( true );
				SendHostInfo( IBattle::HI_Locked );
			}
			sett().SetLastHostMap(TowxString(GetServer().GetCurrentBattle()->GetHostMapName()));
			sett().SaveSettings();
			if ( !IsProxy() ) GetServer().StartHostedBattle();
			else if ( UserExists( GetProxy() ) && GetUser(GetProxy()).Status().in_game ) // relayhost is already ingame, let's try to join it
			{
				StartSpring();
			}
		}
	}
}
VOID CActionSystem::UserExchangeSelf_Update(VOID)
{
	//清空已经不存在的Action
	GetMe()->CleanInvalidAction();

	for(INT i=0; i<EXCHANGE_BOX_SIZE; i++)
	{
		//取得物品
		tObject_Item*	pItem = CDataPool::GetMe()->MyExBox_GetItem(i);
		if(pItem)
		{
			//设置新的物品数据
			UpdateAction_FromItem(pItem);
		}
	}
}
//聊天动作
VOID CActionSystem::UserChatMood_Update(VOID)
{
	GetMe()->CleanInvalidAction();

	INT i = 0;
	do {
		TALK_ACT_STRUCT* pActStruct = SCRIPT_SANDBOX::Talk::s_Talk.GetTalkActStructByID(i++);
		if(pActStruct)
		{
			UpdateAction_FromChatMood(pActStruct);
		}
		else
		{
			break;
		}
	} while(TRUE);
}
VOID CActionSystem::ItemBox_Created(INT nObjId)
{
	//清空原有ItemBox中的所有物品Action
	GetMe()->CleanInvalidAction(true);
	//创建新的物品
	for(INT i=0; i<MAX_BOXITEM_NUMBER; i++)
	{
		//取得物品
		tObject_Item* pItem = CDataPool::GetMe()->ItemBox_GetItem(i);
		if(!pItem) continue;

		UpdateAction_FromItem(pItem);
	}

	//产生事件打开UI箱子
	CGameProcedure::s_pEventSystem->PushEvent(GE_LOOT_OPENED,nObjId);
}
Exemple #30
0
//! @brief Output a message said in the channel.
//!
//! @param who nick of the person who said something.
//! @param message the message to be outputted.
void ChatPanel::Said(const wxString& who, const wxString& message)
{
	if (m_active_users.find(who) == m_active_users.end()) {
		m_active_users.insert(who);
	}

	wxString me = TowxString(GetMe().GetNick());
	wxColour col;
	bool req_user = false;
	if (who.Upper() == me.Upper()) {
		col = sett().GetChatColorMine();
	} else {
		// change the image of the tab to show new events
		SetIconHighlight(highlight_say);
		if (m_type == CPT_User)
			req_user = true;
		//process logic for custom word highlights
		if (ContainsWordToHighlight(message)) {
			req_user = sett().GetRequestAttOnHighlight();
			col = sett().GetChatColorHighlight();
		} else
			col = sett().GetChatColorNormal();
	}

	if ((who == cfg().ReadString(_T("/Channel/bridgebot"))) && (message.StartsWith(_T( "<" ))) && (message.Find(_T( ">" )) != wxNOT_FOUND)) {
		wxString who2;
		wxString message2;
		who2 = message.BeforeFirst('>').AfterFirst('<');
		message2 = message.AfterFirst('>');
		OutputLine(_T( "<" ) + who2 + _T( "> " ) + message2, col);
	} else {
		OutputLine(_T( "<" ) + who + _T( "> " ) + message, col);
	}


	if (req_user) {
		bool inactive = ui().GetActiveChatPanel() != this || !wxTheApp->IsActive();
		if (inactive) {
			ui().mw().RequestUserAttention();
			const wxString msg = wxString::Format(_T("%s:\n%s"), who.c_str(), message.Left(50).c_str());
			UiEvents::GetNotificationEventSender().SendEvent(
			    UiEvents::NotficationData(UiEvents::PrivateMessage, msg));
		}
	}
}