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