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