1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2011-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // player team management for teamwork melees
17 
18 #ifndef INC_C4Teams
19 #define INC_C4Teams
20 
21 #include "lib/C4InputValidation.h"
22 
23 // constant used by lobby to indicate invisible, random team
24 const int32_t TEAMID_Unknown = -1;
25 
26 // constant used by InitScenarioPlayer() to indicate creation of a new team
27 const int32_t TEAMID_New = -1;
28 
29 // one player team
30 class C4Team
31 {
32 private:
33 	// std::vector...
34 	// containing player info IDs
35 	int32_t *piPlayers{nullptr};
36 	int32_t iPlayerCount{0};
37 	int32_t iPlayerCapacity{0};
38 
39 public:
40 	// copying
41 	C4Team(const C4Team &rCopy);
42 	C4Team &operator = (const C4Team &rCopy);
43 
44 protected:
45 	// team identification; usually > 0 for a valid team
46 	int32_t iID{0};
47 	char Name[C4MaxName+1];
48 	int32_t iPlrStartIndex{0}; // 0 for unassigned; 1 to 4 if all players of that team shall be assigned a specific [Player*]-section in the Scenario.txt
49 	uint32_t dwClr{0}; // team color
50 	StdCopyStrBuf sIconSpec; // icon drawing specification for offline or runtime team selection dialog
51 	int32_t iMaxPlayer{0}; // maximum number of players allowed in this team - 0 for infinite
52 
53 	friend class C4TeamList;
54 
55 public:
C4Team()56 	C4Team()  { *Name=0; }
~C4Team()57 	~C4Team() { Clear(); }
58 
59 	void Clear();
60 	void AddPlayer(class C4PlayerInfo &rInfo, bool fAdjustPlayer);  // add player by info; adjusts ID in info and at any joined player
61 	void RemoveIndexedPlayer(int32_t iIndex); // remove info at index; this changes the local list only
62 	void RemovePlayerByID(int32_t iID);
63 
GetPlayerCount()64 	int32_t GetPlayerCount() const { return iPlayerCount; }
GetName()65 	const char *GetName() const { return Name; }
GetID()66 	int32_t GetID() const { return iID; }
67 	bool IsPlayerIDInTeam(int32_t iID); // search list for a player with the given ID
68 	int32_t GetFirstUnjoinedPlayerID() const; // search for a player that does not have the join-flag set
GetPlrStartIndex()69 	int32_t GetPlrStartIndex() const { return iPlrStartIndex; }
GetColor()70 	uint32_t GetColor() const { return dwClr; }
GetIconSpec()71 	const char *GetIconSpec() const { return sIconSpec.getData(); }
IsFull()72 	bool IsFull() const { return iMaxPlayer && (iPlayerCount >= iMaxPlayer); } // whether no more players may join this team
73 	StdStrBuf GetNameWithParticipants() const; // compose team name like "Team 1 (boni, GhostBear, Clonko)"
74 	bool HasWon() const; // return true if any member player of the team has won
75 
GetIndexedPlayer(int32_t iIndex)76 	int32_t GetIndexedPlayer(int32_t iIndex) const { return Inside<int32_t>(iIndex, 0, iPlayerCount-1) ? piPlayers[iIndex] : 0; }
77 
78 	void CompileFunc(StdCompiler *pComp);
79 
80 	// this rechecks teams for all (not removed) players; sets players here by team selection in player infos
81 	void RecheckPlayers();
82 
83 	// this assigns a team color if it's still zero
84 	void RecheckColor(C4TeamList &rForList);
85 };
86 
87 // global team list
88 class C4TeamList
89 {
90 public:
91 	// team config constants
92 	enum ConfigValue
93 	{
94 		TEAM_None                 = 0,
95 		TEAM_Custom               = 1,
96 		TEAM_Active               = 2,
97 		TEAM_AllowHostilityChange = 3,
98 		TEAM_Dist                 = 4,
99 		TEAM_AllowTeamSwitch      = 5,
100 		TEAM_AutoGenerateTeams    = 6,
101 		TEAM_TeamColors           = 7
102 	};
103 
104 	// team distribution configuration
105 	enum TeamDist
106 	{
107 		TEAMDIST_First     = 0,
108 		TEAMDIST_Free      = 0, // anyone can choose teams
109 		TEAMDIST_Host      = 1, // host decides teams
110 		TEAMDIST_None      = 2, // no teams
111 		TEAMDIST_Random    = 3, // fixed random teams
112 		TEAMDIST_RandomInv = 4, // fixed random teams invisible in lobby
113 		TEAMDIST_Last      = 4,
114 	};
115 
116 private:
117 	// std::vector...
118 	C4Team **ppList{nullptr};
119 	int32_t iTeamCount{0};
120 	int32_t iTeamCapacity{0};
121 
122 	int32_t iLastTeamID{0};
123 	bool fAllowHostilityChange{true}; // hostility not fixed
124 	bool fAllowTeamSwitch{false}; // teams not fixed
125 	bool fActive{true};
126 	bool fCustom{false}; // set if read from team file or changed in scenario
127 	bool fTeamColors{false}; // if set, player colors are determined by team colors
128 	bool fAutoGenerateTeams{false}; // teams are generated automatically so there's enough teams for everyone
129 	TeamDist eTeamDist{TEAMDIST_Free};
130 	int32_t iMaxScriptPlayers{0}; // maximum number of script players to be added in the lobby
131 	StdStrBuf sScriptPlayerNames; // default script player names
132 
133 public:
134 	C4TeamList() = default;
~C4TeamList()135 	~C4TeamList() { Clear(); }
136 	void Clear();
137 
138 	C4TeamList &operator =(const C4TeamList &rCopy);
139 
140 private:
141 	// no copying
142 	C4TeamList(const C4TeamList &rCopy);
143 
144 private:
145 	void AddTeam(C4Team *pNewTeam); // add a team; grow list if necessary
146 	void ClearTeams(); // delete all teams
147 	int32_t GetFreeTeamID();
148 	bool GenerateDefaultTeams(int32_t iUpToID); // generate Team 1, Team 2, etc.
149 
150 public:
151 	C4Team *GetTeamByID(int32_t iID) const; // get team by ID
152 	C4Team *GetGenerateTeamByID(int32_t iID); // get team by ID; generate if not existant. Always generate for TEAMID_New.
153 	C4Team *GetTeamByIndex(int32_t iIndex) const; // get team by list index, to enumerate all teams
154 	C4Team *GetTeamByName(const char *szName) const; // match team name; case sensitive and not trimmed
155 	C4Team *GetTeamByPlayerID(int32_t iID) const; // get team by player ID (not number!)
156 	int32_t GetLargestTeamID() const;
157 	C4Team *GetRandomSmallestTeam() const; // get team with least amount of players in it
GetTeamCount()158 	int32_t GetTeamCount() const { return iTeamCount; }
159 
160 	C4Team *CreateTeam(const char *szName); // create a custom team
161 
IsMultiTeams()162 	bool IsMultiTeams() const { return fActive; } // teams can be selected
IsCustom()163 	bool IsCustom() const { return fCustom; }     // whether teams are not generated as default
IsHostilityChangeAllowed()164 	bool IsHostilityChangeAllowed() const { return fAllowHostilityChange; } // allow (temporary) hostility changes at runtime
IsTeamSwitchAllowed()165 	bool IsTeamSwitchAllowed() const { return fAllowTeamSwitch; } // allow permanent team changes at runtime
166 	bool CanLocalChooseTeam() const; // whether the local host can determine teams (e.g., not if teams are random, or if all except the player's current team are full)
167 	bool CanLocalChooseTeam(int32_t idPlayer) const; // whether the local host can determine teams (e.g., not if teams are random, or if all except the player's current team are full)
168 	bool CanLocalSeeTeam() const;
IsTeamColors()169 	bool IsTeamColors() const { return fTeamColors; } // whether team colors are enabled
IsRandomTeam()170 	bool IsRandomTeam() const { return eTeamDist==TEAMDIST_Random ||eTeamDist==TEAMDIST_RandomInv; } // whether a random team mode is selected
171 	bool IsJoin2TeamAllowed(int32_t idTeam, C4PlayerType plrType); // checks whether a team ID is valid and still available for new joins
IsAutoGenerateTeams()172 	bool IsAutoGenerateTeams() const { return fAutoGenerateTeams; }
IsRuntimeJoinTeamChoice()173 	bool IsRuntimeJoinTeamChoice() const { return IsCustom() && IsMultiTeams(); } // whether players joining at runtime must select a team first
GetMaxScriptPlayers()174 	int32_t GetMaxScriptPlayers() const { return iMaxScriptPlayers; } // return max number of script players to be added inthe lobby
175 	int32_t GetForcedTeamSelection(int32_t idForPlayer) const; // if there's only one team for the player to join, return that team ID
176 	StdStrBuf GetScriptPlayerName() const; // get a name to assign to a new script player. Try to avoid name conflicts
177 	bool IsTeamVisible() const; // teams invisible during lobby time if TEAMDIST_RandomInv
178 
179 	void EnforceLeagueRules(); // enforce some league settings, such as disallowing runtime team change
180 
181 	// assign a team ID to player info; recheck if any user-set team infos are valid within the current team options
182 	// creates a new team for melee; assigns the least-used team for teamwork melee
183 	// host/single-call only; using UnsyncedRandom!
184 	bool RecheckPlayerInfoTeams(C4PlayerInfo &rNewJoin, bool fByHost);
185 
186 	// compiler
187 	void CompileFunc(StdCompiler *pComp);
188 	bool Load(C4Group &hGroup, class C4Scenario *pInitDefault, class C4LangStringTable *pLang); // clear self and load from group file (C4CFN_Teams); init default by scen if no team fiel is present
189 	bool Save(C4Group &hGroup); // save to group file (C4CFN_Teams)
190 
191 	// this rechecks teams for all (not removed) players; sets players here by team selection in player infos
192 	void RecheckPlayers();
193 
194 	// this reorders any unjoined players to teams if they are unevenly filled and team distribution is random
195 	// any changed players will be flagged "updated"
196 	void RecheckTeams();
197 
198 	// marks all unjoined players as not-in-team and reassigns a team for them
199 	// also automatically flags all affected player infos as updated
200 	void ReassignAllTeams();
201 
202 private:
203 	// team distribution configuration
204 	StdStrBuf GetTeamDistName(TeamDist eTeamDist) const;
205 public:
206 	void FillTeamDistOptions(C4GUI::ComboBox_FillCB *pFiller) const;
207 	void SendSetTeamDist(TeamDist eNewDist);
GetTeamDist()208 	TeamDist GetTeamDist() const { return eTeamDist; }
209 	StdStrBuf GetTeamDistString() const;
210 	bool HasTeamDistOptions() const;
211 	void SetTeamDistribution(TeamDist eToVal);
212 	void SendSetTeamColors(bool fEnabled);
213 	void SetTeamColors(bool fEnabled);
214 
215 	// return number of non-empty teams. if players have not been assigned, project a guess on future team count.
216 	int32_t GetStartupTeamCount(int32_t startup_player_count);
217 };
218 
219 #endif // INC_C4Teams
220