Beispiel #1
0
int32_t C4TeamList::GetForcedTeamSelection(int32_t idForPlayer) const
{
	// if there's only one team for the player to join, return that team ID
	C4Team *pOKTeam = NULL, *pCheck;
	if (idForPlayer) pOKTeam = GetTeamByPlayerID(idForPlayer); // curent team is always possible, even if full
	int32_t iCheckTeam=0;
	while ((pCheck = GetTeamByIndex(iCheckTeam++)))
		if (!pCheck->IsFull())
		{
			// this team could be joined
			if (pOKTeam && pOKTeam != pCheck)
			{
				// there already was a team that could be joined
				// two alternatives -> team selection is not forced
				return 0;
			}
			pOKTeam = pCheck;
		}
	// was there a team that could be joined?
	if (pOKTeam)
	{
		// if teams are generated on the fly, there would always be the possibility of creating a new team    }
		if (IsAutoGenerateTeams()) return 0;
		// otherwise, this team is forced!
		return pOKTeam->GetID();
	}
	// no team could be joined: Teams auto generated?
	if (IsAutoGenerateTeams())
	{
		// then the only possible way is to join a new team
		return TEAMID_New;
	}
	// otherwise, nothing can be done...
	return 0;
}
Beispiel #2
0
int32_t C4TeamList::GetStartupTeamCount(int32_t startup_player_count)
{
	// Count non-empty teams
	int32_t i_team = 0; C4Team *team;
	int32_t team_count = 0;
	while ((team = GetTeamByIndex(i_team++)))
	{
		if (team->GetPlayerCount() > 0) ++team_count;
	}
	// No populated teams found? This can happen in non-network mode when no players are assigned
	if (!team_count)
	{
		// Teams have not been selected yet, but the map script may want to have an estimate
		// in this case, calculate prospective teams from startup player count
		if (IsCustom() && !IsAutoGenerateTeams())
		{
			// Teams are pre-defined. Assume players will try to distribute broadly on these teams
			team_count = std::min<int32_t>(startup_player_count, GetTeamCount());
		}
		else if (IsRandomTeam())
		{
			// Randomized teams: Players will be put into two teams.
			team_count = std::min<int32_t>(startup_player_count, 2);
		}
		else
		{
			// Teams are auto-added -> fallback to player count
			team_count = startup_player_count;
		}
	}

	return team_count;
}
Beispiel #3
0
bool C4TeamList::IsJoin2TeamAllowed(int32_t idTeam)
{
	// join to new team: Only if new teams can be created
	if (idTeam == TEAMID_New) return IsAutoGenerateTeams();
	// team number must be valid
	C4Team *pTeam = GetTeamByID(idTeam);
	if (!pTeam) return false;
	// team player count must not exceed the limit
	return !pTeam->IsFull();
}
Beispiel #4
0
bool C4TeamList::IsJoin2TeamAllowed(int32_t idTeam, C4PlayerType plrType)
{
	// join to new team: Only if new teams can be created
	if (idTeam == TEAMID_New) return IsAutoGenerateTeams();
	// team number must be valid
	C4Team *pTeam = GetTeamByID(idTeam);
	if (!pTeam) return false;
	// team player count must not exceed the limit, unless it is a script player
	return !pTeam->IsFull() || plrType == C4PT_Script;
}
Beispiel #5
0
void C4TeamList::FillTeamDistOptions(C4GUI::ComboBox_FillCB *pFiller) const
{
	// no teams if disabled
	if (!fActive) return;
	// team distribution options
	pFiller->AddEntry(GetTeamDistName(TEAMDIST_Free).getData(), TEAMDIST_Free);
	pFiller->AddEntry(GetTeamDistName(TEAMDIST_Host).getData(), TEAMDIST_Host);
	if (IsAutoGenerateTeams()) pFiller->AddEntry(GetTeamDistName(TEAMDIST_None).getData(), TEAMDIST_None); // no teams: only for regular melees
	pFiller->AddEntry(GetTeamDistName(TEAMDIST_Random).getData(), TEAMDIST_Random);
	pFiller->AddEntry(GetTeamDistName(TEAMDIST_RandomInv).getData(), TEAMDIST_RandomInv);
	}
Beispiel #6
0
void C4TeamList::EnsureTeamCount()
{
	// in random autogenerate mode, there must be exactly two teams
	if (IsRandomTeam())
	{
		if (IsAutoGenerateTeams() && GetTeamCount() != 2)
		{
			ClearTeams();
			GenerateDefaultTeams(2);
		}
	}
}
Beispiel #7
0
void C4TeamList::RecheckTeams()
{
	// automatic team distributions only
	if (!IsRandomTeam()) return;
	// host decides random teams
	if (!::Control.isCtrlHost())
	{
		// Still make sure that we have the right number of teams on the clients as well so that
		// GetTeamCount() does not report inconsistent values.
		EnsureTeamCount();
		return;
	}
	// random teams in auto generate mode? Make sure there are exactly two teams
	if (IsAutoGenerateTeams() && GetTeamCount() != 2)
		{
		ReassignAllTeams();
		return;
		}
	// redistribute players of largest team that has relocatable players left towards smaller teams
	for (;;)
	{
		C4Team *pLowestTeam = GetRandomSmallestTeam();
		if (!pLowestTeam) break; // no teams: Nothing to re-distribute.
		// get largest team that has relocateable players
		C4Team *pLargestTeam = nullptr;
		C4Team **ppCheck=ppList; int32_t iCnt=iTeamCount;
		for (; iCnt--; ++ppCheck) if (!pLargestTeam || pLargestTeam->GetPlayerCount() > (*ppCheck)->GetPlayerCount())
				if ((*ppCheck)->GetFirstUnjoinedPlayerID())
					pLargestTeam = *ppCheck;
		// no team can redistribute?
		if (!pLargestTeam) break;
		// redistribution won't help much?
		if (pLargestTeam->GetPlayerCount() - pLowestTeam->GetPlayerCount() <= 1) break;
		// okay; redistribute one player!
		int32_t idRedistPlayer = pLargestTeam->GetFirstUnjoinedPlayerID();
		C4PlayerInfo *pInfo = Game.PlayerInfos.GetPlayerInfoByID(idRedistPlayer);
		assert(pInfo);
		if (!pInfo) break; // umn...serious problems
		pLargestTeam->RemovePlayerByID(idRedistPlayer);
		pLowestTeam->AddPlayer(*pInfo, true);
		C4ClientPlayerInfos *pClrInfo = Game.PlayerInfos.GetClientInfoByPlayerID(idRedistPlayer);
		assert(pClrInfo);
		// player info change: mark updated to remote clients get information
		if (pClrInfo)
		{
			pClrInfo->SetUpdated();
		}
	}
}
Beispiel #8
0
bool C4TeamList::CanLocalChooseTeam(int32_t idPlayer) const
{
	// must be possible at all
	if (!CanLocalChooseTeam()) return false;
	// there must be space in a target team
	// always possible if teams are generated on the fly
	if (IsAutoGenerateTeams()) return true;
	// also possible if one of the teams that's not the player's is not full
	C4Team *pCurrentTeam = NULL, *pCheck;
	if (idPlayer) pCurrentTeam = GetTeamByPlayerID(idPlayer);
	int32_t iCheckTeam=0;
	while ((pCheck = GetTeamByIndex(iCheckTeam++)))
		if (pCheck != pCurrentTeam)
			if (!pCheck->IsFull())
				break;
	return !!pCheck;
}
Beispiel #9
0
void C4TeamList::ReassignAllTeams()
{
	assert(::Control.isCtrlHost());
	if (!::Control.isCtrlHost()) return;
	// go through all player infos; reset team in them
	int32_t idStart = -1; C4PlayerInfo *pNfo;
	while ((pNfo = Game.PlayerInfos.GetNextPlayerInfoByID(idStart)))
	{
		idStart = pNfo->GetID();
		if (pNfo->HasJoinIssued()) continue;
		pNfo->SetTeam(0);
		// mark changed info as updated
		C4ClientPlayerInfos *pCltInfo = Game.PlayerInfos.GetClientInfoByPlayerID(idStart);
		assert(pCltInfo);
		if (pCltInfo)
		{
			pCltInfo->SetUpdated();
		}
	}
	// clear players from team lists
	RecheckPlayers();
	// in random autogenerate mode, there must be exactly two teams
	if (IsRandomTeam())
		if (IsAutoGenerateTeams() && GetTeamCount() != 2)
			{
			ClearTeams();
			GenerateDefaultTeams(2);
			}
	// reassign them
	idStart = -1;
	while ((pNfo = Game.PlayerInfos.GetNextPlayerInfoByID(idStart)))
	{
		idStart = pNfo->GetID();
		if (pNfo->HasJoinIssued()) continue;
		assert(!pNfo->GetTeam());
		RecheckPlayerInfoTeams(*pNfo, true);
	}
}
Beispiel #10
0
bool C4TeamList::RecheckPlayerInfoTeams(C4PlayerInfo &rNewJoin, bool fByHost)
{
	// only if enabled
	assert(IsMultiTeams());
	if (!IsMultiTeams()) return false;
	// check whether a new team is to be assigned first
	C4Team *pCurrentTeam = GetTeamByPlayerID(rNewJoin.GetID());
	int32_t idCurrentTeam = pCurrentTeam ? pCurrentTeam->GetID() : 0;
	if (rNewJoin.GetTeam())
	{
		// was that team a change to the current team?
		// no change anyway: OK, skip this info
		if (idCurrentTeam == rNewJoin.GetTeam()) return true;
		// the player had a different team assigned: Check if changes are allowed at all
		if (eTeamDist == TEAMDIST_Free || (eTeamDist == TEAMDIST_Host && fByHost))
			// also make sure that selecting this team is allowed, e.g. doesn't break the team limit
			// this also checks whether the team number is a valid team - but it would accept TEAMID_New, which shouldn't be used in player infos!
			if (rNewJoin.GetTeam() != TEAMID_New && IsJoin2TeamAllowed(rNewJoin.GetTeam()))
				// okay; accept change
				return true;
		// Reject change by reassigning the current team
		rNewJoin.SetTeam(idCurrentTeam);
		// and determine a new team, if none has been assigned yet
		if (idCurrentTeam) return true;
	}
	// new team assignment
	// teams are always needed in the lobby, so there's a team preset to change
	// for runtime joins, teams are needed if specified by teams.txt or if any teams have been created before (to avoid mixed team-noteam-scenarios)
	// but only assign teams in runtime join if the player won't pick it himself
	bool fWillHaveLobby = ::Network.isEnabled() && !::Network.Status.isPastLobby() && Game.fLobby;
	bool fHasOrWillHaveLobby = ::Network.isLobbyActive() || fWillHaveLobby;
	bool fCanPickTeamAtRuntime = !IsRandomTeam() && (rNewJoin.GetType() == C4PT_User) && IsRuntimeJoinTeamChoice();
	bool fIsTeamNeeded = IsRuntimeJoinTeamChoice() || GetTeamCount();
	if (!fHasOrWillHaveLobby && (!fIsTeamNeeded || fCanPickTeamAtRuntime)) return false;
	// get least-used team
	C4Team *pAssignTeam=NULL;
	C4Team *pLowestTeam = GetRandomSmallestTeam();
	// melee mode
	if (IsAutoGenerateTeams() && !IsRandomTeam())
	{
		// reuse old team only if it's empty
		if (pLowestTeam && !pLowestTeam->GetPlayerCount())
			pAssignTeam = pLowestTeam;
		else
		{
			// no empty team: generate new
			GenerateDefaultTeams(iLastTeamID+1);
			pAssignTeam = GetTeamByID(iLastTeamID);
		}
	}
	else
	{
		if (!pLowestTeam)
		{
			// not enough teams defined in teamwork mode?
			// then create two teams as default
			if (!GetTeamByIndex(1))
				GenerateDefaultTeams(2);
			else
				// otherwise, all defined teams are full. This is a scenario error, because MaxPlayer should have been adjusted
				return false;
			pLowestTeam = GetTeamByIndex(0);
		}
		pAssignTeam = pLowestTeam;
	}
	// assign it
	if (!pAssignTeam) return false;
	pAssignTeam->AddPlayer(rNewJoin, true);
	return true;
}