Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 1168-accessing-an-invalid-variable-in-ticcmd_t-crashes-the-game
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • batocera
  • blend-locking
  • blentran
  • blockmap-links
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • few-kart-lua-changes
  • ffloorclip
  • fix-1183
  • fix-cvar-conflicts
  • fix-opengl-shear-roll
  • fix-slope-plane-distortion
  • fix-sw-polyobject-interpolation
  • fix-table-key-archiving
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • font_drawer
  • frictionrefactor
  • fruits-clipper
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • gitlab-ci
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • lugstuff
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • map-components-signedness-fixes
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
141 results

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Jisk/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
117 results
Select Git revision
  • 1392-2-2-15-attempting-to-draw-a-hud-graphic-with-the-same-lump-name-as-a-lua-script-crashes-the
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2214-pre4
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • acs
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • clipmidtex
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • extra-textures
  • few-kart-lua-changes
  • ffloorclip
  • fix-167
  • fix-cvar-conflicts
  • fix-opengl-parameter-crash
  • fix-opengl-shear-roll
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • frictionrefactor
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-maxconditionsets
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • just-in-case
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.15
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
142 results
Show changes
Commits on Source (12)
...@@ -1375,6 +1375,8 @@ void D_SRB2Main(void) ...@@ -1375,6 +1375,8 @@ void D_SRB2Main(void)
CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
Z_Init(); Z_Init();
G_InitGametypes();
clientGamedata = M_NewGameDataStruct(); clientGamedata = M_NewGameDataStruct();
serverGamedata = M_NewGameDataStruct(); serverGamedata = M_NewGameDataStruct();
......
...@@ -308,8 +308,8 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word) ...@@ -308,8 +308,8 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
} }
else if (fastncmp("GT_", word, 3)) { else if (fastncmp("GT_", word, 3)) {
p = word; p = word;
for (i = 0; Gametype_ConstantNames[i]; i++) for (i = 0; i < gametypecount; i++)
if (fastcmp(p, Gametype_ConstantNames[i])) { if (fastcmp(p, gametypes[i].constant_name)) {
CacheAndPushConstant(L, word, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
......
...@@ -1145,7 +1145,7 @@ void readsprite2(MYFILE *f, INT32 num) ...@@ -1145,7 +1145,7 @@ void readsprite2(MYFILE *f, INT32 num)
Z_Free(s); Z_Free(s);
} }
void readgametype(MYFILE *f, char *gtname) void readgametype(MYFILE *f, INT32 num)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word; char *word;
...@@ -1153,20 +1153,13 @@ void readgametype(MYFILE *f, char *gtname) ...@@ -1153,20 +1153,13 @@ void readgametype(MYFILE *f, char *gtname)
char *tmp; char *tmp;
INT32 i, j; INT32 i, j;
INT16 newgtidx = 0; char *gtname = gametypes[num].name;
UINT32 newgtrules = 0; char gtconst[32];
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 gtdescription[441];
char gtconst[MAXLINELEN];
// Empty strings. UINT8 newgtleftcolor, newgtrightcolor;
gtdescription[0] = '\0'; boolean has_desc_colors[2] = { false, false };
gtconst[0] = '\0'; gtconst[0] = '\0';
do do
...@@ -1226,8 +1219,8 @@ void readgametype(MYFILE *f, char *gtname) ...@@ -1226,8 +1219,8 @@ void readgametype(MYFILE *f, char *gtname)
if (word2) if (word2)
{ {
if (!word2lwr) if (!word2lwr)
word2lwr = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); word2lwr = Z_Calloc(MAXLINELEN, PU_STATIC, NULL);
strcpy(word2lwr, word2); strlcpy(word2lwr, word2, MAXLINELEN);
strupr(word2); strupr(word2);
} }
else else
...@@ -1235,49 +1228,84 @@ void readgametype(MYFILE *f, char *gtname) ...@@ -1235,49 +1228,84 @@ void readgametype(MYFILE *f, char *gtname)
if (word2[strlen(word2)-1] == '\n') if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0'; word2[strlen(word2)-1] = '\0';
if (word2lwr[strlen(word2lwr)-1] == '\n')
word2lwr[strlen(word2lwr)-1] = '\0';
i = atoi(word2); i = atoi(word2);
// Name
if (fastcmp(word, "NAME"))
{
Z_Free(gametypes[num].name);
gametypes[num].name = Z_StrDup(word2lwr);
}
// Game type rules // Game type rules
if (fastcmp(word, "RULES")) else if (fastcmp(word, "RULES"))
{ {
// GTR_ // GTR_
newgtrules = (UINT32)get_number(word2); gametypes[num].rules = (UINT32)get_number(word2);
} }
// Identifier // Identifier
else if (fastcmp(word, "IDENTIFIER")) else if (fastcmp(word, "IDENTIFIER"))
{ {
// GT_ // GT_
strncpy(gtconst, word2, MAXLINELEN); strlcpy(gtconst, word2, sizeof(gtconst));
} }
// Point and time limits // Point and time limits
else if (fastcmp(word, "DEFAULTPOINTLIMIT")) else if (fastcmp(word, "DEFAULTPOINTLIMIT"))
newgtpointlimit = (INT32)i; gametypes[num].pointlimit = (INT32)i;
else if (fastcmp(word, "DEFAULTTIMELIMIT")) else if (fastcmp(word, "DEFAULTTIMELIMIT"))
newgttimelimit = (INT32)i; gametypes[num].timelimit = (INT32)i;
// Level platter // Level platter
else if (fastcmp(word, "HEADERCOLOR") || fastcmp(word, "HEADERCOLOUR")) else if (fastcmp(word, "HEADERCOLOR") || fastcmp(word, "HEADERCOLOUR"))
newgtleftcolor = newgtrightcolor = (UINT8)get_number(word2); {
INT32 color = (INT32)i;
if (color >= 0 && color <= 255)
{
newgtleftcolor = newgtrightcolor = (UINT8)color;
has_desc_colors[0] = has_desc_colors[1] = true;
}
else
deh_warning("readgametype %d: Level platter header color %d out of range (0 - 255)", num, i);
}
else if (fastcmp(word, "HEADERLEFTCOLOR") || fastcmp(word, "HEADERLEFTCOLOUR")) else if (fastcmp(word, "HEADERLEFTCOLOR") || fastcmp(word, "HEADERLEFTCOLOUR"))
newgtleftcolor = (UINT8)get_number(word2); {
INT32 color = (INT32)i;
if (color >= 0 && color <= 255)
{
newgtleftcolor = (UINT8)color;
has_desc_colors[0] = true;
}
else
deh_warning("readgametype %d: Level platter header left color %d out of range (0 - 255)", num, i);
}
else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR")) else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR"))
newgtrightcolor = (UINT8)get_number(word2); {
INT32 color = (INT32)i;
if (color >= 0 && color < 255)
{
newgtrightcolor = (UINT8)color;
has_desc_colors[1] = true;
}
else
deh_warning("readgametype %d: Level platter header right color %d out of range (0 - 255)", num, i);
}
// Rankings type // Rankings type
else if (fastcmp(word, "RANKINGTYPE")) else if (fastcmp(word, "RANKINGTYPE"))
{ {
// Case insensitive // Case insensitive
newgtrankingstype = (int)get_number(word2); gametypes[num].rankings_type = (int)get_number(word2);
} }
// Intermission type // Intermission type
else if (fastcmp(word, "INTERMISSIONTYPE")) else if (fastcmp(word, "INTERMISSIONTYPE"))
{ {
// Case sensitive // Case sensitive
newgtinttype = (int)get_number(word2lwr); gametypes[num].intermission_type = (int)get_number(word2lwr);
} }
// Type of level // Type of level
else if (fastcmp(word, "TYPEOFLEVEL")) else if (fastcmp(word, "TYPEOFLEVEL"))
{ {
if (i) // it's just a number if (i) // it's just a number
newgttol = (UINT32)i; gametypes[num].typeoflevel = (UINT32)i;
else else
{ {
UINT32 tol = 0; UINT32 tol = 0;
...@@ -1287,28 +1315,28 @@ void readgametype(MYFILE *f, char *gtname) ...@@ -1287,28 +1315,28 @@ void readgametype(MYFILE *f, char *gtname)
if (fasticmp(tmp, TYPEOFLEVEL[i].name)) if (fasticmp(tmp, TYPEOFLEVEL[i].name))
break; break;
if (!TYPEOFLEVEL[i].name) if (!TYPEOFLEVEL[i].name)
deh_warning("readgametype %s: unknown typeoflevel flag %s\n", gtname, tmp); deh_warning("readgametype %d: unknown typeoflevel flag %s\n", num, tmp);
tol |= TYPEOFLEVEL[i].flag; tol |= TYPEOFLEVEL[i].flag;
} while((tmp = strtok(NULL,",")) != NULL); } while((tmp = strtok(NULL,",")) != NULL);
newgttol = tol; gametypes[num].typeoflevel = tol;
} }
} }
// The SOC probably provided gametype rules as words, // This SOC probably provided gametype rules as words, instead of using the RULES keyword.
// instead of using the RULES keyword. // (For example, "NOSPECTATORSPAWN = TRUE")
// Like for example "NOSPECTATORSPAWN = TRUE".
// This is completely valid, and looks better anyway.
else else
{ {
UINT32 wordgt = 0; UINT32 wordgt = 0;
for (j = 0; GAMETYPERULE_LIST[j]; j++) for (j = 0; GAMETYPERULE_LIST[j]; j++)
if (fastcmp(word, GAMETYPERULE_LIST[j])) { if (fastcmp(word, GAMETYPERULE_LIST[j])) {
wordgt |= (1<<j); wordgt |= (1<<j);
if (i || word2[0] == 'T' || word2[0] == 'Y') if (word2[0] == 'T' || word2[0] == 'Y')
newgtrules |= wordgt; gametypes[num].rules |= wordgt;
else if (word2[0] == 'F' || word2[0] == 'N')
gametypes[num].rules &= ~wordgt;
break; break;
} }
if (!wordgt) if (!wordgt)
deh_warning("readgametype %s: unknown word '%s'", gtname, word); deh_warning("readgametype %d: unknown word '%s'", num, word);
} }
} }
} while (!myfeof(f)); // finish when the line is empty } while (!myfeof(f)); // finish when the line is empty
...@@ -1318,38 +1346,26 @@ void readgametype(MYFILE *f, char *gtname) ...@@ -1318,38 +1346,26 @@ void readgametype(MYFILE *f, char *gtname)
if (word2lwr) if (word2lwr)
Z_Free(word2lwr); Z_Free(word2lwr);
// Ran out of gametype slots if (gtdescription[0])
if (gametypecount == NUMGAMETYPEFREESLOTS) G_SetGametypeDescription(num, gtdescription);
{ if (has_desc_colors[0])
CONS_Alert(CONS_WARNING, "Ran out of free gametype slots!\n"); G_SetGametypeDescriptionLeftColor(num, newgtleftcolor);
return; if (has_desc_colors[1])
} G_SetGametypeDescriptionRightColor(num, newgtrightcolor);
// 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. // Write the constant name.
if (gtconst[0] == '\0') if (gametypes[num].constant_name == NULL)
strncpy(gtconst, gtname, MAXLINELEN); {
G_AddGametypeConstant(newgtidx, (const char *)gtconst); if (gtconst[0] == '\0')
G_AddGametypeConstant(num, gtname);
else
G_AddGametypeConstant(num, gtconst);
}
else if (gtconst[0] != '\0')
G_AddGametypeConstant(num, gtconst);
// Update gametype_cons_t accordingly. // Update gametype_cons_t accordingly.
G_UpdateGametypeSelections(); G_UpdateGametypeSelections();
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
} }
void readlevelheader(MYFILE *f, INT32 num) void readlevelheader(MYFILE *f, INT32 num)
...@@ -4165,6 +4181,22 @@ skincolornum_t get_skincolor(const char *word) ...@@ -4165,6 +4181,22 @@ skincolornum_t get_skincolor(const char *word)
return SKINCOLOR_GREEN; return SKINCOLOR_GREEN;
} }
INT16 get_gametype(const char *word)
{
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 < gametypecount; i++)
{
if (fastcmp(word, gametypes[i].constant_name + 3))
return i;
}
deh_warning("Couldn't find gametype named 'GT_%s'",word);
return GT_COOP;
}
spritenum_t get_sprite(const char *word) spritenum_t get_sprite(const char *word)
{ // Returns the value of SPR_ enumerations { // Returns the value of SPR_ enumerations
spritenum_t i; spritenum_t i;
...@@ -4237,34 +4269,6 @@ menutype_t get_menutype(const char *word) ...@@ -4237,34 +4269,6 @@ menutype_t get_menutype(const char *word)
return MN_NONE; return MN_NONE;
} }
/*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 value of pw_ enumerations
powertype_t i;
if (*word >= '0' && *word <= '9')
return atoi(word);
if (fastncmp("PW_",word,3))
word += 3; // take off the pw_
for (i = 0; i < NUMPOWERS; i++)
if (fastcmp(word, POWERS_LIST[i]))
return i;
deh_warning("Couldn't find power named 'pw_%s'",word);
return pw_invulnerability;
}*/
/// \todo Make ANY of this completely over-the-top math craziness obey the order of operations. /// \todo Make ANY of this completely over-the-top math craziness obey the order of operations.
static fixed_t op_mul(fixed_t a, fixed_t b) { return a*b; } static fixed_t op_mul(fixed_t a, fixed_t b) { return a*b; }
static fixed_t op_div(fixed_t a, fixed_t b) { return a/b; } static fixed_t op_div(fixed_t a, fixed_t b) { return a/b; }
......
...@@ -54,9 +54,8 @@ playersprite_t get_sprite2(const char *word); ...@@ -54,9 +54,8 @@ playersprite_t get_sprite2(const char *word);
sfxenum_t get_sfx(const char *word); sfxenum_t get_sfx(const char *word);
hudnum_t get_huditem(const char *word); hudnum_t get_huditem(const char *word);
menutype_t get_menutype(const char *word); menutype_t get_menutype(const char *word);
//INT16 get_gametype(const char *word);
//powertype_t get_power(const char *word);
skincolornum_t get_skincolor(const char *word); skincolornum_t get_skincolor(const char *word);
INT16 get_gametype(const char *word);
void readwipes(MYFILE *f); void readwipes(MYFILE *f);
void readmaincfg(MYFILE *f); void readmaincfg(MYFILE *f);
...@@ -71,7 +70,7 @@ void readmenu(MYFILE *f, INT32 num); ...@@ -71,7 +70,7 @@ void readmenu(MYFILE *f, INT32 num);
void readtextprompt(MYFILE *f, INT32 num); void readtextprompt(MYFILE *f, INT32 num);
void readcutscene(MYFILE *f, INT32 num); void readcutscene(MYFILE *f, INT32 num);
void readlevelheader(MYFILE *f, INT32 num); void readlevelheader(MYFILE *f, INT32 num);
void readgametype(MYFILE *f, char *gtname); void readgametype(MYFILE *f, INT32 num);
void readsprite2(MYFILE *f, INT32 num); void readsprite2(MYFILE *f, INT32 num);
void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2); void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2);
#ifdef HWRENDER #ifdef HWRENDER
......
...@@ -5326,6 +5326,11 @@ struct int_const_s const INT_CONST[] = { ...@@ -5326,6 +5326,11 @@ struct int_const_s const INT_CONST[] = {
{"int_race",int_race}, {"int_race",int_race},
{"int_comp",int_comp}, {"int_comp",int_comp},
// Ranking types
{"RANKINGS_DEFAULT",RANKINGS_DEFAULT},
{"RANKINGS_COMPETITION",RANKINGS_COMPETITION},
{"RANKINGS_RACE",RANKINGS_RACE},
// Jingles (jingletype_t) // Jingles (jingletype_t)
{"JT_NONE",JT_NONE}, {"JT_NONE",JT_NONE},
{"JT_OTHER",JT_OTHER}, {"JT_OTHER",JT_OTHER},
......
...@@ -186,9 +186,9 @@ void ignorelinesuntilhash(MYFILE *f) ...@@ -186,9 +186,9 @@ void ignorelinesuntilhash(MYFILE *f)
static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char textline[MAXLINELEN];
char *word; char *word;
char *word2; char *word2;
char word2lwr[MAXLINELEN];
INT32 i; INT32 i;
if (!deh_loaded) if (!deh_loaded)
...@@ -203,7 +203,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) ...@@ -203,7 +203,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
while (!myfeof(f)) while (!myfeof(f))
{ {
myfgets(s, MAXLINELEN, f); myfgets(s, MAXLINELEN, f);
memcpy(textline, s, MAXLINELEN);
if (s[0] == '\n' || s[0] == '#') if (s[0] == '\n' || s[0] == '#')
continue; continue;
...@@ -230,10 +229,14 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) ...@@ -230,10 +229,14 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
continue; continue;
} }
word2 = strtok(NULL, " "); word2 = strtok(NULL, " ");
word2lwr[0] = '\0';
if (word2) { if (word2) {
strcpy(word2lwr, word2);
strupr(word2); strupr(word2);
if (word2[strlen(word2) - 1] == '\n') if (word2[strlen(word2) - 1] == '\n')
word2[strlen(word2) - 1] = '\0'; word2[strlen(word2) - 1] = '\0';
if (word2lwr[strlen(word2lwr) - 1] == '\n')
word2lwr[strlen(word2lwr) - 1] = '\0';
i = atoi(word2); i = atoi(word2);
} }
else else
...@@ -389,33 +392,49 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) ...@@ -389,33 +392,49 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
} }
else if (fastcmp(word, "GAMETYPE")) else if (fastcmp(word, "GAMETYPE"))
{ {
// Get the gametype name from textline char *gtname = NULL;
// instead of word2, so that gametype names if (word2lwr[0])
// aren't allcaps
INT32 c;
for (c = 0; c < MAXLINELEN; c++)
{ {
if (textline[c] == '\0') gtname = word2lwr;
break;
if (textline[c] == ' ') for (size_t j = 0; j < strlen(gtname); j++)
{ {
char *gtname = (textline+c+1); if (gtname[j] == '\0')
if (gtname) break;
if (gtname[j] < 32 || gtname[j] == '\n')
{ {
// remove funny characters gtname[j] = '\0';
INT32 j; break;
for (j = 0; j < (MAXLINELEN - c); j++)
{
if (gtname[j] == '\0')
break;
if (gtname[j] < 32)
gtname[j] = '\0';
}
readgametype(f, gtname);
} }
break;
} }
} }
if (!gtname || !strlen(gtname))
{
deh_warning("Invalid gametype name");
ignorelines(f);
}
else
{
INT32 gametype_id = G_GetGametypeByName(gtname);
if (gametype_id == -1)
{
if (!strncmp(gtname, "GT_", 3))
gametype_id = get_gametype(gtname + 3);
else if (gametypecount != NUMGAMETYPEFREESLOTS)
{
gametype_id = G_AddGametype();
CONS_Printf("Added gametype %s\n", gtname);
}
else
deh_warning("Ran out of free gametype slots");
}
if (gametype_id != -1)
readgametype(f, gametype_id);
else
ignorelines(f);
}
} }
else if (fastcmp(word, "CUTSCENE")) else if (fastcmp(word, "CUTSCENE"))
{ {
......
...@@ -98,7 +98,6 @@ extern boolean multiplayer; ...@@ -98,7 +98,6 @@ extern boolean multiplayer;
extern INT16 gametype; extern INT16 gametype;
extern UINT32 gametyperules; extern UINT32 gametyperules;
extern INT16 gametypecount;
extern boolean splitscreen; extern boolean splitscreen;
extern boolean circuitmap; // Does this level have 'circuit mode'? extern boolean circuitmap; // Does this level have 'circuit mode'?
...@@ -390,8 +389,9 @@ typedef struct ...@@ -390,8 +389,9 @@ typedef struct
extern mapheader_t* mapheaderinfo[NUMMAPS]; extern mapheader_t* mapheaderinfo[NUMMAPS];
// Gametypes
#define NUMGAMETYPEFREESLOTS 128 #define NUMGAMETYPEFREESLOTS 128
// Gametypes
enum GameType enum GameType
{ {
GT_COOP = 0, // also used in single player GT_COOP = 0, // also used in single player
...@@ -410,7 +410,7 @@ enum GameType ...@@ -410,7 +410,7 @@ enum GameType
GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1, GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1,
NUMGAMETYPES NUMGAMETYPES
}; };
// If you alter this list, update deh_tables.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c // If you alter this list, update deh_tables.c, MISC_ChangeGameTypeMenu in m_menu.c, and gametypes in g_game.c
// Gametype rules // Gametype rules
enum GameTypeRules enum GameTypeRules
...@@ -449,13 +449,27 @@ enum GameTypeRules ...@@ -449,13 +449,27 @@ enum GameTypeRules
GTR_CUTSCENES = 1<<31, // Play cutscenes, ending, credits, and evaluation GTR_CUTSCENES = 1<<31, // Play cutscenes, ending, credits, and evaluation
}; };
// String names for gametypes enum
extern const char *Gametype_Names[NUMGAMETYPES]; {
extern const char *Gametype_ConstantNames[NUMGAMETYPES]; RANKINGS_DEFAULT,
RANKINGS_COMPETITION,
RANKINGS_RACE
};
// Point and time limits for every gametype typedef struct
extern INT32 pointlimits[NUMGAMETYPES]; {
extern INT32 timelimits[NUMGAMETYPES]; char *name;
char *constant_name;
UINT32 rules;
UINT32 typeoflevel;
UINT8 intermission_type;
INT16 rankings_type;
INT32 pointlimit;
INT32 timelimit;
} gametype_t;
extern gametype_t gametypes[NUMGAMETYPES];
extern INT16 gametypecount;
// TypeOfLevel things // TypeOfLevel things
enum TypeOfLevel enum TypeOfLevel
......
...@@ -3401,7 +3401,7 @@ void G_ExitLevel(void) ...@@ -3401,7 +3401,7 @@ void G_ExitLevel(void)
} }
// See also the enum GameType in doomstat.h // See also the enum GameType in doomstat.h
const char *Gametype_Names[NUMGAMETYPES] = static const char *Gametype_Names[NUMGAMETYPES] =
{ {
"Co-op", // GT_COOP "Co-op", // GT_COOP
"Competition", // GT_COMPETITION "Competition", // GT_COMPETITION
...@@ -3416,8 +3416,7 @@ const char *Gametype_Names[NUMGAMETYPES] = ...@@ -3416,8 +3416,7 @@ const char *Gametype_Names[NUMGAMETYPES] =
"CTF" // GT_CTF "CTF" // GT_CTF
}; };
// For dehacked static const char *Gametype_ConstantNames[NUMGAMETYPES] =
const char *Gametype_ConstantNames[NUMGAMETYPES] =
{ {
"GT_COOP", // GT_COOP "GT_COOP", // GT_COOP
"GT_COMPETITION", // GT_COMPETITION "GT_COMPETITION", // GT_COMPETITION
...@@ -3432,195 +3431,178 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = ...@@ -3432,195 +3431,178 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] =
"GT_CTF" // GT_CTF "GT_CTF" // GT_CTF
}; };
// Gametype rules gametype_t gametypes[NUMGAMETYPES] = {
UINT32 gametypedefaultrules[NUMGAMETYPES] = // GT_COOP
{ {
// Co-op .rules = GTR_CAMPAIGN|GTR_LIVES|GTR_FRIENDLY|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES|GTR_CUTSCENES,
GTR_CAMPAIGN|GTR_LIVES|GTR_FRIENDLY|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES|GTR_CUTSCENES, .typeoflevel = TOL_COOP,
// Competition .intermission_type = int_coop,
GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT, .rankings_type = RANKINGS_DEFAULT,
// Race },
GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT, // GT_COMPETITION
{
// Match .rules = GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT,
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD|GTR_DEATHPENALTY, .typeoflevel = TOL_COMPETITION,
// Team Match .intermission_type = int_comp,
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD, .rankings_type = RANKINGS_COMPETITION,
},
// Tag // GT_RACE
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, {
// Hide and Seek .rules = GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT,
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_HIDEFROZEN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, .typeoflevel = TOL_RACE,
.intermission_type = int_race,
// CTF .rankings_type = RANKINGS_RACE,
GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_TEAMFLAGS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD, },
// GT_MATCH
{
.rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD|GTR_DEATHPENALTY,
.typeoflevel = TOL_MATCH,
.intermission_type = int_match,
.rankings_type = RANKINGS_DEFAULT,
// default settings for match: timelimit 10 mins, no pointlimit
.timelimit = 10,
.pointlimit = 0
},
// GT_TEAMMATCH
{
.rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD,
.typeoflevel = TOL_MATCH,
.intermission_type = int_teammatch,
.rankings_type = RANKINGS_DEFAULT,
// default settings for match: timelimit 10 mins, no pointlimit
.timelimit = 10,
.pointlimit = 0
},
// GT_TAG
{
.rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY,
.typeoflevel = TOL_TAG,
.intermission_type = int_match,
.rankings_type = RANKINGS_DEFAULT,
// default settings for tag: 5 mins, no pointlimit
// Note that tag mode also uses an alternate timing mechanism in tandem with timelimit.
.timelimit = 5,
.pointlimit = 0
},
// GT_HIDEANDSEEK
{
.rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_STARTCOUNTDOWN|GTR_HIDEFROZEN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY,
.typeoflevel = TOL_TAG,
.intermission_type = int_match,
.rankings_type = RANKINGS_DEFAULT,
// default settings for tag: 5 mins, no pointlimit
// Note that tag mode also uses an alternate timing mechanism in tandem with timelimit.
.timelimit = 5,
.pointlimit = 0
},
// GT_CTF
{
.rules = GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_TEAMFLAGS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD,
.typeoflevel = TOL_CTF,
.intermission_type = int_ctf,
.rankings_type = RANKINGS_DEFAULT,
// default settings for CTF: no timelimit, pointlimit 5
.timelimit = 0,
.pointlimit = 5
},
}; };
void G_InitGametypes(void)
{
for (unsigned i = 0; i <= GT_CTF; i++)
{
gametypes[i].name = Z_StrDup(Gametype_Names[i]);
gametypes[i].constant_name = Z_StrDup(Gametype_ConstantNames[i]);
}
}
// //
// Sets a new gametype. // Sets a new gametype, also setting gametype rules accordingly.
// //
void G_SetGametype(INT16 gtype) void G_SetGametype(INT16 gtype)
{ {
gametype = gtype; gametype = gtype;
gametyperules = gametypedefaultrules[gametype]; gametyperules = gametypes[gametype].rules;
} }
// //
// G_AddGametype // Adds a gametype. Returns the new gametype number.
// //
// Add a gametype. Returns the new gametype number. INT16 G_AddGametype(void)
//
INT16 G_AddGametype(UINT32 rules)
{ {
INT16 newgtype = gametypecount; INT16 newgtype = gametypecount;
gametypecount++; gametypecount++;
// Set gametype rules. gametypes[newgtype].name = Z_StrDup("???");
gametypedefaultrules[newgtype] = rules; gametypes[newgtype].rules = 0;
Gametype_Names[newgtype] = "???";
// Update gametype_cons_t accordingly. G_SetGametypeDescription(newgtype, "???");
G_UpdateGametypeSelections(); G_SetGametypeDescriptionLeftColor(newgtype, 54);
G_SetGametypeDescriptionRightColor(newgtype, 54);
return newgtype; return newgtype;
} }
//
// G_AddGametypeConstant
//
// Self-explanatory. Filters out "bad" characters.
//
void G_AddGametypeConstant(INT16 gtype, const char *newgtconst) void G_AddGametypeConstant(INT16 gtype, const char *newgtconst)
{ {
size_t r = 0; // read
size_t w = 0; // write
char *gtconst = Z_Calloc(strlen(newgtconst) + 4, PU_STATIC, NULL); char *gtconst = Z_Calloc(strlen(newgtconst) + 4, PU_STATIC, NULL);
char *tmpconst = Z_Calloc(strlen(newgtconst) + 1, PU_STATIC, NULL); char *tmpconst = Z_Calloc(strlen(newgtconst) + 1, PU_STATIC, NULL);
// Copy the gametype name.
strcpy(tmpconst, newgtconst); strcpy(tmpconst, newgtconst);
// Make uppercase.
strupr(tmpconst); strupr(tmpconst);
// Prepare to write the new constant string now.
strcpy(gtconst, "GT_"); strcpy(gtconst, "GT_");
// Remove characters that will not be allowed in the constant string. size_t w = strlen(gtconst);
for (; r < strlen(tmpconst); r++)
for (size_t r = 0; r < strlen(tmpconst); r++)
{ {
boolean writechar = true;
char rc = tmpconst[r]; char rc = tmpconst[r];
switch (rc) if (isalpha(rc) || isdigit(rc))
{ gtconst[w++] = rc;
// Space, at sign and question mark
case ' ':
case '@':
case '?':
// Used for operations
case '+':
case '-':
case '*':
case '/':
case '%':
case '^':
case '&':
case '!':
// Part of Lua's syntax
case '#':
case '=':
case '~':
case '<':
case '>':
case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
case ':':
case ';':
case ',':
case '.':
writechar = false;
break;
}
if (writechar)
{
gtconst[3 + w] = rc;
w++;
}
} }
// Free the temporary string.
Z_Free(tmpconst); Z_Free(tmpconst);
// Finally, set the constant string. gametypes[gtype].constant_name = gtconst;
Gametype_ConstantNames[gtype] = gtconst;
} }
//
// G_UpdateGametypeSelections
//
// Updates gametype_cons_t.
//
void G_UpdateGametypeSelections(void) void G_UpdateGametypeSelections(void)
{ {
INT32 i; INT32 i;
for (i = 0; i < gametypecount; i++) for (i = 0; i < gametypecount; i++)
{ {
gametype_cons_t[i].value = i; gametype_cons_t[i].value = i;
gametype_cons_t[i].strvalue = Gametype_Names[i]; gametype_cons_t[i].strvalue = gametypes[i].name;
} }
gametype_cons_t[NUMGAMETYPES].value = 0; gametype_cons_t[NUMGAMETYPES].value = 0;
gametype_cons_t[NUMGAMETYPES].strvalue = NULL; gametype_cons_t[NUMGAMETYPES].strvalue = NULL;
cv_newgametype.defaultvalue = gametype_cons_t[0].strvalue;
if (cv_newgametype.string && G_GetGametypeByName(cv_newgametype.string) == -1)
{
cv_newgametype.value = 0;
cv_newgametype.string = gametype_cons_t[0].strvalue;
}
} }
// void G_SetGametypeDescription(INT16 gtype, const char *descriptiontext)
// 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) if (descriptiontext)
strncpy(gametypedesc[gtype].notes, descriptiontext, 441); strlcpy(gametypedesc[gtype].notes, descriptiontext, sizeof gametypedesc[gtype].notes);
gametypedesc[gtype].col[0] = leftcolor; else
gametypedesc[gtype].col[1] = rightcolor; memset(gametypedesc[gtype].notes, 0, sizeof gametypedesc[gtype].notes);
} }
// Gametype rankings void G_SetGametypeDescriptionLeftColor(INT16 gtype, UINT8 color)
INT16 gametyperankings[NUMGAMETYPES] =
{ {
GT_COOP, gametypedesc[gtype].col[0] = color;
GT_COMPETITION, }
GT_RACE,
GT_MATCH,
GT_TEAMMATCH,
GT_TAG,
GT_HIDEANDSEEK,
GT_CTF,
};
// Gametype to TOL (Type Of Level) void G_SetGametypeDescriptionRightColor(INT16 gtype, UINT8 color)
UINT32 gametypetol[NUMGAMETYPES] =
{ {
TOL_COOP, // Co-op gametypedesc[gtype].col[1] = color;
TOL_COMPETITION, // Competition }
TOL_RACE, // Race
TOL_MATCH, // Match
TOL_MATCH, // Team Match
TOL_TAG, // Tag
TOL_TAG, // Hide and Seek
TOL_CTF, // CTF
};
tolinfo_t TYPEOFLEVEL[NUMTOLNAMES] = { tolinfo_t TYPEOFLEVEL[NUMTOLNAMES] = {
{"SOLO",TOL_SP}, {"SOLO",TOL_SP},
...@@ -3668,16 +3650,6 @@ void G_AddTOL(UINT32 newtol, const char *tolname) ...@@ -3668,16 +3650,6 @@ void G_AddTOL(UINT32 newtol, const char *tolname)
TYPEOFLEVEL[i].flag = newtol; TYPEOFLEVEL[i].flag = newtol;
} }
//
// G_AddGametypeTOL
//
// Assigns a type of level to a gametype.
//
void G_AddGametypeTOL(INT16 gtype, UINT32 newtol)
{
gametypetol[gtype] = newtol;
}
// //
// G_GetGametypeByName // G_GetGametypeByName
// //
...@@ -3688,7 +3660,7 @@ INT32 G_GetGametypeByName(const char *gametypestr) ...@@ -3688,7 +3660,7 @@ INT32 G_GetGametypeByName(const char *gametypestr)
INT32 i; INT32 i;
for (i = 0; i < gametypecount; i++) for (i = 0; i < gametypecount; i++)
if (!stricmp(gametypestr, Gametype_Names[i])) if (!stricmp(gametypestr, gametypes[i].name))
return i; return i;
return -1; // unknown gametype return -1; // unknown gametype
...@@ -3834,7 +3806,8 @@ UINT32 G_TOLFlag(INT32 pgametype) ...@@ -3834,7 +3806,8 @@ UINT32 G_TOLFlag(INT32 pgametype)
{ {
if (!multiplayer) if (!multiplayer)
return TOL_SP; return TOL_SP;
return gametypetol[pgametype];
return gametypes[pgametype].typeoflevel;
} }
/** Select a random map with the given typeoflevel flags. /** Select a random map with the given typeoflevel flags.
......
...@@ -191,17 +191,16 @@ void G_SaveGame(UINT32 slot, INT16 mapnum); ...@@ -191,17 +191,16 @@ void G_SaveGame(UINT32 slot, INT16 mapnum);
void G_SaveGameOver(UINT32 slot, boolean modifylives); void G_SaveGameOver(UINT32 slot, boolean modifylives);
extern UINT32 gametypedefaultrules[NUMGAMETYPES];
extern UINT32 gametypetol[NUMGAMETYPES];
extern INT16 gametyperankings[NUMGAMETYPES];
void G_SetGametype(INT16 gametype); void G_SetGametype(INT16 gametype);
INT16 G_AddGametype(UINT32 rules); void G_InitGametypes(void);
INT16 G_AddGametype(void);
void G_AddGametypeConstant(INT16 gtype, const char *newgtconst); void G_AddGametypeConstant(INT16 gtype, const char *newgtconst);
void G_UpdateGametypeSelections(void); void G_UpdateGametypeSelections(void);
void G_AddTOL(UINT32 newtol, const char *tolname); 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); void G_SetGametypeDescription(INT16 gtype, const char *descriptiontext);
void G_SetGametypeDescriptionLeftColor(INT16 gtype, UINT8 color);
void G_SetGametypeDescriptionRightColor(INT16 gtype, UINT8 color);
INT32 G_GetGametypeByName(const char *gametypestr); INT32 G_GetGametypeByName(const char *gametypestr);
boolean G_IsSpecialStage(INT32 mapnum); boolean G_IsSpecialStage(INT32 mapnum);
......
...@@ -1898,7 +1898,7 @@ static void HU_drawGametype(void) ...@@ -1898,7 +1898,7 @@ static void HU_drawGametype(void)
if (gametype < 0 || gametype >= gametypecount) if (gametype < 0 || gametype >= gametypecount)
return; // not a valid gametype??? return; // not a valid gametype???
strvalue = Gametype_Names[gametype]; strvalue = gametypes[gametype].name;
if (splitscreen) if (splitscreen)
V_DrawString(4, 184, 0, strvalue); V_DrawString(4, 184, 0, strvalue);
...@@ -2179,7 +2179,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I ...@@ -2179,7 +2179,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
for (i = 0; i < scorelines; i++) for (i = 0; i < scorelines; i++)
{ {
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP) if (players[tab[i].num].spectator && !G_GametypeUsesCoopLives())
continue; //ignore them. continue; //ignore them.
greycheck = greycheckdef; greycheck = greycheckdef;
...@@ -2256,7 +2256,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I ...@@ -2256,7 +2256,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)) if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
V_DrawSmallScaledPatch(x - exiticon->width/2 - 1, y-3, 0, exiticon); V_DrawSmallScaledPatch(x - exiticon->width/2 - 1, y-3, 0, exiticon);
if (gametyperankings[gametype] == GT_RACE) if (gametypes[gametype].rankings_type == RANKINGS_RACE)
{ {
if (circuitmap) if (circuitmap)
{ {
...@@ -2537,7 +2537,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline ...@@ -2537,7 +2537,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
for (i = 0; i < scorelines; i++) for (i = 0; i < scorelines; i++)
{ {
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP) if (players[tab[i].num].spectator && !G_GametypeUsesCoopLives())
continue; //ignore them. continue; //ignore them.
greycheck = greycheckdef; greycheck = greycheckdef;
...@@ -2604,7 +2604,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline ...@@ -2604,7 +2604,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
} }
// All data drawn with thin string for space. // All data drawn with thin string for space.
if (gametyperankings[gametype] == GT_RACE) if (gametypes[gametype].rankings_type == RANKINGS_RACE)
{ {
if (circuitmap) if (circuitmap)
{ {
...@@ -2644,7 +2644,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor ...@@ -2644,7 +2644,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
for (i = 0; i < scorelines; i++) for (i = 0; i < scorelines; i++)
{ {
if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP) if (players[tab[i].num].spectator && !G_GametypeUsesCoopLives())
continue; //ignore them. continue; //ignore them.
greycheck = greycheckdef; greycheck = greycheckdef;
...@@ -2715,7 +2715,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor ...@@ -2715,7 +2715,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
} }
// All data drawn with thin string for space. // All data drawn with thin string for space.
if (gametyperankings[gametype] == GT_RACE) if (gametypes[gametype].rankings_type == RANKINGS_RACE)
{ {
if (circuitmap) if (circuitmap)
{ {
...@@ -2875,7 +2875,7 @@ static void HU_DrawRankings(void) ...@@ -2875,7 +2875,7 @@ static void HU_DrawRankings(void)
tab[i].num = -1; tab[i].num = -1;
tab[i].name = 0; tab[i].name = 0;
if (gametyperankings[gametype] == GT_RACE && !circuitmap) if (gametypes[gametype].rankings_type == RANKINGS_RACE && !circuitmap)
tab[i].count = INT32_MAX; tab[i].count = INT32_MAX;
} }
...@@ -2895,7 +2895,7 @@ static void HU_DrawRankings(void) ...@@ -2895,7 +2895,7 @@ static void HU_DrawRankings(void)
if (!G_PlatformGametype() && players[i].spectator) if (!G_PlatformGametype() && players[i].spectator)
continue; continue;
if (gametyperankings[gametype] == GT_RACE) if (gametypes[gametype].rankings_type == RANKINGS_RACE)
{ {
if (circuitmap) if (circuitmap)
{ {
...@@ -2918,7 +2918,7 @@ static void HU_DrawRankings(void) ...@@ -2918,7 +2918,7 @@ static void HU_DrawRankings(void)
} }
} }
} }
else if (gametyperankings[gametype] == GT_COMPETITION) else if (gametypes[gametype].rankings_type == RANKINGS_COMPETITION)
{ {
// todo put something more fitting for the gametype here, such as current // todo put something more fitting for the gametype here, such as current
// number of categories led // number of categories led
......
...@@ -155,6 +155,7 @@ static const struct { ...@@ -155,6 +155,7 @@ static const struct {
{META_SFXINFO, "sfxinfo_t"}, {META_SFXINFO, "sfxinfo_t"},
{META_SKINCOLOR, "skincolor_t"}, {META_SKINCOLOR, "skincolor_t"},
{META_COLORRAMP, "skincolor_t.ramp"}, {META_COLORRAMP, "skincolor_t.ramp"},
{META_GAMETYPE, "gametype_t"},
{META_SPRITEINFO, "spriteinfo_t"}, {META_SPRITEINFO, "spriteinfo_t"},
{META_PIVOTLIST, "spriteframepivot_t[]"}, {META_PIVOTLIST, "spriteframepivot_t[]"},
{META_FRAMEPIVOT, "spriteframepivot_t"}, {META_FRAMEPIVOT, "spriteframepivot_t"},
...@@ -3641,17 +3642,16 @@ static int lib_gAddGametype(lua_State *L) ...@@ -3641,17 +3642,16 @@ static int lib_gAddGametype(lua_State *L)
const char *k; const char *k;
lua_Integer i; lua_Integer i;
const char *gtname = NULL; char *gtname = NULL;
const char *gtconst = NULL; char *gtconst = NULL;
const char *gtdescription = NULL; char *gtdescription = NULL;
INT16 newgtidx = 0;
UINT32 newgtrules = 0; UINT32 newgtrules = 0;
UINT32 newgttol = 0; UINT32 newgttol = 0;
INT32 newgtpointlimit = 0; INT32 newgtpointlimit = 0;
INT32 newgttimelimit = 0; INT32 newgttimelimit = 0;
UINT8 newgtleftcolor = 0; UINT8 newgtleftcolor = 54;
UINT8 newgtrightcolor = 0; UINT8 newgtrightcolor = 54;
INT16 newgtrankingstype = -1; INT16 newgtrankingstype = RANKINGS_DEFAULT;
int newgtinttype = 0; int newgtinttype = 0;
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
...@@ -3741,36 +3741,47 @@ static int lib_gAddGametype(lua_State *L) ...@@ -3741,36 +3741,47 @@ static int lib_gAddGametype(lua_State *L)
// Set defaults // Set defaults
if (gtname == NULL) if (gtname == NULL)
gtname = Z_StrDup("Unnamed gametype"); gtname = Z_StrDup("Unnamed gametype");
if (gtdescription == NULL)
gtdescription = Z_StrDup("???"); if (G_GetGametypeByName(gtname) != -1)
{
luaL_error(L, "gametype %s already exists", gtname);
Z_Free(gtname);
Z_Free(gtconst);
Z_Free(gtdescription);
return 0;
}
// Add the new gametype // Add the new gametype
newgtidx = G_AddGametype(newgtrules); INT16 gtype = G_AddGametype();
G_AddGametypeTOL(newgtidx, newgttol);
G_SetGametypeDescription(newgtidx, NULL, newgtleftcolor, newgtrightcolor); gametype_t *gt = &gametypes[gtype];
strncpy(gametypedesc[newgtidx].notes, gtdescription, 441);
gt->name = gtname;
// Not covered by G_AddGametype alone.
if (newgtrankingstype == -1) if (gtconst)
newgtrankingstype = newgtidx; G_AddGametypeConstant(gtype, gtconst);
gametyperankings[newgtidx] = newgtrankingstype; else
intermissiontypes[newgtidx] = newgtinttype; G_AddGametypeConstant(gtype, gtname);
pointlimits[newgtidx] = newgtpointlimit;
timelimits[newgtidx] = newgttimelimit; if (gtdescription)
G_SetGametypeDescription(gtype, gtdescription);
// Write the new gametype name. G_SetGametypeDescriptionLeftColor(gtype, newgtleftcolor);
Gametype_Names[newgtidx] = gtname; G_SetGametypeDescriptionRightColor(gtype, newgtrightcolor);
// Write the constant name. gt->rules = newgtrules;
if (gtconst == NULL) gt->typeoflevel = newgttol;
gtconst = gtname; gt->rankings_type = newgtrankingstype;
G_AddGametypeConstant(newgtidx, gtconst); gt->intermission_type = newgtinttype;
gt->pointlimit = newgtpointlimit;
// Update gametype_cons_t accordingly. gt->timelimit = newgttimelimit;
G_UpdateGametypeSelections(); G_UpdateGametypeSelections();
// done CONS_Printf("Added gametype %s\n", gt->name);
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
Z_Free(gtconst);
Z_Free(gtdescription);
return 0; return 0;
} }
......
...@@ -1899,6 +1899,141 @@ static int colorramp_len(lua_State *L) ...@@ -1899,6 +1899,141 @@ static int colorramp_len(lua_State *L)
return 1; return 1;
} }
///////////////
// GAMETYPES //
///////////////
static int lib_getGametypes(lua_State *L)
{
INT16 i;
lua_remove(L, 1);
i = luaL_checkinteger(L, 1);
if (i < 0 || i >= gametypecount)
return luaL_error(L, "gametypes[] index %d out of range (0 - %d)", i, gametypecount-1);
LUA_PushUserdata(L, &gametypes[i], META_GAMETYPE);
return 1;
}
// #gametypes -> gametypecount
static int lib_gametypeslen(lua_State *L)
{
lua_pushinteger(L, gametypecount);
return 1;
}
enum gametype_e
{
gametype_name,
gametype_rules,
gametype_typeoflevel,
gametype_intermission_type,
gametype_rankings_type,
gametype_pointlimit,
gametype_timelimit
};
const char *const gametype_opt[] = {
"name",
"rules",
"type_of_level",
"intermission_type",
"rankings_type",
"point_limit",
"time_limit",
NULL,
};
static int gametype_fields_ref = LUA_NOREF;
static int gametype_get(lua_State *L)
{
gametype_t *gt = *((gametype_t **)luaL_checkudata(L, 1, META_GAMETYPE));
enum gametype_e field = Lua_optoption(L, 2, gametype_name, gametype_fields_ref);
I_Assert(gt != NULL);
I_Assert(gt >= gametypes);
switch (field)
{
case gametype_name:
lua_pushstring(L, gt->name);
break;
case gametype_rules:
lua_pushinteger(L, gt->rules);
break;
case gametype_typeoflevel:
lua_pushinteger(L, gt->typeoflevel);
break;
case gametype_intermission_type:
lua_pushinteger(L, gt->intermission_type);
break;
case gametype_rankings_type:
lua_pushinteger(L, gt->rankings_type);
break;
case gametype_pointlimit:
lua_pushinteger(L, gt->pointlimit);
break;
case gametype_timelimit:
lua_pushinteger(L, gt->timelimit);
break;
}
return 1;
}
static int gametype_set(lua_State *L)
{
gametype_t *gt = *((gametype_t **)luaL_checkudata(L, 1, META_GAMETYPE));
enum gametype_e field = Lua_optoption(L, 2, -1, gametype_fields_ref);
if (hud_running)
return luaL_error(L, "Do not alter gametype data in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter gametype data in CMD building code!");
I_Assert(gt != NULL);
I_Assert(gt >= gametypes);
switch (field)
{
case gametype_name:
Z_Free(gt->name);
gt->name = Z_StrDup(luaL_checkstring(L, 3));
G_UpdateGametypeSelections();
break;
case gametype_rules:
gt->rules = luaL_checkinteger(L, 3);
break;
case gametype_typeoflevel:
gt->typeoflevel = luaL_checkinteger(L, 3);
break;
case gametype_intermission_type:
gt->intermission_type = luaL_checkinteger(L, 3);
break;
case gametype_rankings_type:
gt->rankings_type = luaL_checkinteger(L, 3);
break;
case gametype_pointlimit:
gt->pointlimit = luaL_checkinteger(L, 3);
break;
case gametype_timelimit:
gt->timelimit = luaL_checkinteger(L, 3);
break;
}
return 0;
}
static int gametype_num(lua_State *L)
{
gametype_t *gt = *((gametype_t **)luaL_checkudata(L, 1, META_GAMETYPE));
I_Assert(gt != NULL);
I_Assert(gt >= gametypes);
lua_pushinteger(L, gt-gametypes);
return 1;
}
////////////////////////////// //////////////////////////////
// //
// Now push all these functions into the Lua state! // Now push all these functions into the Lua state!
...@@ -1916,6 +2051,7 @@ int LUA_InfoLib(lua_State *L) ...@@ -1916,6 +2051,7 @@ int LUA_InfoLib(lua_State *L)
LUA_RegisterUserdataMetatable(L, META_STATE, state_get, state_set, state_num); LUA_RegisterUserdataMetatable(L, META_STATE, state_get, state_set, state_num);
LUA_RegisterUserdataMetatable(L, META_MOBJINFO, mobjinfo_get, mobjinfo_set, mobjinfo_num); LUA_RegisterUserdataMetatable(L, META_MOBJINFO, mobjinfo_get, mobjinfo_set, mobjinfo_num);
LUA_RegisterUserdataMetatable(L, META_GAMETYPE, gametype_get, gametype_set, gametype_num);
LUA_RegisterUserdataMetatable(L, META_SKINCOLOR, skincolor_get, skincolor_set, skincolor_num); LUA_RegisterUserdataMetatable(L, META_SKINCOLOR, skincolor_get, skincolor_set, skincolor_num);
LUA_RegisterUserdataMetatable(L, META_COLORRAMP, colorramp_get, colorramp_set, colorramp_len); LUA_RegisterUserdataMetatable(L, META_COLORRAMP, colorramp_get, colorramp_set, colorramp_len);
LUA_RegisterUserdataMetatable(L, META_SFXINFO, sfxinfo_get, sfxinfo_set, sfxinfo_num); LUA_RegisterUserdataMetatable(L, META_SFXINFO, sfxinfo_get, sfxinfo_set, sfxinfo_num);
...@@ -1931,6 +2067,7 @@ int LUA_InfoLib(lua_State *L) ...@@ -1931,6 +2067,7 @@ int LUA_InfoLib(lua_State *L)
LUA_RegisterGlobalUserdata(L, "spr2defaults", lib_getSpr2default, lib_setSpr2default, lib_spr2namelen); LUA_RegisterGlobalUserdata(L, "spr2defaults", lib_getSpr2default, lib_setSpr2default, lib_spr2namelen);
LUA_RegisterGlobalUserdata(L, "states", lib_getState, lib_setState, lib_statelen); LUA_RegisterGlobalUserdata(L, "states", lib_getState, lib_setState, lib_statelen);
LUA_RegisterGlobalUserdata(L, "mobjinfo", lib_getMobjInfo, lib_setMobjInfo, lib_mobjinfolen); LUA_RegisterGlobalUserdata(L, "mobjinfo", lib_getMobjInfo, lib_setMobjInfo, lib_mobjinfolen);
LUA_RegisterGlobalUserdata(L, "gametypes", lib_getGametypes, NULL, lib_gametypeslen);
LUA_RegisterGlobalUserdata(L, "skincolors", lib_getSkinColor, lib_setSkinColor, lib_skincolorslen); LUA_RegisterGlobalUserdata(L, "skincolors", lib_getSkinColor, lib_setSkinColor, lib_skincolorslen);
LUA_RegisterGlobalUserdata(L, "spriteinfo", lib_getSpriteInfo, lib_setSpriteInfo, lib_spriteinfolen); LUA_RegisterGlobalUserdata(L, "spriteinfo", lib_getSpriteInfo, lib_setSpriteInfo, lib_spriteinfolen);
LUA_RegisterGlobalUserdata(L, "sfxinfo", lib_getSfxInfo, lib_setSfxInfo, lib_sfxlen); LUA_RegisterGlobalUserdata(L, "sfxinfo", lib_getSfxInfo, lib_setSfxInfo, lib_sfxlen);
......
...@@ -29,6 +29,7 @@ extern boolean ignoregameinputs; ...@@ -29,6 +29,7 @@ extern boolean ignoregameinputs;
#define META_SKINCOLOR "SKINCOLOR_T*" #define META_SKINCOLOR "SKINCOLOR_T*"
#define META_COLORRAMP "SKINCOLOR_T*RAMP" #define META_COLORRAMP "SKINCOLOR_T*RAMP"
#define META_SPRITEINFO "SPRITEINFO_T*" #define META_SPRITEINFO "SPRITEINFO_T*"
#define META_GAMETYPE "GAMETYPE_T*"
#define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]" #define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
#define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*" #define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"
......
...@@ -1047,6 +1047,7 @@ enum ...@@ -1047,6 +1047,7 @@ enum
ARCH_SKINCOLOR, ARCH_SKINCOLOR,
ARCH_MOUSE, ARCH_MOUSE,
ARCH_SKIN, ARCH_SKIN,
ARCH_GAMETYPE,
ARCH_TEND=0xFF, ARCH_TEND=0xFF,
}; };
...@@ -1076,6 +1077,7 @@ static const struct { ...@@ -1076,6 +1077,7 @@ static const struct {
{META_SKINCOLOR, ARCH_SKINCOLOR}, {META_SKINCOLOR, ARCH_SKINCOLOR},
{META_MOUSE, ARCH_MOUSE}, {META_MOUSE, ARCH_MOUSE},
{META_SKIN, ARCH_SKIN}, {META_SKIN, ARCH_SKIN},
{META_GAMETYPE, ARCH_GAMETYPE},
{NULL, ARCH_NULL} {NULL, ARCH_NULL}
}; };
...@@ -1404,6 +1406,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1404,6 +1406,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
WRITEUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256 WRITEUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256
break; break;
} }
case ARCH_GAMETYPE:
{
gametype_t *gt = *((gametype_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_GAMETYPE);
WRITEUINT8(save_p, gt - gametypes);
break;
}
default: default:
WRITEUINT8(save_p, ARCH_NULL); WRITEUINT8(save_p, ARCH_NULL);
return 2; return 2;
...@@ -1653,6 +1662,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX) ...@@ -1653,6 +1662,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
case ARCH_SKIN: case ARCH_SKIN:
LUA_PushUserdata(gL, skins[READUINT8(save_p)], META_SKIN); LUA_PushUserdata(gL, skins[READUINT8(save_p)], META_SKIN);
break; break;
case ARCH_GAMETYPE:
LUA_PushUserdata(gL, &gametypes[READUINT8(save_p)], META_GAMETYPE);
break;
case ARCH_TEND: case ARCH_TEND:
return 1; return 1;
} }
......
...@@ -500,7 +500,7 @@ UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data) ...@@ -500,7 +500,7 @@ UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data)
return true; return true;
} }
if ((gametypedefaultrules[gt] & GTR_CAMPAIGN) == 0) if ((gametypes[gt].rules & GTR_CAMPAIGN) == 0)
{ {
// Not a campaign, do whatever you want. // Not a campaign, do whatever you want.
return false; return false;
......
...@@ -5143,7 +5143,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt) ...@@ -5143,7 +5143,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt)
if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE)) if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE))
return true; return true;
if (gt >= 0 && gt < gametypecount && (mapheaderinfo[mapnum]->typeoflevel & gametypetol[gt])) if (gt >= 0 && gt < gametypecount && (mapheaderinfo[mapnum]->typeoflevel & gametypes[gt].typeoflevel))
return true; return true;
return false; return false;
......
...@@ -327,10 +327,6 @@ consvar_t cv_numlaps = CVAR_INIT ("numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT|CV ...@@ -327,10 +327,6 @@ consvar_t cv_numlaps = CVAR_INIT ("numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT|CV
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}}; static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}};
consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT|CV_ALLOWLUA, basenumlaps_cons_t, BaseNumLaps_OnChange); consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT|CV_ALLOWLUA, basenumlaps_cons_t, BaseNumLaps_OnChange);
// Point and time limits for every gametype
INT32 pointlimits[NUMGAMETYPES];
INT32 timelimits[NUMGAMETYPES];
// log elemental hazards -- not a netvar, is local to current player // log elemental hazards -- not a netvar, is local to current player
consvar_t cv_hazardlog = CVAR_INIT ("hazardlog", "Yes", 0, CV_YesNo, NULL); consvar_t cv_hazardlog = CVAR_INIT ("hazardlog", "Yes", 0, CV_YesNo, NULL);
...@@ -443,15 +439,7 @@ const char *netxcmdnames[MAXNETXCMD - 1] = ...@@ -443,15 +439,7 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
*/ */
void D_RegisterServerCommands(void) void D_RegisterServerCommands(void)
{ {
INT32 i; G_UpdateGametypeSelections();
for (i = 0; i < NUMGAMETYPES; 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;
RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor); RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor);
RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref); RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref);
...@@ -1713,7 +1701,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese ...@@ -1713,7 +1701,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
} }
CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d ultmode=%d resetplayers=%d delay=%d skipprecutscene=%d\n", CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d ultmode=%d resetplayers=%d delay=%d skipprecutscene=%d\n",
mapnum, newgametype, pultmode, resetplayers, delay, skipprecutscene); mapnum, newgametype, pultmode, resetplayers, delay, skipprecutscene);
if ((netgame || multiplayer) && !((gametype == newgametype) && (gametypedefaultrules[newgametype] & GTR_CAMPAIGN))) if ((netgame || multiplayer) && !((gametype == newgametype) && (gametypes[newgametype].rules & GTR_CAMPAIGN)))
FLS = false; FLS = false;
if (delay != 2) if (delay != 2)
...@@ -1961,7 +1949,7 @@ static void Command_Map_f(void) ...@@ -1961,7 +1949,7 @@ static void Command_Map_f(void)
{ {
// The player wants us to trek on anyway. Do so. // The player wants us to trek on anyway. Do so.
fromlevelselect = false; fromlevelselect = false;
set_cheated = ((gametypedefaultrules[newgametype] & GTR_CAMPAIGN) == GTR_CAMPAIGN); set_cheated = ((gametypes[newgametype].rules & GTR_CAMPAIGN) == GTR_CAMPAIGN);
} }
} }
else else
...@@ -1969,7 +1957,7 @@ static void Command_Map_f(void) ...@@ -1969,7 +1957,7 @@ static void Command_Map_f(void)
fromlevelselect = fromlevelselect =
( netgame || multiplayer ) && ( netgame || multiplayer ) &&
newgametype == gametype && newgametype == gametype &&
(gametypedefaultrules[newgametype] & GTR_CAMPAIGN); (gametypes[newgametype].rules & GTR_CAMPAIGN);
} }
// Prevent warping to locked levels // Prevent warping to locked levels
...@@ -2297,7 +2285,12 @@ static void Command_Teamchange_f(void) ...@@ -2297,7 +2285,12 @@ static void Command_Teamchange_f(void)
if (COM_Argc() <= 1) if (COM_Argc() <= 1)
{ {
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "red, blue or spectator"); {
if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "red, blue or spectator");
else
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "red or blue");
}
else if (G_GametypeHasSpectators()) else if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "spectator or playing"); CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "spectator or playing");
else else
...@@ -2311,7 +2304,7 @@ static void Command_Teamchange_f(void) ...@@ -2311,7 +2304,7 @@ static void Command_Teamchange_f(void)
NetPacket.packet.newteam = 1; NetPacket.packet.newteam = 1;
else if (!strcasecmp(COM_Argv(1), "blue") || !strcasecmp(COM_Argv(1), "2")) else if (!strcasecmp(COM_Argv(1), "blue") || !strcasecmp(COM_Argv(1), "2"))
NetPacket.packet.newteam = 2; NetPacket.packet.newteam = 2;
else if (!strcasecmp(COM_Argv(1), "spectator") || !strcasecmp(COM_Argv(1), "0")) else if (G_GametypeHasSpectators() && (!strcasecmp(COM_Argv(1), "spectator") || !strcasecmp(COM_Argv(1), "0")))
NetPacket.packet.newteam = 0; NetPacket.packet.newteam = 0;
else else
error = true; error = true;
...@@ -2334,7 +2327,12 @@ static void Command_Teamchange_f(void) ...@@ -2334,7 +2327,12 @@ static void Command_Teamchange_f(void)
if (error) if (error)
{ {
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "red, blue or spectator"); {
if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "red, blue or spectator");
else
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "red or blue");
}
else if (G_GametypeHasSpectators()) else if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "spectator or playing"); CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "spectator or playing");
return; return;
...@@ -2393,9 +2391,14 @@ static void Command_Teamchange2_f(void) ...@@ -2393,9 +2391,14 @@ static void Command_Teamchange2_f(void)
if (COM_Argc() <= 1) if (COM_Argc() <= 1)
{ {
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "red, blue or spectator"); {
if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("changeteam2 <team>: switch to a new team (%s)\n"), "red, blue or spectator");
else
CONS_Printf(M_GetText("changeteam2 <team>: switch to a new team (%s)\n"), "red or blue");
}
else if (G_GametypeHasSpectators()) else if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("changeteam <team>: switch to a new team (%s)\n"), "spectator or playing"); CONS_Printf(M_GetText("changeteam2 <team>: switch to a new team (%s)\n"), "spectator or playing");
else else
CONS_Alert(CONS_NOTICE, M_GetText("This command cannot be used in this gametype.\n")); CONS_Alert(CONS_NOTICE, M_GetText("This command cannot be used in this gametype.\n"));
return; return;
...@@ -2407,7 +2410,7 @@ static void Command_Teamchange2_f(void) ...@@ -2407,7 +2410,7 @@ static void Command_Teamchange2_f(void)
NetPacket.packet.newteam = 1; NetPacket.packet.newteam = 1;
else if (!strcasecmp(COM_Argv(1), "blue") || !strcasecmp(COM_Argv(1), "2")) else if (!strcasecmp(COM_Argv(1), "blue") || !strcasecmp(COM_Argv(1), "2"))
NetPacket.packet.newteam = 2; NetPacket.packet.newteam = 2;
else if (!strcasecmp(COM_Argv(1), "spectator") || !strcasecmp(COM_Argv(1), "0")) else if (G_GametypeHasSpectators() && (!strcasecmp(COM_Argv(1), "spectator") || !strcasecmp(COM_Argv(1), "0")))
NetPacket.packet.newteam = 0; NetPacket.packet.newteam = 0;
else else
error = true; error = true;
...@@ -2431,7 +2434,12 @@ static void Command_Teamchange2_f(void) ...@@ -2431,7 +2434,12 @@ static void Command_Teamchange2_f(void)
if (error) if (error)
{ {
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
CONS_Printf(M_GetText("changeteam2 <team>: switch to a new team (%s)\n"), "red, blue or spectator"); {
if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("changeteam2 <team>: switch to a new team (%s)\n"), "red, blue or spectator");
else
CONS_Printf(M_GetText("changeteam2 <team>: switch to a new team (%s)\n"), "red or blue");
}
else if (G_GametypeHasSpectators()) else if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("changeteam2 <team>: switch to a new team (%s)\n"), "spectator or playing"); CONS_Printf(M_GetText("changeteam2 <team>: switch to a new team (%s)\n"), "spectator or playing");
return; return;
...@@ -2498,7 +2506,12 @@ static void Command_ServerTeamChange_f(void) ...@@ -2498,7 +2506,12 @@ static void Command_ServerTeamChange_f(void)
if (G_TagGametype()) if (G_TagGametype())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "it, notit, playing, or spectator"); CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "it, notit, playing, or spectator");
else if (G_GametypeHasTeams()) else if (G_GametypeHasTeams())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "red, blue or spectator"); {
if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "red, blue or spectator");
else
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "red or blue");
}
else if (G_GametypeHasSpectators()) else if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "spectator or playing"); CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "spectator or playing");
else else
...@@ -2525,7 +2538,7 @@ static void Command_ServerTeamChange_f(void) ...@@ -2525,7 +2538,7 @@ static void Command_ServerTeamChange_f(void)
NetPacket.packet.newteam = 1; NetPacket.packet.newteam = 1;
else if (!strcasecmp(COM_Argv(2), "blue") || !strcasecmp(COM_Argv(2), "2")) else if (!strcasecmp(COM_Argv(2), "blue") || !strcasecmp(COM_Argv(2), "2"))
NetPacket.packet.newteam = 2; NetPacket.packet.newteam = 2;
else if (!strcasecmp(COM_Argv(2), "spectator") || !strcasecmp(COM_Argv(2), "0")) else if (G_GametypeHasSpectators() && (!strcasecmp(COM_Argv(1), "spectator") || !strcasecmp(COM_Argv(1), "0")))
NetPacket.packet.newteam = 0; NetPacket.packet.newteam = 0;
else else
error = true; error = true;
...@@ -2550,7 +2563,12 @@ static void Command_ServerTeamChange_f(void) ...@@ -2550,7 +2563,12 @@ static void Command_ServerTeamChange_f(void)
if (G_TagGametype()) if (G_TagGametype())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "it, notit, playing, or spectator"); CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "it, notit, playing, or spectator");
else if (G_GametypeHasTeams()) else if (G_GametypeHasTeams())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "red, blue or spectator"); {
if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "red, blue or spectator");
else
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "red or blue");
}
else if (G_GametypeHasSpectators()) else if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "spectator or playing"); CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "spectator or playing");
return; return;
...@@ -3864,7 +3882,7 @@ static void Command_ShowGametype_f(void) ...@@ -3864,7 +3882,7 @@ static void Command_ShowGametype_f(void)
// get name string for current gametype // get name string for current gametype
if (gametype >= 0 && gametype < gametypecount) if (gametype >= 0 && gametype < gametypecount)
gametypestr = Gametype_Names[gametype]; gametypestr = gametypes[gametype].name;
if (gametypestr) if (gametypestr)
CONS_Printf(M_GetText("Current gametype is %s\n"), gametypestr); CONS_Printf(M_GetText("Current gametype is %s\n"), gametypestr);
...@@ -4126,9 +4144,9 @@ void D_GameTypeChanged(INT32 lastgametype) ...@@ -4126,9 +4144,9 @@ void D_GameTypeChanged(INT32 lastgametype)
const char *oldgt = NULL, *newgt = NULL; const char *oldgt = NULL, *newgt = NULL;
if (lastgametype >= 0 && lastgametype < gametypecount) if (lastgametype >= 0 && lastgametype < gametypecount)
oldgt = Gametype_Names[lastgametype]; oldgt = gametypes[lastgametype].name;
if (gametype >= 0 && lastgametype < gametypecount) if (gametype >= 0 && lastgametype < gametypecount)
newgt = Gametype_Names[gametype]; newgt = gametypes[gametype].name;
if (oldgt && newgt) if (oldgt && newgt)
CONS_Printf(M_GetText("Gametype was changed from %s to %s\n"), oldgt, newgt); CONS_Printf(M_GetText("Gametype was changed from %s to %s\n"), oldgt, newgt);
...@@ -4142,55 +4160,13 @@ void D_GameTypeChanged(INT32 lastgametype) ...@@ -4142,55 +4160,13 @@ void D_GameTypeChanged(INT32 lastgametype)
else if (!cv_itemrespawn.changed || lastgametype == GT_COMPETITION) else if (!cv_itemrespawn.changed || lastgametype == GT_COMPETITION)
CV_SetValue(&cv_itemrespawn, 1); CV_SetValue(&cv_itemrespawn, 1);
switch (gametype) if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
{ {
case GT_COOP: CV_SetValue(&cv_timelimit, gametypes[gametype].timelimit);
if (!cv_itemrespawntime.changed) CV_SetValue(&cv_pointlimit, gametypes[gametype].pointlimit);
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
break;
case GT_MATCH:
case GT_TEAMMATCH:
if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
{
// default settings for match: timelimit 10 mins, no pointlimit
CV_SetValue(&cv_pointlimit, 0);
CV_SetValue(&cv_timelimit, 10);
}
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
break;
case GT_TAG:
case GT_HIDEANDSEEK:
if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
{
// default settings for tag: 5 mins, no pointlimit
// Note that tag mode also uses an alternate timing mechanism in tandem with timelimit.
CV_SetValue(&cv_timelimit, 5);
CV_SetValue(&cv_pointlimit, 0);
}
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
break;
case GT_CTF:
if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
{
// default settings for CTF: no timelimit, pointlimit 5
CV_SetValue(&cv_timelimit, 0);
CV_SetValue(&cv_pointlimit, 5);
}
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;
} }
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
} }
else if (!multiplayer && !netgame) else if (!multiplayer && !netgame)
{ {
......
...@@ -114,7 +114,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) ...@@ -114,7 +114,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
netbuffer->u.serverinfo.refusereason = GetRefuseReason(node); netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], strncpy(netbuffer->u.serverinfo.gametypename, gametypes[gametype].name,
sizeof netbuffer->u.serverinfo.gametypename); sizeof netbuffer->u.serverinfo.gametypename);
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
......
...@@ -11775,7 +11775,12 @@ void P_SpawnPlayer(INT32 playernum) ...@@ -11775,7 +11775,12 @@ void P_SpawnPlayer(INT32 playernum)
{ {
// Fix stupid non spectator spectators. // Fix stupid non spectator spectators.
if (!p->spectator && !p->ctfteam) if (!p->spectator && !p->ctfteam)
p->spectator = true; {
if (G_GametypeHasSpectators())
p->spectator = true;
else
p->ctfteam = 1;
}
} }
if ((netgame || multiplayer) && ((gametyperules & GTR_SPAWNINVUL) || leveltime) && !p->spectator && !(maptol & TOL_NIGHTS)) if ((netgame || multiplayer) && ((gametyperules & GTR_SPAWNINVUL) || leveltime) && !p->spectator && !(maptol & TOL_NIGHTS))
......
...@@ -7726,7 +7726,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) ...@@ -7726,7 +7726,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// This is needed. Don't touch. // This is needed. Don't touch.
maptol = mapheaderinfo[gamemap-1]->typeoflevel; maptol = mapheaderinfo[gamemap-1]->typeoflevel;
gametyperules = gametypedefaultrules[gametype]; gametyperules = gametypes[gametype].rules;
CON_Drawer(); // let the user know what we are going to do CON_Drawer(); // let the user know what we are going to do
I_FinishUpdate(); // page flip or blit buffer I_FinishUpdate(); // page flip or blit buffer
......