Player start refactor

This commit is contained in:
Lactozilla 2023-08-12 19:45:09 -03:00
parent e56d444c84
commit e4b3c72432
10 changed files with 240 additions and 121 deletions

View file

@ -638,8 +638,7 @@ extern tic_t gametic;
// Player spawn spots.
extern mapthing_t *playerstarts[MAXPLAYERS]; // Cooperative
extern mapthing_t *bluectfstarts[MAXPLAYERS]; // CTF
extern mapthing_t *redctfstarts[MAXPLAYERS]; // CTF
extern mapthing_t *teamstarts[MAXTEAMS][MAXPLAYERS]; // CTF
#define WAYPOINTSEQUENCESIZE 256
#define NUMWAYPOINTSEQUENCES 256

View file

@ -2828,7 +2828,7 @@ void G_SpawnPlayer(INT32 playernum)
P_SpawnPlayer(playernum);
G_MovePlayerToSpawnOrStarpost(playernum);
LUA_HookPlayer(&players[playernum], HOOK(PlayerSpawn)); // Lua hook for player spawning :)
LUA_HookPlayer(&players[playernum], HOOK(PlayerSpawn));
}
void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
@ -2849,57 +2849,55 @@ void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
P_ResetCamera(&players[playernum], &camera2);
}
mapthing_t *G_FindCTFStart(INT32 playernum)
enum
{
INT32 i,j;
PLAYER_START_TYPE_COOP,
PLAYER_START_TYPE_MATCH,
PLAYER_START_TYPE_TEAM
};
if (!numredctfstarts && !numbluectfstarts) //why even bother, eh?
static boolean G_AreCoopStartsAvailable(void)
{
return numcoopstarts != 0;
}
static boolean G_AreMatchStartsAvailable(void)
{
return numdmstarts != 0;
}
static boolean G_AreTeamStartsAvailable(UINT8 team)
{
if (team >= numteams)
return false;
return numteamstarts[team] != 0;
}
static boolean G_AreTeamStartsAvailableForPlayer(INT32 playernum)
{
UINT8 team = players[playernum].ctfteam;
if (team != TEAM_NONE && team < numteams)
return G_AreTeamStartsAvailable(team);
return G_AreMatchStartsAvailable();
}
mapthing_t *G_FindTeamStart(INT32 playernum)
{
UINT8 team = players[playernum].ctfteam;
if (team == TEAM_NONE || team >= numteams)
return G_FindMatchStart(playernum);
if (G_AreTeamStartsAvailable(team))
{
if ((gametyperules & GTR_TEAMFLAGS) && (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)))
CONS_Alert(CONS_WARNING, M_GetText("No CTF starts in this map!\n"));
return NULL;
for (INT32 j = 0; j < MAXPLAYERS; j++)
{
INT32 i = P_RandomKey(numteamstarts[team]);
if (G_CheckSpot(playernum, teamstarts[team][i]))
return teamstarts[team][i];
}
}
if ((!players[playernum].ctfteam && numredctfstarts && (!numbluectfstarts || P_RandomChance(FRACUNIT/2))) || players[playernum].ctfteam == TEAM_RED) //red
{
if (!numredctfstarts)
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_WARNING, M_GetText("No Red Team starts in this map!\n"));
return NULL;
}
for (j = 0; j < 32; j++)
{
i = P_RandomKey(numredctfstarts);
if (G_CheckSpot(playernum, redctfstarts[i]))
return redctfstarts[i];
}
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Red Team starts!\n"));
return NULL;
}
else if (!players[playernum].ctfteam || players[playernum].ctfteam == TEAM_BLUE) //blue
{
if (!numbluectfstarts)
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_WARNING, M_GetText("No Blue Team starts in this map!\n"));
return NULL;
}
for (j = 0; j < 32; j++)
{
i = P_RandomKey(numbluectfstarts);
if (G_CheckSpot(playernum, bluectfstarts[i]))
return bluectfstarts[i];
}
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Blue Team starts!\n"));
return NULL;
}
//should never be reached but it gets stuff to shut up
return NULL;
}
@ -2907,7 +2905,7 @@ mapthing_t *G_FindMatchStart(INT32 playernum)
{
INT32 i, j;
if (numdmstarts)
if (G_AreMatchStartsAvailable())
{
for (j = 0; j < 64; j++)
{
@ -2915,19 +2913,14 @@ mapthing_t *G_FindMatchStart(INT32 playernum)
if (G_CheckSpot(playernum, deathmatchstarts[i]))
return deathmatchstarts[i];
}
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n"));
return NULL;
}
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_WARNING, M_GetText("No Deathmatch starts in this map!\n"));
return NULL;
}
mapthing_t *G_FindCoopStart(INT32 playernum)
{
if (numcoopstarts)
if (G_AreCoopStartsAvailable())
{
//if there's 6 players in a map with 3 player starts, this spawns them 1/2/3/1/2/3.
if (G_CheckSpot(playernum, playerstarts[playernum % numcoopstarts]))
@ -2938,82 +2931,208 @@ mapthing_t *G_FindCoopStart(INT32 playernum)
return playerstarts[0];
}
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
CONS_Alert(CONS_WARNING, M_GetText("No Co-op starts in this map!\n"));
return NULL;
}
// Find a Co-op start, or fallback into other types of starts.
static inline mapthing_t *G_FindCoopStartOrFallback(INT32 playernum)
static mapthing_t *G_FindBestStart(INT32 playernum, INT32 type)
{
mapthing_t *spawnpoint = NULL;
if (!(spawnpoint = G_FindCoopStart(playernum)) // find a Co-op start
&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
spawnpoint = G_FindCTFStart(playernum); // fallback
switch (type)
{
case PLAYER_START_TYPE_COOP:
return G_FindCoopStart(playernum);
case PLAYER_START_TYPE_MATCH:
return G_FindMatchStart(playernum);
case PLAYER_START_TYPE_TEAM:
return G_FindTeamStart(playernum);
}
return NULL;
}
static mapthing_t *G_FindBestStartInOrder(INT32 playernum, INT32 *order, UINT8 numtries)
{
for (unsigned i = 0; i < numtries; i++)
{
mapthing_t *spawnpoint = G_FindBestStart(playernum, order[i]);
if (spawnpoint)
return spawnpoint;
}
return NULL;
}
// Gets a Co-op start, or returns NULL if none was found.
// If no Co-op start was found, it looks for a Match start, and then a team start.
static mapthing_t *G_FindBestCoopStart(INT32 playernum)
{
INT32 order[] = {
PLAYER_START_TYPE_COOP,
PLAYER_START_TYPE_MATCH,
PLAYER_START_TYPE_TEAM
};
return G_FindBestStartInOrder(playernum, order, sizeof(order) / sizeof(order[0]));
}
// Gets a Match start, or returns NULL if none was found.
// If no Match start was found, it looks for a team start, and then a Co-op start.
static mapthing_t *G_FindBestMatchStart(INT32 playernum)
{
INT32 order[] = {
PLAYER_START_TYPE_MATCH,
PLAYER_START_TYPE_TEAM,
PLAYER_START_TYPE_COOP
};
return G_FindBestStartInOrder(playernum, order, sizeof(order) / sizeof(order[0]));
}
// Gets a team start, or returns NULL if none was found.
// If no team start was found, it looks for a Match start, and then a Co-op start.
static mapthing_t *G_FindBestTeamStart(INT32 playernum)
{
INT32 order[] = {
PLAYER_START_TYPE_TEAM,
PLAYER_START_TYPE_MATCH,
PLAYER_START_TYPE_COOP
};
return G_FindBestStartInOrder(playernum, order, sizeof(order) / sizeof(order[0]));
}
// Gets a Co-op start, or shows a warning to the player if none was found.
// If no Co-op start was found, it looks for a Match start, and then a team start.
static mapthing_t *G_GetCoopStartForSpawning(INT32 playernum)
{
player_t *player = &players[playernum];
mapthing_t *spawnpoint = G_FindBestCoopStart(playernum);
if (P_IsLocalPlayer(player))
{
boolean has_starts = G_AreCoopStartsAvailable();
if (spawnpoint && !has_starts)
CONS_Alert(CONS_WARNING, M_GetText("No Co-Op starts in this map!\n"));
else if (spawnpoint == NULL && has_starts) // This never happens, but in case it does, this will display a warning.
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Co-Op starts!\n"));
}
return spawnpoint;
}
// Find a Match start, or fallback into other types of starts.
static inline mapthing_t *G_FindMatchStartOrFallback(INT32 playernum)
// Gets a Match start, or shows a warning to the player if none was found.
// If no Match start was found, it looks for a team start, and then a Co-op start.
static mapthing_t *G_GetMatchStartForSpawning(INT32 playernum)
{
mapthing_t *spawnpoint = NULL;
if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start
&& !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start
spawnpoint = G_FindCoopStart(playernum); // fallback
player_t *player = &players[playernum];
mapthing_t *spawnpoint = G_FindBestMatchStart(playernum);
if (P_IsLocalPlayer(player))
{
boolean has_starts = G_AreMatchStartsAvailable();
if (spawnpoint && !has_starts)
CONS_Alert(CONS_WARNING, M_GetText("No Deathmatch starts in this map!\n"));
else if (spawnpoint == NULL && has_starts)
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n"));
}
return spawnpoint;
}
// Gets a team start, or shows a warning to the player if none was found.
// If no team start was found, it looks for a Match start, and then a Co-op start.
static mapthing_t *G_GetTeamStartForSpawning(INT32 playernum)
{
player_t *player = &players[playernum];
mapthing_t *spawnpoint = G_FindBestTeamStart(playernum);
if (P_IsLocalPlayer(player))
{
boolean has_starts = G_AreTeamStartsAvailableForPlayer(playernum);
if (spawnpoint && !has_starts)
{
if (player->ctfteam)
CONS_Alert(CONS_WARNING, M_GetText("No %s starts in this map!\n"), G_GetTeamName(player->ctfteam));
else
CONS_Alert(CONS_WARNING, M_GetText("No team starts in this map!\n"));
}
else if (spawnpoint == NULL && has_starts)
{
if (player->ctfteam)
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any %s starts!\n"), G_GetTeamName(player->ctfteam));
else
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any team starts!\n"));
}
}
return spawnpoint;
}
mapthing_t *G_FindMapStart(INT32 playernum)
{
mapthing_t *spawnpoint;
if (!playeringame[playernum])
return NULL;
player_t *player = &players[playernum];
mapthing_t *spawnpoint = NULL;
// -- Spectators --
// Order in platform gametypes: Coop->DM->CTF
// And, with deathmatch starts: DM->CTF->Coop
if (players[playernum].spectator)
// Otherwise: DM->CTF->Coop
if (player->spectator)
{
// In platform gametypes, spawn in Co-op starts first
// Overriden by GTR_DEATHMATCHSTARTS.
if (G_PlatformGametype() && !(gametyperules & GTR_DEATHMATCHSTARTS))
spawnpoint = G_FindCoopStartOrFallback(playernum);
spawnpoint = G_GetCoopStartForSpawning(playernum);
else
spawnpoint = G_FindMatchStartOrFallback(playernum);
spawnpoint = G_GetMatchStartForSpawning(playernum);
}
// -- CTF --
// Order: CTF->DM->Coop
else if ((gametyperules & (GTR_TEAMFLAGS|GTR_TEAMS)) && players[playernum].ctfteam)
else if (gametyperules & GTR_TEAMFLAGS)
{
if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start
&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
spawnpoint = G_FindCoopStart(playernum); // fallback
if (player->ctfteam)
spawnpoint = G_GetTeamStartForSpawning(playernum);
else
spawnpoint = G_GetMatchStartForSpawning(playernum);
}
// -- DM/Tag/CTF-spectator/etc --
// -- DM/Tag/etc --
// Order: DM->CTF->Coop
else if (G_TagGametype() ? (!(players[playernum].pflags & PF_TAGIT)) : (gametyperules & GTR_DEATHMATCHSTARTS))
spawnpoint = G_FindMatchStartOrFallback(playernum);
else if (gametyperules & GTR_DEATHMATCHSTARTS)
{
// If the current gametype has teams, but isn't CTF, then this looks for a team start first
// If the player is not in a team, then this just gets a match start.
if (G_GametypeHasTeams() && player->ctfteam > TEAM_NONE && player->ctfteam < numteams)
{
spawnpoint = G_FindTeamStart(playernum);
// If no spawn point was found, but team starts are available, this means there is no good location
// for the player to spawn at. In that situation, we display a message telling the player so.
if (spawnpoint == NULL && G_AreTeamStartsAvailable(player->ctfteam) && P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any %s starts!\n"), G_GetTeamName(player->ctfteam));
}
// If that failed, no warning is shown. Instead, this will look for a match start, which may
// then display a warning if no suitable map starts were found.
if (spawnpoint == NULL)
spawnpoint = G_GetMatchStartForSpawning(playernum);
}
// -- Other game modes --
// Order: Coop->DM->CTF
else
spawnpoint = G_FindCoopStartOrFallback(playernum);
spawnpoint = G_GetCoopStartForSpawning(playernum);
//No spawns found. ANYWHERE.
if (!spawnpoint)
{
if (nummapthings)
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
if (P_IsLocalPlayer(player))
CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n"));
spawnpoint = &mapthings[0];
}
else
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
if (P_IsLocalPlayer(player))
CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n"));
}
}

View file

@ -165,7 +165,7 @@ void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc);
INT32 G_FindMapByNameOrCode(const char *query, char **foundmapnamep);
// XMOD spawning
mapthing_t *G_FindCTFStart(INT32 playernum);
mapthing_t *G_FindTeamStart(INT32 playernum);
mapthing_t *G_FindMatchStart(INT32 playernum);
mapthing_t *G_FindCoopStart(INT32 playernum);
mapthing_t *G_FindMapStart(INT32 playernum);

View file

@ -837,7 +837,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
fmt2 = "%s<%s%s%s>\x80 %s%s";
else // To your team
{
if (players[playernum].ctfteam != 0)
if (players[playernum].ctfteam > TEAM_NONE && players[playernum].ctfteam < numteams)
{
tempteam = Z_StrDup(va("%s[TEAM]", GetChatColorForSkincolor(G_GetTeamColor(players[playernum].ctfteam))));
prefix = tempteam;

View file

@ -1691,7 +1691,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
// Monitor?
else if (thing->flags & MF_MONITOR
&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != TEAM_RED) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != TEAM_BLUE))
&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != G_GetTeam(TEAM_RED)) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != G_GetTeam(TEAM_BLUE)))
&& (!(thing->flags & MF_SOLID) || P_PlayerCanDamage(tmthing->player, thing)))
{
if (thing->z - thing->scale <= tmthing->z + tmthing->height

View file

@ -10042,7 +10042,7 @@ static void P_FlagFuseThink(mobj_t *mobj)
// Assumedly in splitscreen players will be on opposing teams
if (players[consoleplayer].ctfteam == team || splitscreen)
S_StartSound(NULL, sfx_hoop1);
else if (players[consoleplayer].ctfteam != 0)
else if (players[consoleplayer].ctfteam > TEAM_NONE && players[consoleplayer].ctfteam < numteams)
S_StartSound(NULL, sfx_hoop3);
P_SetTarget(&flagmobjs[team], flagmo);
@ -11933,6 +11933,17 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt
return P_GetMobjSpawnHeight(mobjtype, x, y, dz, offset, flip, mthing->scale);
}
static void P_SetTeamStart(UINT8 team, mapthing_t *mthing)
{
if (team != TEAM_NONE && team < numteams && numteamstarts[team] < MAXPLAYERS)
{
teamstarts[team][numteamstarts[team]] = mthing;
numteamstarts[team]++;
numteamstarts[0]++;
mthing->type = 0;
}
}
static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
{
#if MAXPLAYERS > 32
@ -11957,22 +11968,12 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
}
else if (mthing->type == 34) // Red CTF starts
{
if (numredctfstarts < MAXPLAYERS)
{
redctfstarts[numredctfstarts] = mthing;
mthing->type = 0;
numredctfstarts++;
}
P_SetTeamStart(G_GetTeam(TEAM_RED), mthing);
return true;
}
else if (mthing->type == 35) // Blue CTF starts
{
if (numbluectfstarts < MAXPLAYERS)
{
bluectfstarts[numbluectfstarts] = mthing;
mthing->type = 0;
numbluectfstarts++;
}
P_SetTeamStart(G_GetTeam(TEAM_BLUE), mthing);
return true;
}
else if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum)
@ -14068,15 +14069,8 @@ mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
//
void P_ColorTeamMissile(mobj_t *missile, player_t *source)
{
if (G_GametypeHasTeams())
{
if (source->ctfteam != 0)
missile->color = G_GetTeamMissileColor(source->ctfteam);
}
/*
else
missile->color = player->mo->color; //copy color
*/
if (G_GametypeHasTeams() && source->ctfteam > TEAM_NONE && source->ctfteam < numteams)
missile->color = G_GetTeamMissileColor(source->ctfteam);
}
//

View file

@ -144,12 +144,11 @@ mobj_t **blocklinks;
UINT8 *rejectmatrix;
// Maintain single and multi player starting spots.
INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
INT32 numdmstarts, numcoopstarts, numteamstarts[MAXTEAMS];
mapthing_t *deathmatchstarts[MAX_DM_STARTS];
mapthing_t *playerstarts[MAXPLAYERS];
mapthing_t *bluectfstarts[MAXPLAYERS];
mapthing_t *redctfstarts[MAXPLAYERS];
mapthing_t *teamstarts[MAXTEAMS][MAXPLAYERS];
// Maintain waypoints
mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE];
@ -7232,17 +7231,25 @@ static void P_ForceCharacter(const char *forcecharskin)
static void P_ResetSpawnpoints(void)
{
UINT8 i;
UINT8 i, j;
numdmstarts = numredctfstarts = numbluectfstarts = 0;
numdmstarts = 0;
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
playerstarts[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
for (i = 0; i < MAXTEAMS; i++)
{
numteamstarts[i] = 0;
for (j = 0; j < MAXPLAYERS; j++)
teamstarts[i][j] = NULL;
}
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;

View file

@ -24,7 +24,7 @@ extern unsigned char mapmd5[16];
// Player spawn spots for deathmatch.
#define MAX_DM_STARTS 64
extern mapthing_t *deathmatchstarts[MAX_DM_STARTS];
extern INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
extern INT32 numdmstarts, numcoopstarts, numteamstarts[MAXTEAMS];
extern boolean levelloading;
extern UINT8 levelfadecol;

View file

@ -1783,7 +1783,7 @@ void P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller)
// Only red/blue team members can activate this.
if (!(actor && actor->player))
return;
if (actor->player->ctfteam != ((triggerline->args[1] == TMT_RED) ? TEAM_RED : TEAM_BLUE))
if (actor->player->ctfteam != ((triggerline->args[1] == TMT_RED) ? G_GetTeam(TEAM_RED) : G_GetTeam(TEAM_BLUE)))
return;
break;
case 314:

View file

@ -907,7 +907,7 @@ static void ST_drawLivesArea(void)
}
else if (G_GametypeHasTeams())
{
if (stplyr->ctfteam != 0)
if (stplyr->ctfteam > TEAM_NONE && stplyr->ctfteam < numteams)
{
v_colmap = skincolors[G_GetTeamColor(stplyr->ctfteam)].chatcolor;
}
@ -994,7 +994,7 @@ static void ST_drawLivesArea(void)
}
else if (G_GametypeHasTeams())
{
if (stplyr->ctfteam != 0)
if (stplyr->ctfteam > TEAM_NONE && stplyr->ctfteam < numteams)
{
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, G_GetTeamName(stplyr->ctfteam));
}