/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/ * Copyright (c) 2011-2016, The OpenClonk Team and contributors * * Distributed under the terms of the ISC license; see accompanying file * "COPYING" for details. * * "Clonk" is a registered trademark of Matthes Bender, used with permission. * See accompanying file "TRADEMARK" for details. * * To redistribute this file separately, substitute the full license texts * for the above references. */ // player team management for teamwork melees #ifndef INC_C4Teams #define INC_C4Teams #include "lib/C4InputValidation.h" // constant used by lobby to indicate invisible, random team const int32_t TEAMID_Unknown = -1; // constant used by InitScenarioPlayer() to indicate creation of a new team const int32_t TEAMID_New = -1; // one player team class C4Team { private: // std::vector... // containing player info IDs int32_t *piPlayers; int32_t iPlayerCount; int32_t iPlayerCapacity; public: // copying C4Team(const C4Team &rCopy); C4Team &operator = (const C4Team &rCopy); protected: // team identification; usually > 0 for a valid team int32_t iID; char Name[C4MaxName+1]; int32_t iPlrStartIndex; // 0 for unassigned; 1 to 4 if all players of that team shall be assigned a specific [Player*]-section in the Scenario.txt uint32_t dwClr; // team color StdCopyStrBuf sIconSpec; // icon drawing specification for offline or runtime team selection dialog int32_t iMaxPlayer; // maximum number of players allowed in this team - 0 for infinite friend class C4TeamList; public: C4Team() : piPlayers(NULL), iPlayerCount(0), iPlayerCapacity(0), iID(0), iPlrStartIndex(0), dwClr(0), iMaxPlayer(0) { *Name=0; } ~C4Team() { Clear(); } void Clear(); void AddPlayer(class C4PlayerInfo &rInfo, bool fAdjustPlayer); // add player by info; adjusts ID in info and at any joined player void RemoveIndexedPlayer(int32_t iIndex); // remove info at index; this changes the local list only void RemovePlayerByID(int32_t iID); int32_t GetPlayerCount() const { return iPlayerCount; } const char *GetName() const { return Name; } int32_t GetID() const { return iID; } bool IsPlayerIDInTeam(int32_t iID); // search list for a player with the given ID int32_t GetFirstUnjoinedPlayerID() const; // search for a player that does not have the join-flag set int32_t GetPlrStartIndex() const { return iPlrStartIndex; } uint32_t GetColor() const { return dwClr; } const char *GetIconSpec() const { return sIconSpec.getData(); } bool IsFull() const { return iMaxPlayer && (iPlayerCount >= iMaxPlayer); } // whether no more players may join this team StdStrBuf GetNameWithParticipants() const; // compose team name like "Team 1 (boni, GhostBear, Clonko)" bool HasWon() const; // return true if any member player of the team has won int32_t GetIndexedPlayer(int32_t iIndex) const { return Inside(iIndex, 0, iPlayerCount-1) ? piPlayers[iIndex] : 0; } void CompileFunc(StdCompiler *pComp); // this rechecks teams for all (not removed) players; sets players here by team selection in player infos void RecheckPlayers(); // this assigns a team color if it's still zero void RecheckColor(C4TeamList &rForList); }; // global team list class C4TeamList { public: // team config constants enum ConfigValue { TEAM_None = 0, TEAM_Custom = 1, TEAM_Active = 2, TEAM_AllowHostilityChange = 3, TEAM_Dist = 4, TEAM_AllowTeamSwitch = 5, TEAM_AutoGenerateTeams = 6, TEAM_TeamColors = 7 }; // team distribution configuration enum TeamDist { TEAMDIST_First = 0, TEAMDIST_Free = 0, // anyone can choose teams TEAMDIST_Host = 1, // host decides teams TEAMDIST_None = 2, // no teams TEAMDIST_Random = 3, // fixed random teams TEAMDIST_RandomInv = 4, // fixed random teams invisible in lobby TEAMDIST_Last = 4, }; private: // std::vector... C4Team **ppList; int32_t iTeamCount; int32_t iTeamCapacity; int32_t iLastTeamID; bool fAllowHostilityChange; // hostility not fixed bool fAllowTeamSwitch; // teams not fixed bool fActive; bool fCustom; // set if read from team file or changed in scenario bool fTeamColors; // if set, player colors are determined by team colors bool fAutoGenerateTeams; // teams are generated automatically so there's enough teams for everyone TeamDist eTeamDist; int32_t iMaxScriptPlayers; // maximum number of script players to be added in the lobby StdStrBuf sScriptPlayerNames; // default script player names public: C4TeamList() : ppList(NULL), iTeamCount(0), iTeamCapacity(0), iLastTeamID(0), fAllowHostilityChange(true), fAllowTeamSwitch(false), fActive(true), fCustom(false), fTeamColors(false), fAutoGenerateTeams(false), eTeamDist(TEAMDIST_Free), iMaxScriptPlayers(0) {} ~C4TeamList() { Clear(); } void Clear(); C4TeamList &operator =(const C4TeamList &rCopy); private: // no copying C4TeamList(const C4TeamList &rCopy); private: void AddTeam(C4Team *pNewTeam); // add a team; grow list if necessary void ClearTeams(); // delete all teams int32_t GetFreeTeamID(); bool GenerateDefaultTeams(int32_t iUpToID); // generate Team 1, Team 2, etc. public: C4Team *GetTeamByID(int32_t iID) const; // get team by ID C4Team *GetGenerateTeamByID(int32_t iID); // get team by ID; generate if not existant. Always generate for TEAMID_New. C4Team *GetTeamByIndex(int32_t iIndex) const; // get team by list index, to enumerate all teams C4Team *GetTeamByName(const char *szName) const; // match team name; case sensitive and not trimmed C4Team *GetTeamByPlayerID(int32_t iID) const; // get team by player ID (not number!) int32_t GetLargestTeamID() const; C4Team *GetRandomSmallestTeam() const; // get team with least amount of players in it int32_t GetTeamCount() const { return iTeamCount; } C4Team *CreateTeam(const char *szName); // create a custom team bool IsMultiTeams() const { return fActive; } // teams can be selected bool IsCustom() const { return fCustom; } // whether teams are not generated as default bool IsHostilityChangeAllowed() const { return fAllowHostilityChange; } // allow (temporary) hostility changes at runtime bool IsTeamSwitchAllowed() const { return fAllowTeamSwitch; } // allow permanent team changes at runtime 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) 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) bool CanLocalSeeTeam() const; bool IsTeamColors() const { return fTeamColors; } // whether team colors are enabled bool IsRandomTeam() const { return eTeamDist==TEAMDIST_Random ||eTeamDist==TEAMDIST_RandomInv; } // whether a random team mode is selected bool IsJoin2TeamAllowed(int32_t idTeam); // checks whether a team ID is valid and still available for new joins bool IsAutoGenerateTeams() const { return fAutoGenerateTeams; } bool IsRuntimeJoinTeamChoice() const { return IsCustom() && IsMultiTeams(); } // whether players joining at runtime must select a team first int32_t GetMaxScriptPlayers() const { return iMaxScriptPlayers; } // return max number of script players to be added inthe lobby int32_t GetForcedTeamSelection(int32_t idForPlayer) const; // if there's only one team for the player to join, return that team ID StdStrBuf GetScriptPlayerName() const; // get a name to assign to a new script player. Try to avoid name conflicts bool IsTeamVisible() const; // teams invisible during lobby time if TEAMDIST_RandomInv void EnforceLeagueRules(); // enforce some league settings, such as disallowing runtime team change // assign a team ID to player info; recheck if any user-set team infos are valid within the current team options // creates a new team for melee; assigns the least-used team for teamwork melee // host/single-call only; using SafeRandom! bool RecheckPlayerInfoTeams(C4PlayerInfo &rNewJoin, bool fByHost); // compiler void CompileFunc(StdCompiler *pComp); 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 bool Save(C4Group &hGroup); // save to group file (C4CFN_Teams) // this rechecks teams for all (not removed) players; sets players here by team selection in player infos void RecheckPlayers(); // this reorders any unjoined players to teams if they are unevenly filled and team distribution is random // any changed players will be flagged "updated" void RecheckTeams(); // marks all unjoined players as not-in-team and reassigns a team for them // also automatically flags all affected player infos as updated void ReassignAllTeams(); private: // team distribution configuration StdStrBuf GetTeamDistName(TeamDist eTeamDist) const; public: void FillTeamDistOptions(C4GUI::ComboBox_FillCB *pFiller) const; void SendSetTeamDist(TeamDist eNewDist); TeamDist GetTeamDist() const { return eTeamDist; } StdStrBuf GetTeamDistString() const; bool HasTeamDistOptions() const; void SetTeamDistribution(TeamDist eToVal); void SendSetTeamColors(bool fEnabled); void SetTeamColors(bool fEnabled); // return number of non-empty teams. if players have not been assigned, project a guess on future team count. int32_t GetStartupTeamCount(int32_t startup_player_count); }; #endif // INC_C4Teams