Merge branch 'next' of https://git.magicalgirl.moe/STJr/SRB2 into playerthink-hook

This commit is contained in:
Zachary McAlpin 2019-12-26 17:29:54 -06:00
commit 9fe20aa1a3
28 changed files with 1580 additions and 439 deletions

View File

@ -1025,7 +1025,7 @@ static void SV_SendResynch(INT32 node)
netbuffer->packettype = PT_RESYNCHEND;
netbuffer->u.resynchend.randomseed = P_GetRandSeed();
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
resynch_write_ctf(&netbuffer->u.resynchend);
resynch_write_others(&netbuffer->u.resynchend);
@ -2111,10 +2111,10 @@ static void CL_ConnectToServer(boolean viams)
if (i != -1)
{
UINT8 num = serverlist[i].info.gametype;
UINT16 num = serverlist[i].info.gametype;
const char *gametypestr = NULL;
CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername);
if (num < NUMGAMETYPES)
if (num < gametypecount)
gametypestr = Gametype_Names[num];
if (gametypestr)
CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr);
@ -2430,7 +2430,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
}
}
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you!
// If in a special stage, redistribute the player's spheres across
@ -2486,6 +2486,17 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
(void)reason;
#endif
// don't look through someone's view who isn't there
if (playernum == displayplayer)
{
#ifdef HAVE_BLUA
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer], true);
#endif
displayplayer = consoleplayer;
}
// Reset player data
CL_ClearPlayer(playernum);
@ -2503,16 +2514,13 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
}
if (playernum == displayplayer)
displayplayer = consoleplayer; // don't look through someone's view who isn't there
#ifdef HAVE_BLUA
LUA_InvalidatePlayer(&players[playernum]);
#endif
if (G_TagGametype()) //Check if you still have a game. Location flexible. =P
P_CheckSurvivors();
else if (gametype == GT_RACE || gametype == GT_COMPETITION)
else if (gametyperules & GTR_RACE)
P_CheckRacers();
}
@ -3461,7 +3469,7 @@ void SV_StartSinglePlayerServer(void)
server = true;
netgame = false;
multiplayer = false;
gametype = GT_COOP;
G_SetGametype(GT_COOP);
// no more tic the game with this settings!
SV_StopServer();
@ -3740,7 +3748,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (client)
{
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
gametype = netbuffer->u.servercfg.gametype;
G_SetGametype(netbuffer->u.servercfg.gametype);
modifiedgame = netbuffer->u.servercfg.modifiedgame;
for (j = 0; j < MAXPLAYERS; j++)
adminplayers[j] = netbuffer->u.servercfg.adminplayers[j];
@ -4124,7 +4132,7 @@ static void HandlePacketFromPlayer(SINT8 node)
P_SetRandSeed(netbuffer->u.resynchend.randomseed);
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
resynch_read_ctf(&netbuffer->u.resynchend);
resynch_read_others(&netbuffer->u.resynchend);

View File

@ -762,7 +762,7 @@ void D_StartTitle(void)
gameaction = ga_nothing;
displayplayer = consoleplayer = 0;
gametype = GT_COOP;
G_SetGametype(GT_COOP);
paused = false;
advancedemo = false;
F_InitMenuPresValues();
@ -1419,14 +1419,14 @@ void D_SRB2Main(void)
if (newgametype == -1) // reached end of the list with no match
{
j = atoi(sgametype); // assume they gave us a gametype number, which is okay too
if (j >= 0 && j < NUMGAMETYPES)
if (j >= 0 && j < gametypecount)
newgametype = (INT16)j;
}
if (newgametype != -1)
{
j = gametype;
gametype = newgametype;
G_SetGametype(newgametype);
D_GameTypeChanged(j);
}
}

View File

@ -327,6 +327,10 @@ consvar_t cv_numlaps = {"numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_con
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}};
consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL};
// Point and time limits for every gametype
INT32 pointlimits[NUMGAMETYPES];
INT32 timelimits[NUMGAMETYPES];
// log elemental hazards -- not a netvar, is local to current player
consvar_t cv_hazardlog = {"hazardlog", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -381,6 +385,9 @@ char timedemo_csv_id[256];
boolean timedemo_quit;
INT16 gametype = GT_COOP;
UINT32 gametyperules = 0;
INT16 gametypecount = (GT_CTF + 1);
boolean splitscreen = false;
boolean circuitmap = false;
INT32 adminplayers[MAXPLAYERS];
@ -1126,7 +1133,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true;
// Can change skin during initial countdown.
if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE)
if ((gametyperules & GTR_RACE) && leveltime < 4*TICRATE)
return true;
if (G_TagGametype())
@ -1942,7 +1949,7 @@ static void Command_Map_f(void)
if (isdigit(gametypename[0]))
{
d = atoi(gametypename);
if (d >= 0 && d < NUMGAMETYPES)
if (d >= 0 && d < gametypecount)
newgametype = d;
else
{
@ -1950,7 +1957,7 @@ static void Command_Map_f(void)
"Gametype number %d is out of range. Use a number between"
" 0 and %d inclusive. ...Or just use the name. :v\n",
d,
NUMGAMETYPES-1);
gametypecount-1);
Z_Free(realmapname);
Z_Free(mapname);
return;
@ -2069,8 +2076,9 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
lastgametype = gametype;
gametype = READUINT8(*cp);
G_SetGametype(gametype); // I fear putting that macro as an argument
if (gametype < 0 || gametype >= NUMGAMETYPES)
if (gametype < 0 || gametype >= gametypecount)
gametype = lastgametype;
else if (gametype != lastgametype)
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
@ -2413,7 +2421,7 @@ static void Command_Teamchange_f(void)
}
//additional check for hide and seek. Don't allow change of status after hidetime ends.
if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE))
if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE))
{
CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n"));
return;
@ -2510,7 +2518,7 @@ static void Command_Teamchange2_f(void)
}
//additional check for hide and seek. Don't allow change of status after hidetime ends.
if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE))
if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE))
{
CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n"));
return;
@ -2639,7 +2647,7 @@ static void Command_ServerTeamChange_f(void)
}
//additional check for hide and seek. Don't allow change of status after hidetime ends.
if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE))
if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE))
{
CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n"));
return;
@ -2728,6 +2736,16 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
return;
}
#ifdef HAVE_BLUA
// Don't switch team, just go away, please, go awaayyyy, aaauuauugghhhghgh
if (!LUAh_TeamSwitch(&players[playernum], NetPacket.packet.newteam, players[playernum].spectator, NetPacket.packet.autobalance, NetPacket.packet.scrambled))
return;
#endif
//no status changes after hidetime
if ((gametyperules & GTR_HIDEFROZEN) && (leveltime >= (hidetime * TICRATE)))
error = true;
//Make sure that the right team number is sent. Keep in mind that normal clients cannot change to certain teams in certain gametypes.
switch (gametype)
{
@ -2882,7 +2900,15 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
//reset view if you are changed, or viewing someone who was changed.
if (playernum == consoleplayer || displayplayer == playernum)
{
#ifdef HAVE_BLUA
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
if (displayplayer != consoleplayer) // You're already viewing yourself. No big deal.
LUAh_ViewpointSwitch(&players[playernum], &players[displayplayer], true);
#endif
displayplayer = consoleplayer;
}
if (G_GametypeHasTeams())
{
@ -3618,7 +3644,7 @@ static void Command_ShowGametype_f(void)
}
// get name string for current gametype
if (gametype >= 0 && gametype < NUMGAMETYPES)
if (gametype >= 0 && gametype < gametypecount)
gametypestr = Gametype_Names[gametype];
if (gametypestr)
@ -3680,7 +3706,7 @@ void ItemFinder_OnChange(void)
static void PointLimit_OnChange(void)
{
// Don't allow pointlimit in Single Player/Co-Op/Race!
if (server && Playing() && G_PlatformGametype())
if (server && Playing() && !(gametyperules & GTR_POINTLIMIT))
{
if (cv_pointlimit.value)
CV_StealthSetValue(&cv_pointlimit, 0);
@ -3843,7 +3869,7 @@ UINT32 timelimitintics = 0;
static void TimeLimit_OnChange(void)
{
// Don't allow timelimit in Single Player/Co-Op/Race!
if (server && Playing() && cv_timelimit.value != 0 && G_PlatformGametype())
if (server && Playing() && cv_timelimit.value != 0 && !(gametyperules & GTR_TIMELIMIT))
{
CV_SetValue(&cv_timelimit, 0);
return;
@ -3879,9 +3905,9 @@ void D_GameTypeChanged(INT32 lastgametype)
{
const char *oldgt = NULL, *newgt = NULL;
if (lastgametype >= 0 && lastgametype < NUMGAMETYPES)
if (lastgametype >= 0 && lastgametype < gametypecount)
oldgt = Gametype_Names[lastgametype];
if (gametype >= 0 && lastgametype < NUMGAMETYPES)
if (gametype >= 0 && lastgametype < gametypecount)
newgt = Gametype_Names[gametype];
if (oldgt && newgt)
@ -3935,11 +3961,20 @@ void D_GameTypeChanged(INT32 lastgametype)
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
break;
default:
if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
{
CV_SetValue(&cv_timelimit, timelimits[gametype]);
CV_SetValue(&cv_pointlimit, pointlimits[gametype]);
}
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
break;
}
}
else if (!multiplayer && !netgame)
{
gametype = GT_COOP;
G_SetGametype(GT_COOP);
// These shouldn't matter anymore
//CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue);
//CV_SetValue(&cv_itemrespawn, 0);
@ -3948,7 +3983,7 @@ void D_GameTypeChanged(INT32 lastgametype)
// reset timelimit and pointlimit in race/coop, prevent stupid cheats
if (server)
{
if (G_PlatformGametype())
if (!(gametyperules & GTR_POINTLIMIT))
{
if (cv_timelimit.value)
CV_SetValue(&cv_timelimit, 0);
@ -3966,6 +4001,7 @@ void D_GameTypeChanged(INT32 lastgametype)
// When swapping to a gametype that supports spectators,
// make everyone a spectator initially.
// Averted with GTR_NOSPECTATORSPAWN.
if (!splitscreen && (G_GametypeHasSpectators()))
{
INT32 i;
@ -3973,7 +4009,7 @@ void D_GameTypeChanged(INT32 lastgametype)
if (playeringame[i])
{
players[i].ctfteam = 0;
players[i].spectator = true;
players[i].spectator = (gametyperules & GTR_NOSPECTATORSPAWN) ? false : true;
}
}

View File

@ -22,6 +22,7 @@
#include "m_menu.h"
#include "m_misc.h"
#include "f_finale.h"
#include "y_inter.h"
#include "dehacked.h"
#include "st_stuff.h"
#include "i_system.h"
@ -76,6 +77,7 @@ static UINT16 get_mus(const char *word, UINT8 dehacked_mode);
static hudnum_t get_huditem(const char *word);
static menutype_t get_menutype(const char *word);
#ifndef HAVE_BLUA
static INT16 get_gametype(const char *word);
static powertype_t get_power(const char *word);
#endif
@ -590,6 +592,16 @@ static void readfreeslots(MYFILE *f)
} else
CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n");
}
else if (fastcmp(type, "TOL"))
{
if (lastcustomtol > 31)
CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n");
else
{
G_AddTOL((1<<lastcustomtol), word);
lastcustomtol++;
}
}
else
deh_warning("Freeslots: unknown enum class '%s' for '%s_%s'", type, type, word);
}
@ -1095,10 +1107,10 @@ static void readsprite2(MYFILE *f, INT32 num)
Z_Free(s);
}
static const struct {
const char *name;
const UINT16 flag;
} TYPEOFLEVEL[] = {
INT32 numtolinfo = NUMBASETOL;
UINT32 lastcustomtol = 13;
tolinfo_t TYPEOFLEVEL[NUMMAXTOL] = {
{"SOLO",TOL_SP},
{"SP",TOL_SP},
{"SINGLEPLAYER",TOL_SP},
@ -1114,8 +1126,6 @@ static const struct {
{"TAG",TOL_TAG},
{"CTF",TOL_CTF},
{"CUSTOM",TOL_CUSTOM},
{"2D",TOL_2D},
{"MARIO",TOL_MARIO},
{"NIGHTS",TOL_NIGHTS},
@ -1128,6 +1138,216 @@ static const struct {
{NULL, 0}
};
// copypasted from readPlayer :sleep:
static const char *const GAMETYPERULE_LIST[];
static void readgametype(MYFILE *f, char *gtname)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2, *word2lwr = NULL;
char *tmp;
INT32 i, j;
INT16 newgtidx = 0;
UINT32 newgtrules = 0;
UINT32 newgttol = 0;
INT32 newgtpointlimit = 0;
INT32 newgttimelimit = 0;
UINT8 newgtleftcolor = 0;
UINT8 newgtrightcolor = 0;
INT16 newgtrankingstype = -1;
int newgtinttype = 0;
char gtdescription[441];
char gtconst[MAXLINELEN];
// Empty strings.
gtdescription[0] = '\0';
gtconst[0] = '\0';
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
if (fastcmp(word, "DESCRIPTION"))
{
char *descr = NULL;
for (i = 0; i < MAXLINELEN-3; i++)
{
if (s[i] == '=')
{
descr = &s[i+2];
break;
}
}
if (descr)
{
strcpy(gtdescription, descr);
strcat(gtdescription, myhashfgets(descr, sizeof (gtdescription), f));
}
else
strcpy(gtdescription, "");
// For some reason, cutting the string did not work above. Most likely due to strcpy or strcat...
// It works down here, though.
{
INT32 numline = 0;
for (i = 0; i < MAXLINELEN-1; i++)
{
if (numline < 20 && gtdescription[i] == '\n')
numline++;
if (numline >= 20 || gtdescription[i] == '\0' || gtdescription[i] == '#')
break;
}
}
gtdescription[strlen(gtdescription)-1] = '\0';
gtdescription[i] = '\0';
continue;
}
word2 = strtok(NULL, " = ");
if (word2)
{
if (!word2lwr)
word2lwr = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
strcpy(word2lwr, word2);
strupr(word2);
}
else
break;
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
i = atoi(word2);
// Game type rules
if (fastcmp(word, "RULES"))
{
// GTR_
newgtrules = (UINT32)get_number(word2);
}
// Identifier
else if (fastcmp(word, "IDENTIFIER"))
{
// GT_
strncpy(gtconst, word2, MAXLINELEN);
}
// Point and time limits
else if (fastcmp(word, "DEFAULTPOINTLIMIT"))
newgtpointlimit = (INT32)i;
else if (fastcmp(word, "DEFAULTTIMELIMIT"))
newgttimelimit = (INT32)i;
// Level platter
else if (fastcmp(word, "HEADERCOLOR") || fastcmp(word, "HEADERCOLOUR"))
newgtleftcolor = newgtrightcolor = (UINT8)get_number(word2);
else if (fastcmp(word, "HEADERLEFTCOLOR") || fastcmp(word, "HEADERLEFTCOLOUR"))
newgtleftcolor = (UINT8)get_number(word2);
else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR"))
newgtrightcolor = (UINT8)get_number(word2);
// Rankings type
else if (fastcmp(word, "RANKINGTYPE"))
{
// Case insensitive
newgtrankingstype = (int)get_number(word2);
}
// Intermission type
else if (fastcmp(word, "INTERMISSIONTYPE"))
{
// Case sensitive
newgtinttype = (int)get_number(word2lwr);
}
// Type of level
else if (fastcmp(word, "TYPEOFLEVEL"))
{
if (i) // it's just a number
newgttol = (UINT32)i;
else
{
UINT16 tol = 0;
tmp = strtok(word2,",");
do {
for (i = 0; TYPEOFLEVEL[i].name; i++)
if (fasticmp(tmp, TYPEOFLEVEL[i].name))
break;
if (!TYPEOFLEVEL[i].name)
deh_warning("readgametype %s: unknown typeoflevel flag %s\n", gtname, tmp);
tol |= TYPEOFLEVEL[i].flag;
} while((tmp = strtok(NULL,",")) != NULL);
newgttol = tol;
}
}
// The SOC probably provided gametype rules as words,
// instead of using the RULES keyword.
// Like for example "NOSPECTATORSPAWN = TRUE".
// This is completely valid, and looks better anyway.
else
{
UINT32 wordgt = 0;
for (j = 0; GAMETYPERULE_LIST[j]; j++)
if (fastcmp(word, GAMETYPERULE_LIST[j])) {
if (!j) // GTR_CAMPAIGN
wordgt |= 1;
else
wordgt |= (1<<j);
if (i || word2[0] == 'T' || word2[0] == 'Y')
newgtrules |= wordgt;
break;
}
if (!wordgt)
deh_warning("readgametype %s: unknown word '%s'", gtname, word);
}
}
} while (!myfeof(f)); // finish when the line is empty
// Free strings.
Z_Free(s);
if (word2lwr)
Z_Free(word2lwr);
// Ran out of gametype slots
if (gametypecount == NUMGAMETYPEFREESLOTS)
{
CONS_Alert(CONS_WARNING, "Ran out of free gametype slots!\n");
return;
}
// Add the new gametype
newgtidx = G_AddGametype(newgtrules);
G_AddGametypeTOL(newgtidx, newgttol);
G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor);
// Not covered by G_AddGametype alone.
if (newgtrankingstype == -1)
newgtrankingstype = newgtidx;
gametyperankings[newgtidx] = newgtrankingstype;
intermissiontypes[newgtidx] = newgtinttype;
pointlimits[newgtidx] = newgtpointlimit;
timelimits[newgtidx] = newgttimelimit;
// Write the new gametype name.
Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname);
// Write the constant name.
if (gtconst[0] == '\0')
strncpy(gtconst, gtname, MAXLINELEN);
G_AddGametypeConstant(newgtidx, (const char *)gtconst);
// Update gametype_cons_t accordingly.
G_UpdateGametypeSelections();
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
}
static const struct {
const char *name;
const mobjtype_t type;
@ -1395,7 +1615,7 @@ static void readlevelheader(MYFILE *f, INT32 num)
else if (fastcmp(word, "TYPEOFLEVEL"))
{
if (i) // it's just a number
mapheaderinfo[num-1]->typeoflevel = (UINT16)i;
mapheaderinfo[num-1]->typeoflevel = (UINT32)i;
else
{
UINT16 tol = 0;
@ -4172,6 +4392,7 @@ static void ignorelines(MYFILE *f)
static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char textline[MAXLINELEN];
char *word;
char *word2;
INT32 i;
@ -4192,6 +4413,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
char *traverse;
myfgets(s, MAXLINELEN, f);
memcpy(textline, s, MAXLINELEN);
if (s[0] == '\n' || s[0] == '#')
continue;
@ -4380,6 +4602,36 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
ignorelines(f);
}
}
else if (fastcmp(word, "GAMETYPE"))
{
// Get the gametype name from textline
// instead of word2, so that gametype names
// aren't allcaps
INT32 c;
for (c = 0; c < MAXLINELEN; c++)
{
if (textline[c] == '\0')
break;
if (textline[c] == ' ')
{
char *gtname = (textline+c+1);
if (gtname)
{
// remove funny characters
INT32 j;
for (j = 0; j < (MAXLINELEN - c); j++)
{
if (gtname[j] == '\0')
break;
if (gtname[j] < 32)
gtname[j] = '\0';
}
readgametype(f, gtname);
}
break;
}
}
}
else if (fastcmp(word, "CUTSCENE"))
{
if (i > 0 && i < 129)
@ -8650,6 +8902,39 @@ static const char *const PLAYERFLAG_LIST[] = {
NULL // stop loop here.
};
static const char *const GAMETYPERULE_LIST[] = {
"CAMPAIGN",
"RINGSLINGER",
"SPECTATORS",
"FRIENDLYFIRE",
"LIVES",
"TEAMS",
"RACE",
"TAG",
"POINTLIMIT",
"TIMELIMIT",
"HIDETIME",
"HIDEFROZEN",
"BLINDFOLDED",
"FIRSTPERSON",
"MATCHEMERALDS",
"TEAMFLAGS",
"PITYSHIELD",
"DEATHPENALTY",
"NOSPECTATORSPAWN",
"DEATHMATCHSTARTS",
"SPECIALSTAGES",
"EMERALDTOKENS",
"EMERALDHUNT",
"SPAWNENEMIES",
"ALLOWEXIT",
"NOTITLECARD",
"OVERTIME",
"HURTMESSAGES",
"SPAWNINVUL",
NULL
};
#ifdef HAVE_BLUA
// Linedef flags
static const char *const ML_LIST[16] = {
@ -9065,21 +9350,6 @@ struct {
{"tr_trans90",tr_trans90},
{"NUMTRANSMAPS",NUMTRANSMAPS},
// Type of levels
{"TOL_SP",TOL_SP},
{"TOL_COOP",TOL_COOP},
{"TOL_COMPETITION",TOL_COMPETITION},
{"TOL_RACE",TOL_RACE},
{"TOL_MATCH",TOL_MATCH},
{"TOL_TAG",TOL_TAG},
{"TOL_CTF",TOL_CTF},
{"TOL_CUSTOM",TOL_CUSTOM},
{"TOL_2D",TOL_2D},
{"TOL_MARIO",TOL_MARIO},
{"TOL_NIGHTS",TOL_NIGHTS},
{"TOL_ERZ3",TOL_ERZ3},
{"TOL_XMAS",TOL_XMAS},
// Level flags
{"LF_SCRIPTISFILE",LF_SCRIPTISFILE},
{"LF_SPEEDMUSIC",LF_SPEEDMUSIC},
@ -9262,15 +9532,16 @@ struct {
{"DMG_CANHURTSELF",DMG_CANHURTSELF},
{"DMG_DEATHMASK",DMG_DEATHMASK},
// Gametypes, for use with global var "gametype"
{"GT_COOP",GT_COOP},
{"GT_COMPETITION",GT_COMPETITION},
{"GT_RACE",GT_RACE},
{"GT_MATCH",GT_MATCH},
{"GT_TEAMMATCH",GT_TEAMMATCH},
{"GT_TAG",GT_TAG},
{"GT_HIDEANDSEEK",GT_HIDEANDSEEK},
{"GT_CTF",GT_CTF},
// Intermission types
{"int_none",int_none},
{"int_coop",int_coop},
{"int_match",int_match},
{"int_teammatch",int_teammatch},
//{"int_tag",int_tag},
{"int_ctf",int_ctf},
{"int_spec",int_spec},
{"int_race",int_race},
{"int_comp",int_comp},
// Jingles (jingletype_t)
{"JT_NONE",JT_NONE},
@ -9563,7 +9834,7 @@ struct {
};
static mobjtype_t get_mobjtype(const char *word)
{ // Returns the vlaue of MT_ enumerations
{ // Returns the value of MT_ enumerations
mobjtype_t i;
if (*word >= '0' && *word <= '9')
return atoi(word);
@ -9715,8 +9986,22 @@ static menutype_t get_menutype(const char *word)
}
#ifndef HAVE_BLUA
static INT16 get_gametype(const char *word)
{ // Returns the value of GT_ enumerations
INT16 i;
if (*word >= '0' && *word <= '9')
return atoi(word);
if (fastncmp("GT_",word,3))
word += 3; // take off the GT_
for (i = 0; i < NUMGAMETYPES; i++)
if (fastcmp(word, Gametype_ConstantNames[i]+3))
return i;
deh_warning("Couldn't find gametype named 'GT_%s'",word);
return GT_COOP;
}
static powertype_t get_power(const char *word)
{ // Returns the vlaue of pw_ enumerations
{ // Returns the value of pw_ enumerations
powertype_t i;
if (*word >= '0' && *word <= '9')
return atoi(word);
@ -9910,11 +10195,42 @@ static fixed_t find_const(const char **rword)
free(word);
return r;
}
else if (fastncmp("MN_",word,4)) {
else if (fastncmp("MN_",word,3)) {
r = get_menutype(word);
free(word);
return r;
}
else if (fastncmp("GT_",word,4)) {
r = get_gametype(word);
free(word);
return r;
}
else if (fastncmp("GTR_", word, 4)) {
char *p = word+4;
for (i = 0; GAMETYPERULE_LIST[i]; i++)
if (fastcmp(p, GAMETYPERULE_LIST[i])) {
free(word);
return (1<<i);
}
// Not found error
const_warning("game type rule",word);
free(word);
return 0;
}
else if (fastncmp("TOL_", word, 4)) {
char *p = word+4;
for (i = 0; TYPEOFLEVEL[i].name; i++)
if (fastcmp(p, TYPEOFLEVEL[i].name)) {
free(word);
return TYPEOFLEVEL[i].flag;
}
// Not found error
const_warning("typeoflevel",word);
free(word);
return 0;
}
else if (fastncmp("HUD_",word,4)) {
r = get_huditem(word);
free(word);
@ -10124,6 +10440,20 @@ static inline int lib_freeslot(lua_State *L)
}
r++;
}
else if (fastcmp(type, "TOL"))
{
if (lastcustomtol > 31)
CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n");
else
{
UINT32 newtol = (1<<lastcustomtol);
CONS_Printf("TypeOfLevel TOL_%s allocated.\n",word);
G_AddTOL(newtol, word);
lua_pushinteger(L, newtol);
lastcustomtol++;
r++;
}
}
Z_Free(s);
lua_remove(L, 1);
continue;
@ -10228,6 +10558,36 @@ static inline int lib_getenum(lua_State *L)
if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("GT_", word, 3)) {
p = word;
for (i = 0; Gametype_ConstantNames[i]; i++)
if (fastcmp(p, Gametype_ConstantNames[i])) {
lua_pushinteger(L, i);
return 1;
}
if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("GTR_", word, 4)) {
p = word+4;
for (i = 0; GAMETYPERULE_LIST[i]; i++)
if (fastcmp(p, GAMETYPERULE_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i));
return 1;
}
if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("TOL_", word, 4)) {
p = word+4;
for (i = 0; TYPEOFLEVEL[i].name; i++)
if (fastcmp(p, TYPEOFLEVEL[i].name)) {
lua_pushinteger(L, TYPEOFLEVEL[i].flag);
return 1;
}
if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("ML_", word, 3)) {
p = word+3;
for (i = 0; i < 16; i++)
@ -10465,198 +10825,7 @@ static inline int lib_getenum(lua_State *L)
// DYNAMIC variables too!!
// Try not to add anything that would break netgames or timeattack replays here.
// You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime.
if (fastcmp(word,"gamemap")) {
lua_pushinteger(L, gamemap);
return 1;
} else if (fastcmp(word,"maptol")) {
lua_pushinteger(L, maptol);
return 1;
} else if (fastcmp(word,"ultimatemode")) {
lua_pushboolean(L, ultimatemode != 0);
return 1;
} else if (fastcmp(word,"mariomode")) {
lua_pushboolean(L, mariomode != 0);
return 1;
} else if (fastcmp(word,"twodlevel")) {
lua_pushboolean(L, twodlevel != 0);
return 1;
} else if (fastcmp(word,"circuitmap")) {
lua_pushboolean(L, circuitmap);
return 1;
} else if (fastcmp(word,"netgame")) {
lua_pushboolean(L, netgame);
return 1;
} else if (fastcmp(word,"multiplayer")) {
lua_pushboolean(L, multiplayer);
return 1;
} else if (fastcmp(word,"modeattacking")) {
lua_pushboolean(L, modeattacking);
return 1;
} else if (fastcmp(word,"splitscreen")) {
lua_pushboolean(L, splitscreen);
return 1;
} else if (fastcmp(word,"gamecomplete")) {
lua_pushboolean(L, gamecomplete);
return 1;
} else if (fastcmp(word,"devparm")) {
lua_pushboolean(L, devparm);
return 1;
} else if (fastcmp(word,"modifiedgame")) {
lua_pushboolean(L, modifiedgame && !savemoddata);
return 1;
} else if (fastcmp(word,"menuactive")) {
lua_pushboolean(L, menuactive);
return 1;
} else if (fastcmp(word,"paused")) {
lua_pushboolean(L, paused);
return 1;
// begin map vars
} else if (fastcmp(word,"spstage_start")) {
lua_pushinteger(L, spstage_start);
return 1;
} else if (fastcmp(word,"sstage_start")) {
lua_pushinteger(L, sstage_start);
return 1;
} else if (fastcmp(word,"sstage_end")) {
lua_pushinteger(L, sstage_end);
return 1;
} else if (fastcmp(word,"smpstage_start")) {
lua_pushinteger(L, smpstage_start);
return 1;
} else if (fastcmp(word,"smpstage_end")) {
lua_pushinteger(L, smpstage_end);
return 1;
} else if (fastcmp(word,"titlemap")) {
lua_pushinteger(L, titlemap);
return 1;
} else if (fastcmp(word,"titlemapinaction")) {
lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
return 1;
} else if (fastcmp(word,"bootmap")) {
lua_pushinteger(L, bootmap);
return 1;
} else if (fastcmp(word,"tutorialmap")) {
lua_pushinteger(L, tutorialmap);
return 1;
} else if (fastcmp(word,"tutorialmode")) {
lua_pushboolean(L, tutorialmode);
return 1;
// end map vars
// begin CTF colors
} else if (fastcmp(word,"skincolor_redteam")) {
lua_pushinteger(L, skincolor_redteam);
return 1;
} else if (fastcmp(word,"skincolor_blueteam")) {
lua_pushinteger(L, skincolor_blueteam);
return 1;
} else if (fastcmp(word,"skincolor_redring")) {
lua_pushinteger(L, skincolor_redring);
return 1;
} else if (fastcmp(word,"skincolor_bluering")) {
lua_pushinteger(L, skincolor_bluering);
return 1;
// end CTF colors
// begin timers
} else if (fastcmp(word,"invulntics")) {
lua_pushinteger(L, invulntics);
return 1;
} else if (fastcmp(word,"sneakertics")) {
lua_pushinteger(L, sneakertics);
return 1;
} else if (fastcmp(word,"flashingtics")) {
lua_pushinteger(L, flashingtics);
return 1;
} else if (fastcmp(word,"tailsflytics")) {
lua_pushinteger(L, tailsflytics);
return 1;
} else if (fastcmp(word,"underwatertics")) {
lua_pushinteger(L, underwatertics);
return 1;
} else if (fastcmp(word,"spacetimetics")) {
lua_pushinteger(L, spacetimetics);
return 1;
} else if (fastcmp(word,"extralifetics")) {
lua_pushinteger(L, extralifetics);
return 1;
} else if (fastcmp(word,"nightslinktics")) {
lua_pushinteger(L, nightslinktics);
return 1;
} else if (fastcmp(word,"gameovertics")) {
lua_pushinteger(L, gameovertics);
return 1;
} else if (fastcmp(word,"ammoremovaltics")) {
lua_pushinteger(L, ammoremovaltics);
return 1;
// end timers
} else if (fastcmp(word,"gametype")) {
lua_pushinteger(L, gametype);
return 1;
} else if (fastcmp(word,"leveltime")) {
lua_pushinteger(L, leveltime);
return 1;
} else if (fastcmp(word,"curWeather")) {
lua_pushinteger(L, curWeather);
return 1;
} else if (fastcmp(word,"globalweather")) {
lua_pushinteger(L, globalweather);
return 1;
} else if (fastcmp(word,"levelskynum")) {
lua_pushinteger(L, levelskynum);
return 1;
} else if (fastcmp(word,"globallevelskynum")) {
lua_pushinteger(L, globallevelskynum);
return 1;
} else if (fastcmp(word,"mapmusname")) {
lua_pushstring(L, mapmusname);
return 1;
} else if (fastcmp(word,"mapmusflags")) {
lua_pushinteger(L, mapmusflags);
return 1;
} else if (fastcmp(word,"mapmusposition")) {
lua_pushinteger(L, mapmusposition);
return 1;
// local player variables, by popular request
} else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1)
if (consoleplayer < 0 || !playeringame[consoleplayer])
return 0;
LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"displayplayer")) { // player visible on screen (aka display player 1)
if (displayplayer < 0 || !playeringame[displayplayer])
return 0;
LUA_PushUserdata(L, &players[displayplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"secondarydisplayplayer")) { // local/display player 2, for splitscreen
if (!splitscreen || secondarydisplayplayer < 0 || !playeringame[secondarydisplayplayer])
return 0;
LUA_PushUserdata(L, &players[secondarydisplayplayer], META_PLAYER);
return 1;
// end local player variables
} else if (fastcmp(word,"server")) {
if ((!multiplayer || !netgame) && !playeringame[serverplayer])
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array.
LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)");
if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer))
return 0;
LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER);
return 1;
} else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds);
return 1;
} else if (fastcmp(word,"gravity")) {
lua_pushinteger(L, gravity);
return 1;
} else if (fastcmp(word,"VERSIONSTRING")) {
lua_pushstring(L, VERSIONSTRING);
return 1;
} else if (fastcmp(word, "token")) {
lua_pushinteger(L, token);
return 1;
}
return 0;
return LUA_PushGlobals(L, word);
}
int LUA_EnumLib(lua_State *L)
@ -10723,6 +10892,8 @@ static int lib_getActionName(lua_State *L)
return luaL_typerror(L, 1, "action userdata or Lua function");
}
int LUA_SOCLib(lua_State *L)
{
lua_register(L,"freeslot",lib_freeslot);

View File

@ -39,7 +39,7 @@ extern UINT32 mapmusposition;
#define MUSIC_FORCERESET 0x4000 // -*--------------
// Use other bits if necessary.
extern INT16 maptol;
extern UINT32 maptol;
extern UINT8 globalweather;
extern INT32 curWeather;
extern INT32 cursaveslot;
@ -84,6 +84,9 @@ extern boolean addedtogame; // true after the server has added you
extern boolean multiplayer;
extern INT16 gametype;
extern UINT32 gametyperules;
extern INT16 gametypecount;
extern boolean splitscreen;
extern boolean circuitmap; // Does this level have 'circuit mode'?
extern boolean fromlevelselect;
@ -284,7 +287,7 @@ typedef struct
char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway)
char subttl[33]; ///< Subtitle for level
UINT8 actnum; ///< Act number or 0 for none.
UINT16 typeoflevel; ///< Combination of typeoflevel flags.
UINT32 typeoflevel; ///< Combination of typeoflevel flags.
INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end.
char musname[7]; ///< Music track to play. "" for no music.
UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
@ -366,6 +369,70 @@ typedef struct
extern mapheader_t* mapheaderinfo[NUMMAPS];
// Gametypes
#define NUMGAMETYPEFREESLOTS 128
enum GameType
{
GT_COOP = 0, // also used in single player
GT_COMPETITION, // Classic "Race"
GT_RACE,
GT_MATCH,
GT_TEAMMATCH,
GT_TAG,
GT_HIDEANDSEEK,
GT_CTF, // capture the flag
GT_FIRSTFREESLOT,
GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1,
NUMGAMETYPES
};
// If you alter this list, update dehacked.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c
// Gametype rules
enum GameTypeRules
{
GTR_CAMPAIGN = 1, // Linear Co-op map progression, don't allow random maps
GTR_RINGSLINGER = 1<<1, // Outside of Co-op, Competition, and Race (overriden by cv_ringslinger)
GTR_SPECTATORS = 1<<2, // Outside of Co-op, Competition, and Race
GTR_FRIENDLYFIRE = 1<<3, // Always allow friendly fire
GTR_LIVES = 1<<4, // Co-op and Competition
GTR_TEAMS = 1<<5, // Team Match, CTF
GTR_RACE = 1<<6, // Race and Competition
GTR_TAG = 1<<7, // Tag and Hide and Seek
GTR_POINTLIMIT = 1<<8, // Ringslinger point limit
GTR_TIMELIMIT = 1<<9, // Ringslinger time limit
GTR_HIDETIME = 1<<10, // Hide time (Tag and Hide and Seek)
GTR_HIDEFROZEN = 1<<11, // Frozen after hide time (Hide and Seek, but not Tag)
GTR_BLINDFOLDED = 1<<12, // Blindfolded view (Tag and Hide and Seek)
GTR_FIRSTPERSON = 1<<13, // First person camera
GTR_MATCHEMERALDS = 1<<14, // Ringslinger emeralds (Match and CTF)
GTR_TEAMFLAGS = 1<<15, // Gametype has team flags (CTF)
GTR_PITYSHIELD = 1<<16, // Award pity shield
GTR_DEATHPENALTY = 1<<17, // Death score penalty
GTR_NOSPECTATORSPAWN = 1<<18, // Use with GTR_SPECTATORS, spawn in the map instead of with the spectators
GTR_DEATHMATCHSTARTS = 1<<19, // Use deathmatch starts
GTR_SPECIALSTAGES = 1<<20, // Allow special stages
GTR_EMERALDTOKENS = 1<<21, // Spawn emerald tokens
GTR_EMERALDHUNT = 1<<22, // Emerald Hunt
GTR_SPAWNENEMIES = 1<<23, // Spawn enemies
GTR_ALLOWEXIT = 1<<24, // Allow exit sectors
GTR_NOTITLECARD = 1<<25, // Don't show the title card
GTR_OVERTIME = 1<<26, // Allow overtime
GTR_HURTMESSAGES = 1<<27, // Hit and death messages
GTR_SPAWNINVUL = 1<<28, // Babysitting deterrent
};
// String names for gametypes
extern const char *Gametype_Names[NUMGAMETYPES];
extern const char *Gametype_ConstantNames[NUMGAMETYPES];
// Point and time limits for every gametype
extern INT32 pointlimits[NUMGAMETYPES];
extern INT32 timelimits[NUMGAMETYPES];
enum TypeOfLevel
{
TOL_SP = 0x01, ///< Single Player
@ -381,36 +448,26 @@ enum TypeOfLevel
TOL_CTF = 0x40, ///< Capture the Flag
// CTF default = 64
TOL_CUSTOM = 0x80, ///< Custom (Lua-scripted, etc.)
// 0x80 was here
TOL_2D = 0x0100, ///< 2D
TOL_MARIO = 0x0200, ///< Mario
TOL_NIGHTS = 0x0400, ///< NiGHTS
TOL_ERZ3 = 0x0800, ///< ERZ3
TOL_XMAS = 0x1000 ///< Christmas NiGHTS
TOL_XMAS = 0x1000, ///< Christmas NiGHTS
};
// Gametypes
enum GameType
#define NUMBASETOL 18
#define NUMMAXTOL (18 + NUMGAMETYPEFREESLOTS)
typedef struct
{
GT_COOP = 0, // also used in single player
GT_COMPETITION, // Classic "Race"
GT_RACE,
GT_MATCH,
GT_TEAMMATCH,
GT_TAG,
GT_HIDEANDSEEK,
GT_CTF, // capture the flag
NUMGAMETYPES
};
// If you alter this list, update dehacked.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c
// String names for gametypes
extern const char *Gametype_Names[NUMGAMETYPES];
const char *name;
UINT32 flag;
} tolinfo_t;
extern tolinfo_t TYPEOFLEVEL[NUMMAXTOL];
extern INT32 numtolinfo;
extern UINT32 lastcustomtol;
extern tic_t totalplaytime;

View File

@ -79,7 +79,7 @@ UINT16 mapmusflags; // Track and reset bit
UINT32 mapmusposition; // Position to jump to
INT16 gamemap = 1;
INT16 maptol;
UINT32 maptol;
UINT8 globalweather = 0;
INT32 curWeather = PRECIP_NONE;
INT32 cursaveslot = 0; // Auto-save 1p savegame slot
@ -1066,7 +1066,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
// why build a ticcmd if we're paused?
// Or, for that matter, if we're being reborn.
// ...OR if we're blindfolded. No looking into the floor.
if (paused || P_AutoPause() || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK)
if (paused || P_AutoPause() || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametyperules & GTR_TAG)
&& (leveltime < hidetime * TICRATE) && (player->pflags & PF_TAGIT)))))
{
cmd->angleturn = (INT16)(localangle >> 16);
@ -1379,7 +1379,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
//Reset away view if a command is given.
if ((cmd->forwardmove || cmd->sidemove || cmd->buttons)
&& displayplayer != consoleplayer)
{
#ifdef HAVE_BLUA
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
LUAh_ViewpointSwitch(player, &players[displayplayer], true);
#endif
displayplayer = consoleplayer;
}
}
// like the g_buildticcmd 1 but using mouse2, gamcontrolbis, ...
@ -1885,7 +1892,7 @@ void G_StartTitleCard(void)
{
// The title card has been disabled for this map.
// Oh well.
if (mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD)
if (!G_IsTitleCardAvailable())
{
WipeStageTitle = false;
return;
@ -1930,6 +1937,23 @@ void G_PreLevelTitleCard(void)
wipestyleflags = WSF_CROSSFADE;
}
//
// Returns true if the current level has a title card.
//
boolean G_IsTitleCardAvailable(void)
{
// The current level header explicitly disabled the title card.
if (mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD)
return false;
// The current gametype doesn't have a title card.
if (gametyperules & GTR_NOTITLECARD)
return false;
// The title card is available.
return true;
}
INT32 pausedelay = 0;
boolean pausebreakkey = false;
static INT32 camtoggledelay, camtoggledelay2 = 0;
@ -2020,6 +2044,11 @@ boolean G_Responder(event_t *ev)
if (gamestate == GS_LEVEL && ev->type == ev_keydown
&& (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1]))
{
// ViewpointSwitch Lua hook.
#ifdef HAVE_BLUA
UINT8 canSwitchView = 0;
#endif
if (splitscreen || !netgame)
displayplayer = consoleplayer;
else
@ -2034,6 +2063,15 @@ boolean G_Responder(event_t *ev)
if (!playeringame[displayplayer])
continue;
#ifdef HAVE_BLUA
// Call ViewpointSwitch hooks here.
canSwitchView = LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer], false);
if (canSwitchView == 1) // Set viewpoint to this player
break;
else if (canSwitchView == 2) // Skip this player
continue;
#endif
if (players[displayplayer].spectator)
continue;
@ -2642,7 +2680,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
// -- CTF --
// Order: CTF->DM->Coop
if (gametype == GT_CTF && players[playernum].ctfteam)
if ((gametyperules & (GTR_TEAMFLAGS|GTR_TEAMS)) && players[playernum].ctfteam)
{
if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start
&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
@ -2651,7 +2689,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
// -- DM/Tag/CTF-spectator/etc --
// Order: DM->CTF->Coop
else if (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF
else if ((gametyperules & GTR_DEATHMATCHSTARTS) || gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF
|| ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && !(players[playernum].pflags & PF_TAGIT)))
{
if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start
@ -2698,7 +2736,7 @@ mapthing_t *G_FindCTFStart(INT32 playernum)
if (!numredctfstarts && !numbluectfstarts) //why even bother, eh?
{
if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))
if ((gametyperules & GTR_TEAMFLAGS) && (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)))
CONS_Alert(CONS_WARNING, M_GetText("No CTF starts in this map!\n"));
return NULL;
}
@ -3104,7 +3142,7 @@ void G_ExitLevel(void)
CV_SetValue(&cv_teamscramble, cv_scrambleonchange.value);
}
if (gametype != GT_COOP)
if (!(gametyperules & GTR_CAMPAIGN))
CONS_Printf(M_GetText("The round has ended.\n"));
// Remove CEcho text on round end.
@ -3136,6 +3174,221 @@ const char *Gametype_Names[NUMGAMETYPES] =
"CTF" // GT_CTF
};
// For dehacked
const char *Gametype_ConstantNames[NUMGAMETYPES] =
{
"GT_COOP", // GT_COOP
"GT_COMPETITION", // GT_COMPETITION
"GT_RACE", // GT_RACE
"GT_MATCH", // GT_MATCH
"GT_TEAMMATCH", // GT_TEAMMATCH
"GT_TAG", // GT_TAG
"GT_HIDEANDSEEK", // GT_HIDEANDSEEK
"GT_CTF" // GT_CTF
};
// Gametype rules
UINT32 gametypedefaultrules[NUMGAMETYPES] =
{
// Co-op
GTR_CAMPAIGN|GTR_LIVES|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES,
// Competition
GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT,
// Race
GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT,
// Match
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_SPAWNINVUL|GTR_PITYSHIELD|GTR_DEATHPENALTY,
// Team Match
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_SPAWNINVUL|GTR_PITYSHIELD,
// Tag
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_SPAWNINVUL,
// Hide and Seek
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_SPAWNINVUL,
// CTF
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_TEAMFLAGS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_SPAWNINVUL|GTR_PITYSHIELD,
};
//
// G_SetGametype
//
// Set a new gametype, also setting gametype rules accordingly. Yay!
//
void G_SetGametype(INT16 gtype)
{
gametype = gtype;
gametyperules = gametypedefaultrules[gametype];
}
//
// G_AddGametype
//
// Add a gametype. Returns the new gametype number.
//
INT16 G_AddGametype(UINT32 rules)
{
INT16 newgtype = gametypecount;
gametypecount++;
// Set gametype rules.
gametypedefaultrules[newgtype] = rules;
Gametype_Names[newgtype] = "???";
// Update gametype_cons_t accordingly.
G_UpdateGametypeSelections();
return newgtype;
}
//
// G_AddGametypeConstant
//
// Self-explanatory. Filters out "bad" characters.
//
void G_AddGametypeConstant(INT16 gtype, const char *newgtconst)
{
char *gtconst = Z_Malloc(strlen(newgtconst) + 3, PU_STATIC, NULL);
// Copy GT_ and the gametype name.
strcpy(gtconst, "GT_");
strcat(gtconst, newgtconst);
// Make uppercase.
strupr(gtconst);
// Remove characters.
#define REMOVECHAR(chr) \
{ \
char *chrfind = strchr(gtconst, chr); \
while (chrfind) \
{ \
*chrfind = '_'; \
chrfind = strchr(chrfind, chr); \
} \
}
// Space
REMOVECHAR(' ')
// Used for operations
REMOVECHAR('+')
REMOVECHAR('-')
REMOVECHAR('*')
REMOVECHAR('/')
REMOVECHAR('%')
REMOVECHAR('^')
// Part of Lua's syntax
REMOVECHAR('#')
REMOVECHAR('=')
REMOVECHAR('~')
REMOVECHAR('<')
REMOVECHAR('>')
REMOVECHAR('(')
REMOVECHAR(')')
REMOVECHAR('{')
REMOVECHAR('}')
REMOVECHAR('[')
REMOVECHAR(']')
REMOVECHAR(':')
REMOVECHAR(';')
REMOVECHAR(',')
REMOVECHAR('.')
#undef REMOVECHAR
// Finally, set the constant string.
Gametype_ConstantNames[gtype] = gtconst;
}
//
// G_UpdateGametypeSelections
//
// Updates gametype_cons_t.
//
void G_UpdateGametypeSelections(void)
{
INT32 i;
for (i = 0; i < gametypecount; i++)
{
gametype_cons_t[i].value = i;
gametype_cons_t[i].strvalue = Gametype_Names[i];
}
gametype_cons_t[NUMGAMETYPES].value = 0;
gametype_cons_t[NUMGAMETYPES].strvalue = NULL;
}
//
// G_SetGametypeDescription
//
// Set a description for the specified gametype.
// (Level platter)
//
void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolor, UINT8 rightcolor)
{
if (descriptiontext != NULL)
strncpy(gametypedesc[gtype].notes, descriptiontext, 441);
gametypedesc[gtype].col[0] = leftcolor;
gametypedesc[gtype].col[1] = rightcolor;
}
// Gametype rankings
INT16 gametyperankings[NUMGAMETYPES] =
{
GT_COOP,
GT_COMPETITION,
GT_RACE,
GT_MATCH,
GT_TEAMMATCH,
GT_TAG,
GT_HIDEANDSEEK,
GT_CTF,
};
// Gametype to TOL (Type Of Level)
UINT32 gametypetol[NUMGAMETYPES] =
{
TOL_COOP, // Co-op
TOL_COMPETITION, // Competition
TOL_RACE, // Race
TOL_MATCH, // Match
TOL_MATCH, // Team Match
TOL_TAG, // Tag
TOL_TAG, // Hide and Seek
TOL_CTF, // CTF
};
//
// G_AddTOL
//
// Adds a type of level.
//
void G_AddTOL(UINT32 newtol, const char *tolname)
{
TYPEOFLEVEL[numtolinfo].name = Z_StrDup(tolname);
TYPEOFLEVEL[numtolinfo].flag = newtol;
numtolinfo++;
TYPEOFLEVEL[numtolinfo].name = NULL;
TYPEOFLEVEL[numtolinfo].flag = 0;
}
//
// G_AddTOL
//
// Assigns a type of level to a gametype.
//
void G_AddGametypeTOL(INT16 gtype, UINT32 newtol)
{
gametypetol[gtype] = newtol;
}
//
// G_GetGametypeByName
//
@ -3178,8 +3431,8 @@ boolean G_IsSpecialStage(INT32 mapnum)
//
boolean G_GametypeUsesLives(void)
{
// Coop, Competitive
if ((gametype == GT_COOP || gametype == GT_COMPETITION)
// Coop, Competitive
if ((gametyperules & GTR_LIVES)
&& !(modeattacking || metalrecording) // No lives in Time Attack
&& !G_IsSpecialStage(gamemap)
&& !(maptol & TOL_NIGHTS)) // No lives in NiGHTS
@ -3195,7 +3448,7 @@ boolean G_GametypeUsesLives(void)
//
boolean G_GametypeHasTeams(void)
{
return (gametype == GT_TEAMMATCH || gametype == GT_CTF);
return (gametyperules & GTR_TEAMS);
}
//
@ -3206,7 +3459,7 @@ boolean G_GametypeHasTeams(void)
//
boolean G_GametypeHasSpectators(void)
{
return (gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE);
return (gametyperules & GTR_SPECTATORS);
}
//
@ -3217,7 +3470,7 @@ boolean G_GametypeHasSpectators(void)
//
boolean G_RingSlingerGametype(void)
{
return ((gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE) || (cv_ringslinger.value));
return ((gametyperules & GTR_RINGSLINGER) || (cv_ringslinger.value));
}
//
@ -3227,7 +3480,7 @@ boolean G_RingSlingerGametype(void)
//
boolean G_PlatformGametype(void)
{
return (gametype == GT_COOP || gametype == GT_RACE || gametype == GT_COMPETITION);
return (!(gametyperules & GTR_RINGSLINGER));
}
//
@ -3237,7 +3490,7 @@ boolean G_PlatformGametype(void)
//
boolean G_TagGametype(void)
{
return (gametype == GT_TAG || gametype == GT_HIDEANDSEEK);
return (gametyperules & GTR_TAG);
}
/** Get the typeoflevel flag needed to indicate support of a gametype.
@ -3248,18 +3501,9 @@ boolean G_TagGametype(void)
*/
INT16 G_TOLFlag(INT32 pgametype)
{
if (!multiplayer) return TOL_SP;
if (pgametype == GT_COOP) return TOL_COOP;
if (pgametype == GT_COMPETITION) return TOL_COMPETITION;
if (pgametype == GT_RACE) return TOL_RACE;
if (pgametype == GT_MATCH) return TOL_MATCH;
if (pgametype == GT_TEAMMATCH) return TOL_MATCH;
if (pgametype == GT_TAG) return TOL_TAG;
if (pgametype == GT_HIDEANDSEEK) return TOL_TAG;
if (pgametype == GT_CTF) return TOL_CTF;
CONS_Alert(CONS_ERROR, M_GetText("Unknown gametype! %d\n"), pgametype);
return INT16_MAX;
if (!multiplayer)
return TOL_SP;
return gametypetol[pgametype];
}
/** Select a random map with the given typeoflevel flags.
@ -3270,7 +3514,7 @@ INT16 G_TOLFlag(INT32 pgametype)
* has those flags.
* \author Graue <graue@oceanbase.org>
*/
static INT16 RandMap(INT16 tolflags, INT16 pprevmap)
static INT16 RandMap(UINT32 tolflags, INT16 pprevmap)
{
INT16 *okmaps = Z_Malloc(NUMMAPS * sizeof(INT16), PU_STATIC, NULL);
INT32 numokmaps = 0;
@ -3428,10 +3672,10 @@ static void G_DoCompleted(void)
I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1);
// wrap around in race
if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametype == GT_RACE || gametype == GT_COMPETITION))
if (nextmap >= 1100-1 && nextmap <= 1102-1 && !(gametyperules & GTR_CAMPAIGN))
nextmap = (INT16)(spstage_start-1);
if ((gottoken = (gametype == GT_COOP && token)))
if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token)))
{
token--;
@ -3451,7 +3695,7 @@ static void G_DoCompleted(void)
automapactive = false;
if (gametype != GT_COOP)
if (!(gametyperules & GTR_CAMPAIGN))
{
if (cv_advancemap.value == 0) // Stay on same map.
nextmap = prevmap;

View File

@ -143,6 +143,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar,
void G_DoLoadLevel(boolean resetplayer);
void G_StartTitleCard(void);
void G_PreLevelTitleCard(void);
boolean G_IsTitleCardAvailable(void);
void G_DeferedPlayDemo(const char *demo);
// Can be called by the startup code or M_Responder, calls P_SetupLevel.
@ -202,6 +203,18 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill);
void G_StopDemo(void);
boolean G_CheckDemoStatus(void);
extern UINT32 gametypedefaultrules[NUMGAMETYPES];
extern UINT32 gametypetol[NUMGAMETYPES];
extern INT16 gametyperankings[NUMGAMETYPES];
void G_SetGametype(INT16 gametype);
INT16 G_AddGametype(UINT32 rules);
void G_AddGametypeConstant(INT16 gtype, const char *newgtconst);
void G_UpdateGametypeSelections(void);
void G_AddTOL(UINT32 newtol, const char *tolname);
void G_AddGametypeTOL(INT16 gtype, UINT32 newtol);
void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolor, UINT8 rightcolor);
INT32 G_GetGametypeByName(const char *gametypestr);
boolean G_IsSpecialStage(INT32 mapnum);
boolean G_GametypeUsesLives(void);

View File

@ -2066,7 +2066,7 @@ static void HU_drawGametype(void)
{
const char *strvalue = NULL;
if (gametype < 0 || gametype >= NUMGAMETYPES)
if (gametype < 0 || gametype >= gametypecount)
return; // not a valid gametype???
strvalue = Gametype_Names[gametype];
@ -2371,7 +2371,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
for (i = 0; i < scorelines; i++)
{
if (players[tab[i].num].spectator && gametype != GT_COOP)
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP)
continue; //ignore them.
greycheck = greycheckdef;
@ -2434,7 +2434,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
}
}
if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
if (G_GametypeUsesLives() && !(gametyperankings[gametype] == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|(greycheck ? V_60TRANS : 0), va("%dx", players[tab[i].num].lives));
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
{
@ -2447,7 +2447,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
if (gametype == GT_RACE)
if (gametyperankings[gametype] == GT_RACE)
{
if (circuitmap)
{
@ -2541,7 +2541,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
| (greycheck ? 0 : V_TRANSLUCENT)
| V_ALLOWLOWERCASE, name);
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
{
if (players[tab[i].num].gotflag & GF_REDFLAG) // Red
V_DrawFixedPatch((x-10)*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, rflagico, 0);
@ -2669,7 +2669,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer)
| (greycheck ? V_TRANSLUCENT : 0)
| V_ALLOWLOWERCASE, name);
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
{
if (players[tab[i].num].gotflag & GF_REDFLAG) // Red
V_DrawSmallScaledPatch(x-28, y-4, 0, rflagico);
@ -2726,7 +2726,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
for (i = 0; i < scorelines; i++)
{
if (players[tab[i].num].spectator && gametype != GT_COOP)
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP)
continue; //ignore them.
greycheck = greycheckdef;
@ -2743,7 +2743,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
| (greycheck ? V_TRANSLUCENT : 0)
| V_ALLOWLOWERCASE, name);
if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
if (G_GametypeUsesLives() && !(gametyperankings[gametype] == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives
V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives));
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
V_DrawSmallScaledPatch(x-28, y-4, 0, tagico);
@ -2792,7 +2792,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
}
// All data drawn with thin string for space.
if (gametype == GT_RACE)
if (gametyperankings[gametype] == GT_RACE)
{
if (circuitmap)
{
@ -2832,7 +2832,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
for (i = 0; i < scorelines; i++)
{
if (players[tab[i].num].spectator && gametype != GT_COOP)
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP)
continue; //ignore them.
greycheck = greycheckdef;
@ -2902,7 +2902,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
}
// All data drawn with thin string for space.
if (gametype == GT_RACE)
if (gametyperankings[gametype] == GT_RACE)
{
if (circuitmap)
{
@ -3026,21 +3026,21 @@ static void HU_DrawRankings(void)
// draw the current gametype in the lower right
HU_drawGametype();
if (gametype != GT_RACE && gametype != GT_COMPETITION && gametype != GT_COOP)
if (gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT))
{
if (cv_timelimit.value && timelimitintics > 0)
if ((gametyperules & GTR_TIMELIMIT) && cv_timelimit.value && timelimitintics > 0)
{
V_DrawCenteredString(64, 8, 0, "TIME");
V_DrawCenteredString(64, 16, 0, va("%i:%02i", G_TicsToMinutes(stplyr->realtime, true), G_TicsToSeconds(stplyr->realtime)));
}
if (cv_pointlimit.value > 0)
if ((gametyperules & GTR_POINTLIMIT) && cv_pointlimit.value > 0)
{
V_DrawCenteredString(256, 8, 0, "POINT LIMIT");
V_DrawCenteredString(256, 16, 0, va("%d", cv_pointlimit.value));
}
}
else if (gametype == GT_COOP)
else if (gametyperankings[gametype] == GT_COOP)
{
INT32 totalscore = 0;
for (i = 0; i < MAXPLAYERS; i++)
@ -3074,7 +3074,7 @@ static void HU_DrawRankings(void)
tab[i].num = -1;
tab[i].name = 0;
if (gametype == GT_RACE && !circuitmap)
if (gametyperankings[gametype] == GT_RACE && !circuitmap)
tab[i].count = INT32_MAX;
}
@ -3083,7 +3083,7 @@ static void HU_DrawRankings(void)
if (!playeringame[j])
continue;
if (gametype != GT_COOP && players[j].spectator)
if (!G_PlatformGametype() && players[j].spectator)
continue;
for (i = 0; i < MAXPLAYERS; i++)
@ -3091,10 +3091,10 @@ static void HU_DrawRankings(void)
if (!playeringame[i])
continue;
if (gametype != GT_COOP && players[i].spectator)
if (!G_PlatformGametype() && players[i].spectator)
continue;
if (gametype == GT_RACE)
if (gametyperankings[gametype] == GT_RACE)
{
if (circuitmap)
{
@ -3117,7 +3117,7 @@ static void HU_DrawRankings(void)
}
}
}
else if (gametype == GT_COMPETITION)
else if (gametyperankings[gametype] == GT_COMPETITION)
{
// todo put something more fitting for the gametype here, such as current
// number of categories led

View File

@ -12,6 +12,7 @@
#include "doomdef.h"
#ifdef HAVE_BLUA
#include "fastcmp.h"
#include "p_local.h"
#include "p_setup.h" // So we can have P_SetupLevelSky
#ifdef ESLOPE
@ -23,6 +24,8 @@
#include "m_random.h"
#include "s_sound.h"
#include "g_game.h"
#include "m_menu.h"
#include "y_inter.h"
#include "hu_stuff.h" // HU_AddChatText
#include "console.h"
#include "d_netcmd.h" // IsPlayerAdmin
@ -2632,6 +2635,145 @@ static int lib_sStartMusicCaption(lua_State *L)
// G_GAME
////////////
// Copypasted from lib_cvRegisterVar :]
static int lib_gAddGametype(lua_State *L)
{
const char *k;
lua_Integer i;
const char *gtname = NULL;
const char *gtconst = NULL;
const char *gtdescription = NULL;
INT16 newgtidx = 0;
UINT32 newgtrules = 0;
UINT32 newgttol = 0;
INT32 newgtpointlimit = 0;
INT32 newgttimelimit = 0;
UINT8 newgtleftcolor = 0;
UINT8 newgtrightcolor = 0;
INT16 newgtrankingstype = -1;
int newgtinttype = 0;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
// Ran out of gametype slots
if (gametypecount == NUMGAMETYPEFREESLOTS)
return luaL_error(L, "Ran out of free gametype slots!");
#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("G_AddGametype") " (%s)", e);
#define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1)))
lua_pushnil(L);
while (lua_next(L, 1)) {
// stack: gametype table, key/index, value
// 1 2 3
i = 0;
k = NULL;
if (lua_isnumber(L, 2))
i = lua_tointeger(L, 2);
else if (lua_isstring(L, 2))
k = lua_tostring(L, 2);
// Sorry, no gametype rules as key names.
if (i == 1 || (k && fasticmp(k, "name"))) {
if (!lua_isstring(L, 3))
TYPEERROR("name", LUA_TSTRING)
gtname = Z_StrDup(lua_tostring(L, 3));
} else if (i == 2 || (k && fasticmp(k, "identifier"))) {
if (!lua_isstring(L, 3))
TYPEERROR("identifier", LUA_TSTRING)
gtconst = Z_StrDup(lua_tostring(L, 3));
} else if (i == 3 || (k && fasticmp(k, "rules"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("rules", LUA_TNUMBER)
newgtrules = (UINT32)lua_tointeger(L, 3);
} else if (i == 4 || (k && fasticmp(k, "typeoflevel"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("typeoflevel", LUA_TNUMBER)
newgttol = (UINT32)lua_tointeger(L, 3);
} else if (i == 5 || (k && fasticmp(k, "rankingtype"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("rankingtype", LUA_TNUMBER)
newgtrankingstype = (INT16)lua_tointeger(L, 3);
} else if (i == 6 || (k && fasticmp(k, "intermissiontype"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("intermissiontype", LUA_TNUMBER)
newgtinttype = (int)lua_tointeger(L, 3);
} else if (i == 7 || (k && fasticmp(k, "defaultpointlimit"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("defaultpointlimit", LUA_TNUMBER)
newgtpointlimit = (INT32)lua_tointeger(L, 3);
} else if (i == 8 || (k && fasticmp(k, "defaulttimelimit"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("defaulttimelimit", LUA_TNUMBER)
newgttimelimit = (INT32)lua_tointeger(L, 3);
} else if (i == 9 || (k && fasticmp(k, "description"))) {
if (!lua_isstring(L, 3))
TYPEERROR("description", LUA_TSTRING)
gtdescription = Z_StrDup(lua_tostring(L, 3));
} else if (i == 10 || (k && fasticmp(k, "headerleftcolor"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("headerleftcolor", LUA_TNUMBER)
newgtleftcolor = (UINT8)lua_tointeger(L, 3);
} else if (i == 11 || (k && fasticmp(k, "headerrightcolor"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("headerrightcolor", LUA_TNUMBER)
newgtrightcolor = (UINT8)lua_tointeger(L, 3);
// Key name specified
} else if ((!i) && (k && fasticmp(k, "headercolor"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("headercolor", LUA_TNUMBER)
newgtleftcolor = newgtrightcolor = (UINT8)lua_tointeger(L, 3);
}
lua_pop(L, 1);
}
#undef FIELDERROR
#undef TYPEERROR
// pop gametype table
lua_pop(L, 1);
// Set defaults
if (gtname == NULL)
gtname = Z_StrDup("Unnamed gametype");
if (gtdescription == NULL)
gtdescription = Z_StrDup("???");
// Add the new gametype
newgtidx = G_AddGametype(newgtrules);
G_AddGametypeTOL(newgtidx, newgttol);
G_SetGametypeDescription(newgtidx, NULL, newgtleftcolor, newgtrightcolor);
strncpy(gametypedesc[newgtidx].notes, gtdescription, 441);
// Not covered by G_AddGametype alone.
if (newgtrankingstype == -1)
newgtrankingstype = newgtidx;
gametyperankings[newgtidx] = newgtrankingstype;
intermissiontypes[newgtidx] = newgtinttype;
pointlimits[newgtidx] = newgtpointlimit;
timelimits[newgtidx] = newgttimelimit;
// Write the new gametype name.
Gametype_Names[newgtidx] = gtname;
// Write the constant name.
if (gtconst == NULL)
gtconst = gtname;
G_AddGametypeConstant(newgtidx, gtconst);
// Update gametype_cons_t accordingly.
G_UpdateGametypeSelections();
// done
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
return 0;
}
static int lib_gBuildMapName(lua_State *L)
{
INT32 map = luaL_optinteger(L, 1, gamemap);
@ -2991,6 +3133,7 @@ static luaL_Reg lib[] = {
{"S_StartMusicCaption", lib_sStartMusicCaption},
// g_game
{"G_AddGametype", lib_gAddGametype},
{"G_BuildMapName",lib_gBuildMapName},
{"G_DoReborn",lib_gDoReborn},
{"G_SetCustomExitVars",lib_gSetCustomExitVars},

View File

@ -51,6 +51,8 @@ enum hook {
hook_PlayerCanDamage,
hook_PlayerQuit,
hook_IntermissionThinker,
hook_TeamSwitch,
hook_ViewpointSwitch,
hook_PlayerThink,
hook_MAX // last hook
@ -94,6 +96,8 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAft
UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage
void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting
void LUAh_IntermissionThinker(void); // Hook for Y_Ticker
boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); // Hook for team switching in... uh....
UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); // Hook for spy mode
#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink
#endif

View File

@ -62,6 +62,8 @@ const char *const hookNames[hook_MAX+1] = {
"PlayerCanDamage",
"PlayerQuit",
"IntermissionThinker",
"TeamSwitch",
"ViewpointSwitch",
"PlayerThink",
NULL
};
@ -204,6 +206,8 @@ static int lib_addHook(lua_State *L)
case hook_PlayerSpawn:
case hook_FollowMobj:
case hook_PlayerCanDamage:
case hook_TeamSwitch:
case hook_ViewpointSwitch:
case hook_ShieldSpawn:
case hook_ShieldSpecial:
case hook_PlayerThink:
@ -1354,4 +1358,101 @@ void LUAh_IntermissionThinker(void)
}
}
// Hook for team switching
// It's just an edit of LUAh_ViewpointSwitch.
boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble)
{
hook_p hookp;
boolean canSwitchTeam = true;
if (!gL || !(hooksAvailable[hook_TeamSwitch/8] & (1<<(hook_TeamSwitch%8))))
return true;
lua_settop(gL, 0);
for (hookp = playerhooks; hookp; hookp = hookp->next)
{
if (hookp->type != hook_TeamSwitch)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
lua_pushinteger(gL, newteam);
lua_pushboolean(gL, fromspectators);
lua_pushboolean(gL, tryingautobalance);
lua_pushboolean(gL, tryingscramble);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
lua_pushvalue(gL, -6);
if (lua_pcall(gL, 5, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1))
canSwitchTeam = false; // Can't switch team
lua_pop(gL, 1);
}
lua_settop(gL, 0);
return canSwitchTeam;
}
// Hook for spy mode
UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced)
{
hook_p hookp;
UINT8 canSwitchView = 0; // 0 = default, 1 = force yes, 2 = force no.
if (!gL || !(hooksAvailable[hook_ViewpointSwitch/8] & (1<<(hook_ViewpointSwitch%8))))
return 0;
lua_settop(gL, 0);
hud_running = true;
for (hookp = playerhooks; hookp; hookp = hookp->next)
{
if (hookp->type != hook_ViewpointSwitch)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
LUA_PushUserdata(gL, newdisplayplayer, META_PLAYER);
lua_pushboolean(gL, forced);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -4);
lua_pushvalue(gL, -4);
lua_pushvalue(gL, -4);
if (lua_pcall(gL, 3, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1))
{ // if nil, leave canSwitchView = 0.
if (lua_toboolean(gL, -1))
canSwitchView = 1; // Force viewpoint switch
else
canSwitchView = 2; // Skip viewpoint switch
}
lua_pop(gL, 1);
}
lua_settop(gL, 0);
hud_running = false;
return canSwitchView;
}
#endif

View File

@ -34,6 +34,9 @@ enum hud {
hud_coopemeralds,
hud_tokens,
hud_tabemblems,
// Intermission
hud_intermissiontally,
hud_intermissionmessages,
hud_MAX
};
@ -44,4 +47,5 @@ boolean LUA_HudEnabled(enum hud option);
void LUAh_GameHUD(player_t *stplyr);
void LUAh_ScoresHUD(void);
void LUAh_TitleHUD(void);
void LUAh_TitleCardHUD(player_t *stplyr);
void LUAh_TitleCardHUD(player_t *stplayr);
void LUAh_IntermissionHUD(void);

View File

@ -61,6 +61,9 @@ static const char *const hud_disable_options[] = {
"coopemeralds",
"tokens",
"tabemblems",
"intermissiontally",
"intermissionmessages",
NULL};
enum hudinfo {
@ -93,12 +96,14 @@ static const char *const patch_opt[] = {
enum hudhook {
hudhook_game = 0,
hudhook_scores,
hudhook_intermission,
hudhook_title,
hudhook_titlecard
};
static const char *const hudhook_opt[] = {
"game",
"scores",
"intermission",
"title",
"titlecard",
NULL};
@ -1051,13 +1056,16 @@ int LUA_HudLib(lua_State *L)
lua_rawseti(L, -2, 2); // HUD[2] = game rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 3); // HUD[2] = scores rendering functions array
lua_rawseti(L, -2, 3); // HUD[3] = scores rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 4); // HUD[3] = title rendering functions array
lua_rawseti(L, -2, 4); // HUD[4] = intermission rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 5); // HUD[4] = title card rendering functions array
lua_rawseti(L, -2, 5); // HUD[5] = title rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 6); // HUD[6] = title card rendering functions array
lua_setfield(L, LUA_REGISTRYINDEX, "HUD");
luaL_newmetatable(L, META_HUDINFO);
@ -1229,4 +1237,29 @@ void LUAh_TitleCardHUD(player_t *stplayr)
hud_running = false;
}
void LUAh_IntermissionHUD(void)
{
if (!gL || !(hudAvailable & (1<<hudhook_intermission)))
return;
hud_running = true;
lua_pop(gL, -1);
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -1, 4); // HUD[4] = rendering funcs
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
I_Assert(lua_istable(gL, -1));
lua_remove(gL, -3); // pop HUD
lua_pushnil(gL);
while (lua_next(gL, -3) != 0) {
lua_pushvalue(gL, -3); // graphics library (HUD[1])
LUA_Call(gL, 1);
}
lua_pop(gL, -1);
hud_running = false;
}
#endif

View File

@ -18,7 +18,9 @@
#include "w_wad.h"
#include "p_setup.h"
#include "r_state.h"
#include "r_sky.h"
#include "g_game.h"
#include "f_finale.h"
#include "byteptr.h"
#include "p_saveg.h"
#include "p_local.h"
@ -79,8 +81,239 @@ FUNCNORETURN static int LUA_Panic(lua_State *L)
#endif
}
// Moved here from lib_getenum.
int LUA_PushGlobals(lua_State *L, const char *word)
{
if (fastcmp(word,"gamemap")) {
lua_pushinteger(L, gamemap);
return 1;
} else if (fastcmp(word,"maptol")) {
lua_pushinteger(L, maptol);
return 1;
} else if (fastcmp(word,"ultimatemode")) {
lua_pushboolean(L, ultimatemode != 0);
return 1;
} else if (fastcmp(word,"mariomode")) {
lua_pushboolean(L, mariomode != 0);
return 1;
} else if (fastcmp(word,"twodlevel")) {
lua_pushboolean(L, twodlevel != 0);
return 1;
} else if (fastcmp(word,"circuitmap")) {
lua_pushboolean(L, circuitmap);
return 1;
} else if (fastcmp(word,"netgame")) {
lua_pushboolean(L, netgame);
return 1;
} else if (fastcmp(word,"multiplayer")) {
lua_pushboolean(L, multiplayer);
return 1;
} else if (fastcmp(word,"modeattacking")) {
lua_pushboolean(L, modeattacking);
return 1;
} else if (fastcmp(word,"splitscreen")) {
lua_pushboolean(L, splitscreen);
return 1;
} else if (fastcmp(word,"gamecomplete")) {
lua_pushboolean(L, gamecomplete);
return 1;
} else if (fastcmp(word,"devparm")) {
lua_pushboolean(L, devparm);
return 1;
} else if (fastcmp(word,"modifiedgame")) {
lua_pushboolean(L, modifiedgame && !savemoddata);
return 1;
} else if (fastcmp(word,"menuactive")) {
lua_pushboolean(L, menuactive);
return 1;
} else if (fastcmp(word,"paused")) {
lua_pushboolean(L, paused);
return 1;
} else if (fastcmp(word,"bluescore")) {
lua_pushinteger(L, bluescore);
return 1;
} else if (fastcmp(word,"redscore")) {
lua_pushinteger(L, redscore);
return 1;
} else if (fastcmp(word,"timelimit")) {
lua_pushinteger(L, cv_timelimit.value);
return 1;
} else if (fastcmp(word,"pointlimit")) {
lua_pushinteger(L, cv_pointlimit.value);
return 1;
// begin map vars
} else if (fastcmp(word,"spstage_start")) {
lua_pushinteger(L, spstage_start);
return 1;
} else if (fastcmp(word,"sstage_start")) {
lua_pushinteger(L, sstage_start);
return 1;
} else if (fastcmp(word,"sstage_end")) {
lua_pushinteger(L, sstage_end);
return 1;
} else if (fastcmp(word,"smpstage_start")) {
lua_pushinteger(L, smpstage_start);
return 1;
} else if (fastcmp(word,"smpstage_end")) {
lua_pushinteger(L, smpstage_end);
return 1;
} else if (fastcmp(word,"titlemap")) {
lua_pushinteger(L, titlemap);
return 1;
} else if (fastcmp(word,"titlemapinaction")) {
lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
return 1;
} else if (fastcmp(word,"bootmap")) {
lua_pushinteger(L, bootmap);
return 1;
} else if (fastcmp(word,"tutorialmap")) {
lua_pushinteger(L, tutorialmap);
return 1;
} else if (fastcmp(word,"tutorialmode")) {
lua_pushboolean(L, tutorialmode);
return 1;
// end map vars
// begin CTF colors
} else if (fastcmp(word,"skincolor_redteam")) {
lua_pushinteger(L, skincolor_redteam);
return 1;
} else if (fastcmp(word,"skincolor_blueteam")) {
lua_pushinteger(L, skincolor_blueteam);
return 1;
} else if (fastcmp(word,"skincolor_redring")) {
lua_pushinteger(L, skincolor_redring);
return 1;
} else if (fastcmp(word,"skincolor_bluering")) {
lua_pushinteger(L, skincolor_bluering);
return 1;
// end CTF colors
// begin timers
} else if (fastcmp(word,"invulntics")) {
lua_pushinteger(L, invulntics);
return 1;
} else if (fastcmp(word,"sneakertics")) {
lua_pushinteger(L, sneakertics);
return 1;
} else if (fastcmp(word,"flashingtics")) {
lua_pushinteger(L, flashingtics);
return 1;
} else if (fastcmp(word,"tailsflytics")) {
lua_pushinteger(L, tailsflytics);
return 1;
} else if (fastcmp(word,"underwatertics")) {
lua_pushinteger(L, underwatertics);
return 1;
} else if (fastcmp(word,"spacetimetics")) {
lua_pushinteger(L, spacetimetics);
return 1;
} else if (fastcmp(word,"extralifetics")) {
lua_pushinteger(L, extralifetics);
return 1;
} else if (fastcmp(word,"nightslinktics")) {
lua_pushinteger(L, nightslinktics);
return 1;
} else if (fastcmp(word,"gameovertics")) {
lua_pushinteger(L, gameovertics);
return 1;
} else if (fastcmp(word,"ammoremovaltics")) {
lua_pushinteger(L, ammoremovaltics);
return 1;
// end timers
} else if (fastcmp(word,"gametype")) {
lua_pushinteger(L, gametype);
return 1;
} else if (fastcmp(word,"gametyperules")) {
lua_pushinteger(L, gametyperules);
return 1;
} else if (fastcmp(word,"leveltime")) {
lua_pushinteger(L, leveltime);
return 1;
} else if (fastcmp(word,"sstimer")) {
lua_pushinteger(L, sstimer);
return 1;
} else if (fastcmp(word,"curWeather")) {
lua_pushinteger(L, curWeather);
return 1;
} else if (fastcmp(word,"globalweather")) {
lua_pushinteger(L, globalweather);
return 1;
} else if (fastcmp(word,"levelskynum")) {
lua_pushinteger(L, levelskynum);
return 1;
} else if (fastcmp(word,"globallevelskynum")) {
lua_pushinteger(L, globallevelskynum);
return 1;
} else if (fastcmp(word,"mapmusname")) {
lua_pushstring(L, mapmusname);
return 1;
} else if (fastcmp(word,"mapmusflags")) {
lua_pushinteger(L, mapmusflags);
return 1;
} else if (fastcmp(word,"mapmusposition")) {
lua_pushinteger(L, mapmusposition);
return 1;
// local player variables, by popular request
} else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1)
if (consoleplayer < 0 || !playeringame[consoleplayer])
return 0;
LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"displayplayer")) { // player visible on screen (aka display player 1)
if (displayplayer < 0 || !playeringame[displayplayer])
return 0;
LUA_PushUserdata(L, &players[displayplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"secondarydisplayplayer")) { // local/display player 2, for splitscreen
if (!splitscreen || secondarydisplayplayer < 0 || !playeringame[secondarydisplayplayer])
return 0;
LUA_PushUserdata(L, &players[secondarydisplayplayer], META_PLAYER);
return 1;
// end local player variables
} else if (fastcmp(word,"server")) {
if ((!multiplayer || !netgame) && !playeringame[serverplayer])
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array.
LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)");
if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer))
return 0;
LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER);
return 1;
} else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds);
return 1;
} else if (fastcmp(word,"gravity")) {
lua_pushinteger(L, gravity);
return 1;
} else if (fastcmp(word,"VERSIONSTRING")) {
lua_pushstring(L, VERSIONSTRING);
return 1;
} else if (fastcmp(word, "token")) {
lua_pushinteger(L, token);
return 1;
}
return 0;
}
// See the above.
int LUA_CheckGlobals(lua_State *L, const char *word)
{
if (fastcmp(word, "gametyperules"))
gametyperules = (UINT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "redscore"))
redscore = (UINT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "bluescore"))
bluescore = (UINT32)luaL_checkinteger(L, 2);
else
return 0;
// Global variable set, so return and don't error.
return 1;
}
// This function decides which global variables you are allowed to set.
static int noglobals(lua_State *L)
static int setglobals(lua_State *L)
{
const char *csname;
char *name;
@ -106,6 +339,9 @@ static int noglobals(lua_State *L)
return 0;
}
if (LUA_CheckGlobals(L, csname))
return 0;
Z_Free(name);
return luaL_error(L, "Implicit global " LUA_QS " prevented. Create a local variable instead.", csname);
}
@ -144,7 +380,7 @@ static void LUA_ClearState(void)
// lock the global namespace
lua_getmetatable(L, LUA_GLOBALSINDEX);
lua_pushcfunction(L, noglobals);
lua_pushcfunction(L, setglobals);
lua_setfield(L, -2, "__newindex");
lua_newtable(L);
lua_setfield(L, -2, "__metatable");

View File

@ -54,6 +54,8 @@ void LUA_InvalidatePlayer(player_t *player);
void LUA_Step(void);
void LUA_Archive(void);
void LUA_UnArchive(void);
int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_CheckGlobals(lua_State *L, const char *word);
void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
void LUA_CVarChanged(const char *name); // lua_consolelib.c
int Lua_optoption(lua_State *L, int narg,

View File

@ -778,7 +778,7 @@ void Command_CauseCfail_f(void)
P_SetThingPosition(players[consoleplayer].mo);
// CTF consistency test
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
{
if (blueflag) {
P_RemoveMobj(blueflag);

View File

@ -605,7 +605,7 @@ static menuitem_t MISC_ChangeTeamMenu[] =
{IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmTeamChange, 90},
};
static const gtdesc_t gametypedesc[] =
gtdesc_t gametypedesc[NUMGAMETYPES] =
{
{{ 54, 54}, "Play through the single-player campaign with your friends, teaming up to beat Dr Eggman's nefarious challenges!"},
{{103, 103}, "Speed your way through the main acts, competing in several different categories to see who's the best."},
@ -4688,6 +4688,9 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt)
if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE))
return true;
if (gt > 0 && gt < gametypecount && (mapheaderinfo[mapnum]->typeoflevel & gametypetol[gt]))
return true;
return false;
case LLM_LEVELSELECT:
@ -9936,7 +9939,7 @@ static void M_DrawConnectMenu(void)
va("Ping: %u", (UINT32)LONG(serverlist[slindex].info.time)));
gt = "Unknown";
if (serverlist[slindex].info.gametype < NUMGAMETYPES)
if (serverlist[slindex].info.gametype < gametypecount)
gt = Gametype_Names[serverlist[slindex].info.gametype];
V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags,

View File

@ -371,6 +371,7 @@ typedef struct
UINT8 col[2];
char notes[441];
} gtdesc_t;
extern gtdesc_t gametypedesc[NUMGAMETYPES];
// mode descriptions for video mode menu
typedef struct

View File

@ -4985,7 +4985,7 @@ void A_ThrownRing(mobj_t *actor)
continue;
// Don't home in on teammates.
if (gametype == GT_CTF
if ((gametyperules & GTR_TEAMFLAGS)
&& actor->target->player->ctfteam == player->ctfteam)
continue;
}
@ -6591,7 +6591,7 @@ void A_OldRingExplode(mobj_t *actor) {
if (changecolor)
{
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
mo->color = actor->target->color; //copy color
else if (actor->target->player->ctfteam == 2)
mo->color = skincolor_bluering;
@ -6607,7 +6607,7 @@ void A_OldRingExplode(mobj_t *actor) {
if (changecolor)
{
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
mo->color = actor->target->color; //copy color
else if (actor->target->player->ctfteam == 2)
mo->color = skincolor_bluering;
@ -6622,7 +6622,7 @@ void A_OldRingExplode(mobj_t *actor) {
if (changecolor)
{
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
mo->color = actor->target->color; //copy color
else if (actor->target->player->ctfteam == 2)
mo->color = skincolor_bluering;

View File

@ -625,7 +625,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_AddPlayerScore(player, 1000);
if (gametype != GT_COOP || modeattacking) // score only?
if (!(gametyperules & GTR_SPECIALSTAGES) || modeattacking) // score only?
{
S_StartSound(toucher, sfx_chchng);
break;
@ -1888,7 +1888,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
char targetname[MAXPLAYERNAME+4];
char sourcename[MAXPLAYERNAME+4];
if (G_PlatformGametype())
if (!(gametyperules & (GTR_RINGSLINGER|GTR_HURTMESSAGES)))
return; // Not in coop, etc.
if (!player)
@ -2093,7 +2093,7 @@ void P_CheckTimeLimit(void)
if (!(multiplayer || netgame))
return;
if (G_PlatformGametype())
if (!(gametyperules & GTR_TIMELIMIT))
return;
if (leveltime < timelimitintics)
@ -2124,7 +2124,7 @@ void P_CheckTimeLimit(void)
}
//Optional tie-breaker for Match/CTF
else if (cv_overtime.value)
else if ((cv_overtime.value) && (gametyperules & GTR_OVERTIME))
{
INT32 playerarray[MAXPLAYERS];
INT32 tempplayer = 0;
@ -2206,7 +2206,7 @@ void P_CheckPointLimit(void)
if (!(multiplayer || netgame))
return;
if (G_PlatformGametype())
if (!(gametyperules & GTR_POINTLIMIT))
return;
// pointlimit is nonzero, check if it's been reached by this player
@ -2389,7 +2389,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
{
if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording!
G_StopMetalRecording(true);
if (gametype == GT_MATCH // note, no team match suicide penalty
if ((gametyperules & GTR_DEATHPENALTY) // note, no team match suicide penalty
&& ((target == source) || (source == NULL && inflictor == NULL) || (source && !source->player)))
{ // Suicide penalty
if (target->player->score >= 50)
@ -2978,7 +2978,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
player->flyangle += 180; // Shuffle's BETTERNIGHTSMOVEMENT?
player->flyangle %= 360;
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
player->drillmeter -= 5*20;
else
{
@ -3042,7 +3042,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
return false;
// Ignore IT players shooting each other, unless friendlyfire is on.
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE) || (damagetype & DMG_CANHURTSELF)) &&
source && source->player && source->player->pflags & PF_TAGIT)))
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
@ -3058,7 +3058,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
// Don't allow players on the same team to hurt one another,
// unless cv_friendlyfire is on.
if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE) || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
@ -3143,7 +3143,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
return false;
// In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on
if (!cv_friendlyfire.value && (G_PlatformGametype()))
if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && (G_PlatformGametype()))
{
if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only
{
@ -3166,7 +3166,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
{
// Don't allow players on the same team to hurt one another,
// unless cv_friendlyfire is on.
if (!cv_friendlyfire.value && target->player->ctfteam == source->player->ctfteam)
if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && target->player->ctfteam == source->player->ctfteam)
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
@ -3224,7 +3224,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
player->mo->flags2 &= ~MF2_DONTDRAW;
P_SetPlayerMobjState(player->mo, player->mo->info->deathstate);
if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
{
P_PlayerFlagBurst(player, false);
if (source && source->player)
@ -3349,7 +3349,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source,
else
S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss.
if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
{
P_PlayerFlagBurst(player, false);
if (source && source->player)
@ -3383,7 +3383,7 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN
P_AddPlayerScore(source->player, 50);
}
if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)))
{
P_PlayerFlagBurst(player, false);
if (source && source->player)
@ -3426,6 +3426,24 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super])
return;
if (!cv_friendlyfire.value)
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound);
}
}
if (source->player->ctfteam == player->ctfteam)
return;
}
if (inflictor->type == MT_LHRT)
return;
if (player->powers[pw_shield] || player->bot) //If One-Hit Shield
{
P_RemoveShield(player);
@ -3442,7 +3460,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
P_DoPlayerPain(player, inflictor, source);
if (gametype == GT_CTF && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))
if ((gametyperules & GTR_TEAMFLAGS) && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))
P_PlayerFlagBurst(player, false);
if (oldnightstime > 10*TICRATE
@ -3593,7 +3611,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
{
if (source == target)
return false; // Don't hit yourself with your own paraloop, baka
if (source && source->player && !cv_friendlyfire.value
if (source && source->player && !(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE))
&& (gametype == GT_COOP
|| (G_GametypeHasTeams() && player->ctfteam == source->player->ctfteam)))
return false; // Don't run eachother over in special stages and team games and such
@ -3688,7 +3706,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
// by friendly fire. Spilling their rings and other items is enough.
else if (!force && G_GametypeHasTeams()
&& source && source->player && (source->player->ctfteam == player->ctfteam)
&& cv_friendlyfire.value)
&& (cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)))
{
damage = 0;
P_ShieldDamage(player, inflictor, source, damage, damagetype);

View File

@ -615,7 +615,7 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
// Why block opposing teams from tailsflying each other?
// Sneaking into the hands of a flying tails player in Race might be a viable strategy, who knows.
/*
if (gametype == GT_RACE || gametype == GT_COMPETITION
if ((gametyperules & GTR_RACE)
|| (netgame && (tails->spectator || sonic->spectator))
|| (G_TagGametype() && (!(tails->pflags & PF_TAGIT) != !(sonic->pflags & PF_TAGIT)))
|| (gametype == GT_MATCH)

View File

@ -11342,7 +11342,7 @@ void P_RespawnSpecials(void)
}
//CTF rings should continue to respawn as normal rings outside of CTF.
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
{
if (i == MT_REDTEAMRING || i == MT_BLUETEAMRING)
i = MT_RING;
@ -11413,7 +11413,10 @@ void P_SpawnPlayer(INT32 playernum)
{
p->outofcoop = false;
if (netgame && p->jointime < 1)
p->spectator = true;
{
// Averted by GTR_NOSPECTATORSPAWN.
p->spectator = (gametyperules & GTR_NOSPECTATORSPAWN) ? false : true;
}
else if (multiplayer && !netgame)
{
// If you're in a team game and you don't have a team assigned yet...
@ -11456,7 +11459,7 @@ void P_SpawnPlayer(INT32 playernum)
p->skincolor = skincolor_blueteam;
}
if ((netgame || multiplayer) && (gametype != GT_COOP || leveltime) && !p->spectator && !(maptol & TOL_NIGHTS))
if ((netgame || multiplayer) && ((gametyperules & GTR_SPAWNINVUL) || leveltime) && !p->spectator && !(maptol & TOL_NIGHTS))
p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent
mobj = P_SpawnMobj(0, 0, 0, MT_PLAYER);
@ -11861,7 +11864,7 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
else if (mthing->type == mobjinfo[MT_EMERHUNT].doomednum)
{
// Emerald Hunt is Coop only. Don't spawn the emerald yet, but save the spawnpoint for later.
if (gametype == GT_COOP && numhuntemeralds < MAXHUNTEMERALDS)
if ((gametyperules & GTR_EMERALDHUNT) && numhuntemeralds < MAXHUNTEMERALDS)
huntemeralds[numhuntemeralds++] = mthing;
return true;
}
@ -11894,7 +11897,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
if (!cv_powerstones.value)
return false;
if (!(gametype == GT_MATCH || gametype == GT_CTF))
if (!(gametyperules & GTR_MATCHEMERALDS))
return false;
runemeraldmanager = true;
@ -11908,7 +11911,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
break;
case MT_TOKEN:
if (gametype != GT_COOP && gametype != GT_COMPETITION)
if (!(gametyperules & GTR_EMERALDTOKENS))
return false; // Gametype's not right
if (tokenbits == 30)
@ -11938,20 +11941,20 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
return false;
}
if (!G_PlatformGametype())
{
if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS))
return false; // No enemies in ringslinger modes
if (((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS)) && !(gametyperules & GTR_SPAWNENEMIES))
return false; // No enemies in ringslinger modes
if (i == MT_SIGN || i == MT_STARPOST)
return false; // Don't spawn exit signs or starposts in wrong game modes
}
if (!(gametyperules & GTR_ALLOWEXIT) && (i == MT_SIGN))
return false; // Don't spawn exit signs in wrong game modes
if (!G_PlatformGametype() && (i == MT_STARPOST))
return false; // Don't spawn starposts in wrong game modes
if (!G_RingSlingerGametype() || !cv_specialrings.value)
if (P_WeaponOrPanel(i))
return false; // Don't place weapons/panels in non-ringslinger modes
if (gametype != GT_CTF) // CTF specific things
if (!(gametyperules & GTR_TEAMFLAGS)) // CTF specific things
{
if (i == MT_BLUEFLAG || i == MT_REDFLAG)
return false; // No flags in non-CTF modes!
@ -11999,7 +12002,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
// Yeah, this is a dirty hack.
if ((mobjinfo[i].flags & (MF_MONITOR|MF_GRENADEBOUNCE)) == MF_MONITOR)
{
if (gametype == GT_COMPETITION || gametype == GT_RACE)
if (gametyperules & GTR_RACE)
{
// Set powerup boxes to user settings for competition.
switch (cv_competitionboxes.value)
@ -12043,7 +12046,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
return MT_NIGHTSCHIP;
}
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMS))
{
if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING)
return MT_RING;

View File

@ -2539,8 +2539,7 @@ boolean P_SetupLevel(boolean skipprecip)
// chasecam on in chaos, race, coop
// chasecam off in match, tag, capture the flag
chase = (gametype == GT_RACE || gametype == GT_COMPETITION || gametype == GT_COOP)
|| (maptol & TOL_2D);
chase = (!(gametyperules & GTR_FIRSTPERSON)) || (maptol & TOL_2D);
if (!dedicated)
{

View File

@ -4692,7 +4692,7 @@ DoneSection2:
}
case 2: // Special stage GOAL sector / Exit Sector / CTF Flag Return
if (player->bot || !G_PlatformGametype())
if (player->bot || !(gametyperules & GTR_ALLOWEXIT))
break;
if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6)
{
@ -4727,7 +4727,7 @@ DoneSection2:
break;
case 3: // Red Team's Base
if (gametype == GT_CTF && P_IsObjectOnGround(player->mo))
if ((gametyperules & GTR_TEAMFLAGS) && P_IsObjectOnGround(player->mo))
{
if (player->ctfteam == 1 && (player->gotflag & GF_BLUEFLAG))
{
@ -4760,7 +4760,7 @@ DoneSection2:
break;
case 4: // Blue Team's Base
if (gametype == GT_CTF && P_IsObjectOnGround(player->mo))
if ((gametyperules & GTR_TEAMFLAGS) && P_IsObjectOnGround(player->mo))
{
if (player->ctfteam == 2 && (player->gotflag & GF_REDFLAG))
{
@ -7224,14 +7224,14 @@ void P_SpawnSpecials(INT32 fromnetsave)
break;
case 308: // Race-only linedef executor. Triggers once.
if (gametype != GT_RACE && gametype != GT_COMPETITION)
if (!(gametyperules & GTR_RACE))
lines[i].special = 0;
break;
// Linedef executor triggers for CTF teams.
case 309:
case 311:
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
lines[i].special = 0;
break;

View File

@ -387,7 +387,7 @@ UINT8 P_FindLowestMare(void)
mobj_t *mo2;
UINT8 mare = UINT8_MAX;
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
return 0;
// scan the thinkers
@ -793,7 +793,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
P_RestoreMusic(player);
}
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
{
if (player->drillmeter < 48*20)
player->drillmeter = 48*20;
@ -2181,7 +2181,7 @@ void P_DoPlayerExit(player_t *player)
if (cv_allowexitlevel.value == 0 && !G_PlatformGametype())
return;
else if (gametype == GT_RACE || gametype == GT_COMPETITION) // If in Race Mode, allow
else if (gametyperules & GTR_RACE) // If in Race Mode, allow
{
if (!countdown) // a 60-second wait ala Sonic 2.
countdown = (cv_countdowntime.value - 1)*TICRATE + 1; // Use cv_countdowntime
@ -3110,7 +3110,7 @@ static void P_DoPlayerHeadSigns(player_t *player)
}
}
}
else if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) // If you have the flag (duh).
else if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) // If you have the flag (duh).
{
// Spawn a got-flag message over the head of the player that
// has it (but not on your own screen if you have the flag).
@ -4670,7 +4670,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
if (player->powers[pw_carry] == CR_BRAKGOOP)
player->dashspeed = 0;
if (!((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE))
if (!((gametyperules & GTR_RACE) && leveltime < 4*TICRATE))
{
if (player->dashspeed)
{
@ -5048,7 +5048,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
{
if (onground || player->climbing || player->powers[pw_carry])
;
else if (gametype == GT_CTF && player->gotflag)
else if ((gametyperules & GTR_TEAMFLAGS) && player->gotflag)
;
else if (player->pflags & (PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player has used an ability previously
;
@ -5269,7 +5269,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
player->secondjump = 0;
player->pflags &= ~PF_THOKKED;
}
else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag) || player->pflags & PF_SHIELDABILITY)
else if (player->pflags & PF_SLIDING || ((gametyperules & GTR_TEAMFLAGS) && player->gotflag) || player->pflags & PF_SHIELDABILITY)
;
/*else if (P_SuperReady(player))
{
@ -5556,7 +5556,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
{
player->pflags |= PF_JUMPDOWN;
if ((gametype != GT_CTF || !player->gotflag) && !player->exiting)
if ((!(gametyperules & GTR_TEAMFLAGS) || !player->gotflag) && !player->exiting)
{
if (player->secondjump == 1 && player->charability != CA_DOUBLEJUMP)
{
@ -7133,7 +7133,7 @@ static void P_NiGHTSMovement(player_t *player)
&& !player->exiting)
player->nightstime--;
}
else if (gametype != GT_RACE && gametype != GT_COMPETITION
else if (!(gametyperules & GTR_RACE)
&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
&& !(player->capsule && player->capsule->reactiontime)
@ -7289,7 +7289,7 @@ static void P_NiGHTSMovement(player_t *player)
{
player->mo->momx = player->mo->momy = 0;
if (gametype != GT_RACE && gametype != GT_COMPETITION)
if (!(gametyperules & GTR_RACE))
P_SetObjectMomZ(player->mo, FRACUNIT/2, (P_MobjFlip(player->mo)*player->mo->momz >= 0));
else
player->mo->momz = 0;
@ -9531,12 +9531,12 @@ static void P_DeathThink(player_t *player)
player->playerstate = PST_REBORN;
}
if (gametype == GT_RACE || gametype == GT_COMPETITION || (gametype == GT_COOP && (multiplayer || netgame)))
if ((gametyperules & GTR_RACE) || (gametype == GT_COOP && (multiplayer || netgame)))
{
// Keep time rolling in race mode
if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_GAMETYPEOVER) && !stoppedclock)
{
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
{
if (leveltime >= 4*TICRATE)
player->realtime = leveltime - 4*TICRATE;
@ -10360,6 +10360,11 @@ boolean P_SpectatorJoinGame(player_t *player)
else
changeto = (P_RandomFixed() & 1) + 1;
#ifdef HAVE_BLUA
if (!LUAh_TeamSwitch(player, changeto, true, false, false))
return false;
#endif
if (player->mo)
{
P_RemoveMobj(player->mo);
@ -10371,7 +10376,14 @@ boolean P_SpectatorJoinGame(player_t *player)
//Reset away view
if (P_IsLocalPlayer(player) && displayplayer != consoleplayer)
{
#ifdef HAVE_BLUA
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
LUAh_ViewpointSwitch(player, &players[displayplayer], true);
#endif
displayplayer = consoleplayer;
}
if (changeto == 1)
CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x85', M_GetText("Red team"), '\x80');
@ -10385,8 +10397,12 @@ boolean P_SpectatorJoinGame(player_t *player)
{
// Exception for hide and seek. Don't join a game when you simply
// respawn in place and sit there for the rest of the round.
if (!(gametype == GT_HIDEANDSEEK && leveltime > (hidetime * TICRATE)))
if (!((gametyperules & GTR_HIDEFROZEN) && leveltime > (hidetime * TICRATE)))
{
#ifdef HAVE_BLUA
if (!LUAh_TeamSwitch(player, 3, true, false, false))
return false;
#endif
if (player->mo)
{
P_RemoveMobj(player->mo);
@ -10409,7 +10425,14 @@ boolean P_SpectatorJoinGame(player_t *player)
//Reset away view
if (P_IsLocalPlayer(player) && displayplayer != consoleplayer)
{
#ifdef HAVE_BLUA
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
LUAh_ViewpointSwitch(player, &players[displayplayer], true);
#endif
displayplayer = consoleplayer;
}
if (gametype != GT_COOP)
CONS_Printf(M_GetText("%s entered the game.\n"), player_names[player-players]);
@ -10535,7 +10558,7 @@ void P_DoPityCheck(player_t *player)
{
// No pity outside of match or CTF.
if (player->spectator
|| !(gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF))
|| !(gametyperules & GTR_PITYSHIELD))
return;
// Apply pity shield if available.
@ -11373,7 +11396,7 @@ void P_PlayerThink(player_t *player)
I_Error("player %s is in PST_REBORN\n", sizeu1(playeri));
#endif
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
{
INT32 i;
@ -11441,7 +11464,7 @@ void P_PlayerThink(player_t *player)
player->exiting > 0 && player->exiting <= 1*TICRATE &&
(!multiplayer || gametype == GT_COOP ? !mapheaderinfo[gamemap-1]->musinterfadeout : true) &&
// don't fade if we're fading during intermission. follows Y_StartIntermission intertype = int_coop
(gametype == GT_RACE || gametype == GT_COMPETITION ? countdown2 == 0 : true) && // don't fade on timeout
((gametyperules & GTR_RACE) ? countdown2 == 0 : true) && // don't fade on timeout
player->lives > 0 && // don't fade on game over (competition)
P_IsLocalPlayer(player))
{
@ -11558,7 +11581,7 @@ void P_PlayerThink(player_t *player)
player->lives = cv_startinglives.value;
}
if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE)
if ((gametyperules & GTR_RACE) && leveltime < 4*TICRATE)
{
cmd->buttons &= BT_USE; // Remove all buttons except BT_USE
cmd->forwardmove = 0;
@ -11568,7 +11591,7 @@ void P_PlayerThink(player_t *player)
// Synchronizes the "real" amount of time spent in the level.
if (!player->exiting && !stoppedclock)
{
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
{
if (leveltime >= 4*TICRATE)
player->realtime = leveltime - 4*TICRATE;

View File

@ -694,7 +694,7 @@ static void ST_drawTime(void)
else
{
// Counting down the hidetime?
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime <= (hidetime*TICRATE)))
if ((gametyperules & GTR_HIDETIME) && (stplyr->realtime <= (hidetime*TICRATE)))
{
tics = (hidetime*TICRATE - stplyr->realtime);
if (tics < 3*TICRATE)
@ -705,11 +705,11 @@ static void ST_drawTime(void)
else
{
// Hidetime finish!
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime < ((hidetime+1)*TICRATE)))
if ((gametyperules & GTR_HIDETIME) && (stplyr->realtime < ((hidetime+1)*TICRATE)))
ST_drawRaceNum(hidetime*TICRATE - stplyr->realtime);
// Time limit?
if (gametype != GT_COOP && gametype != GT_RACE && gametype != GT_COMPETITION && cv_timelimit.value && timelimitintics > 0)
if ((gametyperules & GTR_TIMELIMIT) && cv_timelimit.value && timelimitintics > 0)
{
if (timelimitintics > stplyr->realtime)
{
@ -723,7 +723,7 @@ static void ST_drawTime(void)
downwards = true;
}
// Post-hidetime normal.
else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK)
else if (gametyperules & GTR_TAG)
tics = stplyr->realtime - hidetime*TICRATE;
// "Shadow! What are you doing? Hurry and get back here
// right now before the island blows up with you on it!"
@ -912,7 +912,7 @@ static void ST_drawLivesArea(void)
else if (stplyr->spectator)
v_colmap = V_GRAYMAP;
// Tag
else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK)
else if (gametyperules & GTR_TAG)
{
if (stplyr->pflags & PF_TAGIT)
{
@ -1228,6 +1228,9 @@ void ST_startTitleCard(void)
//
void ST_preDrawTitleCard(void)
{
if (!G_IsTitleCardAvailable())
return;
if (lt_ticker >= (lt_endtime + TICRATE))
return;
@ -1243,6 +1246,9 @@ void ST_preDrawTitleCard(void)
//
void ST_runTitleCard(void)
{
if (!G_IsTitleCardAvailable())
return;
if (lt_ticker >= (lt_endtime + TICRATE))
return;
@ -1296,6 +1302,9 @@ void ST_drawTitleCard(void)
INT32 zzticker;
patch_t *actpat, *zigzag, *zztext;
if (!G_IsTitleCardAvailable())
return;
#ifdef HAVE_BLUA
if (!LUA_HudEnabled(hud_stagetitle))
goto luahook;
@ -1774,7 +1783,7 @@ static void ST_drawNiGHTSHUD(void)
ST_drawNiGHTSLink();
}
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
{
ST_drawScore();
ST_drawTime();
@ -2215,34 +2224,37 @@ static void ST_drawTextHUD(void)
if (G_IsSpecialStage(gamemap))
textHUDdraw(M_GetText("\x82""Wait for the stage to end..."))
else if (gametype == GT_COOP)
else if (G_PlatformGametype())
{
if (stplyr->lives <= 0
&& cv_cooplives.value == 2
&& (netgame || multiplayer))
if (gametype == GT_COOP)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
if (stplyr->lives <= 0
&& cv_cooplives.value == 2
&& (netgame || multiplayer))
{
if (!playeringame[i])
continue;
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (&players[i] == stplyr)
continue;
if (&players[i] == stplyr)
continue;
if (players[i].lives > 1)
break;
}
if (players[i].lives > 1)
break;
}
if (i != MAXPLAYERS)
textHUDdraw(M_GetText("You'll steal a life on respawn..."))
if (i != MAXPLAYERS)
textHUDdraw(M_GetText("You'll steal a life on respawn..."))
else
textHUDdraw(M_GetText("Wait to respawn..."))
}
else
textHUDdraw(M_GetText("Wait to respawn..."))
}
else
textHUDdraw(M_GetText("Wait to respawn..."))
}
else
else if (G_GametypeHasSpectators())
textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game"))
}
@ -2285,13 +2297,14 @@ static void ST_drawTextHUD(void)
}
}
}
else if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator))
else if ((gametyperules & GTR_TAG) && (!stplyr->spectator))
{
if (leveltime < hidetime * TICRATE)
{
if (stplyr->pflags & PF_TAGIT)
{
textHUDdraw(M_GetText("\x82""You are blindfolded!"))
if (gametyperules & GTR_BLINDFOLDED)
textHUDdraw(M_GetText("\x82""You are blindfolded!"))
textHUDdraw(M_GetText("Waiting for players to hide..."))
}
else if (gametype == GT_HIDEANDSEEK)
@ -2306,7 +2319,8 @@ static void ST_drawTextHUD(void)
textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view"))
donef12 = true;
}
textHUDdraw(M_GetText("You cannot move while hiding."))
if (gametyperules & GTR_HIDEFROZEN)
textHUDdraw(M_GetText("You cannot move while hiding."))
}
}
@ -2328,27 +2342,27 @@ static void ST_drawTeamHUD(void)
if (F_GetPromptHideHud(0)) // y base is 0
return;
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
p = bflagico;
else
p = bmatcico;
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
if (gametype == GT_CTF)
if (gametyperules & GTR_TEAMFLAGS)
p = rflagico;
else
p = rmatcico;
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
if (gametype != GT_CTF)
if (!(gametyperules & GTR_TEAMFLAGS))
goto num;
{
INT32 i;
@ -2676,7 +2690,7 @@ static void ST_overlayDrawer(void)
}
// If you are in overtime, put a big honkin' flashin' message on the screen.
if (G_RingSlingerGametype() && cv_overtime.value
if (((gametyperules & GTR_TIMELIMIT) && (gametyperules & GTR_OVERTIME)) && cv_overtime.value
&& (leveltime > (timelimitintics + TICRATE/2)) && cv_timelimit.value && (leveltime/TICRATE % 2 == 0))
V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_PERPLAYER, M_GetText("OVERTIME!"));
@ -2691,7 +2705,7 @@ static void ST_overlayDrawer(void)
ST_drawMatchHUD();
// Race HUD Stuff
if (gametype == GT_RACE || gametype == GT_COMPETITION)
if (gametyperules & GTR_RACE)
ST_drawRaceHUD();
// Emerald Hunt Indicators
@ -2796,7 +2810,7 @@ void ST_Drawer(void)
if (rendermode != render_none) ST_doPaletteStuff();
// Blindfold!
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK)
if ((gametyperules & GTR_BLINDFOLDED)
&& (leveltime < hidetime * TICRATE))
{
if (players[displayplayer].pflags & PF_TAGIT)

View File

@ -37,6 +37,10 @@
#include "m_cond.h" // condition sets
#include "lua_hook.h" // IntermissionThinker hook
#ifdef HAVE_BLUA
#include "lua_hud.h"
#endif
#ifdef HWRENDER
#include "hardware/hw_main.h"
#endif
@ -164,6 +168,7 @@ static INT32 tallydonetic = -1;
static INT32 endtic = -1;
intertype_t intertype = int_none;
intertype_t intermissiontypes[NUMGAMETYPES];
static void Y_RescaleScreenBuffer(void);
static void Y_AwardCoopBonuses(void);
@ -318,9 +323,17 @@ void Y_IntermissionDrawer(void)
// Bonus loops
INT32 i;
if (intertype == int_none || rendermode == render_none)
if (rendermode == render_none)
return;
if (intertype == int_none)
{
#ifdef HAVE_BLUA
LUAh_IntermissionHUD();
#endif
return;
}
if (!usebuffer)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
@ -358,6 +371,12 @@ void Y_IntermissionDrawer(void)
else
V_DrawPatchFill(bgtile);
#ifdef HAVE_BLUA
LUAh_IntermissionHUD();
if (!LUA_HudEnabled(hud_intermissiontally))
goto skiptallydrawer;
#endif
if (intertype == int_coop)
{
INT32 bonusy;
@ -907,6 +926,12 @@ void Y_IntermissionDrawer(void)
}
}
#ifdef HAVE_BLUA
skiptallydrawer:
if (!LUA_HudEnabled(hud_intermissionmessages))
return;
#endif
if (timer)
V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP,
va("start in %d seconds", timer/TICRATE));
@ -1187,7 +1212,9 @@ void Y_StartIntermission(void)
timer = 1;
}
if (gametype == GT_COOP)
if (intermissiontypes[gametype] != int_none)
intertype = intermissiontypes[gametype];
else if (gametype == GT_COOP)
intertype = (G_IsSpecialStage(gamemap)) ? int_spec : int_coop;
else if (gametype == GT_TEAMMATCH)
intertype = int_teammatch;

View File

@ -31,3 +31,4 @@ typedef enum
int_comp, // Competition
} intertype_t;
extern intertype_t intertype;
extern intertype_t intermissiontypes[NUMGAMETYPES];