Пример #1
0
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();
}
Пример #2
0
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 );
}
Пример #3
0
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 );
            }
        }
    }
}
Пример #4
0
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;
}
Пример #5
0
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;

}
Пример #6
0
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());
}