1 /* Copyright (C) 2007 The SpringLobby Team. All rights reserved. */
2 
3 
4 /**
5 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
6 
7 DO NOT CHANGE THIS FILE!
8 
9 this file is deprecated and will be replaced with
10 
11 lsl/battle/ibattle.cpp
12 
13 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14 **/
15 
16 
17 #include <wx/tokenzr.h>
18 #include <wx/image.h>
19 #include <sstream>
20 #include <wx/timer.h>
21 
22 #include "ibattle.h"
23 #include "utils/debug.h"
24 #include "utils/conversion.h"
25 #include <lslutils/misc.h>
26 #include "uiutils.h"
27 #include "settings.h"
28 #include "ui.h" //only required for preset stuff
29 #include "spring.h"
30 #include <lslutils/conversion.h>
31 #include "springlobbyapp.h"
32 
33 #include <list>
34 #include <algorithm>
35 #include <cmath>
36 #include <set>
37 
38 const unsigned int TIMER_ID         = 102;
39 
IBattle()40 IBattle::IBattle():
41 	wxEvtHandler(),
42   m_map_loaded(false),
43   m_mod_loaded(false),
44   m_map_exists(false),
45   m_mod_exists(false),
46   m_previous_local_mod_name( wxEmptyString ),
47   m_ingame(false),
48   m_auto_unspec(false),
49   m_auto_unspec_num_players(0),
50   m_generating_script(false),
51   m_players_ready(0),
52   m_players_sync(0),
53   m_players_ok(0),
54   m_is_self_in(false),
55 	m_timer ( 0 ),
56 	m_start_time(0)
57 {
58 	ConnectGlobalEvent(this, GlobalEvent::OnUnitsyncReloaded, wxObjectEventFunction(&IBattle::OnUnitsyncReloaded));
59 }
60 
61 
~IBattle()62 IBattle::~IBattle()
63 {
64 	if ( m_is_self_in ) LSL::usync().UnSetCurrentMod();
65 	if ( m_timer ) m_timer->Stop();
66 	delete m_timer;
67 }
68 
IsSynced()69 bool IBattle::IsSynced()
70 {
71     LoadMod();
72     LoadMap();
73     bool synced = true;
74     if ( !m_host_map.hash.empty() && m_host_map.hash != "0" && m_host_map.hash != m_local_map.hash ) synced = false;
75     else if ( !m_host_map.name.empty() && m_local_map.name != m_host_map.name) synced = false;
76     else if ( !m_host_mod.hash.empty() && m_host_mod.hash != "0" && m_host_mod.hash != m_local_mod.hash ) synced = false;
77     else if ( !m_host_mod.name.empty() && m_local_mod.name != m_host_mod.name) synced = false;
78     return synced;
79 }
80 
GetFixColoursPalette(int numteams) const81 std::vector<wxColour> &IBattle::GetFixColoursPalette( int numteams ) const
82 {
83     return GetBigFixColoursPalette( numteams );
84 }
85 
GetFixColour(int i) const86 wxColour IBattle::GetFixColour(int i) const
87 {
88 		int size = m_teams_sizes.size();
89     std::vector<wxColour> palette = GetFixColoursPalette( size );
90 		return palette[i];
91 }
92 
GetPlayerNum(const User & user) const93 int IBattle::GetPlayerNum( const User& user ) const
94 {
95     for (user_map_t::size_type i = 0; i < GetNumUsers(); i++)
96     {
97         if ( &GetUser(i) == &user ) return i;
98     }
99     ASSERT_EXCEPTION(false, _T("The player is not in this game.") );
100     return -1;
101 }
102 
103 #include <algorithm>
104 class DismissColor {
105     protected:
106         typedef std::vector<wxColour>
107             ColorVec;
108         const ColorVec& m_other;
109 
110     public:
DismissColor(const ColorVec & other)111         DismissColor( const ColorVec& other )
112             : m_other( other )
113         {}
114 
operator ()(wxColor to_check)115     bool operator() ( wxColor to_check ) {
116         return std::find ( m_other.begin(), m_other.end(), to_check ) != m_other.end();
117     }
118 };
119 
120 class AreColoursSimilarProxy {
121     int m_mindiff;
122 
123     public:
AreColoursSimilarProxy(int mindiff)124         AreColoursSimilarProxy( int mindiff )
125             : m_mindiff ( mindiff )
126         {}
127 
operator ()(wxColor a,wxColor b)128         bool operator() ( wxColor a, wxColor b ) {
129                 return AreColoursSimilar( a, b, m_mindiff );
130         }
131 };
132 
GetFreeColour(User *) const133 wxColour IBattle::GetFreeColour( User * ) const
134 {
135     typedef std::vector<wxColour>
136         ColorVec;
137 
138     ColorVec current_used_colors;
139     for ( user_map_t::size_type i = 0; i < GetNumUsers(); ++i ) {
140         UserBattleStatus& bs = GetUser( i ).BattleStatus();
141         current_used_colors.push_back( bs.colour );
142     }
143 
144     int inc = 1;
145     while ( true ) {
146         ColorVec fixcolourspalette = GetFixColoursPalette( m_teams_sizes.size() + inc++ );
147 
148         ColorVec::iterator fixcolourspalette_new_end = std::unique( fixcolourspalette.begin(), fixcolourspalette.end(), AreColoursSimilarProxy( 20 ) );
149 
150         fixcolourspalette_new_end = std::remove_if( fixcolourspalette.begin(), fixcolourspalette.end(), DismissColor( current_used_colors ) );
151 
152         if ( fixcolourspalette_new_end != fixcolourspalette.begin() )
153             return (*fixcolourspalette.begin());
154     }
155 }
156 
GetFreeColour(User & for_whom) const157 wxColour IBattle::GetFreeColour( User &for_whom ) const
158 {
159     return GetFreeColour( &for_whom );
160 }
161 
162 
GetNewColour() const163 wxColour IBattle::GetNewColour() const
164 {
165     return GetFreeColour();
166 }
167 
ColourDifference(const wxColour & a,const wxColour & b) const168 int IBattle::ColourDifference(const wxColour &a, const wxColour &b)  const// returns max difference of r,g,b.
169 {
170     return std::max(abs(a.Red()-b.Red()),std::max(abs(a.Green()-b.Green()),abs(a.Blue()-b.Blue())));
171 
172 }
173 
GetFreeTeam(bool excludeme) const174 int IBattle::GetFreeTeam( bool excludeme ) const
175 {
176     int lowest = 0;
177     bool changed = true;
178     while ( changed )
179     {
180         changed = false;
181         for ( user_map_t::size_type i = 0; i < GetNumUsers(); i++ )
182         {
183 						User& user = GetUser( i );
184             if ( ( &user == &GetMe() ) && excludeme ) continue;
185             if ( user.BattleStatus().spectator ) continue;
186             if ( user.BattleStatus().team == lowest )
187             {
188                 lowest++;
189                 changed = true;
190             }
191         }
192     }
193     return lowest;
194 }
195 
GetClosestFixColour(const wxColour & col,const std::vector<int> & excludes,int difference) const196 int IBattle::GetClosestFixColour(const wxColour &col, const std::vector<int> &excludes, int difference) const
197 {
198     std::vector<wxColour> palette = GetFixColoursPalette( m_teams_sizes.size() + 1 );
199     int result=0;
200     int t1=palette.size();
201     int t2=excludes.size();
202     wxLogMessage(_T("GetClosestFixColour %d %d"),t1,t2);
203     for (size_t i=0;i<palette.size();++i)
204     {
205         if ((i>=excludes.size()) || (!excludes[i]))
206         {
207             if (AreColoursSimilar( palette[i],col, difference ))
208             {
209                 return i;
210             }
211         }
212     }
213     return result;
214 }
215 
216 
SendHostInfo(HostInfo)217 void IBattle::SendHostInfo( HostInfo /*unused*/ )
218 {
219 }
220 
SendHostInfo(const wxString &)221 void IBattle::SendHostInfo( const wxString& /*unused*/ )
222 {
223 }
224 
Update(const wxString &)225 void IBattle::Update ( const wxString& /*unused*/)
226 {
227 }
228 
OnUserAdded(User & user)229 User& IBattle::OnUserAdded( User& user )
230 {
231     UserList::AddUser( user );
232 		UserBattleStatus& bs = user.BattleStatus();
233     bs.spectator = false;
234     bs.ready = false;
235     bs.sync = SYNC_UNKNOWN;
236     if ( !bs.IsBot() && IsFounderMe() && GetBattleType() == BT_Played )
237     {
238 			bs.team = GetFreeTeam( &user == &GetMe() );
239 			bs.ally = GetFreeAlly( &user == &GetMe() );
240 			bs.colour = GetFreeColour( user );
241     }
242     if ( IsFounderMe() && ( ( bs.pos.x < 0 ) || ( bs.pos.y < 0 ) ) )
243     {
244     	 UserPosition& pos = bs.pos;
245     	 pos = GetFreePosition();
246     	 UserPositionChanged( user );
247     }
248 	if ( !bs.spectator )
249 	{
250 		PlayerJoinedAlly( bs.ally );
251 		PlayerJoinedTeam( bs.team );
252 	}
253 	if ( bs.spectator && IsFounderMe() ) m_opts.spectators++;
254 	if ( !bs.spectator && !bs.IsBot() )
255 	{
256 		if ( bs.ready ) m_players_ready++;
257 		if ( bs.sync) m_players_sync++;
258 		if ( !bs.ready || !bs.sync ) m_ready_up_map[user.GetNick()] = time(0);
259 		if ( bs.ready && bs.sync ) m_players_ok++;
260 	}
261     return user;
262 }
263 
OnBotAdded(const wxString & nick,const UserBattleStatus & bs)264 User& IBattle::OnBotAdded( const wxString& nick, const UserBattleStatus& bs )
265 {
266 		m_internal_bot_list[nick] = User( nick );
267 		User& user = m_internal_bot_list[nick];
268 		user.UpdateBattleStatus( bs );
269 		User& usr = OnUserAdded( user );
270 		return usr;
271 }
272 
GetNumBots() const273 unsigned int IBattle::GetNumBots() const
274 {
275 		return m_internal_bot_list.size();
276 }
277 
GetNumPlayers() const278 unsigned int IBattle::GetNumPlayers() const
279 {
280 		return GetNumUsers() - GetNumBots();
281 }
282 
GetNumActivePlayers() const283 unsigned int IBattle::GetNumActivePlayers() const
284 {
285 		return GetNumPlayers() - m_opts.spectators;
286 }
287 
OnUserBattleStatusUpdated(User & user,UserBattleStatus status)288 void IBattle::OnUserBattleStatusUpdated( User &user, UserBattleStatus status )
289 {
290 
291     UserBattleStatus previousstatus = user.BattleStatus();
292 
293     user.UpdateBattleStatus( status );
294 	unsigned int oldspeccount = m_opts.spectators;
295 	m_opts.spectators = 0;
296 	m_players_sync = 0;
297 	m_players_ready = 0;
298 	m_players_ok = 0;
299 	m_teams_sizes.clear();
300 	m_ally_sizes.clear();
301 	for ( unsigned int i = 0; i < GetNumUsers(); i++ )
302 	{
303 		User& loopuser = GetUser( i );
304 		UserBattleStatus& loopstatus = loopuser.BattleStatus();
305 		if ( loopstatus.spectator ) m_opts.spectators++;
306 		if ( !loopstatus.IsBot() )
307 		{
308 			if ( !loopstatus.spectator )
309 			{
310 				if ( loopstatus.ready && loopstatus.spectator ) m_players_ready++;
311 				if ( loopstatus.sync ) m_players_sync++;
312 				if ( loopstatus.ready && loopstatus.sync ) m_players_ok++;
313 				PlayerJoinedTeam( loopstatus.team );
314 				PlayerJoinedAlly( loopstatus.ally );
315 			}
316 		}
317 	}
318 	if ( oldspeccount != m_opts.spectators  )
319 	{
320 		if ( IsFounderMe() ) SendHostInfo( HI_Spectators );
321 	}
322 	if ( !status.IsBot() )
323 	{
324 		if ( ( status.ready && status.sync ) || status.spectator )
325 		{
326 			std::map<wxString, time_t>::iterator itor = m_ready_up_map.find( user.GetNick() );
327 			if ( itor != m_ready_up_map.end() )
328 			{
329 				m_ready_up_map.erase( itor );
330 			}
331 		}
332 		if ( ( !status.ready || !status.sync ) && !status.spectator )
333 		{
334 			std::map<wxString, time_t>::iterator itor = m_ready_up_map.find( user.GetNick() );
335 			if ( itor == m_ready_up_map.end() )
336 			{
337 				m_ready_up_map[user.GetNick()] = time(0);
338 			}
339 		}
340 	}
341 }
342 
ShouldAutoStart() const343 bool IBattle::ShouldAutoStart() const
344 {
345 	if ( GetInGame() ) return false;
346 	if ( !IsLocked() && ( GetNumActivePlayers() < m_opts.maxplayers ) ) return false; // proceed checking for ready & symc players only if the battle is full or locked
347 	if ( !IsEveryoneReady() ) return false;
348 	return true;
349 }
350 
OnUserRemoved(User & user)351 void IBattle::OnUserRemoved( User& user )
352 {
353     UserBattleStatus& bs = user.BattleStatus();
354     if ( !bs.spectator )
355     {
356         PlayerLeftTeam( bs.team );
357         PlayerLeftAlly( bs.ally );
358     }
359 	if ( !bs.spectator && !bs.IsBot() )
360 	{
361 		if ( bs.ready ) m_players_ready--;
362 		if ( bs.sync ) m_players_sync--;
363 		if ( bs.ready && bs.sync ) m_players_ok--;
364 	}
365     if ( IsFounderMe() && bs.spectator )
366     {
367         m_opts.spectators--;
368         SendHostInfo( HI_Spectators );
369     }
370     if ( &user == &GetMe() )
371     {
372         OnSelfLeftBattle();
373     }
374     UserList::RemoveUser( user.GetNick() );
375     if ( !bs.IsBot() )
376         user.SetBattle( 0 );
377     else
378     {
379     	UserVecIter itor = m_internal_bot_list.find( user.GetNick() );
380         if ( itor != m_internal_bot_list.end() )
381         {
382             m_internal_bot_list.erase( itor );
383         }
384     }
385 }
386 
387 
IsEveryoneReady() const388 bool IBattle::IsEveryoneReady() const
389 {
390 	for ( unsigned int i = 0; i < GetNumPlayers(); i++ )
391 	{
392 		User& usr = GetUser( i );
393 		UserBattleStatus& status = usr.BattleStatus();
394 		if ( status.IsBot() ) continue;
395 		if ( status.spectator ) continue;
396 		if ( &usr == &GetMe() ) continue;
397 		if ( !status.ready ) return false;
398 		if ( !status.sync ) return false;
399 	}
400 	return true;
401 }
402 
403 
404 
AddStartRect(unsigned int allyno,unsigned int left,unsigned int top,unsigned int right,unsigned int bottom)405 void IBattle::AddStartRect( unsigned int allyno, unsigned int left, unsigned int top, unsigned int right, unsigned int bottom )
406 {
407     BattleStartRect sr;
408 
409     sr.ally = allyno;
410     sr.left = left;
411     sr.top = top;
412     sr.right = right;
413     sr.bottom = bottom;
414     sr.toadd = true;
415     sr.todelete = false;
416     sr.toresize = false;
417     sr.exist = true;
418 
419     m_rects[allyno] = sr;
420 }
421 
422 
423 
RemoveStartRect(unsigned int allyno)424 void IBattle::RemoveStartRect( unsigned int allyno )
425 {
426     std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
427 	if( rect_it == m_rects.end() )
428 		return;
429 
430 	rect_it->second.todelete = true;
431     //BattleStartRect sr = m_rects[allyno];
432     //sr.todelete = true;
433     //m_rects[allyno] = sr;
434 }
435 
436 
ResizeStartRect(unsigned int allyno)437 void IBattle::ResizeStartRect( unsigned int allyno )
438 {
439     std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
440 	if( rect_it == m_rects.end() )
441 		return;
442 
443 	rect_it->second.toresize = true;
444     //BattleStartRect sr = m_rects[allyno];
445     //&&sr.toresize = true;
446     //m_rects[allyno] = sr;
447 }
448 
449 
StartRectRemoved(unsigned int allyno)450 void IBattle::StartRectRemoved( unsigned int allyno )
451 {
452 	std::map<unsigned int,BattleStartRect>::const_iterator rect_it = m_rects.find(allyno);
453 	if( rect_it == m_rects.end() )
454 		return;
455 
456 	if ( rect_it->second.todelete ) m_rects.erase(allyno);
457 }
458 
459 
StartRectResized(unsigned int allyno)460 void IBattle::StartRectResized( unsigned int allyno )
461 {
462     std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
463 	if( rect_it == m_rects.end() )
464 		return;
465 
466 	rect_it->second.toresize = false;
467     //BattleStartRect sr = m_rects[allyno];
468     //sr.toresize = false;
469     //m_rects[allyno] = sr;
470 }
471 
472 
StartRectAdded(unsigned int allyno)473 void IBattle::StartRectAdded( unsigned int allyno )
474 {
475     std::map<unsigned int,BattleStartRect>::iterator rect_it = m_rects.find(allyno);
476 	if( rect_it == m_rects.end() )
477 		return;
478 
479 	rect_it->second.toadd = false;
480     //BattleStartRect sr = m_rects[allyno];
481     //sr.toadd = false;
482     //m_rects[allyno] = sr;
483 }
484 
485 
GetStartRect(unsigned int allyno) const486 BattleStartRect IBattle::GetStartRect( unsigned int allyno ) const
487 {
488 	std::map<unsigned int,BattleStartRect>::const_iterator rect_it = m_rects.find(allyno);
489 	if( rect_it != m_rects.end() )
490 		return (*rect_it).second;
491 	return BattleStartRect();
492 }
493 
494 //total number of start rects
GetNumRects() const495 unsigned int IBattle::GetNumRects() const
496 {
497     return m_rects.size();
498 }
499 
500 //key of last start rect in the map
GetLastRectIdx() const501 unsigned int IBattle::GetLastRectIdx() const
502 {
503 	if(GetNumRects() > 0)
504 		return m_rects.rbegin()->first;
505 
506 	return 0;
507 
508 }
509 
510 //return  the lowest currently unused key in the map of rects.
GetNextFreeRectIdx() const511 unsigned int IBattle::GetNextFreeRectIdx() const
512 {
513 	//check for unused allyno keys
514 	for(unsigned int i = 0; i <= GetLastRectIdx(); i++)
515 	{
516 		if(!GetStartRect(i).IsOk())
517 			return i;
518 	}
519 	return GetNumRects(); //if all rects are in use, or no elements exist, return first possible available allyno.
520 }
521 
ClearStartRects()522 void IBattle::ClearStartRects()
523 {
524     m_rects.clear();
525 }
526 
ForceSide(User & user,int side)527 void IBattle::ForceSide( User& user, int side )
528 {
529 	if ( IsFounderMe() || user.BattleStatus().IsBot() )
530 	{
531 		 user.BattleStatus().side = side;
532 	}
533 }
534 
ForceTeam(User & user,int team)535 void IBattle::ForceTeam( User& user, int team )
536 {
537   if ( IsFounderMe() || user.BattleStatus().IsBot() )
538   {
539 		if ( !user.BattleStatus().spectator )
540 		{
541 			PlayerLeftTeam( user.BattleStatus().team );
542 			PlayerJoinedTeam( team );
543 		}
544 		user.BattleStatus().team = team;
545   }
546 }
547 
548 
ForceAlly(User & user,int ally)549 void IBattle::ForceAlly( User& user, int ally )
550 {
551 
552   if ( IsFounderMe() || user.BattleStatus().IsBot() )
553   {
554 		if ( !user.BattleStatus().spectator )
555 		{
556 			PlayerLeftAlly( user.BattleStatus().ally );
557 			PlayerJoinedAlly( ally );
558 		}
559 		user.BattleStatus().ally = ally;
560   }
561 
562 }
563 
564 
ForceColour(User & user,const wxColour & col)565 void IBattle::ForceColour( User& user, const wxColour& col )
566 {
567   if ( IsFounderMe() || user.BattleStatus().IsBot() )
568 		{
569 			 user.BattleStatus().colour = col;
570 		}
571 
572 }
573 
PlayerJoinedTeam(int team)574 void IBattle::PlayerJoinedTeam( int team )
575 {
576 	std::map<int, int>::const_iterator itor = m_teams_sizes.find( team );
577 	if ( itor == m_teams_sizes.end() ) m_teams_sizes[team] = 1;
578 	else m_teams_sizes[team] = m_teams_sizes[team] + 1;
579 }
580 
PlayerJoinedAlly(int ally)581 void IBattle::PlayerJoinedAlly( int ally )
582 {
583 	std::map<int, int>::const_iterator iter = m_ally_sizes.find( ally );
584 	if ( iter == m_ally_sizes.end() ) m_ally_sizes[ally] = 1;
585 	else m_ally_sizes[ally] = m_ally_sizes[ally] + 1;
586 }
587 
PlayerLeftTeam(int team)588 void IBattle::PlayerLeftTeam( int team )
589 {
590 	std::map<int, int>::iterator itor = m_teams_sizes.find( team );
591 	if ( itor != m_teams_sizes.end() )
592 	{
593 		 itor->second = itor->second -1;
594 		if ( itor->second == 0 )
595 		{
596 			m_teams_sizes.erase( itor );
597 		}
598 	}
599 }
600 
PlayerLeftAlly(int ally)601 void IBattle::PlayerLeftAlly( int ally )
602 {
603 	std::map<int, int>::iterator iter = m_ally_sizes.find( ally );
604 	if ( iter != m_ally_sizes.end() )
605 	{
606 		iter->second = iter->second - 1;
607 		if ( iter->second == 0 )
608 		{
609 			m_ally_sizes.erase( iter );
610 		}
611 	}
612 }
613 
ForceSpectator(User & user,bool spectator)614 void IBattle::ForceSpectator( User& user, bool spectator )
615 {
616 		if ( IsFounderMe() || user.BattleStatus().IsBot() )
617 		{
618 			UserBattleStatus& status = user.BattleStatus();
619 
620 			if ( !status.spectator ) // leaving spectator status
621 			{
622 				PlayerJoinedTeam( status.team );
623 				PlayerJoinedAlly( status.ally );
624 				if ( status.ready && !status.IsBot() ) m_players_ready++;
625 			}
626 
627 			if (spectator) // entering spectator status
628 			{
629 				PlayerLeftTeam( status.team );
630 				PlayerLeftAlly( status.ally );
631 				if ( status.ready && !status.IsBot() ) m_players_ready--;
632 			}
633 
634 			if ( IsFounderMe() )
635 			{
636 				if ( status.spectator != spectator )
637 				{
638 					if ( spectator )
639 					{
640 							m_opts.spectators++;
641 					}
642 					else
643 					{
644 							m_opts.spectators--;
645 					}
646 					SendHostInfo( HI_Spectators );
647 				}
648 			}
649 			user.BattleStatus().spectator = spectator;
650 		}
651 }
652 
SetHandicap(User & user,int handicap)653 void IBattle::SetHandicap( User& user, int handicap)
654 {
655 		if ( IsFounderMe() || user.BattleStatus().IsBot() )
656 		{
657 			 user.BattleStatus().handicap = handicap;
658 		}
659 }
660 
661 
KickPlayer(User & user)662 void IBattle::KickPlayer( User& user )
663 {
664 		if ( IsFounderMe() || user.BattleStatus().IsBot() )
665 		{
666 			 OnUserRemoved( user );
667 		}
668 }
669 
GetFreeAlly(bool excludeme) const670 int IBattle::GetFreeAlly( bool excludeme ) const
671 {
672   int lowest = 0;
673   bool changed = true;
674   while ( changed )
675    {
676     changed = false;
677     for ( unsigned int i = 0; i < GetNumUsers(); i++ )
678     {
679       User& user = GetUser( i );
680       if ( ( &user == &GetMe() ) && excludeme ) continue;
681       if ( user.BattleStatus().spectator ) continue;
682       if ( user.BattleStatus().ally == lowest )
683       {
684         lowest++;
685         changed = true;
686       }
687     }
688   }
689   return lowest;
690 }
691 
GetFreePosition()692 UserPosition IBattle::GetFreePosition()
693 {
694 	UserPosition ret;
695   LSL::UnitsyncMap map = LoadMap();
696   for ( int i = 0; i < int(map.info.positions.size()); i++ )
697 	{
698     bool taken = false;
699     for ( unsigned int bi = 0; bi < GetNumUsers(); bi++ )
700     {
701       User& user = GetUser( bi );
702       UserBattleStatus& status = user.BattleStatus();
703       if ( status.spectator ) continue;
704       if ( ( map.info.positions[i].x == status.pos.x ) && ( map.info.positions[i].y == status.pos.y ) )
705       {
706         taken = true;
707         break;
708       }
709     }
710     if ( !taken )
711     {
712       ret.x = LSL::Util::Clamp(map.info.positions[i].x, 0, map.info.width);
713       ret.y = LSL::Util::Clamp(map.info.positions[i].y, 0, map.info.height);
714       return ret;
715     }
716   }
717   ret.x = map.info.width / 2;
718   ret.y = map.info.height / 2;
719   return ret;
720 }
721 
722 
SetHostMap(const wxString & _mapname,const wxString & _hash)723 void IBattle::SetHostMap(const wxString& _mapname, const wxString& _hash)
724 {
725 	assert(!_mapname.empty());
726   const std::string mapname(STD_STRING(_mapname));
727   const std::string hash(STD_STRING(_hash));
728   if ( mapname != m_host_map.name || hash != m_host_map.hash )
729   {
730     m_map_loaded = false;
731     m_host_map.name = mapname;
732     m_host_map.hash = hash;
733     if ( !m_host_map.hash.empty() && m_host_map.hash != "0" )
734 		m_map_exists = LSL::usync().MapExists( m_host_map.name, m_host_map.hash );
735 	else
736 		m_map_exists = LSL::usync().MapExists( m_host_map.name );
737 	#ifndef __WXMSW__ //!TODO why not on win?
738 		if ( m_map_exists && !spring().IsRunning() )
739 			LSL::usync().PrefetchMap( m_host_map.name );
740 	#endif
741   }
742 }
743 
744 
SetLocalMap(const LSL::UnitsyncMap & map)745 void IBattle::SetLocalMap(const LSL::UnitsyncMap& map)
746 {
747 	assert(!map.name.empty());
748   if ( map.name != m_local_map.name || map.hash != m_local_map.hash ) {
749     m_local_map = map;
750     m_map_loaded = true;
751     if ( !m_host_map.hash.empty() && m_host_map.hash != "0" )
752 		m_map_exists = LSL::usync().MapExists( m_host_map.name, m_host_map.hash );
753 	else
754 		m_map_exists = LSL::usync().MapExists( m_host_map.name );
755     #ifndef __WXMSW__
756 		if ( m_map_exists && !spring().IsRunning() )
757 			LSL::usync().PrefetchMap( m_host_map.name );
758     #endif
759     if ( IsFounderMe() ) // save all rects infos
760     {
761 
762     }
763   }
764 }
765 
766 
LoadMap()767 const LSL::UnitsyncMap& IBattle::LoadMap()
768 {
769   if (( !m_map_loaded ) && (!m_host_map.name.empty())){
770     try {
771       ASSERT_EXCEPTION( m_map_exists, _T("Map does not exist: ") + TowxString(m_host_map.name) );
772       m_local_map = LSL::usync().GetMapEx( m_host_map.name );
773 	  bool options_loaded = CustomBattleOptions().loadOptions( LSL::OptionsWrapper::MapOption, m_host_map.name );
774 	  ASSERT_EXCEPTION( options_loaded, _T("couldn't load the map options") );
775       m_map_loaded = true;
776 
777     } catch (...) {}
778   }
779   return m_local_map;
780 }
781 
782 
GetHostMapName() const783 wxString IBattle::GetHostMapName() const
784 {
785   return TowxString(m_host_map.name);
786 }
787 
788 
GetHostMapHash() const789 wxString IBattle::GetHostMapHash() const
790 {
791   return TowxString(m_host_map.hash);
792 }
793 
794 
SetHostMod(const wxString & _modname,const wxString & _hash)795 void IBattle::SetHostMod( const wxString& _modname, const wxString& _hash )
796 {
797     const std::string modname(STD_STRING(_modname));
798     const std::string hash(STD_STRING(_hash));
799   if ( m_host_mod.name != modname || m_host_mod.hash != hash )
800   {
801     m_mod_loaded = false;
802     m_host_mod.name = modname;
803     m_host_mod.hash = hash;
804     if ( !m_host_mod.hash.empty() && m_host_mod.hash != "0" )
805         m_mod_exists = LSL::usync().ModExists( m_host_mod.name, m_host_mod.hash );
806     else
807         m_mod_exists = LSL::usync().ModExists( m_host_mod.name );
808   }
809 }
810 
811 
SetLocalMod(const LSL::UnitsyncMod & mod)812 void IBattle::SetLocalMod( const LSL::UnitsyncMod& mod )
813 {
814   if ( mod.name != m_local_mod.name || mod.hash != m_local_mod.hash )
815   {
816     m_previous_local_mod_name = TowxString(m_local_mod.name);
817     m_local_mod = mod;
818     m_mod_loaded = true;
819     if ( !m_host_mod.hash.empty() && m_host_mod.hash != "0" )
820         m_mod_exists = LSL::usync().ModExists( m_host_mod.name, m_host_mod.hash );
821     else
822         m_mod_exists = LSL::usync().ModExists( m_host_mod.name );
823   }
824 }
825 
826 
LoadMod()827 const LSL::UnitsyncMod& IBattle::LoadMod()
828 {
829 	assert(!m_host_mod.name.empty());
830   if ( !m_mod_loaded )
831    {
832     try {
833       ASSERT_EXCEPTION( m_mod_exists, _T("Mod does not exist.") );
834       m_local_mod = LSL::usync().GetMod( m_host_mod.name );
835 	  bool options_loaded = CustomBattleOptions().loadOptions( LSL::OptionsWrapper::ModOption, m_host_mod.name );
836 	  ASSERT_EXCEPTION( options_loaded, _T("couldn't load the mod options") );
837       m_mod_loaded = true;
838     } catch (...) {}
839   }
840   return m_local_mod;
841 }
842 
843 
GetHostModName() const844 wxString IBattle::GetHostModName() const
845 {
846   return TowxString(m_host_mod.name);
847 }
848 
849 
GetHostModHash() const850 wxString IBattle::GetHostModHash() const
851 {
852   return TowxString(m_host_mod.hash);
853 }
854 
855 
MapExists() const856 bool IBattle::MapExists() const
857 {
858   return m_map_exists;
859 //  return LSL::usync().MapExists( m_map.name, m_map.hash );
860 }
861 
862 
ModExists() const863 bool IBattle::ModExists() const
864 {
865   return m_mod_exists;
866 //  return LSL::usync().ModExists( m_host_mod.name, m_host_mod.hash );
867 }
868 
RestrictUnit(const wxString & unitname,int count)869 void IBattle::RestrictUnit( const wxString& unitname, int count )
870 {
871   m_restricted_units[ unitname ] = count;
872 }
873 
874 
UnrestrictUnit(const wxString & unitname)875 void IBattle::UnrestrictUnit( const wxString& unitname )
876 {
877   std::map<wxString,int>::iterator pos = m_restricted_units.find( unitname );
878   if ( pos == m_restricted_units.end() ) return;
879   m_restricted_units.erase( pos );
880 }
881 
882 
UnrestrictAllUnits()883 void IBattle::UnrestrictAllUnits()
884 {
885   m_restricted_units.clear();
886 }
887 
888 
RestrictedUnits() const889 std::map<wxString,int> IBattle::RestrictedUnits() const
890 {
891   return m_restricted_units;
892 }
893 
OnSelfLeftBattle()894 void IBattle::OnSelfLeftBattle()
895 {
896 	GetMe().BattleStatus().spectator = false; // always reset back yourself to player when rejoining
897 	if ( m_timer ) m_timer->Stop();
898 	delete m_timer;
899 	m_timer = 0;
900     m_is_self_in = false;
901 	for( size_t j = 0; j < GetNumUsers(); ++j  )
902 	{
903 		User& u = GetUser( j );
904 		if ( u.GetBattleStatus().IsBot() )
905 		{
906 			OnUserRemoved( u );
907 			ui().OnUserLeftBattle( *this, u, true );
908 			j--;
909 		}
910 	}
911     ClearStartRects();
912     m_teams_sizes.clear();
913     m_ally_sizes.clear();
914     m_players_ready = 0;
915     m_players_sync = 0;
916 	m_players_ok = 0;
917 	LSL::usync().UnSetCurrentMod(); //left battle
918 }
919 
OnUnitsyncReloaded(wxEvent &)920 void IBattle::OnUnitsyncReloaded( wxEvent& /*data*/ )
921 {
922     if ( !m_host_mod.hash.empty() && m_host_mod.hash != "0" )
923         m_mod_exists = LSL::usync().ModExists( m_host_mod.name, m_host_mod.hash);
924     else
925         m_mod_exists = LSL::usync().ModExists( m_host_mod.name );
926     if ( !m_host_map.hash.empty() && m_host_map.hash != "0" )
927         m_map_exists = LSL::usync().MapExists( m_host_map.name, m_host_map.hash );
928     else
929         m_map_exists = LSL::usync().MapExists( m_host_map.name );
930 }
931 
932 
FixPresetName(const wxString & name)933 static wxString FixPresetName( const wxString& name )
934 {
935   // look name up case-insensitively
936   const wxArrayString& presetList = sett().GetPresetList();
937   int index = presetList.Index( name, false /*case insensitive*/ );
938   if ( index == -1 ) return wxEmptyString;
939 
940   // set preset to the actual name, with correct case
941   return presetList[index];
942 }
943 
944 
LoadOptionsPreset(const wxString & name)945 bool IBattle::LoadOptionsPreset( const wxString& name )
946 {
947   wxString preset = FixPresetName(name);
948   if (preset == wxEmptyString) return false; //preset not found
949   m_preset = preset;
950 
951   for ( unsigned int i = 0; i < LSL::OptionsWrapper::LastOption; i++)
952   {
953     std::map<wxString,wxString> options = sett().GetHostingPreset( m_preset, i );
954     if ( (LSL::OptionsWrapper::GameOption)i != LSL::OptionsWrapper::PrivateOptions )
955     {
956 	  for ( std::map<wxString,wxString>::const_iterator itor = options.begin(); itor != options.end(); ++itor )
957       {
958             wxLogWarning( itor->first + _T(" ::: ") + itor->second );
959             CustomBattleOptions().setSingleOption( STD_STRING(itor->first),
960                                                    STD_STRING(itor->second),
961                                                    (LSL::OptionsWrapper::GameOption)i );
962       }
963     }
964     else
965     {
966       if ( !options[_T("mapname")].IsEmpty() )
967       {
968         if (LSL::usync().MapExists(STD_STRING(options[_T("mapname")]))) {
969             LSL::UnitsyncMap map = LSL::usync().GetMapEx(STD_STRING(options[_T("mapname")]) );
970             SetLocalMap( map );
971             SendHostInfo( HI_Map );
972         }
973         else if ( !ui().OnPresetRequiringMap( options[_T("mapname")] ) ) {
974             //user didn't want to download the missing map, so set to empty to not have it tried to be loaded again
975             options[_T("mapname")] = wxEmptyString;
976             sett().SetHostingPreset( m_preset, i, options );
977         }
978       }
979 
980 		for( unsigned int j = 0; j <= GetLastRectIdx(); ++j ) {
981 			if ( GetStartRect( j ).IsOk() )
982 				RemoveStartRect(j); // remove all rects that might come from map presets
983 		}
984 		SendHostInfo( IBattle::HI_StartRects );
985 
986       unsigned int rectcount = s2l( options[_T("numrects")] );
987       for ( unsigned int loadrect = 0; loadrect < rectcount; loadrect++)
988       {
989         int ally = s2l(options[_T("rect_") + TowxString(loadrect) + _T("_ally")]);
990         if ( ally == 0 ) continue;
991         AddStartRect( ally - 1, s2l(options[_T("rect_") + TowxString(loadrect) + _T("_left")]), s2l(options[_T("rect_") + TowxString(loadrect) + _T("_top")]), s2l(options[_T("rect_") + TowxString(loadrect) + _T("_right")]), s2l(options[_T("rect_") + TowxString(loadrect) + _T("_bottom")]) );
992       }
993       SendHostInfo( HI_StartRects );
994 
995       wxStringTokenizer tkr( options[_T("restrictions")], _T('\t') );
996       m_restricted_units.clear();
997       while( tkr.HasMoreTokens() )
998       {
999       	wxString unitinfo = tkr.GetNextToken();
1000       	RestrictUnit( unitinfo.BeforeLast(_T('=')), s2l( unitinfo.AfterLast(_T('=')) ) );
1001       }
1002       SendHostInfo( HI_Restrictions );
1003 	  Update( wxFormat( _T("%d_restrictions") ) % LSL::OptionsWrapper::PrivateOptions );
1004 
1005     }
1006   }
1007   SendHostInfo( HI_Send_All_opts );
1008   ui().ReloadPresetList();
1009   return true;
1010 }
1011 
1012 
SaveOptionsPreset(const wxString & name)1013 void IBattle::SaveOptionsPreset( const wxString& name )
1014 {
1015   m_preset = FixPresetName(name);
1016   if (m_preset == wxEmptyString) m_preset = name; //new preset
1017 
1018   for ( int i = 0; i < (int)LSL::OptionsWrapper::LastOption; i++)
1019   {
1020     if ( (LSL::OptionsWrapper::GameOption)i != LSL::OptionsWrapper::PrivateOptions )
1021     {
1022       const auto opts = CustomBattleOptions().getOptionsMap( (LSL::OptionsWrapper::GameOption)i );
1023       std::map<wxString, wxString> wopts;
1024       for( const auto pair : opts)
1025           wopts.insert(std::make_pair(TowxString(pair.first), TowxString(pair.second)));
1026       sett().SetHostingPreset( m_preset, (LSL::OptionsWrapper::GameOption)i, wopts);
1027     }
1028     else
1029     {
1030       std::map<wxString,wxString> opts;
1031       opts[_T("mapname")] = GetHostMapName();
1032       unsigned int validrectcount = 0;
1033       if ( LSL::Util::FromString<long>(
1034                CustomBattleOptions().getSingleValue("startpostype", LSL::OptionsWrapper::EngineOption ) ) == ST_Choose )
1035       {
1036         unsigned int boxcount = GetLastRectIdx();
1037         for ( unsigned int boxnum = 0; boxnum <= boxcount; boxnum++ )
1038         {
1039           BattleStartRect rect = GetStartRect( boxnum );
1040           if ( rect.IsOk() )
1041           {
1042             opts[_T("rect_") + TowxString(validrectcount) + _T("_ally")] = TowxString( rect.ally + 1 );
1043             opts[_T("rect_") + TowxString(validrectcount) + _T("_left")] = TowxString( rect.left );
1044             opts[_T("rect_") + TowxString(validrectcount) + _T("_top")] = TowxString( rect.top );
1045             opts[_T("rect_") + TowxString(validrectcount) + _T("_bottom")] = TowxString( rect.bottom );
1046             opts[_T("rect_") + TowxString(validrectcount) + _T("_right")] = TowxString( rect.right );
1047             validrectcount++;
1048           }
1049         }
1050       }
1051       opts[_T("numrects")] = TowxString( validrectcount );
1052 
1053       wxString restrictionsstring;
1054 	  for ( std::map<wxString, int>::const_iterator itor = m_restricted_units.begin(); itor != m_restricted_units.end(); ++itor )
1055       {
1056         restrictionsstring << itor->first << _T('=') << TowxString(itor->second) << _T('\t');
1057       }
1058       opts[_T("restrictions")] = restrictionsstring;
1059 
1060       sett().SetHostingPreset( m_preset, (LSL::OptionsWrapper::GameOption)i, opts );
1061     }
1062   }
1063   sett().SaveSettings();
1064   ui().ReloadPresetList();
1065 }
1066 
1067 
GetCurrentPreset()1068 wxString IBattle::GetCurrentPreset()
1069 {
1070   return m_preset;
1071 }
1072 
1073 
DeletePreset(const wxString & name)1074 void IBattle::DeletePreset( const wxString& name )
1075 {
1076   wxString preset = FixPresetName(name);
1077   if ( m_preset == preset ) m_preset = wxEmptyString;
1078   sett().DeletePreset( preset );
1079   ui().ReloadPresetList();
1080 }
1081 
GetPresetList()1082 wxArrayString IBattle::GetPresetList()
1083 {
1084   return sett().GetPresetList();
1085 }
1086 
UserPositionChanged(const User &)1087 void IBattle::UserPositionChanged( const User& /*unused*/ )
1088 {
1089 }
1090 
AddUserFromDemo(User & user)1091 void IBattle::AddUserFromDemo( User& user )
1092 {
1093 	user.BattleStatus().isfromdemo = true;
1094 	m_internal_user_list[user.GetNick()] = user;
1095 	UserList::AddUser( m_internal_user_list[user.GetNick()] );
1096 }
1097 
SetProxy(const wxString & value)1098 void IBattle::SetProxy( const wxString& value )
1099 {
1100 	m_opts.proxyhost = value;
1101 }
1102 
IsProxy() const1103 bool IBattle::IsProxy() const
1104 {
1105 	return !m_opts.proxyhost.IsEmpty();
1106 }
1107 
GetProxy() const1108 wxString IBattle::GetProxy() const
1109 {
1110 	return m_opts.proxyhost;
1111 }
1112 
IsFounderMe() const1113 bool IBattle::IsFounderMe() const
1114 {
1115 	return ( ( m_opts.founder == GetMe().GetNick() ) || ( IsProxy()  && !m_generating_script ) );
1116 }
1117 
IsFounder(const User & user) const1118 bool IBattle::IsFounder( const User& user ) const
1119 {
1120     if ( UserExists( m_opts.founder ) ) {
1121     	try
1122     	{
1123         return &GetFounder() == &user;
1124 			}catch(...){return false;}
1125     }
1126     else
1127         return false;
1128 }
1129 
GetMyPlayerNum() const1130 int IBattle::GetMyPlayerNum() const
1131 {
1132     return GetPlayerNum( GetMe() );
1133 }
1134 
1135 
LoadScriptMMOpts(const wxString & sectionname,const SL::PDataList & node)1136 void IBattle::LoadScriptMMOpts( const wxString& sectionname, const SL::PDataList& node )
1137 {
1138 	if ( !node.ok() ) return;
1139 	SL::PDataList section ( node->Find(sectionname) );
1140     if ( !section.ok() ) return;
1141     LSL::OptionsWrapper& opts = CustomBattleOptions();
1142 	for ( SL::PNode n = section->First(); n != section->Last(); n = section->Next( n ) )
1143     {
1144         if ( !n.ok() ) continue;
1145             opts.setSingleOption( STD_STRING(n->Name()), STD_STRING(section->GetString( n->Name() )) );
1146     }
1147 }
1148 
LoadScriptMMOpts(const SL::PDataList & node)1149 void IBattle::LoadScriptMMOpts( const SL::PDataList& node )
1150 {
1151 	if ( !node.ok() ) return;
1152     LSL::OptionsWrapper& opts = CustomBattleOptions();
1153     auto options = opts.getOptionsMap(LSL::OptionsWrapper::EngineOption);
1154     for (const auto i : options)
1155     {
1156         opts.setSingleOption( i.first, STD_STRING(node->GetString( TowxString(i.first), TowxString(i.second))));
1157     }
1158 }
1159 
1160 //! (koshi) don't delete commented things please, they might be need in the future and i'm lazy
GetBattleFromScript(bool loadmapmod)1161 void IBattle::GetBattleFromScript( bool loadmapmod )
1162 {
1163 
1164     BattleOptions opts;
1165     std::stringstream ss ( (const char *)GetScript().mb_str(wxConvUTF8) );// no need to convert wxstring-->std::string-->std::stringstream, convert directly.
1166 	SL::PDataList script( ParseTDF(ss) );
1167 
1168 	SL::PDataList replayNode ( script->Find(_T("GAME") ) );
1169     if ( replayNode.ok() )
1170     {
1171 
1172         wxString modname = replayNode->GetString( _T("GameType") );
1173         wxString modhash = replayNode->GetString( _T("ModHash") );
1174         if ( !modhash.IsEmpty() ) modhash = MakeHashUnsigned( modhash );
1175         SetHostMod( modname, modhash );
1176 
1177         //don't have the maphash, what to do?
1178         //ui download function works with mapname if hash is empty, so works for now
1179         wxString mapname    = replayNode->GetString( _T("MapName") );
1180 			  wxString maphash    = replayNode->GetString( _T("MapHash") );
1181         if ( !maphash.IsEmpty() ) maphash = MakeHashUnsigned( maphash );
1182         SetHostMap( mapname, maphash );
1183 
1184 //        opts.ip         = replayNode->GetString( _T("HostIP") );
1185 //        opts.port       = replayNode->GetInt  ( _T("HostPort"), DEFAULT_EXTERNAL_UDP_SOURCE_PORT );
1186         opts.spectators = 0;
1187 
1188         int playernum = replayNode->GetInt  ( _T("NumPlayers"), 0);
1189         int usersnum = replayNode->GetInt  ( _T("NumUsers"), 0);
1190         if ( usersnum > 0 ) playernum = usersnum;
1191 //        int allynum = replayNode->GetInt  ( _T("NumAllyTeams"), 1);
1192 //        int teamnum = replayNode->GetInt  ( _T("NumTeams"), 1);
1193 
1194 
1195 
1196         LSL::StringVector sides;
1197         if ( loadmapmod )
1198         {
1199             sides = LSL::usync().GetSides(STD_STRING(modname));
1200         }
1201 
1202 				IBattle::TeamVec parsed_teams = GetParsedTeamsVec();
1203 				IBattle::AllyVec parsed_allies = GetParsedAlliesVec();
1204 
1205         //[PLAYERX] sections
1206         for ( int i = 0; i < playernum ; ++i )
1207         {
1208 			SL::PDataList player ( replayNode->Find( _T("PLAYER") + TowxString(i) ) );
1209 			SL::PDataList bot ( replayNode->Find( _T("AI") + TowxString(i) ) );
1210             if ( player.ok() || bot.ok() )
1211             {
1212 								if ( bot.ok() ) player = bot;
1213                 User user ( player->GetString( _T("Name") ), (player->GetString( _T("CountryCode")).Upper() ), 0);
1214                 UserBattleStatus& status = user.BattleStatus();
1215                 status.isfromdemo = true;
1216                 status.spectator = player->GetInt( _T("Spectator"), 0 );
1217                 opts.spectators += user.BattleStatus().spectator;
1218                 status.team = player->GetInt( _T("Team") );
1219 				if ( !status.spectator )
1220 				{
1221 					PlayerJoinedTeam( status.team );
1222 				}
1223                 status.sync = true;
1224                 status.ready = true;
1225                 if ( status.spectator ) m_opts.spectators++;
1226 				else
1227 				{
1228 					if ( !bot.ok() )
1229 					{
1230 						if ( status.ready) m_players_ready++;
1231 						if ( status.sync ) m_players_sync++;
1232 						if ( status.sync && status.ready ) m_players_ok++;
1233 					}
1234 				}
1235 
1236                 //! (koshi) changed this from ServerRankContainer to RankContainer
1237                 user.Status().rank = (UserStatus::RankContainer)player->GetInt( _T("Rank"), -1 );
1238 
1239                 if ( bot.ok() )
1240                 {
1241                 	status.aishortname = bot->GetString( _T("ShortName" ) );
1242                 	status.aiversion = bot->GetString( _T("Version" ) );
1243                 	int ownerindex = bot->GetInt( _T("Host" ) );
1244 					SL::PDataList aiowner ( replayNode->Find( _T("PLAYER") + TowxString(ownerindex) ) );
1245                 	if ( aiowner.ok() )
1246                 	{
1247                 		status.owner = aiowner->GetString( _T("Name") );
1248                 	}
1249                 }
1250 
1251                 IBattle::TeamInfoContainer teaminfos = parsed_teams[user.BattleStatus().team];
1252                 if ( !teaminfos.exist )
1253                 {
1254 									SL::PDataList team( replayNode->Find( _T("TEAM") + TowxString( user.BattleStatus().team ) ) );
1255 									if ( team.ok() )
1256 									{
1257 											teaminfos.exist = true;
1258 											teaminfos.TeamLeader = team->GetInt( _T("TeamLeader"), 0 );
1259 											teaminfos.StartPosX = team->GetInt( _T("StartPosX"), -1 );
1260 											teaminfos.StartPosY = team->GetInt( _T("StartPosY"), -1 );
1261 											teaminfos.AllyTeam = team->GetInt( _T("AllyTeam"), 0 );
1262 											teaminfos.RGBColor = GetColorFromFloatStrng( team->GetString( _T("RGBColor") ) );
1263 											teaminfos.SideName = team->GetString( _T("Side"), wxEmptyString );
1264 											teaminfos.Handicap = team->GetInt( _T("Handicap"), 0 );
1265                                             const int sidepos = LSL::Util::IndexInSequence(sides, STD_STRING(teaminfos.SideName));
1266 											teaminfos.SideNum = sidepos;
1267 											parsed_teams[ user.BattleStatus().team ] = teaminfos;
1268 									}
1269                 }
1270                 if ( teaminfos.exist )
1271                 {
1272 										status.ally = teaminfos.AllyTeam;
1273 										status.pos.x = teaminfos.StartPosX;
1274 										status.pos.y = teaminfos.StartPosY;
1275 										status.colour = teaminfos.RGBColor;
1276 										status.handicap = teaminfos.Handicap;
1277 										if ( !status.spectator )
1278 										{
1279 											PlayerJoinedAlly( status.ally );
1280 										}
1281 										if ( teaminfos.SideNum >= 0 ) status.side = teaminfos.SideNum;
1282 										IBattle::AllyInfoContainer allyinfos = parsed_allies[user.BattleStatus().ally];
1283 										if ( !allyinfos.exist )
1284 										{
1285 												SL::PDataList ally( replayNode->Find( _T("ALLYTEAM") + TowxString( user.BattleStatus().ally ) ) );
1286 												if ( ally.ok() )
1287 												{
1288 													allyinfos.exist = true;
1289 													allyinfos.NumAllies = ally->GetInt( _T("NumAllies"), 0 );
1290 													allyinfos.StartRectLeft = ally->GetInt( _T("StartRectLeft"), 0 );
1291 													allyinfos.StartRectTop = ally->GetInt( _T("StartRectTop"), 0 );
1292 													allyinfos.StartRectRight = ally->GetInt( _T("StartRectRight"), 0 );
1293 													allyinfos.StartRectBottom = ally->GetInt( _T("StartRectBottom"), 0 );
1294 													parsed_allies[ user.BattleStatus().ally ] = allyinfos;
1295 													AddStartRect( user.BattleStatus().ally, allyinfos.StartRectTop, allyinfos.StartRectTop, allyinfos.StartRectRight, allyinfos.StartRectBottom );
1296 												}
1297 										}
1298                 }
1299 
1300                 AddUserFromDemo( user );
1301             }
1302 
1303         }
1304         SetParsedTeamsVec( parsed_teams );
1305         SetParsedAlliesVec( parsed_allies );
1306 
1307         //MMoptions, this'll fail unless loading map/mod into wrapper first
1308         if ( loadmapmod )
1309         {
1310 					LoadScriptMMOpts( _T("mapoptions"), replayNode );
1311 					LoadScriptMMOpts( _T("modoptions"), replayNode );
1312         }
1313 
1314         opts.maxplayers = playernum ;
1315 
1316     }
1317     SetBattleOptions( opts );
1318 }
1319 
SetInGame(bool ingame)1320 void IBattle::SetInGame(bool ingame)
1321 {
1322 	m_ingame = ingame;
1323 	if (m_ingame) m_start_time = wxGetUTCTime();
1324 	else m_start_time = 0;
1325 }
1326 
GetBattleRunningTime() const1327 long IBattle::GetBattleRunningTime() const
1328 {
1329 	if (!GetInGame()) return 0;
1330 	if (m_start_time == 0 ) return 0;
1331 	return wxGetUTCTime() - m_start_time;
1332 }
1333 
1334