void IBattle::SaveOptionsPreset( const wxString& name ) { m_preset = FixPresetName(name); if (m_preset == _T("")) m_preset = name; //new preset for ( int i = 0; i < (int)OptionsWrapper::LastOption; i++) { if ( (OptionsWrapper::GameOption)i != OptionsWrapper::PrivateOptions ) { sett().SetHostingPreset( m_preset, (OptionsWrapper::GameOption)i, CustomBattleOptions().getOptionsMap( (OptionsWrapper::GameOption)i ) ); } else { std::map<wxString,wxString> opts; opts[_T("mapname")] = GetHostMapName(); unsigned int validrectcount = 0; if ( s2l (CustomBattleOptions().getSingleValue( _T("startpostype"), OptionsWrapper::EngineOption ) ) == ST_Choose ) { unsigned int boxcount = GetLastRectIdx(); for ( unsigned int boxnum = 0; boxnum <= boxcount; boxnum++ ) { BattleStartRect rect = GetStartRect( boxnum ); if ( rect.IsOk() ) { opts[_T("rect_") + TowxString(validrectcount) + _T("_ally")] = TowxString( rect.ally + 1 ); opts[_T("rect_") + TowxString(validrectcount) + _T("_left")] = TowxString( rect.left ); opts[_T("rect_") + TowxString(validrectcount) + _T("_top")] = TowxString( rect.top ); opts[_T("rect_") + TowxString(validrectcount) + _T("_bottom")] = TowxString( rect.bottom ); opts[_T("rect_") + TowxString(validrectcount) + _T("_right")] = TowxString( rect.right ); validrectcount++; } } } opts[_T("numrects")] = TowxString( validrectcount ); wxString restrictionsstring; for ( std::map<wxString, int>::const_iterator itor = m_restricted_units.begin(); itor != m_restricted_units.end(); ++itor ) { restrictionsstring << itor->first << _T('=') << TowxString(itor->second) << _T('\t'); } opts[_T("restrictions")] = restrictionsstring; sett().SetHostingPreset( m_preset, (OptionsWrapper::GameOption)i, opts ); } } sett().SaveSettings(); ui().ReloadPresetList(); }
void Battle::SaveMapDefaults() { // save map preset wxString mapname = LoadMap().name; wxString startpostype = CustomBattleOptions().getSingleValue( _T("startpostype"), OptionsWrapper::EngineOption ); sett().SetMapLastStartPosType( mapname, startpostype); std::vector<Settings::SettStartBox> rects; for( unsigned int i = 0; i <= GetLastRectIdx(); ++i ) { BattleStartRect rect = GetStartRect( i ); if ( rect.IsOk() ) { Settings::SettStartBox box; box.ally = rect.ally; box.topx = rect.left; box.topy = rect.top; box.bottomx = rect.right; box.bottomy = rect.bottom; rects.push_back( box ); } } sett().SetMapLastRectPreset( mapname, rects ); }
void Battle::Autobalance( BalanceType balance_type, bool support_clans, bool strong_clans, int numallyteams ) { wxLogMessage(_T("Autobalancing alliances, type=%d, clans=%d, strong_clans=%d, numallyteams=%d"),balance_type, support_clans,strong_clans, numallyteams); //size_t i; //int num_alliances; std::vector<Alliance>alliances; if ( numallyteams == 0 || numallyteams == -1 ) // 0 or 1 -> use num start rects { int ally = 0; for ( unsigned int i = 0; i < GetNumRects(); ++i ) { BattleStartRect sr = GetStartRect(i); if ( sr.IsOk() ) { ally=i; alliances.push_back( Alliance( ally ) ); ally++; } } // make at least two alliances while ( alliances.size() < 2 ) { alliances.push_back( Alliance( ally ) ); ally++; } } else { for ( int i = 0; i < numallyteams; i++ ) alliances.push_back( Alliance( i ) ); } //for(i=0;i<alliances.size();++i)alliances[i].allynum=i; wxLogMessage( _T("number of alliances: %u"), alliances.size() ); std::vector<User*> players_sorted; players_sorted.reserve( GetNumUsers() ); for ( size_t i = 0; i < GetNumUsers(); ++i ) { User& usr = GetUser( i ); if ( !usr.BattleStatus().spectator ) { players_sorted.push_back( &usr ); } } // remove players in the same team so only one remains std::map< int, User*> dedupe_teams; for ( std::vector<User*>::iterator it = players_sorted.begin(); it != players_sorted.end(); it++ ) { dedupe_teams[(*it)->BattleStatus().team] = *it; } players_sorted.clear(); players_sorted.reserve( dedupe_teams.size() ); for ( std::map<int, User*>::iterator it = dedupe_teams.begin(); it != dedupe_teams.end(); it++ ) { players_sorted.push_back( it->second ); } shuffle( players_sorted ); std::map<wxString, Alliance> clan_alliances; if ( support_clans ) { for ( size_t i=0; i < players_sorted.size(); ++i ) { wxString clan = players_sorted[i]->GetClan(); if ( !clan.empty() ) { clan_alliances[clan].AddPlayer( players_sorted[i] ); } } }; if ( balance_type != balance_random ) std::sort( players_sorted.begin(), players_sorted.end(), PlayerRankCompareFunction ); if ( support_clans ) { std::map<wxString, Alliance>::iterator clan_it = clan_alliances.begin(); while ( clan_it != clan_alliances.end() ) { Alliance &clan = (*clan_it).second; // if clan is too small (only 1 clan member in battle) or too big, dont count it as clan if ( ( clan.players.size() < 2 ) || ( !strong_clans && ( clan.players.size() > ( ( players_sorted.size() + alliances.size() -1 ) / alliances.size() ) ) ) ) { wxLogMessage( _T("removing clan %s"), (*clan_it).first.c_str() ); std::map<wxString, Alliance>::iterator next = clan_it; ++next; clan_alliances.erase( clan_it ); clan_it = next; continue; } wxLogMessage( _T("Inserting clan %s"), (*clan_it).first.c_str() ); std::sort( alliances.begin(), alliances.end() ); float lowestrank = alliances[0].ranksum; int rnd_k = 1;// number of alliances with rank equal to lowestrank while ( size_t( rnd_k ) < alliances.size() ) { if ( fabs( alliances[rnd_k].ranksum - lowestrank ) > 0.01 ) break; rnd_k++; } wxLogMessage( _T("number of lowestrank alliances with same rank=%d"), rnd_k ); alliances[my_random( rnd_k )].AddAlliance( clan ); ++clan_it; } } for ( size_t i = 0; i < players_sorted.size(); ++i ) { // skip clanners, those have been added already. if ( clan_alliances.count( players_sorted[i]->GetClan() ) > 0 ) { wxLogMessage( _T("clanner already added, nick=%s"), players_sorted[i]->GetNick().c_str() ); continue; } // find alliances with lowest ranksum // insert current user into random one out of them // since performance doesnt matter here, i simply sort alliances, // then find how many alliances in beginning have lowest ranksum // note that balance player ranks range from 1 to 1.1 now // i.e. them are quasi equal // so we're essentially adding to alliance with smallest number of players, // the one with smallest ranksum. std::sort( alliances.begin(), alliances.end() ); float lowestrank = alliances[0].ranksum; int rnd_k = 1;// number of alliances with rank equal to lowestrank while ( size_t( rnd_k ) < alliances.size() ) { if ( fabs( alliances[rnd_k].ranksum - lowestrank ) > 0.01 ) break; rnd_k++; } wxLogMessage( _T("number of lowestrank alliances with same rank=%d"), rnd_k ); alliances[my_random( rnd_k )].AddPlayer( players_sorted[i] ); } UserList::user_map_t::size_type totalplayers = GetNumUsers(); for ( size_t i = 0; i < alliances.size(); ++i ) { for ( size_t j = 0; j < alliances[i].players.size(); ++j ) { ASSERT_LOGIC( alliances[i].players[j], _T("fail in Autobalance, NULL player") ); int balanceteam = alliances[i].players[j]->BattleStatus().team; wxLogMessage( _T("setting team %d to alliance %d"), balanceteam, i ); for ( size_t h = 0; h < totalplayers; h++ ) // change ally num of all players in the team { User& usr = GetUser( h ); if ( usr.BattleStatus().team == balanceteam ) ForceAlly( usr, alliances[i].allynum ); } } } }
void AutoHost::OnSaidBattle( const wxString& /*unused*/, const wxString& msg ) { // do nothing if autohost functionality is disabled if ( !m_enabled ) return; // protect against command spam time_t currentTime = time( NULL ); if ( ( currentTime - m_lastActionTime ) < 5 ) return; // check for autohost commands wxString command = msg.BeforeFirst( _T( ' ' ) ); wxString params = msg.AfterFirst( _T( ' ' ) ); if ( command == _T( "!start" ) ) { StartBattle(); } else if ( command == _T( "!balance" ) ) { unsigned int num = s2l( params ); m_battle.Autobalance( IBattle::balance_random, false, false, num ); m_battle.DoAction( _T( "is auto-balancing alliances ..." ) ); } else if ( command == _T( "!cbalance" ) ) { unsigned int num = s2l( params ); m_battle.Autobalance( IBattle::balance_random, true, false, num ); m_battle.DoAction( _T( "is auto-balancing alliances ..." ) ); } else if ( command == _T( "!help" ) ) { m_battle.DoAction( _T( "The following commands are available ( <> = mandatory value, {} = optional value ):" ) ); m_battle.DoAction( _T( "!addbox <topx> <topy> <bottomx> <bottomy> {allynumber}: adds a <allynumber> start restriction to the given coordinates, coordinates range from 0 to 200." ) ); m_battle.DoAction( _T( "!balance {number}: tries to put players into allyteams by how many start boxes there are, uses {number} allyteams if present." ) ); m_battle.DoAction( _T( "!cbalance {number}: see !balance but tries to put clanmates together first." ) ); m_battle.DoAction( _T( "!fixcolors: changes players duplicate colours so they are unique." ) ); m_battle.DoAction( _T( "!fixids {number}: tries to put players into control teams by number, if number is omitted it assignes as different controlteam per player." ) ); m_battle.DoAction( _T( "!cfixids {number}: see !fixids but tries to put clanmates together first." ) ); m_battle.DoAction( _T( "!help: this guide." ) ); m_battle.DoAction( _T( "!listprofiles: lists the available battle profiles." ) ); m_battle.DoAction( _T( "!loadprofile profilename: loads an available battle profile." ) ); m_battle.DoAction( _T( "!lock: prevents more people to join." ) ); m_battle.DoAction( _T( "!map <name>: switches to <name>." ) ); m_battle.DoAction( _T( "!removebox <allynumber>: deletes <allynumber> start restriction's box." ) ); m_battle.DoAction( _T( "!ring {name}: rings players that are not ready or {name} if specified." ) ); m_battle.DoAction( _T( "!set <optionname> <value>: sets battle option <optionname> to <value>" ) ); m_battle.DoAction( _T( "!spectunsynced: sets all players with unsynced status to be spectators." ) ); m_battle.DoAction( _T( "!start: starts the battle." ) ); m_battle.DoAction( _T( "!unlock: opens the battle again." ) ); } else if ( command == _T( "!ring" ) ) { if ( !params.IsEmpty() ) { wxString user = GetBestMatch( m_userlist, params ); try { User& u = m_battle.GetUser( user ); m_battle.RingPlayer( u ); m_battle.DoAction( _T( "is ringing " ) + user ); } catch ( ... ) { m_battle.DoAction( _T( "cannot ring " ) + user ); } } else { m_battle.RingNotReadyPlayers(); m_battle.DoAction( _T( "is ringing players not ready ..." ) ); } } else if ( command == _T( "!listprofiles" ) ) { wxArrayString profilelist = m_battle.GetPresetList(); unsigned int count = profilelist.GetCount(); if ( count == 0 ) { m_battle.DoAction( _T( "There are no presets available." ) ); } else { m_battle.DoAction( _T( "The following presets are available:" ) ); for ( unsigned int i = 0; i < count; i++ ) { m_battle.DoAction( profilelist[i] ); } } } else if ( command == _T( "!loadprofile" ) ) { wxString profilename = GetBestMatch( m_battle.GetPresetList(), params ); if ( !m_battle.LoadOptionsPreset( profilename ) ) m_battle.DoAction( _T( "Profile not found, use !listprofiles for a list of available profiles." ) ); else m_battle.DoAction( _T( "has loaded profile: " ) + profilename ); } else if ( command == _T( "!fixcolors" ) ) { m_battle.FixColours(); m_battle.DoAction( _T( "is fixing colors." ) ); } else if ( command == _T( "!lock" ) ) { m_battle.SetIsLocked( true ); m_battle.DoAction( _T( "has locked the battle." ) ); m_battle.SendHostInfo( IBattle::HI_Locked ); } else if ( command == _T( "!unlock" ) ) { m_battle.SetIsLocked( false ); m_battle.DoAction( _T( "has unlocked the battle." ) ); m_battle.SendHostInfo( IBattle::HI_Locked ); } else if ( command == _T( "!fixids" ) ) { unsigned int num = s2l( params ); m_battle.FixTeamIDs( IBattle::balance_divide, false, false, num ); m_battle.DoAction( _T( "is auto-balancing control teams ..." ) ); } else if ( command == _T( "!cfixids" ) ) { unsigned int num = s2l( params ); m_battle.FixTeamIDs( IBattle::balance_divide, true, true, num ); m_battle.DoAction( _T( "is auto-balancing control teams ..." ) ); } else if ( command == _T( "!spectunsynced" ) ) { m_battle.ForceUnsyncedToSpectate(); m_battle.DoAction( _T( "is forcing unsynced players to be spectators." ) ); } else if ( command == _T( "!map" ) ) { if ( params.IsEmpty() ) m_battle.DoAction( _T( "cannot switch to void mapname" ) ); else { wxString mapname = GetBestMatch( usync().GetMapList(), params ); try { UnitSyncMap map = usync().GetMap( mapname ); m_battle.SetLocalMap( map ); m_battle.DoAction( _T( "is switching to map " ) + mapname ); m_battle.SendHostInfo( IBattle::HI_Map ); } catch ( ... ) { m_battle.DoAction( _T( "cannot switch to map " ) + mapname ); } } } else if ( command == _T( "!set" ) ) { wxString key = params.BeforeFirst( _T( ' ' ) ); wxString value = params.AfterFirst( _T( ' ' ) ); bool exists = m_battle.CustomBattleOptions().keyExists( key ); if ( exists ) { bool result = m_battle.CustomBattleOptions().setSingleOption( key, value ); if ( result ) { OptionsWrapper::GameOption section = m_battle.CustomBattleOptions().GetSection( key ); m_battle.SendHostInfo( wxString::Format( _T( "%d_%s" ), section, key.c_str() ) ); m_battle.DoAction( _T( "has set option " ) + key + _T( " to value " ) + value ); } else m_battle.DoAction( _T( "cannot set option " ) + key + _T( " to value " ) + value + _T( ", reason: invalid value." ) ); } else { m_battle.DoAction( _T( "cannot find option entry " ) + key ); } } else if ( command == _T( "!addbox" ) ) { long allynumber; long topleftx; long toplefty; long bottomrightx; long bottomrighty; wxArrayString values = wxStringTokenize( params, _T( " " ) ); int numvalues = values.GetCount(); if ( numvalues > 4 || numvalues < 3 ) m_battle.DoAction( _T( "has recieved an invalid number of params for !addbox" ) ); else { bool valueok = values[0].ToLong( &topleftx ); valueok = valueok && values[1].ToLong( &toplefty ); valueok = valueok && values[2].ToLong( &bottomrightx ); valueok = valueok && values[3].ToLong( &bottomrighty ); if ( numvalues == 5 ) { valueok = valueok && values[4].ToLong( &allynumber ); valueok = valueok && ( allynumber > 0 ); } else { allynumber = m_battle.GetNextFreeRectIdx(); } valueok = valueok && ( topleftx >= 0 ) && ( topleftx <= 200 ); valueok = valueok && ( toplefty >= 0 ) && ( toplefty <= 200 ); valueok = valueok && ( bottomrightx >= 0 ) && ( bottomrightx <= 200 ); valueok = valueok && ( bottomrighty >= 0 ) && ( bottomrighty <= 200 ); if ( valueok ) { allynumber = allynumber - 1; BattleStartRect rect = m_battle.GetStartRect( allynumber ); if ( rect.IsOk() ) { m_battle.DoAction( _T( "cannot add a startbox for allyteam " ) + TowxString( allynumber ) + _T( " because one is already present." ) ); } else { m_battle.AddStartRect( allynumber, topleftx, toplefty, bottomrightx, bottomrighty ); m_battle.SendHostInfo( IBattle::HI_StartRects ); m_battle.DoAction( _T( "has added start box for allyteam " ) + TowxString( allynumber ) ); } } else { m_battle.DoAction( _T( "has recieved an invalid param for !addbox" ) ); } } } else if ( command == _T( "!removebox" ) ) { long boxnumber; bool numberok = params.ToLong( &boxnumber ); if ( numberok ) { boxnumber = boxnumber - 1; BattleStartRect rect = m_battle.GetStartRect( boxnumber ); if ( rect.IsOk() ) { m_battle.RemoveStartRect( boxnumber ); m_battle.SendHostInfo( IBattle::HI_StartRects ); m_battle.DoAction( _T( "has removed the start box for allyteam " ) + TowxString( boxnumber ) ); } else { m_battle.DoAction( _T( "cannot find start box " ) + params ); } } else { m_battle.DoAction( _T( "has recieved an invalid param to !removebox command" ) ); } } else return; m_lastActionTime = currentTime; }
wxString Spring::WriteScriptTxt( IBattle& battle ) const { wxLogMessage(_T("0 WriteScriptTxt called ")); wxString ret; TDFWriter tdf(ret); // Start generating the script. tdf.EnterSection( _T("GAME") ); tdf.Append( _T("HostIP"), battle.GetHostIp() ); if ( battle.IsFounderMe() ) { if ( battle.GetNatType() == NAT_Hole_punching ) tdf.Append( _T("HostPort"), battle.GetMyInternalUdpSourcePort() ); else tdf.Append(_T("HostPort"), battle.GetHostPort() ); } else { tdf.Append( _T("HostPort"), battle.GetHostPort() ); if ( battle.GetNatType() == NAT_Hole_punching ) { tdf.Append( _T("SourcePort"), battle.GetMyInternalUdpSourcePort() ); } else if ( sett().GetClientPort() != 0) { tdf.Append( _T("SourcePort"), sett().GetClientPort() ); /// this allows to play with broken router by setting SourcePort to some forwarded port. } } tdf.Append( _T("IsHost"), battle.IsFounderMe() ); tdf.Append(_T("MyPlayerName"), battle.GetMe().GetNick() ); if ( !battle.IsFounderMe() ) { tdf.LeaveSection(); return ret; } /********************************************************************************** Host-only section **********************************************************************************/ tdf.AppendLineBreak(); tdf.Append(_T("ModHash"), battle.LoadMod().hash ); tdf.Append(_T("MapHash"), battle.LoadMap().hash ); tdf.Append( _T("Mapname"), battle.GetHostMapName() ); tdf.Append( _T("GameType"), battle.GetHostModName() ); tdf.AppendLineBreak(); switch ( battle.GetBattleType() ) { case BT_Played: break; case BT_Replay: { wxString path = battle.GetPlayBackFilePath(); if ( path.Find(_T("/")) != wxNOT_FOUND ) path.BeforeLast(_T('/')); tdf.Append( _T("DemoFile"), path ); tdf.AppendLineBreak(); break; } case BT_Savegame: { wxString path = battle.GetPlayBackFilePath(); if ( path.Find(_T("/")) != wxNOT_FOUND ) path.BeforeLast(_T('/')); tdf.Append( _T("Savefile"), path ); tdf.AppendLineBreak(); break; } default: wxLogDebugFunc( _T("") ); break; } long startpostype; battle.CustomBattleOptions().getSingleValue( _T("startpostype"), OptionsWrapper::EngineOption ).ToLong( &startpostype ); std::vector<StartPos> remap_positions; if ( battle.IsProxy() && ( startpostype != IBattle::ST_Pick ) && ( startpostype != IBattle::ST_Choose ) ) { std::set<int> parsedteams; unsigned int NumUsers = battle.GetNumUsers(); unsigned int NumTeams = 0; for ( unsigned int i = 0; i < NumUsers; i++ ) { User& usr = battle.GetUser( i ); UserBattleStatus& status = usr.BattleStatus(); if ( status.spectator ) continue; if ( parsedteams.find( status.team ) != parsedteams.end() ) continue; // skip duplicates parsedteams.insert( status.team ); NumTeams++; } MapInfo infos = battle.LoadMap().info; unsigned int nummapstartpositions = infos.positions.size(); unsigned int copysize = std::min( nummapstartpositions, NumTeams ); remap_positions = std::vector<StartPos> ( infos.positions.begin(), infos.positions.begin() + copysize ); // only add the first x positions if ( startpostype == IBattle::ST_Random ) { random_shuffle( remap_positions.begin(), remap_positions.end() ); // shuffle the positions } } if ( battle.IsProxy() ) { if ( ( startpostype == IBattle::ST_Random ) || ( startpostype == IBattle::ST_Fixed ) ) { tdf.Append( _T("startpostype"), IBattle::ST_Pick ); } else tdf.Append( _T("startpostype"), startpostype ); } else tdf.Append( _T("startpostype"), startpostype ); tdf.EnterSection( _T("mapoptions") ); OptionsWrapper::wxStringTripleVec optlistMap = battle.CustomBattleOptions().getOptions( OptionsWrapper::MapOption ); for (OptionsWrapper::wxStringTripleVec::const_iterator it = optlistMap.begin(); it != optlistMap.end(); ++it) { tdf.Append(it->first,it->second.second); } tdf.LeaveSection(); tdf.EnterSection(_T("modoptions")); OptionsWrapper::wxStringTripleVec optlistMod = battle.CustomBattleOptions().getOptions( OptionsWrapper::ModOption ); for (OptionsWrapper::wxStringTripleVec::const_iterator it = optlistMod.begin(); it != optlistMod.end(); ++it) { tdf.Append(it->first,it->second.second); } tdf.LeaveSection(); std::map<wxString,int> units = battle.RestrictedUnits(); tdf.Append( _T("NumRestrictions"), units.size()); tdf.EnterSection( _T("RESTRICT") ); int restrictcount = 0; for ( std::map<wxString, int>::iterator itor = units.begin(); itor != units.end(); itor++ ) { tdf.Append(_T("Unit") + TowxString( restrictcount ), itor->first ); tdf.Append(_T("Limit") + TowxString( restrictcount ), itor->second ); restrictcount++; } tdf.LeaveSection(); tdf.AppendLineBreak(); if ( battle.IsProxy() ) { tdf.Append( _T("NumPlayers"), battle.GetNumPlayers() -1 ); tdf.Append( _T("NumUsers"), battle.GetNumUsers() -1 ); } else { tdf.Append( _T("NumPlayers"), battle.GetNumPlayers() ); tdf.Append( _T("NumUsers"), battle.GetNumUsers() ); } tdf.AppendLineBreak(); unsigned int NumUsers = battle.GetNumUsers(); typedef std::map<int, int> ProgressiveTeamsVec; typedef ProgressiveTeamsVec::iterator ProgressiveTeamsVecIter; ProgressiveTeamsVec teams_to_sorted_teams; // original team -> progressive team int free_team = 0; std::map<User*, int> player_to_number; // player -> ordernumber srand ( time(NULL) ); for ( unsigned int i = 0; i < NumUsers; i++ ) { User& user = battle.GetUser( i ); UserBattleStatus& status = user.BattleStatus(); if ( !status.spectator ) { ProgressiveTeamsVecIter itor = teams_to_sorted_teams.find ( status.team ); if ( itor == teams_to_sorted_teams.end() ) { teams_to_sorted_teams[status.team] = free_team; free_team++; } } if ( battle.IsProxy() && ( user.GetNick() == battle.GetFounder().GetNick() ) ) continue; if ( status.IsBot() ) continue; tdf.EnterSection( _T("PLAYER") + TowxString( i ) ); tdf.Append( _T("Name"), user.GetNick() ); tdf.Append( _T("CountryCode"), user.GetCountry().Lower()); tdf.Append( _T("Spectator"), status.spectator ); tdf.Append( _T("Rank"), (int)user.GetRank() ); tdf.Append( _T("IsFromDemo"), int(status.isfromdemo) ); if ( !status.spectator ) { tdf.Append( _T("Team"), teams_to_sorted_teams[status.team] ); } else { int speccteam = 0; if ( teams_to_sorted_teams.size() != 0 ) speccteam = rand() % teams_to_sorted_teams.size(); tdf.Append( _T("Team"), speccteam ); } tdf.LeaveSection(); player_to_number[&user] = i; } if ( usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) ) { for ( unsigned int i = 0; i < NumUsers; i++ ) { User& user = battle.GetUser( i ); UserBattleStatus& status = user.BattleStatus(); if ( !status.IsBot() ) continue; tdf.EnterSection( _T("AI") + TowxString( i ) ); tdf.Append( _T("Name"), user.GetNick() ); // AI's nick; tdf.Append( _T("ShortName"), status.aishortname ); // AI libtype tdf.Append( _T("Version"), status.aiversion ); // AI libtype version tdf.Append( _T("Team"), teams_to_sorted_teams[status.team] ); tdf.Append( _T("IsFromDemo"), int(status.isfromdemo) ); tdf.Append( _T("Host"), player_to_number[&battle.GetUser( status.owner )] ); tdf.EnterSection( _T("Options") ); int optionmapindex = battle.CustomBattleOptions().GetAIOptionIndex( user.GetNick() ); if ( optionmapindex > 0 ) { OptionsWrapper::wxStringTripleVec optlistMod_ = battle.CustomBattleOptions().getOptions( (OptionsWrapper::GameOption)optionmapindex ); for (OptionsWrapper::wxStringTripleVec::const_iterator it = optlistMod_.begin(); it != optlistMod_.end(); ++it) { tdf.Append(it->first,it->second.second); } } tdf.LeaveSection(); tdf.LeaveSection(); player_to_number[&user] = i; } } tdf.AppendLineBreak(); std::set<int> parsedteams; wxArrayString sides = usync().GetSides( battle.GetHostModName() ); for ( unsigned int i = 0; i < NumUsers; i++ ) { User& usr = battle.GetUser( i ); UserBattleStatus& status = usr.BattleStatus(); if ( status.spectator ) continue; if ( parsedteams.find( status.team ) != parsedteams.end() ) continue; // skip duplicates parsedteams.insert( status.team ); tdf.EnterSection( _T("TEAM") + TowxString( teams_to_sorted_teams[status.team] ) ); if ( !usync().VersionSupports( IUnitSync::USYNC_GetSkirmishAI ) && status.IsBot() ) { tdf.Append( _T("AIDLL"), status.aishortname ); tdf.Append( _T("TeamLeader"), player_to_number[&battle.GetUser( status.owner )] ); // bot owner is the team leader } else { if ( status.IsBot() ) { tdf.Append( _T("TeamLeader"), player_to_number[&battle.GetUser( status.owner )] ); } else { tdf.Append( _T("TeamLeader"), player_to_number[&usr] ); } } if ( battle.IsProxy() ) { if ( startpostype == IBattle::ST_Pick ) { tdf.Append(_T("StartPosX"), status.pos.x ); tdf.Append(_T("StartPosZ"), status.pos.y ); } else if ( ( startpostype == IBattle::ST_Fixed ) || ( startpostype == IBattle::ST_Random ) ) { int teamnumber = teams_to_sorted_teams[status.team]; if ( teamnumber < int(remap_positions.size()) ) // don't overflow { StartPos position = remap_positions[teamnumber]; tdf.Append(_T("StartPosX"), position.x ); tdf.Append(_T("StartPosZ"), position.y ); } } } else { if ( startpostype == IBattle::ST_Pick ) { tdf.Append(_T("StartPosX"), status.pos.x ); tdf.Append(_T("StartPosZ"), status.pos.y ); } } tdf.Append( _T("AllyTeam"),status.ally ); wxString colourstring = TowxString( status.colour.Red()/255.0 ) + _T(' ') + TowxString( status.colour.Green()/255.0 ) + _T(' ') + TowxString( status.colour.Blue()/255.0 ); tdf.Append( _T("RGBColor"), colourstring); unsigned int side = status.side; if ( side < sides.GetCount() ) tdf.Append( _T("Side"), sides[side] ); tdf.Append( _T("Handicap"), status.handicap ); tdf.LeaveSection(); } tdf.AppendLineBreak(); unsigned int maxiter = std::max( NumUsers, battle.GetLastRectIdx() + 1 ); std::set<int> parsedallys; for ( unsigned int i = 0; i < maxiter; i++ ) { User& usr = battle.GetUser( i ); UserBattleStatus& status = usr.BattleStatus(); BattleStartRect sr = battle.GetStartRect( i ); if ( status.spectator && !sr.IsOk() ) continue; int ally = status.ally; if ( status.spectator ) ally = i; if ( parsedallys.find( ally ) != parsedallys.end() ) continue; // skip duplicates sr = battle.GetStartRect( ally ); parsedallys.insert( ally ); tdf.EnterSection( _T("ALLYTEAM") + TowxString( ally ) ); tdf.Append( _T("NumAllies"), 0 ); if ( sr.IsOk() ) { const char* old_locale = std::setlocale(LC_NUMERIC, "C"); tdf.Append( _T("StartRectLeft"), wxString::Format( _T("%.3f"), sr.left / 200.0 ) ); tdf.Append( _T("StartRectTop"), wxString::Format( _T("%.3f"), sr.top / 200.0 ) ); tdf.Append( _T("StartRectRight"), wxString::Format( _T("%.3f"), sr.right / 200.0 ) ); tdf.Append( _T("StartRectBottom"), wxString::Format( _T("%.3f"), sr.bottom / 200.0 ) ); std::setlocale(LC_NUMERIC, old_locale); } tdf.LeaveSection(); } tdf.LeaveSection(); return ret; }
wxString Spring::WriteScriptTxt( IBattle& battle ) const { wxLogMessage(_T("0 WriteScriptTxt called ")); std::stringstream ret; LSL::TDF::TDFWriter tdf(ret); // Start generating the script. tdf.EnterSection("GAME"); if ( battle.IsFounderMe() ) { tdf.Append("HostIP", ""); //Listen on all addresses for connections when hosting if ( battle.GetNatType() == NAT_Hole_punching ) tdf.Append("HostPort", battle.GetMyInternalUdpSourcePort() ); else tdf.Append("HostPort", battle.GetHostPort() ); } else { tdf.Append("HostIP", battle.GetHostIp() ); tdf.Append("HostPort", battle.GetHostPort() ); if ( battle.GetNatType() == NAT_Hole_punching ) { tdf.Append("SourcePort", battle.GetMyInternalUdpSourcePort() ); } else if ( sett().GetClientPort() != 0) { tdf.Append("SourcePort", sett().GetClientPort() ); /// this allows to play with broken router by setting SourcePort to some forwarded port. } } tdf.Append("IsHost", battle.IsFounderMe() ); User& me = battle.GetMe(); tdf.Append("MyPlayerName", me.GetNick()); if ( !me.BattleStatus().scriptPassword.empty() ) { tdf.Append("MyPasswd", me.BattleStatus().scriptPassword); } if ( !battle.IsFounderMe() ) { tdf.LeaveSection(); return TowxString(ret.str()); } /********************************************************************************** Host-only section **********************************************************************************/ tdf.AppendLineBreak(); tdf.Append("ModHash", battle.LoadMod().hash); tdf.Append("MapHash", battle.LoadMap().hash); tdf.Append("Mapname", battle.GetHostMapName()); tdf.Append("GameType", battle.GetHostModName()); tdf.AppendLineBreak(); switch ( battle.GetBattleType() ) { case BT_Played: break; case BT_Replay: { wxString path = TowxString(battle.GetPlayBackFilePath()); if ( path.Find(_T("/")) != wxNOT_FOUND ) path.BeforeLast(_T('/')); tdf.Append("DemoFile", STD_STRING(path)); tdf.AppendLineBreak(); break; } case BT_Savegame: { wxString path = TowxString(battle.GetPlayBackFilePath()); if ( path.Find(_T("/")) != wxNOT_FOUND ) path.BeforeLast(_T('/')); tdf.Append("Savefile", STD_STRING(path)); tdf.AppendLineBreak(); break; } default: slLogDebugFunc(""); break; } const long startpostype = LSL::Util::FromString<long>( battle.CustomBattleOptions().getSingleValue("startpostype", LSL::Enum::EngineOption )); std::vector<LSL::StartPos> remap_positions; if ( battle.IsProxy() && ( startpostype != IBattle::ST_Pick ) && ( startpostype != IBattle::ST_Choose ) ) { std::set<int> parsedteams; unsigned int NumUsers = battle.GetNumUsers(); unsigned int NumTeams = 0; for ( unsigned int i = 0; i < NumUsers; i++ ) { User& usr = battle.GetUser( i ); UserBattleStatus& status = usr.BattleStatus(); if ( status.spectator ) continue; if ( parsedteams.find( status.team ) != parsedteams.end() ) continue; // skip duplicates parsedteams.insert( status.team ); NumTeams++; } LSL::MapInfo infos = battle.LoadMap().info; unsigned int nummapstartpositions = infos.positions.size(); unsigned int copysize = std::min( nummapstartpositions, NumTeams ); remap_positions = std::vector<LSL::StartPos> ( infos.positions.begin(), infos.positions.begin() + copysize ); // only add the first x positions if ( startpostype == IBattle::ST_Random ) { std::random_shuffle( remap_positions.begin(), remap_positions.end() ); // shuffle the positions } } if ( battle.IsProxy() ) { if ( ( startpostype == IBattle::ST_Random ) || ( startpostype == IBattle::ST_Fixed ) ) { tdf.Append("startpostype", IBattle::ST_Pick ); } else tdf.Append("startpostype", startpostype ); } else tdf.Append("startpostype", startpostype ); tdf.EnterSection("mapoptions"); for (const auto& it : battle.CustomBattleOptions().getOptions( LSL::Enum::MapOption )) { tdf.Append(it.first, it.second.second); } tdf.LeaveSection(); tdf.EnterSection("modoptions"); tdf.Append("relayhoststartpostype", startpostype ); // also save the original wanted setting for (const auto& it : battle.CustomBattleOptions().getOptions( LSL::Enum::ModOption )) { tdf.Append(it.first, it.second.second); } tdf.LeaveSection(); std::map<std::string,int> units = battle.RestrictedUnits(); tdf.Append("NumRestrictions", units.size()); tdf.EnterSection("RESTRICT"); int restrictcount = 0; for ( std::map<std::string, int>::const_iterator itor = units.begin(); itor != units.end(); ++itor ) { tdf.Append(stdprintf("Unit%d", restrictcount), itor->first ); tdf.Append(stdprintf("Limit%d", restrictcount), itor->second ); restrictcount++; } tdf.LeaveSection(); tdf.AppendLineBreak(); if ( battle.IsProxy() ) { tdf.Append("NumPlayers", battle.GetNumPlayers() -1 ); tdf.Append("NumUsers", battle.GetNumUsers() -1 ); } else { tdf.Append("NumPlayers", battle.GetNumPlayers() ); tdf.Append("NumUsers", battle.GetNumUsers() ); } tdf.AppendLineBreak(); unsigned int NumUsers = battle.GetNumUsers(); typedef std::map<int, int> ProgressiveTeamsVec; typedef ProgressiveTeamsVec::iterator ProgressiveTeamsVecIter; ProgressiveTeamsVec teams_to_sorted_teams; // original team -> progressive team int free_team = 0; std::map<User*, int> player_to_number; // player -> ordernumber srand ( time(NULL) ); for ( unsigned int i = 0; i < NumUsers; i++ ) { User& user = battle.GetUser( i ); UserBattleStatus& status = user.BattleStatus(); if ( !status.spectator ) { ProgressiveTeamsVecIter itor = teams_to_sorted_teams.find ( status.team ); if ( itor == teams_to_sorted_teams.end() ) { teams_to_sorted_teams[status.team] = free_team; free_team++; } } if ( battle.IsProxy() && ( user.GetNick() == battle.GetFounder().GetNick() ) ) continue; if ( status.IsBot() ) continue; tdf.EnterSection(stdprintf("PLAYER%d", i)); tdf.Append("Name", user.GetNick() ); tdf.Append("CountryCode", STD_STRING(TowxString(user.GetCountry()).Lower())); tdf.Append("Spectator", status.spectator ); tdf.Append("Rank", (int)user.GetRank() ); tdf.Append("IsFromDemo", int(status.isfromdemo) ); if ( !status.scriptPassword.empty() ) { tdf.Append("Password", status.scriptPassword ); } if ( !status.spectator ) { tdf.Append("Team", teams_to_sorted_teams[status.team] ); } else { int speccteam = 0; if ( !teams_to_sorted_teams.empty() ) speccteam = rand() % teams_to_sorted_teams.size(); tdf.Append("Team", speccteam ); } tdf.LeaveSection(); player_to_number[&user] = i; } for ( unsigned int i = 0; i < NumUsers; i++ ) { User& user = battle.GetUser( i ); UserBattleStatus& status = user.BattleStatus(); if ( !status.IsBot() ) continue; tdf.EnterSection(stdprintf("AI%d", i)); tdf.Append("Name", user.GetNick()); // AI's nick; tdf.Append("ShortName", status.aishortname ); // AI libtype tdf.Append("Version", status.aiversion ); // AI libtype version tdf.Append("Team", teams_to_sorted_teams[status.team] ); tdf.Append("IsFromDemo", int(status.isfromdemo) ); tdf.Append("Host", player_to_number[&battle.GetUser( status.owner )] ); tdf.EnterSection("Options"); int optionmapindex = battle.CustomBattleOptions().GetAIOptionIndex(user.GetNick()); if ( optionmapindex > 0 ) { for (const auto& it : battle.CustomBattleOptions().getOptions((LSL::Enum::GameOption)optionmapindex )) { tdf.Append(it.first, it.second.second); } } tdf.LeaveSection(); tdf.LeaveSection(); player_to_number[&user] = i; } tdf.AppendLineBreak(); std::set<int> parsedteams; const auto sides = LSL::usync().GetSides(battle.GetHostModName()); for ( unsigned int i = 0; i < NumUsers; i++ ) { User& usr = battle.GetUser( i ); UserBattleStatus& status = usr.BattleStatus(); if ( status.spectator ) continue; if ( parsedteams.find( status.team ) != parsedteams.end() ) continue; // skip duplicates parsedteams.insert( status.team ); tdf.EnterSection(stdprintf("TEAM%d", teams_to_sorted_teams[status.team])); if ( status.IsBot() ) { tdf.Append("TeamLeader", player_to_number[&battle.GetUser( status.owner )] ); } else { tdf.Append("TeamLeader", player_to_number[&usr] ); } if ( battle.IsProxy() ) { if ( startpostype == IBattle::ST_Pick ) { tdf.Append("StartPosX", status.pos.x ); tdf.Append("StartPosZ", status.pos.y ); } else if ( ( startpostype == IBattle::ST_Fixed ) || ( startpostype == IBattle::ST_Random ) ) { int teamnumber = teams_to_sorted_teams[status.team]; if ( teamnumber < int(remap_positions.size()) ) { // don't overflow LSL::StartPos position = remap_positions[teamnumber]; tdf.Append("StartPosX", position.x ); tdf.Append("StartPosZ", position.y ); } } } else { if ( startpostype == IBattle::ST_Pick ) { tdf.Append("StartPosX", status.pos.x ); tdf.Append("StartPosZ", status.pos.y ); } } tdf.Append("AllyTeam",status.ally ); wxString colourstring = TowxString( status.colour.Red()/255.0 ) + _T(' ') + TowxString( status.colour.Green()/255.0 ) + _T(' ') + TowxString( status.colour.Blue()/255.0 ); tdf.Append("RGBColor", STD_STRING(colourstring)); unsigned int side = status.side; if ( side < sides.size() ) tdf.Append("Side", sides[side] ); tdf.Append("Handicap", status.handicap ); tdf.LeaveSection(); } tdf.AppendLineBreak(); unsigned int maxiter = std::max( NumUsers, battle.GetLastRectIdx() + 1 ); std::set<int> parsedallys; for ( unsigned int i = 0; i < maxiter; i++ ) { User& usr = battle.GetUser( i ); UserBattleStatus& status = usr.BattleStatus(); BattleStartRect sr = battle.GetStartRect( i ); if ( status.spectator && !sr.IsOk() ) continue; int ally = status.ally; if ( status.spectator ) ally = i; if ( parsedallys.find( ally ) != parsedallys.end() ) continue; // skip duplicates sr = battle.GetStartRect( ally ); parsedallys.insert( ally ); tdf.EnterSection( stdprintf("ALLYTEAM%d", ally)); tdf.Append("NumAllies", 0 ); if ( startpostype == IBattle::ST_Choose ) { if ( sr.IsOk() ) { const char* old_locale = std::setlocale(LC_NUMERIC, "C"); tdf.Append("StartRectLeft", wxFormat( _T("%.3f") ) % ( sr.left / 200.0 ) ); tdf.Append("StartRectTop", wxFormat( _T("%.3f") ) % ( sr.top / 200.0 ) ); tdf.Append("StartRectRight", wxFormat( _T("%.3f") ) % ( sr.right / 200.0 ) ); tdf.Append("StartRectBottom", wxFormat( _T("%.3f") ) % ( sr.bottom / 200.0 ) ); std::setlocale(LC_NUMERIC, old_locale); } } tdf.LeaveSection(); } tdf.LeaveSection(); return TowxString(ret.str()); }