void C4Team::AddPlayer(C4PlayerInfo &rInfo, bool fAdjustPlayer) { // must not happen! assert(rInfo.GetID()); if (!rInfo.GetID()) return; // add player; grow vector if necessary if (iPlayerCount >= iPlayerCapacity) { int32_t *piNewPlayers = new int32_t[iPlayerCapacity = (iPlayerCount+4)&~3]; if (iPlayerCount) memcpy(piNewPlayers, piPlayers, iPlayerCount*sizeof(int32_t)); delete [] piPlayers; piPlayers = piNewPlayers; } // store new player piPlayers[iPlayerCount++] = rInfo.GetID(); if (!fAdjustPlayer) return; // set values in info rInfo.SetTeam(GetID()); if (Game.Teams.IsTeamColors()) rInfo.SetColor(GetColor()); // and in actual player, if it is joined already if (rInfo.IsJoined()) { C4Player *pJoinedPlr = ::Players.GetByInfoID(rInfo.GetID()); assert(pJoinedPlr || (rInfo.GetType() == C4PT_Script)); if (pJoinedPlr) { pJoinedPlr->Team = GetID(); if (Game.Teams.IsTeamColors()) pJoinedPlr->SetPlayerColor(GetColor()); } } }
bool C4PlayerList::Save(C4Group &hGroup, bool fStoreTiny, const C4PlayerInfoList &rStoreList) { StdStrBuf sTempFilename; bool fSuccess = true; // Save to external player files and add to group for (C4Player *pPlr=First; pPlr; pPlr=pPlr->Next) { // save only those in the list, and only those with a filename C4PlayerInfo *pNfo = rStoreList.GetPlayerInfoByID(pPlr->ID); if (!pNfo) continue; if (!pNfo->GetFilename() || !*pNfo->GetFilename()) continue;; // save over original file? bool fStoreOnOriginal = (!fStoreTiny && pNfo->GetType() == C4PT_User); // Create temporary file sTempFilename.Copy(Config.AtTempPath(pNfo->GetFilename())); if (fStoreOnOriginal) if (!C4Group_CopyItem(pPlr->Filename, sTempFilename.getData())) return false; // Open group C4Group PlrGroup; if (!PlrGroup.Open(sTempFilename.getData(), !fStoreOnOriginal)) return false; // Save player if (!pPlr->Save(PlrGroup, true, fStoreOnOriginal)) return false; PlrGroup.Close(); // Add temp file to group if (!hGroup.Move(sTempFilename.getData(), pNfo->GetFilename())) return false; } return fSuccess; }
void C4Network2Players::JoinUnjoinedPlayersInControlQueue(C4ClientPlayerInfos *pNewPacket) { // only host may join any players to the queue assert(::Network.isHost()); // check all players int i=0; C4PlayerInfo *pInfo; while ((pInfo = pNewPacket->GetPlayerInfo(i++))) // not yet joined and no savegame assignment? if (!pInfo->HasJoinIssued()) if (!pInfo->GetAssociatedSavegamePlayerID()) { // join will be marked when queue is executed (C4Player::Join) // but better mark join now already to prevent permanent sending overkill pInfo->SetJoinIssued(); // do so! C4Network2Res *pPlrRes = pInfo->GetRes(); C4Network2Client *pClient = ::Network.Clients.GetClientByID(pNewPacket->GetClientID()); if (!pPlrRes || (!pClient && pNewPacket->GetClientID() != ::Control.ClientID())) if (pInfo->GetType() != C4PT_Script) { // failure: Non-script players must have a res to join from! const char *szPlrName = pInfo->GetName(); if (!szPlrName) szPlrName="???"; LogF("Network: C4Network2Players::JoinUnjoinedPlayersInControlQueue failed to join player %s!", szPlrName); continue; } if (pPlrRes) { // join with resource Game.Input.Add(CID_JoinPlr, new C4ControlJoinPlayer(pPlrRes->getFile(), pNewPacket->GetClientID(), pInfo->GetID(), pPlrRes->getCore())); } else { // join without resource (script player) Game.Input.Add(CID_JoinPlr, new C4ControlJoinPlayer(NULL, pNewPacket->GetClientID(), pInfo->GetID())); } } }
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; }