1 /* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
2 //
3 // Class: BattleroomListCtrl
4 //
5
6 #include <wx/intl.h>
7 #include <wx/menu.h>
8 #include <wx/numdlg.h>
9 #include <wx/colordlg.h>
10 #include <wx/colour.h>
11 #include <wx/log.h>
12
13 #include <stdexcept>
14 #include <vector>
15
16 #include "battleroomlistctrl.h"
17 #include "iconimagelist.h"
18 #include "battle.h"
19 #include "uiutils.h"
20 #include "user.h"
21 #include "server.h"
22 #include "utils/debug.h"
23 #include "utils/conversion.h"
24 #include "uiutils.h"
25 #include "countrycodes.h"
26 #include "mainwindow.h"
27 #include "aui/auimanager.h"
28 #include "utils/customdialogs.h"
29 #include "settings.h"
30
31 template<> SortOrder CustomVirtListCtrl<User*,BattleroomListCtrl>::m_sortorder = SortOrder();
32
BEGIN_EVENT_TABLE(BattleroomListCtrl,BattleroomListCtrl::BaseType)33 BEGIN_EVENT_TABLE( BattleroomListCtrl, BattleroomListCtrl::BaseType )
34
35 EVT_LIST_ITEM_RIGHT_CLICK( BRLIST_LIST, BattleroomListCtrl::OnListRightClick )
36 EVT_MENU ( BRLIST_SPEC, BattleroomListCtrl::OnSpecSelect )
37 EVT_MENU ( BRLIST_KICK, BattleroomListCtrl::OnKickPlayer )
38 EVT_LIST_ITEM_ACTIVATED( BRLIST_LIST, BattleroomListCtrl::OnActivateItem )
39 // EVT_MENU ( BRLIST_ADDCREATEGROUP, BattleroomListCtrl::OnPlayerAddToGroup )
40 // EVT_MENU ( BRLIST_ADDTOGROUP, BattleroomListCtrl::OnPlayerAddToGroup )
41 EVT_MENU ( BRLIST_RING, BattleroomListCtrl::OnRingPlayer )
42 EVT_MENU ( BRLIST_COLOUR, BattleroomListCtrl::OnColourSelect )
43 EVT_MENU ( BRLIST_HANDICAP, BattleroomListCtrl::OnHandicapSelect )
44 #if wxUSE_TIPWINDOW
45 #ifndef __WXMSW__ //disables tooltips on win
46 EVT_MOTION(BattleroomListCtrl::OnMouseMotion)
47 #endif
48 #endif
49 END_EVENT_TABLE()
50
51
52
53 BattleroomListCtrl::BattleroomListCtrl( wxWindow* parent, IBattle* battle, bool readonly, bool showingame )
54 : CustomVirtListCtrl< User *,BattleroomListCtrl>(parent, BRLIST_LIST, wxDefaultPosition, wxDefaultSize,
55 wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL, _T("BattleroomListCtrl"),
56 3, &BattleroomListCtrl::CompareOneCrit,
57 true /*highlight*/, UserActions::ActHighlight, !readonly /*periodic sort*/ ),
58 m_battle(battle),
59 m_popup(0),
60 m_sel_user(0),
61 m_sides(0),
62 m_spec_item(0),
63 m_handicap_item(0),
64 m_ro(readonly),
65 m_showingame(showingame),
66 m_status_column_index(-1),
67 m_ingame_column_index(-1),
68 m_faction_column_index(-1),
69 m_colour_column_index(-1),
70 m_country_column_index(-1),
71 m_rank_column_index(-1),
72 m_nick_column_index(-1),
73 m_team_column_index(-1),
74 m_ally_column_index(-1),
75 m_resourcebonus_column_index(-1)
76 {
77 GetAui().manager->AddPane( this, wxLEFT, _T("battleroomlistctrl") );
78
79 wxListItem col;
80
81 int count = 0;
82 AddColumn( count, wxLIST_AUTOSIZE_USEHEADER, _T("Status"), _T("Player/Bot") );
83 m_status_column_index = count;
84 count++;
85 if ( m_showingame )
86 {
87 AddColumn( count, 55, _T("Ingame"), _T("Battleroom status") );
88 m_ingame_column_index = count;
89 count++;
90 }
91
92 AddColumn( count, wxLIST_AUTOSIZE_USEHEADER, _T("Faction"), _T("Faction icon") );
93 m_faction_column_index = count;
94 count++;
95 AddColumn( count, wxLIST_AUTOSIZE_USEHEADER, _T("Colour"), _T("Teamcolour") );
96 m_colour_column_index = count;
97 count++;
98 AddColumn( count, wxLIST_AUTOSIZE_USEHEADER, _T("Country"), _T("Country") );
99 m_country_column_index = count;
100 count++;
101 AddColumn( count, wxLIST_AUTOSIZE_USEHEADER, _T("Rank"), _T("Rank") );
102 m_rank_column_index = count;
103 count++;
104 AddColumn( count, 165, _("Nickname"), _T("Ingame name"));
105 m_nick_column_index = count;
106 count++;
107 AddColumn( count, wxLIST_AUTOSIZE_USEHEADER, _("Team"), _T("Team number") );
108 m_team_column_index = count;
109 count++;
110 AddColumn( count, wxLIST_AUTOSIZE_USEHEADER, _("Ally"), _T("Ally number") );
111 m_ally_column_index = count;
112 count++;
113 AddColumn( count, wxLIST_AUTOSIZE_USEHEADER, _("Resource Bonus"), _T("Resource Bonus") );
114 m_resourcebonus_column_index = count;
115
116 if ( m_sortorder.size() == 0 ) {
117 m_sortorder[0].col = m_team_column_index;
118 m_sortorder[0].direction = true;
119 m_sortorder[1].col = m_ally_column_index;
120 m_sortorder[1].direction = true;
121 m_sortorder[2].col = m_nick_column_index;
122 m_sortorder[2].direction = true;
123 }
124
125 if ( !m_ro )
126 {
127 m_popup = new UserMenu(this, this);
128 wxMenu* m_teams;
129 m_teams = new wxMenu();
130
131 for ( unsigned int i = 0; i < SPRING_MAX_TEAMS; i++ )
132 {
133 wxMenuItem* team = new wxMenuItem( m_teams, BRLIST_TEAM + i, wxFormat( _T("%d") ) % (i+1), wxEmptyString, wxITEM_NORMAL );
134 m_teams->Append( team );
135 Connect( BRLIST_TEAM + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnTeamSelect ) );
136 }
137 m_popup->Append( -1, _("Team"), m_teams );
138
139 wxMenu* m_allies = new wxMenu();
140 for ( unsigned int i = 0; i < SPRING_MAX_ALLIES; i++ )
141 {
142 wxMenuItem* ally = new wxMenuItem( m_allies, BRLIST_ALLY + i, wxFormat( _T("%d") ) % (i+1), wxEmptyString, wxITEM_NORMAL );
143 m_allies->Append( ally );
144 Connect( BRLIST_ALLY + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnAllySelect ) );
145 }
146 m_popup->Append( -1, _("Ally"), m_allies );
147
148 m_sides = new wxMenu();
149 SetBattle( battle );
150 m_popup->Append( -1, _("Side"), m_sides );
151
152 m_popup->AppendSeparator();
153
154 wxMenuItem* m_colours = new wxMenuItem( m_popup, BRLIST_COLOUR, _("Set color"), wxEmptyString, wxITEM_NORMAL );
155 m_popup->Append( m_colours );
156
157 m_popup->AppendSeparator();
158
159 m_handicap_item = new wxMenuItem( m_popup, BRLIST_HANDICAP, _("Set Resource Bonus"), wxEmptyString, wxITEM_NORMAL );
160 m_popup->Append( m_handicap_item );
161
162 m_popup->AppendSeparator();
163
164 m_spec_item = new wxMenuItem( m_popup, BRLIST_SPEC, wxString( _("Spectator") ) , wxEmptyString, wxITEM_CHECK );
165 m_popup->Append( m_spec_item );
166
167 m_popup->AppendSeparator();
168
169 wxMenuItem* kick = new wxMenuItem( m_popup, BRLIST_KICK, wxString( _("Kick") ) , wxEmptyString, wxITEM_NORMAL );
170 m_popup->Append( kick );
171 wxMenuItem* ring = new wxMenuItem( m_popup, BRLIST_RING, wxString( _("Ring") ) , wxEmptyString, wxITEM_NORMAL );
172 m_popup->Append( ring );
173
174 }
175 }
176
177
~BattleroomListCtrl()178 BattleroomListCtrl::~BattleroomListCtrl()
179 {
180
181 }
182
SetBattle(IBattle * battle)183 void BattleroomListCtrl::SetBattle( IBattle* battle )
184 {
185 m_battle = battle;
186 for ( unsigned int i = 0; i < side_vector.size(); i++ )
187 {
188 wxMenuItem* side = side_vector[i];
189 m_popup->Remove( side );
190 m_sides->Destroy( side ); // delete side;
191 Disconnect( BRLIST_SIDE + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnSideSelect ) );
192 }
193 m_data.clear();
194 side_vector.clear();
195 if ( m_battle && m_sides )
196 {
197 try
198 {
199 const wxArrayString sides = LSL::Util::vectorToArrayString(
200 LSL::usync().GetSides(STD_STRING(m_battle->GetHostModName())));
201 for ( unsigned int i = 0; i < sides.GetCount(); i++ )
202 {
203 wxMenuItem* side = new wxMenuItem( m_sides, BRLIST_SIDE + i, sides[i], wxEmptyString, wxITEM_NORMAL );
204 m_sides->Append( side );
205 side_vector.push_back( side );
206 Connect( BRLIST_SIDE + i, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnSideSelect ) );
207 }
208 } catch (...) {}
209 }
210 }
211
GetBattle()212 IBattle& BattleroomListCtrl::GetBattle()
213 {
214 ASSERT_EXCEPTION( m_battle, _T("m_battle == 0") );
215 return *m_battle;
216 }
217
AddUser(User & user)218 void BattleroomListCtrl::AddUser( User& user )
219 {
220 //first time setting is necessary to have color in replay/savegame used controls
221 if ( !user.BattleStatus().spectator )
222 icons().SetColourIcon( user.BattleStatus().colour );
223 if ( AddItem( &user ) )
224 return;
225
226 wxLogWarning( _T("user already in battleroom list.") );
227 }
228
RemoveUser(User & user)229 void BattleroomListCtrl::RemoveUser( User& user )
230 {
231 if ( RemoveItem( &user ) )
232 return;
233
234 wxLogError( _T("Didn't find the user to remove in battleroomlistctrl.") );
235 }
236
UpdateUser(User & user)237 void BattleroomListCtrl::UpdateUser( User& user )
238 {
239 if ( !user.BattleStatus().spectator )
240 icons().SetColourIcon( user.BattleStatus().colour );
241 wxArrayString sides = LSL::Util::vectorToArrayString(LSL::usync().GetSides(STD_STRING(m_battle->GetHostModName())));
242 ASSERT_EXCEPTION( user.BattleStatus().side < (long)sides.GetCount(), _T("Side index too high") );
243 user.SetSideiconIndex( icons().GetSideIcon( m_battle->GetHostModName(), user.BattleStatus().side ) );
244 int index = GetIndexFromData( &user );
245 UpdateUser( index );
246 }
247
GetItemAttr(long item) const248 wxListItemAttr * BattleroomListCtrl::GetItemAttr(long item) const
249 {
250 if ( item == -1 || item >= (long)m_data.size())
251 return NULL;
252
253 const User& user = *GetDataFromIndex( item );
254 bool is_bot = user.BattleStatus().IsBot();
255
256 if ( !is_bot ) {
257 return HighlightItemUser( user.GetNick() );
258 }
259
260 return NULL;
261 }
262
GetItemColumnImage(long item,long column) const263 int BattleroomListCtrl::GetItemColumnImage(long item, long column) const
264 {
265 if ( (item == -1) || (item >= (long)m_data.size()) || (m_battle == NULL) )
266 return -1;
267
268 const User& user = *GetDataFromIndex( item );
269 bool is_bot = user.BattleStatus().IsBot();
270 bool is_spec = user.BattleStatus().spectator;
271 if ( column == m_status_column_index ) {
272 if ( !is_bot ) {
273 if ( m_battle->IsFounder( user ) ) {
274 return icons().GetHostIcon( is_spec );
275 }
276 else {
277 return icons().GetReadyIcon( is_spec, user.BattleStatus().ready, user.BattleStatus().sync, is_bot );
278 }
279 }
280 else
281 return icons().ICON_BOT;
282 }
283 if ( column == m_ingame_column_index ) return user.GetStatusIconIndex();
284 if ( column == m_colour_column_index ) return is_spec ? -1 : icons().GetColourIcon( user.BattleStatus().colour );
285 if ( column == m_country_column_index ) return is_bot ? -1 : icons().GetFlagIcon( user.GetCountry() );
286 if ( column == m_rank_column_index ) return is_bot ? -1 : icons().GetRankIcon( user.GetStatus().rank );
287 if ( column == m_faction_column_index ) return is_spec ? -1 : user.GetSideiconIndex();
288 if ( column == m_nick_column_index ) return -1;
289 else
290 {
291 const wxString msg = wxFormat(_("column oob in BattleroomListCtrl::OnGetItemColumnImage: %d" )) % column;
292 wxLogWarning( msg);
293 return -1;
294 }
295 }
296
GetItemText(long item,long column) const297 wxString BattleroomListCtrl::GetItemText(long item, long column) const
298 {
299 if ( (item == -1) || (item >= (long)m_data.size()) || (m_battle == NULL))
300 return wxEmptyString;
301
302 const User& user = *GetDataFromIndex( item );
303 bool is_bot = user.BattleStatus().IsBot();
304 bool is_spec = user.BattleStatus().spectator;
305
306 if ( column == m_faction_column_index ) {
307 try {
308 auto sides = LSL::usync().GetSides(STD_STRING(m_battle->GetHostModName()));
309 ASSERT_EXCEPTION( user.BattleStatus().side < (long)sides.size(), _T("Side index too high") );
310 }
311 catch ( ... ) {
312 return wxFormat( _T("s%d") ) % (user.BattleStatus().side + 1);
313 }
314 return wxEmptyString;
315 }
316 if ( column == m_nick_column_index ) {
317 if ( is_bot ) {
318 wxString botname = user.BattleStatus().aishortname;
319 if ( !user.BattleStatus().aiversion.IsEmpty() ) botname += _T(" ") + user.BattleStatus().aiversion;
320 if ( !LSL::usync().VersionSupports( LSL::USYNC_GetSkirmishAI ) )
321 {
322 if ( botname.Find(_T('.')) != wxNOT_FOUND ) botname = botname.BeforeLast(_T('.'));
323 if ( botname.Find(_T('/')) != wxNOT_FOUND ) botname = botname.AfterLast(_T('/'));
324 if ( botname.Find(_T('\\')) != wxNOT_FOUND ) botname = botname.AfterLast(_T('\\'));
325 if ( botname.Find(_T("LuaAI:")) != wxNOT_FOUND ) botname = botname.AfterFirst(_T(':'));
326 }
327 return (wxFormat(_T("%s - %s (%s)")) % user.GetNick() % botname % user.BattleStatus().owner);
328 }
329 else
330 return user.GetNick();
331 }
332 if ( column == m_team_column_index ) return is_spec ? (wxString)wxEmptyString : (wxFormat( _T("%d") ) % ( user.BattleStatus().team + 1 ) );
333 if ( column == m_ally_column_index ) return is_spec ? (wxString)wxEmptyString : (wxFormat( _T("%d") ) % ( user.BattleStatus().ally + 1 ) );
334 if ( column == m_resourcebonus_column_index ) return is_spec ? (wxString)wxEmptyString : (wxFormat( _T("%d%%") ) % user.BattleStatus().handicap );
335 if ( column == m_country_column_index ) return wxEmptyString;
336
337 return wxEmptyString;
338 }
339
UpdateUser(const int & index)340 void BattleroomListCtrl::UpdateUser( const int& index )
341 {
342 wxWindowUpdateLocker lock( this );
343 RefreshItem( index );
344 MarkDirtySort();
345 }
346
OnListRightClick(wxListEvent & event)347 void BattleroomListCtrl::OnListRightClick( wxListEvent& event )
348 {
349 wxLogDebugFunc( wxEmptyString );
350 if ( m_ro ) return;
351 int index = event.GetIndex();
352
353 if ( index == -1 || index >= (long)m_data.size()) return;
354
355 User& user = *GetDataFromIndex( event.GetIndex() );
356 m_sel_user = &user; //this is set for event handlers
357
358 if ( user.BattleStatus().IsBot() )
359 {
360 wxLogMessage(_T("Bot"));
361
362 int item = m_popup->FindItem( _("Spectator") );
363 m_popup->Enable( item, false );
364 m_popup->Check( item, false );
365 m_popup->Enable( m_popup->FindItem( _("Ring") ), false );
366 m_popup->Enable( m_popup->FindItem( _("Kick") ),true);
367 }
368 else
369 {
370 wxLogMessage(_T("User"));
371 assert( m_popup );
372 int item = m_popup->FindItem( _("Spectator") );
373 m_popup->Check( item, m_sel_user->BattleStatus().spectator );
374 m_popup->Enable( item, true );
375 m_popup->Enable( m_popup->FindItem( _("Ring") ), true );
376 bool isSelUserMe = ( ui().IsThisMe(user) );
377 m_popup->Enable( m_popup->FindItem( _("Kick") ),!isSelUserMe);
378 }
379
380 wxLogMessage(_T("Popup"));
381 m_popup->EnableItems( !user.BattleStatus().IsBot(), GetSelectedUserNick() );//this updates groups, therefore we need to update the connection to evt handlers too
382 std::vector<int> groups_ids = m_popup->GetGroupIds();
383 for (std::vector<int>::const_iterator it = groups_ids.begin(); it != groups_ids.end(); ++it) {
384 Connect( *it, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnUserMenuAddToGroup ), 0, this );
385 }
386 Connect( GROUP_ID_NEW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnUserMenuCreateGroup), 0, this );
387 PopupMenu( m_popup );
388 wxLogMessage(_T("Done"));
389 }
390
391
OnTeamSelect(wxCommandEvent & event)392 void BattleroomListCtrl::OnTeamSelect( wxCommandEvent& event )
393 {
394 wxLogDebugFunc( wxEmptyString );
395 int team = event.GetId() - BRLIST_TEAM;
396 if( m_sel_user ) ((Battle*)m_battle)->ForceTeam( *m_sel_user, team );
397 }
398
399
OnAllySelect(wxCommandEvent & event)400 void BattleroomListCtrl::OnAllySelect( wxCommandEvent& event )
401 {
402 wxLogDebugFunc( wxEmptyString );
403 int ally = event.GetId() - BRLIST_ALLY;
404 if( m_sel_user ) ((Battle*)m_battle)->ForceAlly( *m_sel_user, ally );
405 }
406
407
OnColourSelect(wxCommandEvent &)408 void BattleroomListCtrl::OnColourSelect( wxCommandEvent& /*unused*/ )
409 {
410 wxLogDebugFunc( wxEmptyString );
411
412 wxColour CurrentColour = m_sel_user->BattleStatus().colour;
413 CurrentColour = GetColourFromUser(this, CurrentColour);
414 if ( !CurrentColour.IsOk() ) return;
415 if( m_sel_user ) ((Battle*)m_battle)->ForceColour( *m_sel_user, CurrentColour );
416
417 }
418
419
OnSideSelect(wxCommandEvent & event)420 void BattleroomListCtrl::OnSideSelect( wxCommandEvent& event )
421 {
422 wxLogDebugFunc( wxEmptyString );
423 int side = event.GetId() - BRLIST_SIDE;
424 if( m_sel_user ) ((Battle*)m_battle)->ForceSide( *m_sel_user, side );
425 }
426
427
OnHandicapSelect(wxCommandEvent &)428 void BattleroomListCtrl::OnHandicapSelect( wxCommandEvent& /*unused*/ )
429 {
430 wxLogDebugFunc( wxEmptyString );
431 if( !m_sel_user ) return;
432 long handicap = wxGetNumberFromUser( _("Please enter a value between 0 and 100"), _("Set Resource Bonus"), wxEmptyString, m_sel_user->BattleStatus().handicap, 0, 100, (wxWindow*)&ui().mw(), wxDefaultPosition );
433 if ( handicap != -1 )
434 {
435 ((Battle*)m_battle)->SetHandicap( *m_sel_user, handicap );
436 }
437 }
438
439
OnSpecSelect(wxCommandEvent &)440 void BattleroomListCtrl::OnSpecSelect( wxCommandEvent& /*unused*/ )
441 {
442 wxLogDebugFunc( wxEmptyString );
443 if ( m_sel_user ) ((Battle*)m_battle)->ForceSpectator( *m_sel_user, m_spec_item->IsChecked() );
444 }
445
446
OnKickPlayer(wxCommandEvent &)447 void BattleroomListCtrl::OnKickPlayer( wxCommandEvent& /*unused*/ )
448 {
449 wxLogDebugFunc( wxEmptyString );
450 if ( m_sel_user ) ((Battle*)m_battle)->KickPlayer( *m_sel_user );
451 }
452
453
OnRingPlayer(wxCommandEvent &)454 void BattleroomListCtrl::OnRingPlayer( wxCommandEvent& /*unused*/ )
455 {
456 wxLogDebugFunc( wxEmptyString );
457 if ( m_sel_user ) ((Battle*)m_battle)->GetServer().Ring( m_sel_user->GetNick() );
458 }
459
Sort()460 void BattleroomListCtrl::Sort()
461 {
462 if ( m_data.size() > 0 )
463 {
464 SaveSelection();
465 SLInsertionSort( m_data, m_comparator );
466 RestoreSelection();
467 }
468 }
469
CompareOneCrit(DataType u1,DataType u2,int col,int dir) const470 int BattleroomListCtrl::CompareOneCrit(DataType u1, DataType u2, int col, int dir) const
471 {
472 if ( col == m_status_column_index ) return dir * CompareStatus( u1, u2, m_battle );
473 if ( col == m_ingame_column_index ) return dir * CompareLobbyStatus( u1, u2 );
474 if ( col == m_faction_column_index ) return dir * CompareSide( u1, u2 );
475 if ( col == m_colour_column_index ) return dir * CompareColor( u1, u2 );
476 if ( col == m_country_column_index ) return dir * compareSimple( u1, u2 );
477 if ( col == m_rank_column_index ) return dir * CompareRank( u1, u2 );
478 if ( col == m_nick_column_index ) return dir * u1->GetNick().CmpNoCase( u2->GetNick() );
479 if ( col == m_team_column_index ) return dir * CompareTeam( u1, u2 );
480 if ( col == m_ally_column_index ) return dir * CompareAlly( u1, u2 );
481 if ( col == m_resourcebonus_column_index ) return dir * CompareHandicap( u1, u2 );
482 return 0;
483 }
484
CompareLobbyStatus(const DataType user1,const DataType user2)485 int BattleroomListCtrl::CompareLobbyStatus( const DataType user1, const DataType user2 )
486 {
487 int u1 = 0, u2 = 0;
488
489 if ( user1->GetStatus().bot )
490 u1 += 1000;
491 if ( user2->GetStatus().bot )
492 u2 += 1000;
493 if ( user1->GetStatus().moderator )
494 u1 += 100;
495 if ( user2->GetStatus().moderator )
496 u2 += 100;
497 if ( user1->GetStatus().in_game )
498 u1 += -10;
499 if ( user2->GetStatus().in_game )
500 u2 += -10;
501 if ( user1->GetStatus().away )
502 u1 += -5;
503 if ( user2->GetStatus().away )
504 u2 += -5;
505
506 // inverse the order
507 if ( u1 < u2 )
508 return -1;
509 if ( u1 > u2 )
510 return 1;
511
512 return 0;
513 }
514
CompareStatus(const DataType user1,const DataType user2,const IBattle * battle)515 int BattleroomListCtrl::CompareStatus(const DataType user1, const DataType user2, const IBattle* battle )
516 {
517 int status1 = 0;
518 if ( user1->BattleStatus().IsBot() )
519 {
520 status1 = 9;
521 }
522 else
523 {
524 try
525 {
526 if ( &battle->GetFounder() != user1 )
527 status1 = 1;
528 }catch(...){}
529 if ( user1->BattleStatus().ready )
530 status1 += 5;
531 if ( user1->BattleStatus().sync )
532 status1 += 7;
533 if ( user1->BattleStatus().spectator )
534 status1 += 10;
535 }
536
537 int status2 = 0;
538 if ( user2->BattleStatus().IsBot() )
539 {
540 status2 = 9;
541 }
542 else
543 {
544 try
545 {
546 if ( &battle->GetFounder() != user2 )
547 status2 = 1;
548 }catch(...){}
549 if ( user2->BattleStatus().ready )
550 status2 += 5;
551 if ( user2->BattleStatus().sync )
552 status2 += 7;
553 if ( user2->BattleStatus().spectator )
554 status2 += 10;
555 }
556
557 if ( status1 < status2 )
558 return -1;
559 if ( status1 > status2 )
560 return 1;
561
562 return 0;
563 }
564
CompareSide(const DataType user1,const DataType user2)565 int BattleroomListCtrl::CompareSide(const DataType user1, const DataType user2)
566 {
567 if ( !user1 && !user2 ) return 0;
568 else if ( !user1 ) return 1;
569 else if ( !user2 ) return -1;
570
571 int side1;
572 if ( user1->BattleStatus().spectator )
573 side1 = 1000;
574 else
575 side1 = user1->BattleStatus().side;
576
577 int side2;
578 if ( user2->BattleStatus().spectator )
579 side2 = 1000;
580 else
581 side2 = user2->BattleStatus().side;
582
583 if ( side1 < side2 )
584 return -1;
585 if ( side1 > side2 )
586 return 1;
587
588 return 0;
589 }
590
CompareColor(const DataType user1,const DataType user2)591 int BattleroomListCtrl::CompareColor(const DataType user1, const DataType user2)
592 {
593 if ( !user1 && !user2 ) return 0;
594 else if ( !user1 ) return 1;
595 else if ( !user2 ) return -1;
596
597 int color1_r, color1_g, color1_b;
598
599 if ( user1->BattleStatus().spectator ) return -1;
600 color1_r = user1->BattleStatus().colour.Red();
601 color1_g = user1->BattleStatus().colour.Green();
602 color1_b = user1->BattleStatus().colour.Blue();
603
604 int color2_r, color2_g, color2_b;
605
606 if ( user2->BattleStatus().spectator ) return 1;
607 color2_r = user2->BattleStatus().colour.Red();
608 color2_g = user2->BattleStatus().colour.Green();
609 color2_b = user2->BattleStatus().colour.Blue();
610
611 if ( (color1_r + color1_g + color1_b)/3 < (color2_r + color2_g + color2_b)/3 )
612 return -1;
613 if ( (color1_r + color1_g + color1_b)/3 > (color2_r + color2_g + color2_b)/3 )
614 return 1;
615
616 return 0;
617 }
618
619
CompareRank(const DataType user1,const DataType user2)620 int BattleroomListCtrl::CompareRank(const DataType user1, const DataType user2)
621 {
622 if ( !user1 && !user2 ) return 0;
623 else if ( !user1 ) return 1;
624 else if ( !user2 ) return -1;
625
626 int rank1;
627 if ( user1->BattleStatus().IsBot() )
628 rank1 = 1000;
629 else
630 rank1 = user1->GetStatus().rank;
631
632 int rank2;
633 if ( user2->BattleStatus().IsBot() )
634 rank2 = 1000;
635 else
636 rank2 = user2->GetStatus().rank;
637
638 if ( rank1 < rank2 )
639 return -1;
640 if ( rank1 > rank2 )
641 return 1;
642
643 return 0;
644 }
645
CompareTeam(const DataType user1,const DataType user2)646 int BattleroomListCtrl::CompareTeam(const DataType user1, const DataType user2)
647 {
648 if ( !user1 && !user2 ) return 0;
649 else if ( !user1 ) return 1;
650 else if ( !user2 ) return -1;
651
652 int team1;
653 if ( user1->BattleStatus().spectator )
654 team1 = 1000;
655 else
656 team1 = user1->BattleStatus().team;
657
658 int team2;
659 if ( user2->BattleStatus().spectator )
660 team2 = 1000;
661 else
662 team2 = user2->BattleStatus().team;
663
664 if ( team1 < team2 )
665 return -1;
666 if ( team1 > team2 )
667 return 1;
668
669 return 0;
670 }
671
CompareAlly(const DataType user1,const DataType user2)672 int BattleroomListCtrl::CompareAlly(const DataType user1, const DataType user2)
673 {
674 if ( !user1 && !user2 ) return 0;
675 else if ( !user1 ) return 1;
676 else if ( !user2 ) return -1;
677
678 int ally1;
679 if ( user1->BattleStatus().spectator )
680 ally1 = 1000;
681 else
682 ally1 = user1->BattleStatus().ally;
683
684 int ally2;
685 if ( user2->BattleStatus().spectator )
686 ally2 = 1000;
687 else
688 ally2 = user2->BattleStatus().ally;
689
690 if ( ally1 < ally2 )
691 return -1;
692 if ( ally1 > ally2 )
693 return 1;
694
695 return 0;
696 }
697
698
CompareHandicap(const DataType user1,const DataType user2)699 int BattleroomListCtrl::CompareHandicap(const DataType user1, const DataType user2)
700 {
701 int handicap1;
702 if ( user1->BattleStatus().spectator )
703 handicap1 = 1000;
704 else
705 handicap1 = user1->BattleStatus().handicap;
706
707 int handicap2;
708 if ( user2->BattleStatus().spectator )
709 handicap2 = 1000;
710 else
711 handicap2 = user2->BattleStatus().handicap;
712
713 if ( handicap1 < handicap2 )
714 return -1;
715 if ( handicap1 > handicap2 )
716 return 1;
717
718 return 0;
719 }
720
SetTipWindowText(const long item_hit,const wxPoint & position)721 void BattleroomListCtrl::SetTipWindowText( const long item_hit, const wxPoint& position)
722 {
723 if ( item_hit < 0 || item_hit >= (long)m_data.size() )
724 return;
725 if ( !m_battle ) return;
726 const User& user = *GetDataFromIndex( item_hit );
727
728 int column = getColumnFromPosition( position );
729 if (column > (int)m_colinfovec.size() || column < 0)
730 {
731 m_tiptext = wxEmptyString;
732 }
733 else
734 {
735 if ( column == m_status_column_index ) // is bot?
736 {
737 m_tiptext = wxEmptyString;
738
739 if ( user.BattleStatus().IsBot() )
740 {
741 m_tiptext += _("AI (bot)\n");
742 }
743 else
744 {
745 m_tiptext += _("Human\n");
746 }
747
748 if ( user.BattleStatus().spectator )
749 {
750 m_tiptext += _("Spectator\n");
751 }
752 else
753 {
754 m_tiptext += _("Player\n");
755 }
756
757 if ( m_battle->IsFounder( user ) )
758 {
759 m_tiptext += _("Host\n");
760 }
761 else
762 {
763 m_tiptext += _("Client\n");
764 }
765
766 if ( user.BattleStatus().ready )
767 {
768 m_tiptext += _("Ready\n");
769 }
770 else
771 {
772 m_tiptext += _("Not ready\n");
773 }
774
775 if ( user.BattleStatus().sync == SYNC_SYNCED )
776 {
777 m_tiptext += _("In sync");
778 }
779 else
780 {
781 m_tiptext += _("Not in sync");
782 }
783 }
784 else if ( column == m_faction_column_index ) // icon
785 {
786 m_tiptext = wxEmptyString;
787 if ( user.BattleStatus().spectator )
788 {
789 m_tiptext = _T("Spectators have no side");
790 }
791 else
792 {
793 try
794 {
795 const auto sides = LSL::usync().GetSides(STD_STRING(m_battle->GetHostModName()));
796 const int side = user.BattleStatus().side;
797 if ( side < (int)sides.size() )
798 m_tiptext = TowxString(sides[side]);
799 }
800 catch (...){}
801 }
802 }
803 else if ( column == m_ingame_column_index ) // lobby status
804 {
805 m_tiptext = _T( "This " );
806 if ( user.GetStatus().bot )
807 {
808 m_tiptext << _T( "bot " );
809 }
810 else if ( user.GetStatus().moderator )
811 {
812 m_tiptext << _T( "moderator " );
813 }
814 else
815 {
816 m_tiptext << _T( "player " );
817 }
818
819 if ( user.GetStatus().in_game )
820 {
821 m_tiptext << _T( "is ingame" );
822 }
823 else if ( user.GetStatus().away )
824 {
825 m_tiptext << _T( "is away" );
826 }
827 else
828 {
829 m_tiptext << _T( "is available" );
830 }
831 }
832 else if ( column == m_country_column_index ) // country
833 {
834 m_tiptext = user.BattleStatus().IsBot() ? _T("This bot is from nowhere particular") : GetFlagNameFromCountryCode(user.GetCountry());
835 }
836 else if ( column == m_rank_column_index ) // rank
837 {
838 m_tiptext = user.BattleStatus().IsBot() ? _T("This bot has no rank") : user.GetRankName(user.GetStatus().rank);
839 }
840 else if ( column == m_nick_column_index ) //name
841 {
842 m_tiptext = user.BattleStatus().IsBot() ?user.GetNick() : user.GetNick();
843 }
844 else m_tiptext = m_colinfovec[column].tip;
845 }
846 }
847
OnUserMenuAddToGroup(wxCommandEvent & event)848 void BattleroomListCtrl::OnUserMenuAddToGroup( wxCommandEvent& event )
849 {
850 int id = event.GetId();
851 wxString groupname = m_popup->GetGroupByEvtID(id);
852 wxString nick = GetSelectedUserNick();
853 useractions().AddUserToGroup( groupname, nick );
854 Disconnect( GROUP_ID_NEW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( BattleroomListCtrl::OnUserMenuCreateGroup), 0, this );
855 }
856
OnUserMenuDeleteFromGroup(wxCommandEvent &)857 void BattleroomListCtrl::OnUserMenuDeleteFromGroup( wxCommandEvent& /*unused*/ )
858 {
859 wxString nick = GetSelectedUserNick();
860 useractions().RemoveUser( nick );
861 }
862
OnUserMenuCreateGroup(wxCommandEvent &)863 void BattleroomListCtrl::OnUserMenuCreateGroup( wxCommandEvent& /*unused*/ )
864 {
865 wxString name;
866 if ( ui().AskText( _("Enter name"),
867 _("Please enter the name for the new group.\nAfter clicking ok you will be taken to adjust its settings."), name ) )
868 {
869 wxString nick = GetSelectedUserNick();
870
871 useractions().AddGroup( name );
872 useractions().AddUserToGroup( name, nick );
873 ui().mw().ShowConfigure( MainWindow::OPT_PAGE_GROUPS );
874 }
875 }
876
GetSelectedUserNick()877 wxString BattleroomListCtrl::GetSelectedUserNick()
878 {
879 if ( m_selected_index < 0 || m_selected_index >= (long)m_data.size() )
880 return wxEmptyString;
881 else
882 return m_data[m_selected_index]->GetNick();
883 }
884
OnActivateItem(wxListEvent &)885 void BattleroomListCtrl::OnActivateItem( wxListEvent& /*unused*/ )
886 {
887 if ( m_ro )
888 return;
889 if ( m_selected_index < 0 || m_selected_index >= (long)m_data.size() )
890 return;
891
892 const User* usr = m_data[m_selected_index];
893 if ( usr != NULL && !usr->BattleStatus().IsBot() )
894 ui().mw().OpenPrivateChat( *usr );
895 }
896
GetIndexFromData(const DataType & data) const897 int BattleroomListCtrl::GetIndexFromData(const DataType& data) const
898 {
899 const User* user = data;
900 static long seekpos;
901 seekpos = LSL::Util::Clamp( seekpos, 0l , (long)m_data.size() );
902 int index = seekpos;
903
904 for ( DataCIter f_idx = m_data.begin() + seekpos; f_idx != m_data.end() ; ++f_idx )
905 {
906 if ( user == *f_idx )
907 {
908 seekpos = index;
909 return seekpos;
910 }
911 index++;
912 }
913 //it's ok to init with seekpos, if it had changed this would not be reached
914 int r_index = seekpos - 1;
915 for ( DataRevCIter r_idx = m_data.rbegin() + ( m_data.size() - seekpos ); r_idx != m_data.rend() ; ++r_idx )
916 {
917 if ( user == *r_idx )
918 {
919 seekpos = r_index;
920 return seekpos;
921 }
922 r_index--;
923 }
924
925 return -1;
926 }
927
928