31 : piPlayers(new int32_t[rCopy.GetPlayerCount()]),
32 iPlayerCount(rCopy.GetPlayerCount()),
33 iPlayerCapacity(rCopy.GetPlayerCount()),
34 iID(rCopy.GetID()), iPlrStartIndex(rCopy.iPlrStartIndex), dwClr(rCopy.dwClr),
35 sIconSpec(rCopy.GetIconSpec()), iMaxPlayer(rCopy.iMaxPlayer)
40 for (int32_t i = 0; i < iPlayerCount; i++)
46 delete [] piPlayers; piPlayers =
nullptr;
47 iPlayerCount = iPlayerCapacity =
iMaxPlayer = 0;
55 assert(rInfo.
GetID());
56 if (!rInfo.
GetID())
return;
58 if (iPlayerCount >= iPlayerCapacity)
60 int32_t *piNewPlayers =
new int32_t[iPlayerCapacity = (iPlayerCount+4)&~3];
61 if (iPlayerCount) memcpy(piNewPlayers, piPlayers, iPlayerCount*
sizeof(int32_t));
62 delete [] piPlayers; piPlayers = piNewPlayers;
65 piPlayers[iPlayerCount++] = rInfo.
GetID();
66 if (!fAdjustPlayer)
return;
86 assert(Inside<int32_t>(iIndex, 0, iPlayerCount-1));
87 if (!Inside<int32_t>(iIndex, 0, iPlayerCount-1))
return;
89 for (int32_t i = iIndex+1; i < iPlayerCount; ++i)
90 piPlayers[i-1] = piPlayers[i];
98 for (i=0; i < iPlayerCount; ++i)
99 if (piPlayers[i] == iID)
break;
100 if (i == iPlayerCount) { assert(
false);
return; }
107 int32_t i=iPlayerCount, *piPlr = piPlayers;
108 while (i--)
if (*piPlr++ == iID)
return true;
115 int32_t i=iPlayerCount, idPlr, *piPlr = piPlayers;
132 if (pComp->
isDeserializer()) {
delete [] piPlayers; piPlayers =
new int32_t [iPlayerCapacity = iPlayerCount];
ZeroMem(piPlayers,
sizeof(*piPlayers) * iPlayerCount); }
143 for (int32_t i=0; i<iPlayerCount; ++i)
146 if ((
id = piPlayers[i]))
172 const int32_t C4MaxTeamColorChangeTries = 100;
175 const int defTeamColorCount = 10;
176 DWORD defTeamColorRGB[defTeamColorCount] = { 0xF40000, 0x00C800, 0xFCF41C, 0x2020FF,
177 0xC48444, 0xFFFFFF, 0x848484, 0xFF00EF,
181 if (
iID >=1 &&
iID <=defTeamColorCount)
184 dwClr = defTeamColorRGB[
iID-1] | 0xff000000;
189 for (int32_t iTry=1; iTry<C4MaxTeamColorChangeTries; ++iTry)
192 int32_t iIdx=0;
C4Team *pTeam;
bool fOK=
true;
218 int32_t iTeamPlrCount=0;
225 if (iTeamPlrCount++) sTeamName.
Append(
", ");
237 bool fHasWon =
false;
238 for (int32_t i=0; i<iPlayerCount; ++i)
241 if ((
id = piPlayers[i]))
260 delete [] ppList; ppList =
nullptr;
262 fAllowHostilityChange =
true;
263 fAllowTeamSwitch =
false;
267 eTeamDist = TEAMDIST_Free;
268 fAutoGenerateTeams =
false;
269 iMaxScriptPlayers = 0;
270 sScriptPlayerNames.Clear();
276 if ((iTeamCount = iTeamCapacity = rCopy.iTeamCount))
277 ppList =
new C4Team *[iTeamCapacity];
278 for (
int i = 0; i < iTeamCount; i++)
279 ppList[i] =
new C4Team(*rCopy.ppList[i]);
280 iLastTeamID = rCopy.iLastTeamID;
281 fAllowHostilityChange = rCopy.fAllowHostilityChange;
282 fAllowTeamSwitch = rCopy.fAllowTeamSwitch;
283 fCustom = rCopy.fCustom;
284 fActive = rCopy.fActive;
285 eTeamDist = rCopy.eTeamDist;
286 fTeamColors = rCopy.fTeamColors;
287 fAutoGenerateTeams = rCopy.fAutoGenerateTeams;
288 sScriptPlayerNames = rCopy.sScriptPlayerNames;
295 if (!fActive)
return false;
299 case TEAMDIST_Free:
return true;
302 case TEAMDIST_Random:
303 case TEAMDIST_RandomInv:
305 default: assert(
false);
return false;
312 if (!CanLocalChooseTeam())
return false;
315 if (IsAutoGenerateTeams())
return true;
317 C4Team *pCurrentTeam =
nullptr, *pCheck;
318 if (idPlayer) pCurrentTeam = GetTeamByPlayerID(idPlayer);
319 int32_t iCheckTeam=0;
320 while ((pCheck = GetTeamByIndex(iCheckTeam++)))
321 if (pCheck != pCurrentTeam)
322 if (!pCheck->IsFull())
329 if (!fActive)
return false;
331 if (eTeamDist != TEAMDIST_RandomInv)
return true;
335 void C4TeamList::AddTeam(
C4Team *pNewTeam)
338 if (iTeamCount >= iTeamCapacity)
342 C4Team **ppNewTeams =
new C4Team*[(iTeamCapacity = ((iTeamCount+4)&~3))];
343 if (iTeamCount) memcpy(ppNewTeams, ppList, iTeamCount*
sizeof(
C4Team *));
344 delete [] ppList; ppList = ppNewTeams;
347 ppList[iTeamCount++] = pNewTeam;
349 iLastTeamID = std::max(pNewTeam->
iID, iLastTeamID);
352 void C4TeamList::ClearTeams()
356 if (iTeamCount) {
while (iTeamCount--)
delete *(ppTeam++); iTeamCount = 0; }
364 pNewTeam->
iID = iLastTeamID + 1;
371 bool C4TeamList::GenerateDefaultTeams(int32_t iUpToID)
374 while (iLastTeamID < iUpToID)
378 if (!CreateTeam(TeamName))
return false;
385 C4Team **ppCheck=ppList; int32_t
iCnt=iTeamCount;
386 for (; iCnt--; ++ppCheck)
if ((*ppCheck)->GetID() ==
iID)
return *ppCheck;
393 if (!IsMultiTeams())
return nullptr;
395 if (iID ==
TEAMID_New) iID = GetLargestTeamID()+1;
397 C4Team *pTeam = GetTeamByID(iID);
398 if (pTeam)
return pTeam;
400 GenerateDefaultTeams(iID);
401 return GetTeamByID(iID);
407 if (!Inside<int32_t>(iIndex, 0, iTeamCount-1))
return nullptr;
409 return ppList[iIndex];
415 C4Team **ppCheck=ppList; int32_t
iCnt=iTeamCount;
416 for (; iCnt--; ++ppCheck)
if (
SEqual((*ppCheck)->GetName(), szName))
return *ppCheck;
422 C4Team **ppCheck=ppList; int32_t
iCnt=iTeamCount;
423 for (; iCnt--; ++ppCheck)
if ((*ppCheck)->IsPlayerIDInTeam(iID))
return *ppCheck;
429 int32_t iLargest = 0;
430 C4Team **ppCheck=ppList; int32_t
iCnt=iTeamCount;
431 for (; iCnt--; ++ppCheck) iLargest = std::max((*ppCheck)->GetID(), iLargest);
437 C4Team *pLowestTeam =
nullptr;
int iLowestTeamCount = 0;
438 C4Team **ppCheck=ppList; int32_t
iCnt=iTeamCount;
439 for (; iCnt--; ++ppCheck)
441 if ((*ppCheck)->IsFull())
continue;
442 if (!pLowestTeam || pLowestTeam->
GetPlayerCount() > (*ppCheck)->GetPlayerCount())
444 pLowestTeam = *ppCheck;
445 iLowestTeamCount = 1;
447 else if (pLowestTeam->
GetPlayerCount() == (*ppCheck)->GetPlayerCount())
449 pLowestTeam = *ppCheck;
457 if (eTeamDist == TEAMDIST_RandomInv)
466 assert(IsMultiTeams());
467 if (!IsMultiTeams())
return false;
469 C4Team *pCurrentTeam = GetTeamByPlayerID(rNewJoin.
GetID());
470 int32_t idCurrentTeam = pCurrentTeam ? pCurrentTeam->
GetID() : 0;
475 if (idCurrentTeam == rNewJoin.
GetTeam())
return true;
477 if (eTeamDist == TEAMDIST_Free || (eTeamDist == TEAMDIST_Host && fByHost))
484 rNewJoin.
SetTeam(idCurrentTeam);
486 if (idCurrentTeam)
return true;
494 bool fCanPickTeamAtRuntime = !IsRandomTeam() && (rNewJoin.
GetType() ==
C4PT_User) && IsRuntimeJoinTeamChoice();
495 bool fIsTeamNeeded = IsRuntimeJoinTeamChoice() || GetTeamCount();
496 if (!fHasOrWillHaveLobby && (!fIsTeamNeeded || fCanPickTeamAtRuntime))
return false;
498 C4Team *pAssignTeam=
nullptr;
499 C4Team *pLowestTeam = GetRandomSmallestTeam();
501 if (IsAutoGenerateTeams() && !IsRandomTeam())
505 pAssignTeam = pLowestTeam;
509 GenerateDefaultTeams(iLastTeamID+1);
510 pAssignTeam = GetTeamByID(iLastTeamID);
519 if (!GetTeamByIndex(1))
520 GenerateDefaultTeams(2);
524 pLowestTeam = GetTeamByIndex(0);
526 pAssignTeam = pLowestTeam;
529 if (!pAssignTeam)
return false;
537 if (idTeam ==
TEAMID_New)
return IsAutoGenerateTeams();
539 C4Team *pTeam = GetTeamByID(idTeam);
540 if (!pTeam)
return false;
557 {
"Free", TEAMDIST_Free },
558 {
"Host", TEAMDIST_Host },
559 {
"None", TEAMDIST_None },
560 {
"Random", TEAMDIST_Random },
561 {
"RandomInv", TEAMDIST_RandomInv },
563 pComp->
Value(
mkNamingAdapt(mkEnumAdaptT<uint8_t>(eTeamDist, TeamDistEntries),
"TeamDistribution", TEAMDIST_Free));
569 int32_t iOldTeamCount = iTeamCount;
574 while (iOldTeamCount--)
delete ppList[iOldTeamCount];
576 if ((iTeamCapacity = iTeamCount))
578 ppList =
new C4Team *[iTeamCapacity];
579 memset(ppList, 0,
sizeof(
C4Team *)*iTeamCapacity);
598 iLastTeamID = std::max(GetLargestTeamID(), iLastTeamID);
600 if (!iTeamCount) fAutoGenerateTeams =
true;
613 if (!pInitDefault)
return false;
618 fAllowHostilityChange =
true;
620 fAutoGenerateTeams =
true;
627 fAllowHostilityChange =
true;
640 int32_t iTeam=0;
C4Team *pTeam;
641 while ((pTeam = GetTeamByIndex(iTeam++)))
665 C4Team **ppCheck=ppList; int32_t
iCnt=iTeamCount;
666 for (; iCnt--; ++ppCheck) (*ppCheck)->RecheckPlayers();
672 if (!IsRandomTeam())
return;
676 if (IsAutoGenerateTeams() && GetTeamCount() != 2)
684 C4Team *pLowestTeam = GetRandomSmallestTeam();
685 if (!pLowestTeam)
break;
687 C4Team *pLargestTeam =
nullptr;
688 C4Team **ppCheck=ppList; int32_t
iCnt=iTeamCount;
689 for (; iCnt--; ++ppCheck)
if (!pLargestTeam || pLargestTeam->
GetPlayerCount() > (*ppCheck)->GetPlayerCount())
690 if ((*ppCheck)->GetFirstUnjoinedPlayerID())
691 pLargestTeam = *ppCheck;
693 if (!pLargestTeam)
break;
721 idStart = pNfo->
GetID();
736 if (IsAutoGenerateTeams() && GetTeamCount() != 2)
739 GenerateDefaultTeams(2);
745 idStart = pNfo->
GetID();
748 RecheckPlayerInfoTeams(*pNfo,
true);
761 default:
return(
FormatString(
"TEAMDIST_undefined(%d)", (
int) eTeamDist));
768 if (!fActive)
return;
770 pFiller->
AddEntry(GetTeamDistName(TEAMDIST_Free).getData(), TEAMDIST_Free);
771 pFiller->
AddEntry(GetTeamDistName(TEAMDIST_Host).getData(), TEAMDIST_Host);
772 if (IsAutoGenerateTeams()) pFiller->
AddEntry(GetTeamDistName(TEAMDIST_None).getData(), TEAMDIST_None);
773 pFiller->
AddEntry(GetTeamDistName(TEAMDIST_Random).getData(), TEAMDIST_Random);
774 pFiller->
AddEntry(GetTeamDistName(TEAMDIST_RandomInv).getData(), TEAMDIST_RandomInv);
787 return GetTeamDistName(eTeamDist);
798 if (!
Inside(eToVal, TEAMDIST_First, TEAMDIST_Last)) { assert(
false);
return; }
805 if (IsRandomTeam() || eTeamDist==TEAMDIST_None)
829 if (fEnabled == fTeamColors)
return;
831 fTeamColors = fEnabled;
847 fAllowTeamSwitch =
false;
853 C4Team *pOKTeam =
nullptr, *pCheck;
854 if (idForPlayer) pOKTeam = GetTeamByPlayerID(idForPlayer);
855 int32_t iCheckTeam=0;
856 while ((pCheck = GetTeamByIndex(iCheckTeam++)))
857 if (!pCheck->IsFull())
860 if (pOKTeam && pOKTeam != pCheck)
872 if (IsAutoGenerateTeams())
return 0;
874 return pOKTeam->
GetID();
877 if (IsAutoGenerateTeams())
892 while (sScriptPlayerNames.GetSection(iNameIdx++, &sOut,
'|'))
903 int32_t i_team = 0;
C4Team *team;
904 int32_t team_count = 0;
905 while ((team = GetTeamByIndex(i_team++)))
914 if (IsCustom() && !IsAutoGenerateTeams())
917 team_count = std::min<int32_t>(startup_player_count, GetTeamCount());
919 else if (IsRandomTeam())
922 team_count = std::min<int32_t>(startup_player_count, 2);
927 team_count = startup_player_count;
const char * GetName() const
void SetColor(DWORD dwUseClr)
void SendSetTeamDist(TeamDist eNewDist)
C4PlayerInfo * GetNextPlayerInfoByID(int32_t id) const
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
StdNamingCountAdapt< int_t > mkNamingCountAdapt(int_t &iCount, const char *szName)
void RecheckColor(C4TeamList &rForList)
uint32_t UnsyncedRandom()
void SetTeam(int32_t idToTeam)
bool GetSection(size_t idx, StdStrBuf *psOutSection, char cSeparator=';') const
int32_t GetPlayerCount() const
C4Team * GetGenerateTeamByID(int32_t iID)
bool HasTeamDistOptions() const
C4Team * GetTeamByPlayerID(int32_t iID) const
void SendSetTeamColors(bool fEnabled)
int32_t GetIndexedPlayer(int32_t iIndex) const
bool IsTeamVisible() const
C4Team * CreateTeam(const char *szName)
void UpdatePlayerAttributes(C4ClientPlayerInfos *pForInfo, bool fResolveConflicts)
bool SEqual(const char *szStr1, const char *szStr2)
const char * LoadResStr(const char *id)
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
void AppendChar(char cChar)
bool Load(C4Group &hGroup, class C4Scenario *pInitDefault, class C4LangStringTable *pLang)
void RemoveIndexedPlayer(int32_t iIndex)
bool Save(C4Group &hGroup)
bool RecheckPlayerInfoTeams(C4PlayerInfo &rNewJoin, bool fByHost)
int32_t GetFirstUnjoinedPlayerID() const
const char * GetName() const
DWORD GenerateRandomPlayerColor(int32_t iTry)
StdStrBuf GetNameWithParticipants() const
StdArrayAdapt< T > mkArrayAdapt(T *pArray, int iSize)
C4PlayerType GetType() const
void SetTeamColors(bool fEnabled)
bool IsTeamColors() const
void SendUpdatedPlayers()
void AddPlayer(class C4PlayerInfo &rInfo, bool fAdjustPlayer)
void DoInput(C4PacketType eCtrlType, C4ControlPacket *pPkt, C4ControlDeliveryType eDelivery)
void Append(const char *pnData, size_t iChars)
StdPtrAdapt< T > mkPtrAdaptNoNull(T *&rpObj)
bool HasJoinIssued() const
void SetPlayerColor(uint32_t dwNewClr)
C4PlayerInfo * GetActivePlayerInfoByName(const char *szName)
bool CanLocalSeeTeam() const
void ReplaceStrings(StdStrBuf &rBuf)
C4ClientPlayerInfos * GetClientInfoByPlayerID(int32_t id) const
void Value(const T &rStruct)
const char * getData() const
virtual bool isDeserializer()
bool DeleteEntry(const char *szFilename, bool fRecycle=false)
void RemovePlayerByID(int32_t iID)
C4PlayerInfoList & PlayerInfos
C4Team * GetRandomSmallestTeam() const
bool LoadEntryString(const char *szEntryName, StdStrBuf *Buf)
bool IsColorConflict(DWORD dwClr1, DWORD dwClr2)
bool IsPlayerIDInTeam(int32_t iID)
C4Team * GetTeamByName(const char *szName) const
StdStrBuf GetScriptPlayerName() const
void CompileFunc(StdCompiler *pComp)
C4Network2Players Players
bool CanLocalChooseTeam() const
bool Add(const char *szFile, const char *szAddAs)
#define mkStringAdaptMA(szString)
void AddEntry(const char *szText, int32_t id)
void SetTeamDistribution(TeamDist eToVal)
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
C4TeamList & operator=(const C4TeamList &rCopy)
void CompileFunc(StdCompiler *pComp)
StdStrBuf GetTeamDistString() const
std::enable_if< std::is_pod< T >::value >::type ZeroMem(T *lpMem, size_t dwSize)
bool IsJoin2TeamAllowed(int32_t idTeam, C4PlayerType plrType)
int32_t GetForcedTeamSelection(int32_t idForPlayer) const
void FillTeamDistOptions(C4GUI::ComboBox_FillCB *pFiller) const
C4Team * GetTeamByIndex(int32_t iIndex) const
StdArrayAdapt< T, M > mkArrayAdaptMap(T *pArray, int iSize, M &&map)
int32_t GetLargestTeamID() const
void EnforceLeagueRules()
int32_t GetStartupTeamCount(int32_t startup_player_count)
bool Inside(T ival, U lbound, V rbound)
C4PlayerInfo * GetPlayerInfoByID(int32_t id) const
C4Player * GetByInfoID(int iInfoID) const
bool isLobbyActive() const
uint32_t GetColor() const
StdStrBuf FormatString(const char *szFmt,...)
C4Team * GetTeamByID(int32_t iID) const