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