static void G_Players_f (const player_t *player) { int count = 0; char smallBuf[64]; char largeBuf[1280]; player_t *p; /* print information */ largeBuf[0] = 0; p = NULL; while ((p = G_PlayerGetNextActiveHuman(p))) { Com_sprintf(smallBuf, sizeof(smallBuf), "(%i) Team %i %s status: %s\n", p->num, p->pers.team, p->pers.netname, (p->roundDone ? "waiting" : "playing")); /* can't print all of them in one packet */ if (strlen(smallBuf) + strlen(largeBuf) > sizeof(largeBuf) - 100) { Q_strcat(largeBuf, "...\n", sizeof(largeBuf)); break; } Q_strcat(largeBuf, smallBuf, sizeof(largeBuf)); count++; } G_ClientPrintf(player, PRINT_CONSOLE, "%s\n%i players\n", largeBuf, count); }
/** * @brief Chose a team that should start the match * @param[in] player In singleplayer mode the team of this player will get the first turn * @sa SVCmd_StartGame_f */ static void G_GetStartingTeam (const player_t* player) { int teamCount; int playerCount; int knownTeams[MAX_TEAMS]; player_t *p; /* return with no action if activeTeam already assigned or if are in single-player mode */ if (G_MatchIsRunning()) return; if (sv_maxclients->integer == 1) { level.activeTeam = player->pers.team; level.teamOfs = MAX_TEAMS - level.activeTeam; return; } /* count number of currently connected unique teams and players (human controlled players only) */ p = NULL; teamCount = 0; playerCount = 0; while ((p = G_PlayerGetNextActiveHuman(p))) { int j; playerCount++; for (j = 0; j < teamCount; j++) { if (p->pers.team == knownTeams[j]) break; } if (j == teamCount) knownTeams[teamCount++] = p->pers.team; } if (teamCount) { const int teamIndex = (int) (frand() * (teamCount - 1) + 0.5); G_PrintStats("Starting new game: %s with %i teams", level.mapname, teamCount); level.activeTeam = knownTeams[teamIndex]; level.teamOfs = MAX_TEAMS - level.activeTeam; p = NULL; while ((p = G_PlayerGetNextActiveHuman(p))) if (p->pers.team != level.activeTeam) p->roundDone = true; } }
/** * @brief Check whether a forced turn end should be executed */ void G_CheckForceEndRound (void) { /* check for roundlimits in multiplayer only */ if (!sv_roundtimelimit->integer || G_IsSinglePlayer()) return; if (!G_MatchIsRunning()) return; if (level.time != ceil(level.time)) return; const int diff = level.roundstartTime + sv_roundtimelimit->integer - level.time; switch (diff) { case 240: gi.BroadcastPrintf(PRINT_HUD, _("4 minutes left until forced turn end.")); return; case 180: gi.BroadcastPrintf(PRINT_HUD, _("3 minutes left until forced turn end.")); return; case 120: gi.BroadcastPrintf(PRINT_HUD, _("2 minutes left until forced turn end.")); return; case 60: gi.BroadcastPrintf(PRINT_HUD, _("1 minute left until forced turn end.")); return; case 30: gi.BroadcastPrintf(PRINT_HUD, _("30 seconds left until forced turn end.")); return; case 15: gi.BroadcastPrintf(PRINT_HUD, _("15 seconds left until forced turn end.")); return; } /* active team still has time left */ if (level.time < level.roundstartTime + sv_roundtimelimit->integer) return; gi.BroadcastPrintf(PRINT_HUD, _("Current active team hit the max round time.")); /* store this in a local variable, as the global variable is changed in G_ClientEndRound */ const int activeTeam = level.activeTeam; /* set all team members to ready (only human players) */ Player* p = nullptr; while ((p = G_PlayerGetNextActiveHuman(p))) { if (p->getTeam() == activeTeam) { G_ClientEndRound(*p); level.nextEndRound = level.framenum; } } level.roundstartTime = level.time; }
/** * @brief Converts player mask to vis mask * @param[in] playerMask The player bit mask (contains the player numbers) that * is converted to a vis mask * @return Returns a vis mask for all the teams of the connected players that * are marked in the given @c playerMask. */ teammask_t G_PMToVis (playermask_t playerMask) { player_t *p; teammask_t teamMask = 0; /* don't handle the ai players, here */ p = NULL; while ((p = G_PlayerGetNextActiveHuman(p))) { if (playerMask & G_PlayerToPM(p)) teamMask |= G_TeamToVisMask(p->pers.team); } return teamMask; }
/** * @brief Converts vis mask to player mask * @param[in] vis_mask The visibility bit mask (contains the team numbers) that * is converted to a player mask * @return Returns a playermask for all the teams of the connected players that * are marked in the given @c vis_mask. */ unsigned int G_VisToPM (vismask_t vis_mask) { player_t *p; unsigned int playerMask; playerMask = 0; /* don't handle the ai players, here */ p = NULL; while ((p = G_PlayerGetNextActiveHuman(p))) { if (vis_mask & G_TeamToVisMask(p->pers.team)) playerMask |= G_PlayerToPM(p); } return playerMask; }
/** * @brief Gets player for given team. * @param[in] team The team the player data should be searched for * @return The inuse player for the given team or @c NULL when no player found. * @todo What if there are multiple players for a team (multiplayer coop match) */ player_t* G_GetPlayerForTeam (int team) { player_t *p; /* search corresponding player (even ai players) */ p = NULL; while ((p = G_PlayerGetNextActiveHuman(p))) if (p->pers.team == team) /* found player */ return p; p = NULL; while ((p = G_PlayerGetNextActiveAI(p))) if (p->pers.team == team) /* found player */ return p; return NULL; }
static void G_Say_f (player_t *player, bool arg0, bool team) { char text[256]; player_t *p; if (gi.Cmd_Argc() < 2 && !arg0) return; if (G_CheckFlood(player)) return; if (!team) Com_sprintf(text, sizeof(text), "%s: ", player->pers.netname); else Com_sprintf(text, sizeof(text), "^B%s (team): ", player->pers.netname); if (arg0) { Q_strcat(text, gi.Cmd_Argv(0), sizeof(text)); Q_strcat(text, " ", sizeof(text)); Q_strcat(text, gi.Cmd_Args(), sizeof(text)); } else { const char *p = gi.Cmd_Args(); const char *token = Com_Parse(&p); Q_strcat(text, token, sizeof(text)); } Q_strcat(text, "\n", sizeof(text)); if (sv_dedicated->integer) gi.DPrintf("%s", text); p = NULL; while ((p = G_PlayerGetNextActiveHuman(p))) { if (team && p->pers.team != player->pers.team) continue; G_ClientPrintf(p, PRINT_CHAT, "%s", text); } }
static void G_Say_f (Player& player, bool arg0, bool team) { if (gi.Cmd_Argc() < 2 && !arg0) return; if (G_CheckFlood(player)) return; char text[256]; if (arg0) { Com_sprintf(text, sizeof(text), "%s %s", gi.Cmd_Argv(0), gi.Cmd_Args()); } else { Com_sprintf(text, sizeof(text), "%s", gi.Cmd_Args()); } /* strip quotes */ char* s = text; if (s[0] == '"' && s[strlen(s) - 1] == '"') { s[strlen(s) - 1] = '\0'; s++; } if (sv_dedicated->integer) { if (!team) gi.DPrintf("%s: %s\n", player.pers.netname, s); else gi.DPrintf("^B%s (team): %s\n", player.pers.netname, s); } Player* p = nullptr; while ((p = G_PlayerGetNextActiveHuman(p))) { if (team && p->getTeam() != player.getTeam()) continue; if (!team) G_ClientPrintf(*p, PRINT_CHAT, "%s: %s\n", player.pers.netname, s); else G_ClientPrintf(*p, PRINT_CHAT, "^B%s (team): %s\n", player.pers.netname, s); } }
/** * @brief Sets the teamnum var for this match * @param[in] player Pointer to connected player * @todo Check whether there are enough free spawnpoints in all cases */ static void G_GetTeam (player_t * player) { player_t *p; int playersInGame = 0; /* player has already a team */ if (player->pers.team > 0) { Com_DPrintf(DEBUG_GAME, "Player %s is already on team %i\n", player->pers.netname, player->pers.team); return; } /* number of currently connected players (no ai players) */ p = NULL; while ((p = G_PlayerGetNextActiveHuman(p))) playersInGame++; /* randomly assign a teamnumber in deathmatch games */ if (playersInGame <= 1 && sv_maxclients->integer > 1 && !sv_teamplay->integer) { int spawnCheck[MAX_TEAMS]; int spawnSpots = 0; int randomSpot; int i; /* skip civilian teams */ for (i = TEAM_PHALANX; i < MAX_TEAMS; i++) { spawnCheck[i] = 0; /* check whether there are spawnpoints for this team */ if (level.num_spawnpoints[i]) spawnCheck[spawnSpots++] = i; } /* we need at least 2 different team spawnpoints for multiplayer in a death match game */ if (spawnSpots < 2) gi.Error("G_GetTeam: Not enough spawn spots in map!"); /* assign random valid team number */ i = spawnSpots; randomSpot = rand() % spawnSpots; for (;;) { const int team = spawnCheck[randomSpot]; if (i == 0) gi.Error("G_GetTeam: Could not assign a team!"); if (G_SetTeamForPlayer(player, team)) { gi.DPrintf("%s has been randomly assigned to team %i\n", player->pers.netname, G_ClientGetTeamNum(player)); break; } i--; randomSpot = (randomSpot + 1) % spawnSpots; } return; } /* find a team */ if (sv_maxclients->integer == 1) G_SetTeamForPlayer(player, TEAM_PHALANX); else if (sv_teamplay->integer) { /* set the team specified in the userinfo */ const int i = G_ClientGetTeamNumPref(player); gi.DPrintf("Get a team for teamplay for %s\n", player->pers.netname); /* civilians are at team zero */ if (i > TEAM_CIVILIAN && sv_maxteams->integer >= i) { G_SetTeamForPlayer(player, i); gi.BroadcastPrintf(PRINT_CONSOLE, "serverconsole: %s has chosen team %i\n", player->pers.netname, i); } else { gi.DPrintf("Team %i is not valid - choose a team between 1 and %i\n", i, sv_maxteams->integer); G_SetTeamForPlayer(player, TEAM_DEFAULT); } } else { int i; /* search team */ gi.DPrintf("Getting a multiplayer team for %s\n", player->pers.netname); for (i = TEAM_CIVILIAN + 1; i < MAX_TEAMS; i++) { if (level.num_spawnpoints[i]) { bool teamAvailable = true; p = NULL; /* check if team is in use (only human controlled players) */ while ((p = G_PlayerGetNextActiveAI(p))) { if (p->pers.team == i) { Com_DPrintf(DEBUG_GAME, "Team %i is already in use\n", i); /* team already in use */ teamAvailable = false; break; } } if (teamAvailable) break; } } /* set the team */ if (i < MAX_TEAMS) { /* remove ai player */ p = NULL; while ((p = G_PlayerGetNextActiveHuman(p))) { if (p->pers.team == i) { gi.BroadcastPrintf(PRINT_CONSOLE, "Removing ai player..."); p->inuse = false; break; } } Com_DPrintf(DEBUG_GAME, "Assigning %s to team %i\n", player->pers.netname, i); G_SetTeamForPlayer(player, i); } else { gi.DPrintf("No free team - disconnecting '%s'\n", player->pers.netname); G_ClientDisconnect(player); } } }
/** * @sa G_PlayerSoldiersCount */ void G_ClientEndRound (Player& player) { Player* p; const int lastTeamIndex = (G_GetActiveTeam() + level.teamOfs) % MAX_TEAMS; if (!G_IsAIPlayer(&player)) { /* inactive players can't end their inactive turn :) */ if (level.activeTeam != player.getTeam()) return; /* check for "team oszillation" */ if (level.framenum < level.nextEndRound) return; level.nextEndRound = level.framenum + 20; } /* only use this for teamplay matches like coopX or fight2on2 and above * also skip this for ai players, this is only called when all ai actors * have finished their 'thinking' */ if (!G_IsAIPlayer(&player) && sv_teamplay->integer) { /* check if all team members are ready */ if (!player.roundDone) { player.roundDone = true; G_EventEndRoundAnnounce(player); G_EventEnd(); } p = nullptr; while ((p = G_PlayerGetNextActiveHuman(p))) if (p->getTeam() == level.activeTeam && !p->roundDone && G_PlayerSoldiersCount(*p) > 0) return; p = nullptr; while ((p = G_PlayerGetNextActiveAI(p))) if (p->getTeam() == level.activeTeam && !p->roundDone && G_PlayerSoldiersCount(*p) > 0) return; } else { player.roundDone = true; } /* clear any remaining reaction fire */ G_ReactionFireOnEndTurn(); if (!G_IsAIPlayer(&player)) { if (g_lastseen->integer > 0) { Edict* ent = nullptr; while ((ent = G_EdictsGetNextActor(ent))) { if (G_IsAI(ent) && G_IsVisibleForTeam(ent, level.activeTeam)) { player.lastSeen = level.actualRound; break; } } if (level.actualRound - player.lastSeen > g_lastseen->integer) { Com_Printf("round end triggered by g_lastseen (player %i (team %i) last seen in round %i of %i rounds)\n", player.getNum(), level.activeTeam, player.lastSeen, level.actualRound); G_MatchEndTrigger(-1, 0); } } } /* let all the invisible players perish now */ G_CheckVisTeamAll(level.activeTeam, VIS_APPEAR, nullptr); G_GetNextActiveTeam(); AI_CheckRespawn(TEAM_ALIEN); /* no other team left? */ if (!G_MatchIsRunning()) return; if (lastTeamIndex > (level.activeTeam + level.teamOfs) % MAX_TEAMS) level.actualRound++; /* communicate next player in row to clients */ G_EventEndRound(); /* store the round start time to be able to abort the round after a give time */ level.roundstartTime = level.time; /* Wounded team members bleed */ G_BleedWounds(level.activeTeam); /* Update the state of stuned team-members. The actual statistics are sent below! */ G_UpdateStunState(level.activeTeam); /* Give the actors of the now active team their TUs. */ G_GiveTimeUnits(level.activeTeam); /* apply morale behaviour, reset reaction fire */ G_ReactionFireReset(level.activeTeam); if (mor_panic->integer) G_MoraleBehaviour(level.activeTeam); G_UpdateCarriedWeight(level.activeTeam); /* start ai - there is only one player for ai teams, and the last pointer must only * be updated for ai players */ p = G_GetPlayerForTeam(level.activeTeam); if (p == nullptr) gi.Error("Could not find player for team %i", level.activeTeam); /* finish off events */ G_EventEnd(); /* reset ready flag for every player on the current team (even ai players) */ p = nullptr; while ((p = G_PlayerGetNextActiveHuman(p))) { if (p->getTeam() == level.activeTeam) { p->roundDone = false; } } p = nullptr; while ((p = G_PlayerGetNextActiveAI(p))) { if (p->getTeam() == level.activeTeam) { p->roundDone = false; } } }