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

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
  • 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
  • Jisk/srb-2-beef-jerky
117 results
Select Git revision
Show changes
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -108,6 +108,7 @@ char *nongnu_strcasestr(const char *in, const char *what);
int startswith (const char *base, const char *tag);
int endswith (const char *base, const char *tag);
char *xstrtok(char *line, const char *delims);
#if defined (_WIN32) || defined (__HAIKU__)
#define HAVE_DOSSTR_FUNCS
......
......@@ -206,5 +206,20 @@ void I_GetCursorPosition(INT32 *x, INT32 *y)
(void)y;
}
const char *I_GetSysName(void)
{
return NULL;
}
void I_SetTextInputMode(boolean active)
{
(void)active;
}
boolean I_GetTextInputMode(void)
{
return false;
}
#include "../sdl/dosstr.c"
......@@ -5,8 +5,6 @@
rendermode_t rendermode = render_none;
rendermode_t chosenrendermode = render_none;
boolean highcolor = false;
boolean allow_fullscreen = false;
consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL);
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -229,6 +229,7 @@ static UINT8 cutscene_boostspeed = 0;
char stjrintro[9] = "STJRI000";
static huddrawlist_h luahuddrawlist_title;
static huddrawlist_h luahuddrawlist_continue[2];
//
// This alters the text string cutscene_disptext.
......@@ -297,7 +298,7 @@ static void F_NewCutscene(const char *basetext)
cutscene_basetext = basetext;
memset(cutscene_disptext,0,sizeof(cutscene_disptext));
cutscene_writeptr = cutscene_baseptr = 0;
cutscene_textspeed = 9;
cutscene_textspeed = 8;
cutscene_textcount = TICRATE/2;
}
......@@ -313,22 +314,22 @@ const char *introtext[NUMINTROSCENES];
static tic_t introscenetime[NUMINTROSCENES] =
{
5*TICRATE, // STJr Presents
11*TICRATE + (TICRATE/2), // Two months had passed since...
15*TICRATE + (TICRATE/2), // As it was about to drain the rings...
14*TICRATE, // What Sonic, Tails, and Knuckles...
18*TICRATE, // About once every year, a strange...
19*TICRATE + (TICRATE/2), // Curses! Eggman yelled. That ridiculous...
19*TICRATE + (TICRATE/4), // It was only later that he had an idea...
10*TICRATE + (TICRATE/2), // Before beginning his scheme, Eggman decided to give Sonic...
16*TICRATE, // We're ready to fire in 15 seconds, the robot said...
16*TICRATE, // Meanwhile, Sonic was tearing across the zones...
10*TICRATE + (TICRATE/2), // Two months had passed since...
12*TICRATE + ((TICRATE/4) * 3), // As it was about to drain the rings...
12*TICRATE + (TICRATE/4), // What Sonic, Tails, and Knuckles...
16*TICRATE, // About once every year, a strange...
20*TICRATE + (TICRATE/2), // Curses! Eggman yelled. That ridiculous...
18*TICRATE + (TICRATE/4), // It was only later that he had an idea...
9*TICRATE + (TICRATE/2), // Before beginning his scheme, Eggman decided to give Sonic...
14*TICRATE, // We're ready to fire in 15 seconds, the robot said...
14*TICRATE + (TICRATE/2), // Meanwhile, Sonic was tearing across the zones...
16*TICRATE + (TICRATE/2), // Sonic knew he was getting closer to the city...
17*TICRATE, // Greenflower City was gone...
7*TICRATE, // You're not quite as dead as we thought, huh?...
11*TICRATE + (TICRATE/2), // Greenflower City was gone...
8*TICRATE, // You're not quite as dead as we thought, huh?...
8*TICRATE, // We'll see... let's give you a quick warm up...
18*TICRATE + (TICRATE/2), // Eggman took this as his cue and blasted off...
16*TICRATE, // Easy! We go find Eggman and stop his...
25*TICRATE, // I'm just finding what mission obje...
15*TICRATE, // Easy! We go find Eggman and stop his...
23*TICRATE, // I'm just finding what mission obje...
};
// custom intros
......@@ -1064,12 +1065,12 @@ static const char *credits[] = {
"Julio \"Chaos Zero 64\" Guir",
"\"Hanicef\"",
"\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
"\"hazepastel\"",
"Kepa \"Nev3r\" Iceta",
"Thomas \"Shadow Hog\" Igoe",
"Iestyn \"Monster Iestyn\" Jealous",
"\"Kaito Sinclaire\"",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
"\"katsy\"",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
"\"Lat'\"", // SRB2-CHAT, the chat window from Kart
"\"LZA\"",
......@@ -1079,6 +1080,7 @@ static const char *credits[] = {
"Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol
"John \"JTE\" Muniz",
"Colin \"Sonict\" Pfaff",
"\"Radicalicious\"",
"James \"james\" Robert Roman",
"Sean \"Sryder13\" Ryder",
"Ehab \"Wolfy\" Saeed",
......@@ -1102,7 +1104,8 @@ static const char *credits[] = {
"\"ChrispyPixels\"",
"Paul \"Boinciel\" Clempson",
"Sally \"TehRealSalt\" Cochenour",
"\"Dave Lite\"",
"\"DaJumpJump\"", // New Ringslinger graphics (2.2.14)
"\"DeltaSanic\"",
"Desmond \"Blade\" DesJardins",
"Sherman \"CoatRack\" DesJardins",
"\"DirkTheHusky\"",
......@@ -1118,6 +1121,7 @@ static const char *credits[] = {
"Alice \"Alacroix\" de Lemos",
"Logan \"Hyperchaotix\" McCloud",
"Alexander \"DrTapeworm\" Moench-Ford",
"\"orbitalviolet\"", // summit showdown hehehehe (aka Evertone)
"Andrew \"Senku Niola\" Moran",
"\"MotorRoach\"",
"Phillip \"TelosTurntable\" Robinson",
......@@ -1126,6 +1130,7 @@ static const char *credits[] = {
"David \"Instant Sonic\" Spencer Jr.",
"\"SSNTails\"",
"Daniel \"Inazuma\" Trinh",
"Samuel \"Spectorious\" Tuttle",
"\"VelocitOni\"",
"Jarrett \"JEV3\" Voight",
"",
......@@ -1134,6 +1139,7 @@ static const char *credits[] = {
"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo
"Malcolm \"RedXVI\" Brown",
"Dave \"DemonTomatoDave\" Bulmer",
"Dan Cidoni", // aka Krabs
"Paul \"Boinciel\" Clempson",
"\"Cyan Helkaraxe\"",
"Claire \"clairebun\" Ellis",
......@@ -1152,24 +1158,30 @@ static const char *credits[] = {
"Colette \"fickleheart\" Bordelon",
"Hank \"FuriousFox\" Brannock",
"Matthew \"Fawfulfan\" Chapman",
"Dan Cidoni", // aka Krabs
"Paul \"Boinciel\" Clempson",
"Sally \"TehRealSalt\" Cochenour",
"Desmond \"Blade\" DesJardins",
"Sherman \"CoatRack\" DesJardins",
"Ben \"Mystic\" Geyer",
"Nathan \"Jazz\" Giroux",
"\"GomaTheMascar\"",
"Vivian \"toaster\" Grannell",
"James \"SeventhSentinel\" Hall",
"Kepa \"Nev3r\" Iceta",
"Thomas \"Shadow Hog\" Igoe",
"Mujamel \"MK\" Khan",
"\"Kaito Sinclaire\"",
"Alexander \"DrTapeworm\" Moench-Ford",
"\"Radicalicious\"",
"\"Revan\"",
"Anna \"QueenDelta\" Sandlin",
"Wessel \"sphere\" Smit",
"\"SSNTails\"",
"Aaron \"Othius\" Stojkov",
"Rob Tisdell",
"\"Torgo\"",
"Samuel \"Spectorious\" Tuttle",
"Jarrett \"JEV3\" Voight",
"Johnny \"Sonikku\" Wallbank",
"Marco \"mazmazz\" Zafra",
......@@ -1281,6 +1293,9 @@ void F_CreditDrawer(void)
UINT8 colornum;
const UINT8 *colormap;
// compensation for y on non-green resolutions, used to prevent text from disappearing before reaching the top
UINT16 compy = (vid.height - (BASEVIDHEIGHT * vid.dup)) / 2;
if (players[consoleplayer].skincolor)
colornum = players[consoleplayer].skincolor;
else
......@@ -1312,17 +1327,17 @@ void F_CreditDrawer(void)
y += 80<<FRACBITS;
break;
case 1:
if (y>>FRACBITS > -20)
if (y>>FRACBITS > -20-compy)
V_DrawCreditString((160 - (V_CreditStringWidth(&credits[i][1])>>1))<<FRACBITS, y, 0, &credits[i][1]);
y += 30<<FRACBITS;
break;
case 2:
if (y>>FRACBITS > -10)
if (y>>FRACBITS > -10-compy)
V_DrawStringAtFixed((BASEVIDWIDTH-V_StringWidth(&credits[i][1], V_ALLOWLOWERCASE|V_YELLOWMAP))<<FRACBITS>>1, y, V_ALLOWLOWERCASE|V_YELLOWMAP, &credits[i][1]);
y += 12<<FRACBITS;
break;
default:
if (y>>FRACBITS > -10)
if (y>>FRACBITS > -10-compy)
V_DrawStringAtFixed(32<<FRACBITS, y, V_ALLOWLOWERCASE, credits[i]);
y += 12<<FRACBITS;
break;
......@@ -2332,7 +2347,7 @@ void F_SkyScroll(const char *patchname)
}
#define LOADTTGFX(arr, name, maxf) \
lumpnum = W_CheckNumForName(name); \
lumpnum = W_CheckNumForPatchName(name); \
if (lumpnum != LUMPERROR) \
{ \
arr[0] = W_CachePatchName(name, PU_PATCH_LOWPRIORITY); \
......@@ -2346,7 +2361,7 @@ else if (strlen(name) <= 6) \
{ \
sprintf(&lumpname[cnt], "%.2hu", (UINT16)(i+1)); \
lumpname[8] = 0; \
lumpnum = W_CheckNumForName(lumpname); \
lumpnum = W_CheckNumForPatchName(lumpname); \
if (lumpnum != LUMPERROR) \
arr[i] = W_CachePatchName(lumpname, PU_PATCH_LOWPRIORITY); \
else \
......@@ -3431,7 +3446,7 @@ void F_TitleScreenTicker(boolean run)
{
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -3527,11 +3542,16 @@ void F_TitleDemoTicker(void)
// ==========
static skin_t *contskins[2];
static UINT8 cont_spr2[2][6];
static UINT16 cont_spr2[2][6];
static UINT8 *contcolormaps[2];
static player_t *contPlayers[2];
static skincolornum_t contColors[2]; // it's possible to change your skincolor in the continue screen, so this is for Lua to identify the skincolor that was used to cache the colormap
static boolean contOverrides[2];
void F_StartContinue(void)
{
UINT8 i;
I_Assert(!netgame && !multiplayer);
if (continuesInSession && players[consoleplayer].continues <= 0)
......@@ -3554,9 +3574,12 @@ void F_StartContinue(void)
S_ChangeMusicInternal("_conti", false);
S_StopSounds();
contPlayers[0] = &players[consoleplayer];
contskins[0] = skins[players[consoleplayer].skin];
cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT1, NULL);
cont_spr2[0][2] = contskins[0]->contangle & 7;
contColors[0] = players[consoleplayer].skincolor;
contcolormaps[0] = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE);
cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes;
cont_spr2[0][5] = max(1, contskins[0]->contspeed);
......@@ -3570,9 +3593,12 @@ void F_StartContinue(void)
else // HACK
secondplaya = 1;
contPlayers[1] = &players[secondplaya];
contskins[1] = skins[players[secondplaya].skin];
cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT4, NULL);
cont_spr2[1][2] = (contskins[1]->contangle >> 3) & 7;
contColors[1] = players[secondplaya].skincolor;
contcolormaps[1] = R_GetTranslationColormap(players[secondplaya].skin, players[secondplaya].skincolor, GTC_CACHE);
cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes;
if (cont_spr2[1][0] == SPR2_CNT4)
......@@ -3592,6 +3618,58 @@ void F_StartContinue(void)
timetonext = (11*TICRATE)+11;
continuetime = 0;
// allocate and/or clear Lua continue screen draw lists
for (i = 0; i < 2; i++)
{
if (!LUA_HUD_IsDrawListValid(luahuddrawlist_continue[i]))
{
LUA_HUD_DestroyDrawList(luahuddrawlist_continue[i]);
luahuddrawlist_continue[i] = LUA_HUD_CreateDrawList();
}
LUA_HUD_ClearDrawList(luahuddrawlist_continue[i]);
contOverrides[i] = false;
}
}
static void F_DestroyContinueDrawLists(void)
{
UINT8 i;
for (i = 0; i < 2; i++)
{
LUA_HUD_DestroyDrawList(luahuddrawlist_continue[i]);
luahuddrawlist_continue[i] = NULL;
contOverrides[i] = false;
}
}
static void F_DrawContinueCharacter(INT32 dx, INT32 dy, UINT8 n)
{
spritedef_t *sprdef;
spriteframe_t *sprframe;
patch_t *patch;
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_continue[n]);
contOverrides[n] = LUA_HookCharacterHUD
(
HUD_HOOK(continue), luahuddrawlist_continue[n], contPlayers[n],
dx, dy, contskins[n]->highresscale,
(INT32)(contskins[n]->skinnum), cont_spr2[n][0], cont_spr2[n][1], cont_spr2[n][2] + 1, contColors[n], // add 1 to rotation to convert internal angle numbers (0-7) to WAD editor angle numbers (1-8)
imcontinuing ? continuetime : timetonext, imcontinuing
);
}
LUA_HUD_DrawList(luahuddrawlist_continue[n]);
if (contOverrides[n] == true)
return;
sprdef = &contskins[n]->sprites[cont_spr2[n][0]];
sprframe = &sprdef->spriteframes[cont_spr2[n][1]];
patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);
V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);
}
//
......@@ -3600,8 +3678,6 @@ void F_StartContinue(void)
//
void F_ContinueDrawer(void)
{
spritedef_t *sprdef;
spriteframe_t *sprframe;
patch_t *patch;
INT32 i, x = (BASEVIDWIDTH>>1), ncontinues = players[consoleplayer].continues;
char numbuf[9] = "CONTNUM*";
......@@ -3646,7 +3722,7 @@ void F_ContinueDrawer(void)
else if (ncontinues > 10)
{
if (!(continuetime & 1) || continuetime > 17)
V_DrawContinueIcon(x, 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor);
V_DrawContinueIcon(x, 68, 0, contskins[0]->skinnum, contColors[0]);
V_DrawScaledPatch(x+12, 66, 0, stlivex);
V_DrawRightAlignedString(x+38, 64, 0,
va("%d",(imcontinuing ? ncontinues-1 : ncontinues)));
......@@ -3660,7 +3736,7 @@ void F_ContinueDrawer(void)
{
if (i == (ncontinues/2) && ((continuetime & 1) || continuetime > 17))
continue;
V_DrawContinueIcon(x - (i*30), 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor);
V_DrawContinueIcon(x - (i*30), 68, 0, contskins[0]->skinnum, contColors[0]);
}
x = BASEVIDWIDTH>>1;
}
......@@ -3700,21 +3776,12 @@ void F_ContinueDrawer(void)
else if (lift[0] > TICRATE+5)
lift[0] = TICRATE+5;
#define drawchar(dx, dy, n) {\
sprdef = &contskins[n]->sprites[cont_spr2[n][0]];\
sprframe = &sprdef->spriteframes[cont_spr2[n][1]];\
patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);\
V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);\
}
if (offsy < 0)
drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
if (contskins[1])
drawchar((BASEVIDWIDTH<<(FRACBITS-1))+offsx, ((140-lift[1])<<FRACBITS)+offsy, 1);
F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))+offsx, ((140-lift[1])<<FRACBITS)+offsy, 1);
if (offsy >= 0)
drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
#undef drawchar
F_DrawContinueCharacter((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])<<FRACBITS)-offsy, 0);
if (timetonext > (11*TICRATE))
V_DrawFadeScreen(31, timetonext-(11*TICRATE));
......@@ -3730,6 +3797,7 @@ void F_ContinueTicker(void)
{
if (!(--timetonext))
{
F_DestroyContinueDrawLists();
Command_ExitGame_f();
return;
}
......@@ -3739,6 +3807,7 @@ void F_ContinueTicker(void)
{
if (++continuetime == 3*TICRATE)
{
F_DestroyContinueDrawLists();
G_Continue();
return;
}
......@@ -4058,7 +4127,7 @@ static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *b
// reuse:
// cutnum -> promptnum
// scenenum -> pagenum
lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname);
lumpnum_t iconlump = W_CheckNumForPatchName(textprompts[cutnum]->page[scenenum].iconname);
*pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4;
*rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside);
......@@ -4384,11 +4453,10 @@ void F_GetPromptPageByNamedTag(const char *tag, INT32 *promptnum, INT32 *pagenum
if (!tag || !tag[0])
return;
strncpy(suffixedtag, tag, 33);
suffixedtag[32] = 0;
strncpy(suffixedtag, tag, sizeof(suffixedtag)-1);
if (tutorialmode)
suffixed = F_GetTextPromptTutorialTag(suffixedtag, 33);
suffixed = F_GetTextPromptTutorialTag(suffixedtag, sizeof(suffixedtag)-1);
for (*promptnum = 0 + tutorialpromptnum; *promptnum < MAX_PROMPTS; (*promptnum)++)
{
......@@ -4451,7 +4519,7 @@ void F_TextPromptDrawer(void)
if (!promptactive)
return;
iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname);
iconlump = W_CheckNumForPatchName(textprompts[cutnum]->page[scenenum].iconname);
F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr);
// Draw gfx first
......@@ -4521,9 +4589,9 @@ void F_TextPromptDrawer(void)
players[j].powers[pw_nocontrol] = 1;\
if (players[j].mo)\
{\
if (players[j].mo->state == states+S_PLAY_STND && players[j].mo->tics != -1)\
if (P_IsPlayerInState(&players[j], S_PLAY_STND) && players[j].mo->tics != -1)\
players[j].mo->tics++;\
else if (players[j].mo->state == states+S_PLAY_WAIT)\
else if (P_IsPlayerInState(&players[j], S_PLAY_WAIT))\
P_SetMobjState(players[j].mo, S_PLAY_STND);\
}\
}
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -96,7 +96,7 @@ typedef enum
extern ttmode_enum ttmode;
extern UINT8 ttscale;
// ttmode user vars
extern char ttname[9];
extern char ttname[8+1];
extern INT16 ttx;
extern INT16 tty;
extern INT16 ttloop;
......
......@@ -569,7 +569,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
if (rendermode == render_opengl)
{
// send in the wipe type and wipe frame because we need to cache the graphic
HWR_DoTintedWipe(wipetype, wipeframe-1);
HWR_DoWipe(wipetype, wipeframe-1);
}
else
#endif
......
......@@ -444,12 +444,11 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
#if defined(__linux__) || defined(__FreeBSD__)
if (dent->d_type == DT_UNKNOWN)
if (lstat(searchpath,&fsstat) == 0 && S_ISDIR(fsstat.st_mode))
if (dent->d_type == DT_UNKNOWN || dent->d_type == DT_LNK)
if (stat(searchpath,&fsstat) == 0 && S_ISDIR(fsstat.st_mode))
dent->d_type = DT_DIR;
// Linux and FreeBSD has a special field for file type on dirent, so use that to speed up lookups.
// FIXME: should we also follow symlinks?
if (dent->d_type == DT_DIR && depthleft)
#else
if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
......@@ -699,6 +698,15 @@ static void initdirpath(char *dirpath, size_t *dirpathindex, int depthleft)
dirpathindex[depthleft]--;
}
//sortdir by name?
static int lumpnamecompare(const void *A, const void *B)
{
const lumpinfo_t *pA = A;
const lumpinfo_t *pB = B;
return strcmp((pA->fullname), (pB->fullname));
}
lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders)
{
DIR **dirhandle;
......@@ -889,6 +897,9 @@ lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders)
free(dirpathindex);
free(dirhandle);
//sort files and directories
qsort (lumpinfo, numlumps, sizeof(lumpinfo_t), lumpnamecompare);
(*nlmp) = numlumps;
return lumpinfo;
}
......@@ -1179,13 +1190,13 @@ boolean preparefilemenu(boolean samedepth)
size_t i;
if (filenamebuf == NULL)
filenamebuf = calloc(sizeof(char) * MAX_WADPATH, numwadfiles);
filenamebuf = calloc(numwadfiles, sizeof(char) * MAX_WADPATH);
for (i = 0; i < numwadfiles; i++)
{
if (!filenamebuf[i][0])
{
strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH);
strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH-1);
filenamebuf[i][MAX_WADPATH - 1] = '\0';
nameonly(filenamebuf[i]);
}
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -67,6 +67,8 @@ static UINT8 *metalbuffer = NULL;
static UINT8 *metal_p;
static UINT16 metalversion;
consvar_t cv_resyncdemo = CVAR_INIT("resyncdemo", "On", 0, CV_OnOff, NULL);
// extra data stuff (events registered this frame while recording)
static struct {
UINT8 flags; // EZT flags
......@@ -409,7 +411,7 @@ void G_WriteGhostTic(mobj_t *ghost)
{
oldghost.sprite2 = ghost->sprite2;
ziptic |= GZT_SPR2;
WRITEUINT8(demo_p,oldghost.sprite2);
WRITEUINT16(demo_p,oldghost.sprite2);
}
// Check for sprite set changes
......@@ -509,7 +511,7 @@ void G_WriteGhostTic(mobj_t *ghost)
temp = ghost->player->followmobj->z-ghost->z;
WRITEFIXED(demo_p,temp);
if (followtic & FZT_SKIN)
WRITEUINT8(demo_p,ghost->player->followmobj->sprite2);
WRITEUINT16(demo_p,ghost->player->followmobj->sprite2);
WRITEUINT16(demo_p,ghost->player->followmobj->sprite);
WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK));
WRITEUINT16(demo_p,ghost->player->followmobj->color);
......@@ -545,6 +547,9 @@ void G_ConsGhostTic(void)
testmo = players[0].mo;
if (P_MobjWasRemoved(testmo))
return; // No valid mobj exists, probably because of unexpected quit
// Grab ghost data.
ziptic = READUINT8(demo_p);
if (ziptic & GZT_XYZ)
......@@ -571,7 +576,7 @@ void G_ConsGhostTic(void)
if (ziptic & GZT_FRAME)
demo_p++;
if (ziptic & GZT_SPR2)
demo_p++;
demo_p += (demoversion < 0x0011) ? sizeof(UINT8) : sizeof(UINT16);
if (ziptic & GZT_EXTRA)
{ // But wait, there's more!
......@@ -605,7 +610,7 @@ void G_ConsGhostTic(void)
mobj = NULL;
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mobj = (mobj_t *)th;
if (mobj->type == (mobjtype_t)type && mobj->x == x && mobj->y == y && mobj->z == z)
......@@ -640,7 +645,7 @@ void G_ConsGhostTic(void)
// momx, momy and momz
demo_p += (demoversion < 0x000e) ? sizeof(INT16) * 3 : sizeof(fixed_t) * 3;
if (followtic & FZT_SKIN)
demo_p++;
demo_p += (demoversion < 0x0011) ? sizeof(UINT8) : sizeof(UINT16);
demo_p += sizeof(UINT16);
demo_p++;
demo_p += (demoversion==0x000c) ? 1 : sizeof(UINT16);
......@@ -660,11 +665,14 @@ void G_ConsGhostTic(void)
CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n"));
demosynced = false;
P_UnsetThingPosition(testmo);
testmo->x = oldghost.x;
testmo->y = oldghost.y;
P_SetThingPosition(testmo);
testmo->z = oldghost.z;
if (cv_resyncdemo.value)
{
P_UnsetThingPosition(testmo);
testmo->x = oldghost.x;
testmo->y = oldghost.y;
P_SetThingPosition(testmo);
testmo->z = oldghost.z;
}
}
if (*demo_p == DEMOMARKER)
......@@ -722,7 +730,7 @@ void G_GhostTicker(void)
if (ziptic & GZT_FRAME)
g->oldmo.frame = READUINT8(g->p);
if (ziptic & GZT_SPR2)
g->oldmo.sprite2 = READUINT8(g->p);
g->oldmo.sprite2 = (g->version < 0x0011) ? READUINT8(g->p) : READUINT16(g->p);
// Update ghost
P_UnsetThingPosition(g->mo);
......@@ -771,7 +779,7 @@ void G_GhostTicker(void)
{
g->mo->destscale = READFIXED(g->p);
if (g->mo->destscale != g->mo->scale)
P_SetScale(g->mo, g->mo->destscale);
P_SetScale(g->mo, g->mo->destscale, false);
}
if (xziptic & EZT_THOKMASK)
{ // Let's only spawn ONE of these per frame, thanks.
......@@ -810,7 +818,7 @@ void G_GhostTicker(void)
mobj->frame = (states[mobjinfo[type].spawnstate].frame & FF_FRAMEMASK) | tr_trans60<<FF_TRANSSHIFT;
mobj->color = g->mo->color;
mobj->skin = g->mo->skin;
P_SetScale(mobj, (mobj->destscale = g->mo->scale));
P_SetScale(mobj, g->mo->scale, true);
if (type == MT_THOK) // spintrail-specific modification for MT_THOK
{
......@@ -926,7 +934,7 @@ void G_GhostTicker(void)
else
follow->destscale = g->mo->destscale;
if (follow->destscale != follow->scale)
P_SetScale(follow, follow->destscale);
P_SetScale(follow, follow->destscale, false);
P_UnsetThingPosition(follow);
temp = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
......@@ -937,7 +945,7 @@ void G_GhostTicker(void)
follow->z = g->mo->z + temp;
P_SetThingPosition(follow);
if (followtic & FZT_SKIN)
follow->sprite2 = READUINT8(g->p);
follow->sprite2 = (g->version < 0x0011) ? READUINT8(g->p) : READUINT16(g->p);
else
follow->sprite2 = 0;
follow->sprite = READUINT16(g->p);
......@@ -1052,7 +1060,7 @@ void G_ReadMetalTic(mobj_t *metal)
oldmetal.frame = G_ConvertOldFrameFlags(oldmetal.frame);
}
if (ziptic & GZT_SPR2)
oldmetal.sprite2 = READUINT8(metal_p);
oldmetal.sprite2 = (metalversion < 0x0011) ? READUINT8(metal_p) : READUINT16(metal_p);
// Set movement, position, and angle
// oldmetal contains where you're supposed to be.
......@@ -1079,7 +1087,7 @@ void G_ReadMetalTic(mobj_t *metal)
{
metal->destscale = READFIXED(metal_p);
if (metal->destscale != metal->scale)
P_SetScale(metal, metal->destscale);
P_SetScale(metal, metal->destscale, false);
}
if (xziptic & EZT_THOKMASK)
{ // Let's only spawn ONE of these per frame, thanks.
......@@ -1117,7 +1125,7 @@ void G_ReadMetalTic(mobj_t *metal)
mobj->angle = metal->angle;
mobj->color = metal->color;
mobj->skin = metal->skin;
P_SetScale(mobj, (mobj->destscale = metal->scale));
P_SetScale(mobj, metal->scale, true);
if (type == MT_THOK) // spintrail-specific modification for MT_THOK
{
......@@ -1184,7 +1192,7 @@ void G_ReadMetalTic(mobj_t *metal)
else
follow->destscale = metal->destscale;
if (follow->destscale != follow->scale)
P_SetScale(follow, follow->destscale);
P_SetScale(follow, follow->destscale, false);
P_UnsetThingPosition(follow);
temp = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
......@@ -1195,7 +1203,7 @@ void G_ReadMetalTic(mobj_t *metal)
follow->z = metal->z + temp;
P_SetThingPosition(follow);
if (followtic & FZT_SKIN)
follow->sprite2 = READUINT8(metal_p);
follow->sprite2 = (metalversion < 0x0011) ? READUINT8(metal_p) : READUINT16(metal_p);
else
follow->sprite2 = 0;
follow->sprite = READUINT16(metal_p);
......@@ -1203,7 +1211,7 @@ void G_ReadMetalTic(mobj_t *metal)
if (metalversion < 0x000f)
follow->frame = G_ConvertOldFrameFlags(follow->frame);
follow->angle = metal->angle;
follow->color = (metalversion==0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
follow->color = (metalversion == 0x000c) ? READUINT8(metal_p) : READUINT16(metal_p);
if (!(followtic & FZT_SPAWNED))
{
......@@ -1304,7 +1312,7 @@ void G_WriteMetalTic(mobj_t *metal)
{
oldmetal.sprite2 = metal->sprite2;
ziptic |= GZT_SPR2;
WRITEUINT8(demo_p,oldmetal.sprite2);
WRITEUINT16(demo_p,oldmetal.sprite2);
}
// Check for sprite set changes
......@@ -1379,7 +1387,7 @@ void G_WriteMetalTic(mobj_t *metal)
temp = metal->player->followmobj->z-metal->z;
WRITEFIXED(demo_p,temp);
if (followtic & FZT_SKIN)
WRITEUINT8(demo_p,metal->player->followmobj->sprite2);
WRITEUINT16(demo_p,metal->player->followmobj->sprite2);
WRITEUINT16(demo_p,metal->player->followmobj->sprite);
WRITEUINT32(demo_p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits
WRITEUINT16(demo_p,metal->player->followmobj->color);
......@@ -1442,6 +1450,7 @@ void G_BeginRecording(void)
char *filename;
UINT16 totalfiles;
UINT8 *m;
save_t savebuffer;
if (demo_p)
return;
......@@ -1591,7 +1600,11 @@ void G_BeginRecording(void)
}
// Save netvar data
CV_SaveDemoVars(&demo_p);
savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_SaveDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
memset(&oldcmd,0,sizeof(oldcmd));
memset(&oldghost,0,sizeof(oldghost));
......@@ -1650,7 +1663,7 @@ static void G_LoadDemoExtraFiles(UINT8 **pp, UINT16 this_demo_version)
UINT16 totalfiles;
char filename[MAX_WADPATH];
UINT8 md5sum[16];
filestatus_t ncs;
filestatus_t ncs = FS_NOTFOUND;
boolean toomany = false;
boolean alreadyloaded;
UINT16 i, j;
......@@ -2224,10 +2237,24 @@ void G_DoPlayDemo(char *defdemoname)
// net var data
#ifdef OLD22DEMOCOMPAT
if (demoversion < 0x000d)
CV_LoadOldDemoVars(&demo_p);
{
save_t savebuffer;
savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_LoadOldDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
}
else
#endif
CV_LoadDemoVars(&demo_p);
{
save_t savebuffer;
savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_LoadDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
}
// Sigh ... it's an empty demo.
if (*demo_p == DEMOMARKER)
......@@ -2603,10 +2630,10 @@ void G_AddGhost(char *defdemoname)
}
gh->oldmo.color = gh->mo->color;
gh->mo->state = states+S_PLAY_STND;
gh->mo->state = &states[S_PLAY_STND];
gh->mo->sprite = gh->mo->state->sprite;
gh->mo->sprite2 = (gh->mo->state->frame & FF_FRAMEMASK);
//gh->mo->frame = tr_trans30<<FF_TRANSSHIFT;
gh->mo->sprite2 = P_GetStateSprite2(gh->mo->state);
gh->mo->frame = (gh->mo->state->frame & ~FF_FRAMEMASK) | P_GetSprite2StateFrame(gh->mo->state);
gh->mo->flags2 |= MF2_DONTDRAW;
gh->fadein = (9-3)*6; // fade from invisible to trans30 over as close to 35 tics as possible
gh->mo->tics = -1;
......@@ -2665,7 +2692,7 @@ void G_DoPlayMetal(void)
// find metal sonic
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo = (mobj_t *)th;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -35,6 +35,7 @@ typedef enum
} demo_file_override_e;
extern demo_file_override_e demofileoverride;
extern consvar_t cv_resyncdemo;
// Quit after playing a demo from cmdline.
extern boolean singledemo;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -256,8 +256,6 @@ boolean precache = true; // if true, load all graphics at start
INT16 prevmap, nextmap;
static UINT8 *savebuffer;
// Analog Control
static void UserAnalog_OnChange(void);
static void UserAnalog2_OnChange(void);
......@@ -1337,7 +1335,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
#if NUM_WEAPONS > 10
"Add extra inputs to g_input.h/gamecontrols_e"
#endif
//use the three avaliable bits to determine the weapon.
//use the four avaliable bits to determine the weapon.
cmd->buttons &= ~BT_WEAPONMASK;
for (i = 0; i < NUM_WEAPONS; ++i)
if (PLAYERINPUTDOWN(ssplayer, GC_WEPSLOT1 + i))
......@@ -1355,14 +1353,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
axis = PlayerJoyAxis(ssplayer, JA_FIRENORMAL);
if (PLAYERINPUTDOWN(ssplayer, GC_FIRENORMAL) || (usejoystick && axis > 0))
cmd->buttons |= BT_FIRENORMAL;
// Toss flag button
if (PLAYERINPUTDOWN(ssplayer, GC_TOSSFLAG))
cmd->buttons |= BT_TOSSFLAG;
// Shield button
if (PLAYERINPUTDOWN(ssplayer, GC_SHIELD))
cmd->buttons |= BT_SHIELD;
// Lua scriptable buttons
if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM1))
......@@ -1377,6 +1370,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0))
cmd->buttons |= BT_SPIN;
if (gamestate == GS_INTRO) // prevent crash in intro
{
cmd->angleturn = ticcmd_oldangleturn[forplayer];
cmd->aiming = G_ClipAimingPitch(myaiming);
return;
}
// Centerview can be a toggle in simple mode!
{
static boolean last_centerviewdown[2], centerviewhold[2]; // detect taps for toggle behavior
......@@ -1411,7 +1411,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
ticcmd_centerviewdown[forplayer] = true;
}
else if (ticcmd_centerviewdown[forplayer])
else if (ticcmd_centerviewdown[forplayer] || (leveltime < 5))
{
if (controlstyle == CS_SIMPLE)
{
......@@ -1426,6 +1426,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
{
if (
P_MobjWasRemoved(ticcmd_ztargetfocus[forplayer]) ||
(leveltime < 5) ||
(player->playerstate != PST_LIVE) ||
player->exiting ||
!ticcmd_ztargetfocus[forplayer]->health ||
(ticcmd_ztargetfocus[forplayer]->type == MT_EGGMOBILE3 && !ticcmd_ztargetfocus[forplayer]->movecount) // Sea Egg is moving around underground and shouldn't be tracked
)
......@@ -1457,7 +1460,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]);
newtarget->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
if (player->mo && P_AproxDistance(
if (player->mo && R_PointToDist2(0, 0,
player->mo->x - ticcmd_ztargetfocus[forplayer]->x,
player->mo->y - ticcmd_ztargetfocus[forplayer]->y
) > 50*player->mo->scale)
......@@ -1917,6 +1920,8 @@ void G_DoLoadLevel(boolean resetplayer)
//
void G_StartTitleCard(void)
{
ST_stopTitleCard();
// The title card has been disabled for this map.
// Oh well.
if (!G_IsTitleCardAvailable())
......@@ -2265,6 +2270,11 @@ boolean G_LuaResponder(event_t *ev)
cancelled = LUA_HookKey(ev, HOOK(KeyUp));
LUA_InvalidateUserdata(ev);
}
else if (ev->type == ev_text)
{
cancelled = LUA_HookText(ev, HOOK(TextInput));
LUA_InvalidateUserdata(ev);
}
return cancelled;
}
......@@ -2605,6 +2615,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
boolean spectator;
boolean outofcoop;
boolean removing;
boolean muted;
INT16 bot;
SINT8 pity;
INT16 rings;
......@@ -2622,6 +2633,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
spectator = players[player].spectator;
outofcoop = players[player].outofcoop;
removing = players[player].removing;
muted = players[player].muted;
pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER));
playerangleturn = players[player].angleturn;
oldrelangleturn = players[player].oldrelangleturn;
......@@ -2699,6 +2711,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->spectator = spectator;
p->outofcoop = outofcoop;
p->removing = removing;
p->muted = muted;
p->angleturn = playerangleturn;
p->oldrelangleturn = oldrelangleturn;
......@@ -2755,7 +2768,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->pflags |= PF_SPINDOWN;
p->pflags |= PF_ATTACKDOWN;
p->pflags |= PF_JUMPDOWN;
p->pflags |= PF_SHIELDDOWN;
p->playerstate = PST_LIVE;
p->panim = PA_IDLE; // standing animation
......@@ -3050,7 +3062,7 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo)
// scan all thinkers
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -3333,7 +3345,7 @@ void G_AddPlayer(INT32 playernum)
p->playerstate = PST_REBORN;
p->height = mobjinfo[MT_PLAYER].height;
p->height = skins[p->skin]->height;
if (G_GametypeUsesLives() || ((netgame || multiplayer) && (gametyperules & GTR_FRIENDLY)))
p->lives = cv_startinglives.value;
......@@ -4009,7 +4021,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent)
INT32 i;
INT16 newmapnum;
boolean spec = G_IsSpecialStage(gamemap);
// go to next level
// newmapnum is 0-based, unlike gamemap
if (nextmapoverride != 0)
......@@ -4113,7 +4125,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent)
if (spec && (!gottoken || ignoretokens) && !nextmapoverride)
newmapnum = lastmap; // Exiting from a special stage? Go back to the game. Tails 08-11-2001
if (!(gametyperules & GTR_CAMPAIGN))
{
if (cv_advancemap.value == 0) // Stay on same map.
......@@ -4121,7 +4133,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent)
else if (cv_advancemap.value == 2) // Go to random map.
newmapnum = RandMap(G_TOLFlag(gametype_to_use), prevmap);
}
return newmapnum;
}
......@@ -4131,7 +4143,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent)
static void G_DoCompleted(void)
{
INT32 i;
tokenlist = 0; // Reset the list
if (modeattacking && pausedelay)
......@@ -4159,7 +4171,7 @@ static void G_DoCompleted(void)
//Get and set prevmap/nextmap
prevmap = (INT16)(gamemap-1);
nextmap = G_GetNextMap(false, false);
automapactive = false;
// We are committed to this map now.
......@@ -4328,6 +4340,8 @@ static void G_DoContinued(void)
// when something new is added.
void G_EndGame(void)
{
LUA_HookVoid(HOOK(GameEnd));
// Only do evaluation and credits in coop games.
if (gametyperules & GTR_CUTSCENES)
{
......@@ -4377,7 +4391,7 @@ void G_LoadGameSettings(void)
// Loads the main data file, which stores information such as emblems found, etc.
void G_LoadGameData(gamedata_t *data)
{
size_t length;
save_t savebuffer;
INT32 i, j;
UINT32 versionID;
......@@ -4419,18 +4433,18 @@ void G_LoadGameData(gamedata_t *data)
return;
}
length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer);
if (!length)
savebuffer.size = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer.buf);
if (!savebuffer.size)
{
// No gamedata. We can save a new one.
data->loaded = true;
return;
}
save_p = savebuffer;
savebuffer.pos = 0;
// Version check
versionID = READUINT32(save_p);
versionID = P_ReadUINT32(&savebuffer);
if (versionID != GAMEDATA_ID
#ifdef COMPAT_GAMEDATA_ID // backwards compat behavior
&& versionID != COMPAT_GAMEDATA_ID
......@@ -4441,8 +4455,7 @@ void G_LoadGameData(gamedata_t *data)
if (strcmp(srb2home,"."))
gdfolder = srb2home;
Z_Free(savebuffer);
save_p = NULL;
Z_Free(savebuffer.buf);
I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
}
......@@ -4454,14 +4467,14 @@ void G_LoadGameData(gamedata_t *data)
}
#endif
data->totalplaytime = READUINT32(save_p);
data->totalplaytime = P_ReadUINT32(&savebuffer);
#ifdef COMPAT_GAMEDATA_ID
if (versionID == COMPAT_GAMEDATA_ID)
{
// We'll temporarily use the old condition when loading an older file.
// The proper mod-specific hash will get saved in afterwards.
boolean modded = READUINT8(save_p);
boolean modded = P_ReadUINT8(&savebuffer);
if (modded && !savemoddata)
{
......@@ -4481,13 +4494,13 @@ void G_LoadGameData(gamedata_t *data)
strcpy(currentfilename, gamedatafilename);
STRBUFCPY(backupfilename, strcat(currentfilename, bak));
FIL_WriteFile(va(pandf, srb2home, backupfilename), savebuffer, length);
FIL_WriteFile(va(pandf, srb2home, backupfilename), &savebuffer.buf, savebuffer.size);
}
else
#endif
{
// Quick & dirty hash for what mod this save file is for.
UINT32 modID = READUINT32(save_p);
UINT32 modID = P_ReadUINT32(&savebuffer);
UINT32 expectedID = quickncasehash(timeattackfolder, sizeof timeattackfolder);
if (modID != expectedID)
......@@ -4499,50 +4512,50 @@ void G_LoadGameData(gamedata_t *data)
// TODO put another cipher on these things? meh, I don't care...
for (i = 0; i < NUMMAPS; i++)
if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX)
if ((data->mapvisited[i] = P_ReadUINT8(&savebuffer)) > MV_MAX)
goto datacorrupt;
// To save space, use one bit per collected/achieved/unlocked flag
for (i = 0; i < max_emblems;)
{
rtemp = READUINT8(save_p);
rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_emblems; ++j)
data->collected[j+i] = ((rtemp >> j) & 1);
i += j;
}
for (i = 0; i < max_extraemblems;)
{
rtemp = READUINT8(save_p);
rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_extraemblems; ++j)
data->extraCollected[j+i] = ((rtemp >> j) & 1);
i += j;
}
for (i = 0; i < max_unlockables;)
{
rtemp = READUINT8(save_p);
rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_unlockables; ++j)
data->unlocked[j+i] = ((rtemp >> j) & 1);
i += j;
}
for (i = 0; i < max_conditionsets;)
{
rtemp = READUINT8(save_p);
rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_conditionsets; ++j)
data->achieved[j+i] = ((rtemp >> j) & 1);
i += j;
}
data->timesBeaten = READUINT32(save_p);
data->timesBeatenWithEmeralds = READUINT32(save_p);
data->timesBeatenUltimate = READUINT32(save_p);
data->timesBeaten = P_ReadUINT32(&savebuffer);
data->timesBeatenWithEmeralds = P_ReadUINT32(&savebuffer);
data->timesBeatenUltimate = P_ReadUINT32(&savebuffer);
// Main records
for (i = 0; i < NUMMAPS; ++i)
{
recscore = READUINT32(save_p);
rectime = (tic_t)READUINT32(save_p);
recrings = READUINT16(save_p);
save_p++; // compat
recscore = P_ReadUINT32(&savebuffer);
rectime = (tic_t)P_ReadUINT32(&savebuffer);
recrings = P_ReadUINT16(&savebuffer);
P_ReadUINT8(&savebuffer); // compat
if (recrings > 10000 || recscore > MAXSCORE)
goto datacorrupt;
......@@ -4559,16 +4572,16 @@ void G_LoadGameData(gamedata_t *data)
// Nights records
for (i = 0; i < NUMMAPS; ++i)
{
if ((recmares = READUINT8(save_p)) == 0)
if ((recmares = P_ReadUINT8(&savebuffer)) == 0)
continue;
G_AllocNightsRecordData((INT16)i, data);
for (curmare = 0; curmare < (recmares+1); ++curmare)
{
data->nightsrecords[i]->score[curmare] = READUINT32(save_p);
data->nightsrecords[i]->grade[curmare] = READUINT8(save_p);
data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p);
data->nightsrecords[i]->score[curmare] = P_ReadUINT32(&savebuffer);
data->nightsrecords[i]->grade[curmare] = P_ReadUINT8(&savebuffer);
data->nightsrecords[i]->time[curmare] = (tic_t)P_ReadUINT32(&savebuffer);
if (data->nightsrecords[i]->grade[curmare] > GRADE_S)
{
......@@ -4580,8 +4593,7 @@ void G_LoadGameData(gamedata_t *data)
}
// done
Z_Free(savebuffer);
save_p = NULL;
Z_Free(savebuffer.buf);
// Don't consider loaded until it's a success!
// It used to do this much earlier, but this would cause the gamedata to
......@@ -4602,8 +4614,7 @@ void G_LoadGameData(gamedata_t *data)
if (strcmp(srb2home,"."))
gdfolder = srb2home;
Z_Free(savebuffer);
save_p = NULL;
Z_Free(savebuffer.buf);
I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
}
......@@ -4613,41 +4624,44 @@ void G_LoadGameData(gamedata_t *data)
// Saves the main data file, which stores information such as emblems found, etc.
void G_SaveGameData(gamedata_t *data)
{
UINT8 *data_p;
save_t savebuffer;
size_t length;
INT32 i, j;
UINT8 btemp;
INT32 curmare;
if (!data)
return; // data struct not valid
if (!data->loaded)
return; // If never loaded (-nodata), don't save
data_p = savebuffer = (UINT8 *)malloc(GAMEDATASIZE);
if (!data_p)
savebuffer.size = GAMEDATASIZE;
savebuffer.buf = (UINT8 *)malloc(savebuffer.size);
if (!savebuffer.buf)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
return;
}
savebuffer.pos = 0;
if (usedCheats)
{
free(savebuffer);
savebuffer = NULL;
free(savebuffer.buf);
return;
}
// Version test
WRITEUINT32(data_p, GAMEDATA_ID);
P_WriteUINT32(&savebuffer, GAMEDATA_ID);
WRITEUINT32(data_p, data->totalplaytime);
P_WriteUINT32(&savebuffer, data->totalplaytime);
WRITEUINT32(data_p, quickncasehash(timeattackfolder, sizeof timeattackfolder));
P_WriteUINT32(&savebuffer, quickncasehash(timeattackfolder, sizeof timeattackfolder));
// TODO put another cipher on these things? meh, I don't care...
for (i = 0; i < NUMMAPS; i++)
WRITEUINT8(data_p, (data->mapvisited[i] & MV_MAX));
P_WriteUINT8(&savebuffer, (data->mapvisited[i] & MV_MAX));
// To save space, use one bit per collected/achieved/unlocked flag
for (i = 0; i < MAXEMBLEMS;)
......@@ -4655,7 +4669,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0;
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
btemp |= (data->collected[j+i] << j);
WRITEUINT8(data_p, btemp);
P_WriteUINT8(&savebuffer, btemp);
i += j;
}
for (i = 0; i < MAXEXTRAEMBLEMS;)
......@@ -4663,7 +4677,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0;
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
btemp |= (data->extraCollected[j+i] << j);
WRITEUINT8(data_p, btemp);
P_WriteUINT8(&savebuffer, btemp);
i += j;
}
for (i = 0; i < MAXUNLOCKABLES;)
......@@ -4671,7 +4685,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0;
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
btemp |= (data->unlocked[j+i] << j);
WRITEUINT8(data_p, btemp);
P_WriteUINT8(&savebuffer, btemp);
i += j;
}
for (i = 0; i < MAXCONDITIONSETS;)
......@@ -4679,30 +4693,30 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0;
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
btemp |= (data->achieved[j+i] << j);
WRITEUINT8(data_p, btemp);
P_WriteUINT8(&savebuffer, btemp);
i += j;
}
WRITEUINT32(data_p, data->timesBeaten);
WRITEUINT32(data_p, data->timesBeatenWithEmeralds);
WRITEUINT32(data_p, data->timesBeatenUltimate);
P_WriteUINT32(&savebuffer, data->timesBeaten);
P_WriteUINT32(&savebuffer, data->timesBeatenWithEmeralds);
P_WriteUINT32(&savebuffer, data->timesBeatenUltimate);
// Main records
for (i = 0; i < NUMMAPS; i++)
{
if (data->mainrecords[i])
{
WRITEUINT32(data_p, data->mainrecords[i]->score);
WRITEUINT32(data_p, data->mainrecords[i]->time);
WRITEUINT16(data_p, data->mainrecords[i]->rings);
P_WriteUINT32(&savebuffer, data->mainrecords[i]->score);
P_WriteUINT32(&savebuffer, data->mainrecords[i]->time);
P_WriteUINT16(&savebuffer, data->mainrecords[i]->rings);
}
else
{
WRITEUINT32(data_p, 0);
WRITEUINT32(data_p, 0);
WRITEUINT16(data_p, 0);
P_WriteUINT32(&savebuffer, 0);
P_WriteUINT32(&savebuffer, 0);
P_WriteUINT16(&savebuffer, 0);
}
WRITEUINT8(data_p, 0); // compat
P_WriteUINT8(&savebuffer, 0); // compat
}
// NiGHTS records
......@@ -4710,25 +4724,22 @@ void G_SaveGameData(gamedata_t *data)
{
if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares)
{
WRITEUINT8(data_p, 0);
P_WriteUINT8(&savebuffer, 0);
continue;
}
WRITEUINT8(data_p, data->nightsrecords[i]->nummares);
P_WriteUINT8(&savebuffer, data->nightsrecords[i]->nummares);
for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare)
{
WRITEUINT32(data_p, data->nightsrecords[i]->score[curmare]);
WRITEUINT8(data_p, data->nightsrecords[i]->grade[curmare]);
WRITEUINT32(data_p, data->nightsrecords[i]->time[curmare]);
P_WriteUINT32(&savebuffer, data->nightsrecords[i]->score[curmare]);
P_WriteUINT8(&savebuffer, data->nightsrecords[i]->grade[curmare]);
P_WriteUINT32(&savebuffer, data->nightsrecords[i]->time[curmare]);
}
}
length = data_p - savebuffer;
FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer, length);
free(savebuffer);
savebuffer = NULL;
FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer.buf, savebuffer.pos);
free(savebuffer.buf);
}
#define VERSIONSIZE 16
......@@ -4739,7 +4750,7 @@ void G_SaveGameData(gamedata_t *data)
//
void G_LoadGame(UINT32 slot, INT16 mapoverride)
{
size_t length;
save_t savebuffer;
char vcheck[VERSIONSIZE];
char savename[255];
......@@ -4756,18 +4767,18 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
else
sprintf(savename, savegamename, slot);
length = FIL_ReadFile(savename, &savebuffer);
if (!length)
savebuffer.size = FIL_ReadFile(savename, &savebuffer.buf);
if (!savebuffer.size)
{
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
return;
}
save_p = savebuffer;
savebuffer.pos = 0;
memset(vcheck, 0, sizeof (vcheck));
sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION);
if (strcmp((const char *)save_p, (const char *)vcheck))
if (strcmp((const char *)&savebuffer.buf[savebuffer.pos], (const char *)vcheck))
{
#ifdef SAVEGAME_OTHERVERSIONS
M_StartMessage(M_GetText("Save game from different version.\nYou can load this savegame, but\nsaving afterwards will be disabled.\n\nDo you want to continue anyway?\n\n(Press 'Y' to confirm)\n"),
......@@ -4777,15 +4788,14 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
M_ClearMenus(true); // so ESC backs out to title
M_StartMessage(M_GetText("Save game from different version\n\nPress ESC\n"), NULL, MM_NOTHING);
Command_ExitGame_f();
Z_Free(savebuffer);
save_p = savebuffer = NULL;
Z_Free(savebuffer.buf);
// no cheating!
memset(&savedata, 0, sizeof(savedata));
#endif
return; // bad version
}
save_p += VERSIONSIZE;
savebuffer.pos += VERSIONSIZE;
// if (demoplayback) // reset game engine
// G_StopDemo();
......@@ -4794,13 +4804,12 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
// automapactive = false;
// dearchive all the modifications
if (!P_LoadGame(mapoverride))
if (!P_LoadGame(&savebuffer, mapoverride))
{
M_ClearMenus(true); // so ESC backs out to title
M_StartMessage(M_GetText("Savegame file corrupted\n\nPress ESC\n"), NULL, MM_NOTHING);
Command_ExitGame_f();
Z_Free(savebuffer);
save_p = savebuffer = NULL;
Z_Free(savebuffer.buf);
// no cheating!
memset(&savedata, 0, sizeof(savedata));
......@@ -4808,13 +4817,12 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
}
if (marathonmode)
{
marathontime = READUINT32(save_p);
marathonmode |= READUINT8(save_p);
marathontime = P_ReadUINT32(&savebuffer);
marathonmode |= P_ReadUINT8(&savebuffer);
}
// done
Z_Free(savebuffer);
save_p = savebuffer = NULL;
Z_Free(savebuffer.buf);
displayplayer = consoleplayer;
multiplayer = splitscreen = false;
......@@ -4832,6 +4840,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
//
void G_SaveGame(UINT32 slot, INT16 mapnum)
{
save_t savebuffer;
boolean saved;
char savename[256] = "";
const char *backup;
......@@ -4845,33 +4854,32 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
gameaction = ga_nothing;
{
char name[VERSIONSIZE];
size_t length;
save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
if (!save_p)
savebuffer.size = SAVEGAMESIZE;
savebuffer.buf = (UINT8 *)malloc(savebuffer.size);
if (!savebuffer.buf)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
return;
}
savebuffer.pos = 0;
memset(name, 0, sizeof (name));
sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION);
WRITEMEM(save_p, name, VERSIONSIZE);
P_WriteMem(&savebuffer, name, VERSIONSIZE);
P_SaveGame(mapnum);
P_SaveGame(&savebuffer, mapnum);
if (marathonmode)
{
UINT32 writetime = marathontime;
if (!(marathonmode & MA_INGAME))
writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map
WRITEUINT32(save_p, writetime);
WRITEUINT8(save_p, (marathonmode & ~MA_INIT));
P_WriteUINT32(&savebuffer, writetime);
P_WriteUINT8(&savebuffer, (marathonmode & ~MA_INIT));
}
length = save_p - savebuffer;
saved = FIL_WriteFile(backup, savebuffer, length);
free(savebuffer);
save_p = savebuffer = NULL;
saved = FIL_WriteFile(backup, savebuffer.buf, savebuffer.pos);
free(savebuffer.buf);
}
gameaction = ga_nothing;
......@@ -4883,11 +4891,10 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
}
#define BADSAVE goto cleanup;
#define CHECKPOS if (save_p >= end_p) BADSAVE
void G_SaveGameOver(UINT32 slot, boolean modifylives)
{
save_t savebuffer;
boolean saved = false;
size_t length;
char vcheck[VERSIONSIZE];
char savename[255];
const char *backup;
......@@ -4898,42 +4905,38 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
sprintf(savename, savegamename, slot);
backup = va("%s",savename);
length = FIL_ReadFile(savename, &savebuffer);
if (!length)
savebuffer.size = FIL_ReadFile(savename, &savebuffer.buf);
if (!savebuffer.size)
{
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
return;
}
savebuffer.pos = 0;
{
char temp[sizeof(timeattackfolder)];
UINT8 *end_p = savebuffer + length;
UINT8 *lives_p;
SINT8 pllives;
#ifdef NEWSKINSAVES
INT16 backwardsCompat = 0;
#endif
save_p = savebuffer;
// Version check
memset(vcheck, 0, sizeof (vcheck));
sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION);
if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE
save_p += VERSIONSIZE;
if (strcmp((const char *)&savebuffer.buf[savebuffer.pos], (const char *)vcheck)) BADSAVE
savebuffer.pos += VERSIONSIZE;
// P_UnArchiveMisc()
(void)READINT16(save_p);
CHECKPOS
(void)READUINT16(save_p); // emeralds
CHECKPOS
READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to
(void)P_ReadINT16(&savebuffer);
(void)P_ReadUINT16(&savebuffer); // emeralds
P_ReadStringN(&savebuffer, temp, sizeof(temp)); // mod it belongs to
if (strcmp(temp, timeattackfolder)) BADSAVE
// P_UnArchivePlayer()
CHECKPOS
#ifdef NEWSKINSAVES
backwardsCompat = READUINT16(save_p);
CHECKPOS
backwardsCompat = P_ReadUINT16(&savebuffer);
if (backwardsCompat == NEWSKINSAVES) // New save, read skin names
#endif
......@@ -4941,47 +4944,37 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
char ourSkinName[SKINNAMESIZE+1];
char botSkinName[SKINNAMESIZE+1];
READSTRINGN(save_p, ourSkinName, SKINNAMESIZE);
CHECKPOS
P_ReadStringN(&savebuffer, ourSkinName, SKINNAMESIZE);
READSTRINGN(save_p, botSkinName, SKINNAMESIZE);
CHECKPOS
P_ReadStringN(&savebuffer, botSkinName, SKINNAMESIZE);
}
WRITEUINT8(save_p, numgameovers);
CHECKPOS
P_WriteUINT8(&savebuffer, numgameovers);
lives_p = save_p;
pllives = READSINT8(save_p); // lives
CHECKPOS
lives_p = &savebuffer.buf[savebuffer.pos];
pllives = P_ReadSINT8(&savebuffer); // lives
if (modifylives && pllives < startinglivesbalance[numgameovers])
{
pllives = startinglivesbalance[numgameovers];
WRITESINT8(lives_p, pllives);
*lives_p = startinglivesbalance[numgameovers];
}
(void)READINT32(save_p); // Score
CHECKPOS
(void)READINT32(save_p); // continues
(void)P_ReadINT32(&savebuffer); // Score
(void)P_ReadINT32(&savebuffer); // continues
// File end marker check
CHECKPOS
switch (READUINT8(save_p))
switch (P_ReadUINT8(&savebuffer))
{
case 0xb7:
{
UINT8 i, banksinuse;
CHECKPOS
banksinuse = READUINT8(save_p);
CHECKPOS
banksinuse = P_ReadUINT8(&savebuffer);
if (banksinuse > NUM_LUABANKS)
BADSAVE
for (i = 0; i < banksinuse; i++)
{
(void)READINT32(save_p);
CHECKPOS
(void)P_ReadINT32(&savebuffer);
}
if (READUINT8(save_p) != 0x1d)
if (P_ReadUINT8(&savebuffer) != 0x1d)
BADSAVE
}
case 0x1d:
......@@ -4991,7 +4984,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
}
// done
saved = FIL_WriteFile(backup, savebuffer, length);
saved = FIL_WriteFile(backup, savebuffer.buf, savebuffer.size);
}
cleanup:
......@@ -4999,11 +4992,9 @@ cleanup:
CONS_Printf(M_GetText("Game saved.\n"));
else if (!saved)
CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename));
Z_Free(savebuffer);
save_p = savebuffer = NULL;
Z_Free(savebuffer.buf);
}
#undef CHECKPOS
#undef BADSAVE
//
......@@ -5400,7 +5391,7 @@ void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc)
INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep)
{
boolean usemapcode = false;
INT32 newmapnum;
INT32 newmapnum = -1;
size_t mapnamelen = strlen(mapname);
char *p;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -576,7 +576,9 @@ static const char *gamecontrolname[NUM_GAMECONTROLS] =
"weapon5",
"weapon6",
"weapon7",
"shield",
"weapon8",
"weapon9",
"weapon10",
"fire",
"firenormal",
"tossflag",
......@@ -691,7 +693,6 @@ void G_DefineDefaultControls(void)
gamecontroldefault[gcs_fps][GC_CENTERVIEW ][0] = KEY_LCTRL;
gamecontroldefault[gcs_fps][GC_JUMP ][0] = KEY_SPACE;
gamecontroldefault[gcs_fps][GC_SPIN ][0] = KEY_LSHIFT;
gamecontroldefault[gcs_fps][GC_SHIELD ][0] = KEY_LALT;
gamecontroldefault[gcs_fps][GC_FIRE ][0] = KEY_RCTRL;
gamecontroldefault[gcs_fps][GC_FIRE ][1] = KEY_MOUSE1+0;
gamecontroldefault[gcs_fps][GC_FIRENORMAL ][0] = KEY_RALT;
......@@ -712,7 +713,6 @@ void G_DefineDefaultControls(void)
gamecontroldefault[gcs_platform][GC_CENTERVIEW ][0] = KEY_END;
gamecontroldefault[gcs_platform][GC_JUMP ][0] = KEY_SPACE;
gamecontroldefault[gcs_platform][GC_SPIN ][0] = KEY_LSHIFT;
gamecontroldefault[gcs_platform][GC_SHIELD ][0] = KEY_LALT;
gamecontroldefault[gcs_platform][GC_FIRE ][0] = 's';
gamecontroldefault[gcs_platform][GC_FIRE ][1] = KEY_MOUSE1+0;
gamecontroldefault[gcs_platform][GC_FIRENORMAL ][0] = 'w';
......@@ -728,6 +728,9 @@ void G_DefineDefaultControls(void)
gamecontroldefault[i][GC_WEPSLOT5 ][0] = '5';
gamecontroldefault[i][GC_WEPSLOT6 ][0] = '6';
gamecontroldefault[i][GC_WEPSLOT7 ][0] = '7';
gamecontroldefault[i][GC_WEPSLOT8 ][0] = '8';
gamecontroldefault[i][GC_WEPSLOT9 ][0] = '9';
gamecontroldefault[i][GC_WEPSLOT10 ][0] = '0';
gamecontroldefault[i][GC_TOSSFLAG ][0] = '\'';
gamecontroldefault[i][GC_CAMTOGGLE ][0] = 'v';
gamecontroldefault[i][GC_CAMRESET ][0] = 'r';
......@@ -746,15 +749,15 @@ void G_DefineDefaultControls(void)
gamecontroldefault[i][GC_CUSTOM1 ][1] = KEY_JOY1+1; // B
gamecontroldefault[i][GC_CUSTOM2 ][1] = KEY_JOY1+3; // Y
gamecontroldefault[i][GC_CUSTOM3 ][1] = KEY_JOY1+8; // Left Stick
gamecontroldefault[i][GC_SHIELD ][1] = KEY_JOY1+4; // LB
gamecontroldefault[i][GC_CAMTOGGLE ][1] = KEY_JOY1+4; // LB
gamecontroldefault[i][GC_CENTERVIEW ][1] = KEY_JOY1+5; // RB
gamecontroldefault[i][GC_SCORES ][1] = KEY_JOY1+6; // Back
gamecontroldefault[i][GC_SCREENSHOT ][1] = KEY_JOY1+6; // Back
gamecontroldefault[i][GC_SYSTEMMENU ][0] = KEY_JOY1+7; // Start
gamecontroldefault[i][GC_WEAPONPREV ][1] = KEY_HAT1+2; // D-Pad Left
gamecontroldefault[i][GC_WEAPONNEXT ][1] = KEY_HAT1+3; // D-Pad Right
gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = KEY_JOY1+9; // Right Stick
gamecontroldefault[i][GC_TOSSFLAG ][1] = KEY_HAT1+0; // D-Pad Up
gamecontroldefault[i][GC_CAMTOGGLE ][1] = KEY_HAT1+1; // D-Pad Down
gamecontroldefault[i][GC_SCORES ][1] = KEY_HAT1+1; // D-Pad Down
// Second player controls only have joypad defaults
gamecontrolbisdefault[i][GC_JUMP ][1] = KEY_2JOY1+0; // A
......@@ -762,15 +765,15 @@ void G_DefineDefaultControls(void)
gamecontrolbisdefault[i][GC_CUSTOM1 ][1] = KEY_2JOY1+1; // B
gamecontrolbisdefault[i][GC_CUSTOM2 ][1] = KEY_2JOY1+3; // Y
gamecontrolbisdefault[i][GC_CUSTOM3 ][1] = KEY_2JOY1+8; // Left Stick
gamecontrolbisdefault[i][GC_SHIELD ][1] = KEY_2JOY1+4; // LB
gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = KEY_2JOY1+4; // LB
gamecontrolbisdefault[i][GC_CENTERVIEW ][1] = KEY_2JOY1+5; // RB
//gamecontrolbisdefault[i][GC_SCORES ][1] = KEY_2JOY1+6; // Back
gamecontrolbisdefault[i][GC_SCREENSHOT ][1] = KEY_2JOY1+6; // Back
//gamecontrolbisdefault[i][GC_SYSTEMMENU ][0] = KEY_2JOY1+7; // Start
gamecontrolbisdefault[i][GC_WEAPONPREV ][1] = KEY_2HAT1+2; // D-Pad Left
gamecontrolbisdefault[i][GC_WEAPONNEXT ][1] = KEY_2HAT1+3; // D-Pad Right
gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = KEY_2JOY1+9; // Right Stick
gamecontrolbisdefault[i][GC_TOSSFLAG ][1] = KEY_2HAT1+0; // D-Pad Up
gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = KEY_2HAT1+1; // D-Pad Down
//gamecontrolbisdefault[i][GC_SCORES ][1] = KEY_2HAT1+1; // D-Pad Down
}
}
......@@ -1001,7 +1004,6 @@ static void setcontrol(INT32 (*gc)[2])
// TODO: 2.3: Delete the "use" alias
namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin";
for (numctrl = 0; numctrl < NUM_GAMECONTROLS && stricmp(namectrl, gamecontrolname[numctrl]);
numctrl++)
......
......@@ -74,7 +74,9 @@ typedef enum
GC_WEPSLOT5,
GC_WEPSLOT6,
GC_WEPSLOT7,
GC_SHIELD,
GC_WEPSLOT8,
GC_WEPSLOT9,
GC_WEPSLOT10,
GC_FIRE,
GC_FIRENORMAL,
GC_TOSSFLAG,
......
......@@ -10,5 +10,6 @@ target_sources(SRB2SDL2 PRIVATE
hw_md3load.c
hw_model.c
hw_batching.c
hw_shaders.c
r_opengl/r_opengl.c
)
......@@ -9,4 +9,5 @@ hw_md2load.c
hw_md3load.c
hw_model.c
hw_batching.c
hw_shaders.c
r_opengl/r_opengl.c
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Sonic Team Junior.
// Copyright (C) 2020-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -76,7 +76,7 @@ void HWR_SetCurrentTexture(GLMipmap_t *texture)
// If batching is enabled, this function collects the polygon data and the chosen texture
// for later use in HWR_RenderBatches. Otherwise the rendering backend is used to
// render the polygon immediately.
void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial)
void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader_target, boolean horizonSpecial)
{
if (currently_batching)
{
......@@ -114,7 +114,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt
polygonArray[polygonArraySize].numVerts = iNumPts;
polygonArray[polygonArraySize].polyFlags = PolyFlags;
polygonArray[polygonArraySize].texture = current_texture;
polygonArray[polygonArraySize].shader = shader;
polygonArray[polygonArraySize].shader = (shader_target != SHADER_NONE) ? HWR_GetShaderFromTarget(shader_target) : shader_target;
polygonArray[polygonArraySize].horizonSpecial = horizonSpecial;
// default to polygonArraySize so we don't lose order on horizon lines
// (yes, it's supposed to be negative, since we're sorting in that direction)
......@@ -134,7 +134,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt
DIGEST(hash, pSurf->PolyColor.rgba);
if (cv_glshaders.value && gl_shadersavailable)
{
DIGEST(hash, shader);
DIGEST(hash, shader_target);
DIGEST(hash, pSurf->TintColor.rgba);
DIGEST(hash, pSurf->FadeColor.rgba);
DIGEST(hash, pSurf->LightInfo.light_level);
......@@ -151,10 +151,9 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt
}
else
{
if (shader)
HWD.pfnSetShader(shader);
HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags);
}
HWD.pfnSetShader((shader_target != SHADER_NONE) ? HWR_GetShaderFromTarget(shader_target) : shader_target);
HWD.pfnDrawPolygon(pSurf, pOutVerts, iNumPts, PolyFlags);
}
}
static int comparePolygons(const void *p1, const void *p2)
......@@ -312,7 +311,6 @@ void HWR_RenderBatches(void)
int nextIndex = polygonIndexArray[polygonReadPos];
if (polygonArray[index].hash != polygonArray[nextIndex].hash)
{
changeState = true;
nextShader = polygonArray[nextIndex].shader;
nextTexture = polygonArray[nextIndex].texture;
nextPolyFlags = polygonArray[nextIndex].polyFlags;
......@@ -321,14 +319,17 @@ void HWR_RenderBatches(void)
nextTexture = 0;
if (currentShader != nextShader && cv_glshaders.value && gl_shadersavailable)
{
changeState = true;
changeShader = true;
}
if (currentTexture != nextTexture)
{
changeState = true;
changeTexture = true;
}
if (currentPolyFlags != nextPolyFlags)
{
changeState = true;
changePolyFlags = true;
}
if (cv_glshaders.value && gl_shadersavailable)
......@@ -340,6 +341,7 @@ void HWR_RenderBatches(void)
currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start ||
currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end)
{
changeState = true;
changeSurfaceInfo = true;
}
}
......@@ -347,6 +349,7 @@ void HWR_RenderBatches(void)
{
if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba)
{
changeState = true;
changeSurfaceInfo = true;
}
}
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Sonic Team Junior.
// Copyright (C) 2020-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
......@@ -32,6 +32,14 @@
INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes
INT32 textureformat = GL_TEXFMT_P_8; // use chromakey for hole
RGBA_t mapPalette[256] = {0}; // the palette for the currently loaded level or menu etc.
// Returns a pointer to the palette which should be used for caching textures.
RGBA_t *HWR_GetTexturePalette(void)
{
return HWR_ShouldUsePaletteRendering() ? mapPalette : pLocalPalette;
}
static INT32 format2bpp(GLTextureFormat_t format)
{
if (format == GL_TEXFMT_RGBA)
......@@ -49,7 +57,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
INT32 pblockheight, INT32 blockmodulo,
fixed_t yfracstep, fixed_t scale_y,
texpatch_t *originPatch, INT32 patchheight,
INT32 bpp)
INT32 bpp, RGBA_t *palette)
{
fixed_t yfrac, position, count;
UINT8 *dest;
......@@ -90,13 +98,11 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
if (position + count >= pblockheight)
count = pblockheight - position;
dest = block + (position*blockmodulo);
while (count > 0)
for (dest = block + (position*blockmodulo); count > 0; count--, dest += blockmodulo, yfrac += yfracstep)
{
count--;
texel = source[yfrac>>FRACBITS];
alpha = 0xFF;
// Make pixel transparent if chroma keyed
if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
alpha = 0x00;
......@@ -107,13 +113,22 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
switch (bpp)
{
case 2:
{
texelu16 = *((UINT16*)dest);
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
{
if (originPatch->style == AST_TRANSLUCENT && originPatch->alpha < ASTTextureBlendingThreshold[0])
continue;
if (!(texelu16 & 0xFF00) && originPatch->alpha <= ASTTextureBlendingThreshold[1])
continue;
texel = ASTBlendPaletteIndexes(texelu16 & 0xFF, texel, originPatch->style, originPatch->alpha);
}
texelu16 = (UINT16)((alpha<<8) | texel);
memcpy(dest, &texelu16, sizeof(UINT16));
break;
}
case 3:
colortemp = V_GetColor(texel);
colortemp = palette[texel];
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
{
RGBA_t rgbatexel;
......@@ -123,7 +138,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
break;
case 4:
colortemp = V_GetColor(texel);
colortemp = palette[texel];
colortemp.s.alpha = alpha;
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
{
......@@ -141,9 +156,6 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm
*dest = texel;
break;
}
dest += blockmodulo;
yfrac += yfracstep;
}
}
}
......@@ -152,7 +164,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
INT32 pblockheight, INT32 blockmodulo,
fixed_t yfracstep, fixed_t scale_y,
texpatch_t *originPatch, INT32 patchheight,
INT32 bpp)
INT32 bpp, RGBA_t *palette)
{
fixed_t yfrac, position, count;
UINT8 *dest;
......@@ -194,13 +206,11 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
if (position + count >= pblockheight)
count = pblockheight - position;
dest = block + (position*blockmodulo);
while (count > 0)
for (dest = block + (position*blockmodulo); count > 0; count--, dest += blockmodulo, yfrac -= yfracstep)
{
count--;
texel = source[yfrac>>FRACBITS];
alpha = 0xFF;
// Make pixel transparent if chroma keyed
if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
alpha = 0x00;
......@@ -211,13 +221,20 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
switch (bpp)
{
case 2:
texelu16 = *((UINT16*)dest);
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha);
{
if (originPatch->style == AST_TRANSLUCENT && originPatch->alpha < ASTTextureBlendingThreshold[0])
continue;
if (!(texelu16 & 0xFF00) && originPatch->alpha <= ASTTextureBlendingThreshold[1])
continue;
texel = ASTBlendPaletteIndexes(texelu16 & 0xFF, texel, originPatch->style, originPatch->alpha);
}
texelu16 = (UINT16)((alpha<<8) | texel);
memcpy(dest, &texelu16, sizeof(UINT16));
break;
case 3:
colortemp = V_GetColor(texel);
colortemp = palette[texel];
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
{
RGBA_t rgbatexel;
......@@ -227,7 +244,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8));
break;
case 4:
colortemp = V_GetColor(texel);
colortemp = palette[texel];
colortemp.s.alpha = alpha;
if ((originPatch != NULL) && (originPatch->style != AST_COPY))
{
......@@ -245,9 +262,6 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
*dest = texel;
break;
}
dest += blockmodulo;
yfrac -= yfracstep;
}
}
}
......@@ -269,10 +283,13 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap,
UINT8 *block = mipmap->data;
INT32 bpp;
INT32 blockmodulo;
RGBA_t *palette;
if (pwidth <= 0 || pheight <= 0)
return;
palette = HWR_GetTexturePalette();
ncols = pwidth;
// source advance
......@@ -298,7 +315,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap,
pblockheight, blockmodulo,
yfracstep, scale_y,
NULL, pheight, // not that pheight is going to get used anyway...
bpp);
bpp, palette);
}
}
......@@ -317,16 +334,19 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap,
INT32 bpp;
INT32 blockmodulo;
INT32 width, height;
RGBA_t *palette;
// Column drawing function pointer.
static void (*ColumnDrawerPointer)(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap,
INT32 pblockheight, INT32 blockmodulo,
fixed_t yfracstep, fixed_t scale_y,
texpatch_t *originPatch, INT32 patchheight,
INT32 bpp);
INT32 bpp, RGBA_t *palette);
if (texture->width <= 0 || texture->height <= 0)
return;
palette = HWR_GetTexturePalette();
ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache;
x1 = patch->originx;
......@@ -386,7 +406,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap,
pblockheight, blockmodulo,
yfracstep, scale_y,
patch, height,
bpp);
bpp, palette);
}
}
......@@ -419,7 +439,7 @@ static UINT8 *MakeBlock(GLMipmap_t *grMipmap)
// Create a composite texture from patches, adapt the texture size to a power of 2
// height and width for the hardware texture cache.
//
static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex, GLMipmap_t *mipmap)
{
UINT8 *block;
texture_t *texture;
......@@ -427,50 +447,13 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
INT32 blockwidth, blockheight, blocksize;
INT32 i;
boolean skyspecial = false; //poor hack for Legacy large skies..
texture = textures[texnum];
// hack the Legacy skies..
if (texture->name[0] == 'S' &&
texture->name[1] == 'K' &&
texture->name[2] == 'Y' &&
(texture->name[4] == 0 ||
texture->name[5] == 0)
)
{
skyspecial = true;
grtex->mipmap.flags = TF_WRAPXY; // don't use the chromakey for sky
}
else
grtex->mipmap.flags = TF_CHROMAKEYED | TF_WRAPXY;
grtex->mipmap.width = (UINT16)texture->width;
grtex->mipmap.height = (UINT16)texture->height;
grtex->mipmap.format = textureformat;
blockwidth = texture->width;
blockheight = texture->height;
blocksize = (blockwidth * blockheight);
block = MakeBlock(&grtex->mipmap);
if (skyspecial) //Hurdler: not efficient, but better than holes in the sky (and it's done only at level loading)
{
INT32 j;
RGBA_t col;
col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX);
for (j = 0; j < blockheight; j++)
{
for (i = 0; i < blockwidth; i++)
{
block[4*(j*blockwidth+i)+0] = col.s.red;
block[4*(j*blockwidth+i)+1] = col.s.green;
block[4*(j*blockwidth+i)+2] = col.s.blue;
block[4*(j*blockwidth+i)+3] = 0xff;
}
}
}
blocksize = blockwidth * blockheight;
block = MakeBlock(mipmap);
// Composite the columns together.
for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
......@@ -500,19 +483,19 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
realpatch = W_CachePatchNumPwad(wadnum, lumpnum, PU_PATCH);
}
HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch);
HWR_DrawTexturePatchInCache(mipmap, blockwidth, blockheight, texture, patch, realpatch);
if (free_patch)
Patch_Free(realpatch);
}
//Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :(
if (format2bpp(grtex->mipmap.format)==4)
if (format2bpp(mipmap->format)==4)
{
for (i = 3; i < blocksize*4; i += 4) // blocksize*4 because blocksize doesn't include the bpp
{
if (block[i] == 0)
{
grtex->mipmap.flags |= TF_TRANSPARENT;
mipmap->flags |= TF_TRANSPARENT;
break;
}
}
......@@ -641,8 +624,6 @@ void HWR_FreeTextureColormaps(patch_t *patch)
Z_Free(next->data);
if (next->colormap)
Z_Free(next->colormap);
next->data = NULL;
next->colormap = NULL;
HWD.pfnDeleteTexture(next);
// Free the old colormap mipmap from memory.
......@@ -694,12 +675,24 @@ void HWR_InitMapTextures(void)
gl_maptexturesloaded = false;
}
static void FreeMapTexture(GLMapTexture_t *tex)
static void DeleteTextureMipmap(GLMipmap_t *grMipmap, boolean delete_mipmap)
{
HWD.pfnDeleteTexture(&tex->mipmap);
if (tex->mipmap.data)
Z_Free(tex->mipmap.data);
tex->mipmap.data = NULL;
HWD.pfnDeleteTexture(grMipmap);
if (delete_mipmap)
Z_Free(grMipmap->data);
}
static void FreeMapTexture(GLMapTexture_t *tex, boolean delete_chromakeys)
{
if (tex->mipmap.nextcolormap)
{
DeleteTextureMipmap(tex->mipmap.nextcolormap, delete_chromakeys);
free(tex->mipmap.nextcolormap);
tex->mipmap.nextcolormap = NULL;
}
DeleteTextureMipmap(&tex->mipmap, true);
}
void HWR_FreeMapTextures(void)
......@@ -708,8 +701,8 @@ void HWR_FreeMapTextures(void)
for (i = 0; i < gl_numtextures; i++)
{
FreeMapTexture(&gl_textures[i]);
FreeMapTexture(&gl_flats[i]);
FreeMapTexture(&gl_textures[i], true);
FreeMapTexture(&gl_flats[i], false);
}
// now the heap don't have any 'user' pointing to our
......@@ -739,57 +732,74 @@ void HWR_LoadMapTextures(size_t pnumtextures)
gl_maptexturesloaded = true;
}
void HWR_SetPalette(RGBA_t *palette)
{
HWD.pfnSetPalette(palette);
// hardware driver will flush there own cache if cache is non paletized
// now flush data texture cache so 32 bit texture are recomputed
if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA)
{
Z_FreeTag(PU_HWRCACHE);
Z_FreeTag(PU_HWRCACHE_UNLOCKED);
}
}
// --------------------------------------------------------------------------
// Make sure texture is downloaded and set it as the source
// --------------------------------------------------------------------------
GLMapTexture_t *HWR_GetTexture(INT32 tex)
GLMapTexture_t *HWR_GetTexture(INT32 tex, boolean chromakeyed)
{
GLMapTexture_t *grtex;
if (tex < 0 || tex >= (signed)gl_numtextures)
{
#ifdef PARANOIA
if ((unsigned)tex >= gl_numtextures)
I_Error("HWR_GetTexture: tex >= numtextures\n");
I_Error("HWR_GetTexture: Invalid texture ID %d", tex);
#else
tex = 0;
#endif
}
// Every texture in memory, stored in the
// hardware renderer's bit depth format. Wow!
grtex = &gl_textures[tex];
GLMapTexture_t *grtex = &gl_textures[tex];
// Generate texture if missing from the cache
if (!grtex->mipmap.data && !grtex->mipmap.downloaded)
HWR_GenerateTexture(tex, grtex);
GLMipmap_t *grMipmap = &grtex->mipmap;
GLMipmap_t *originalMipmap = grMipmap;
// If hardware does not have the texture, then call pfnSetTexture to upload it
if (!grtex->mipmap.downloaded)
HWD.pfnSetTexture(&grtex->mipmap);
HWR_SetCurrentTexture(&grtex->mipmap);
if (!originalMipmap->downloaded)
{
originalMipmap->flags = TF_WRAPXY;
originalMipmap->width = (UINT16)textures[tex]->width;
originalMipmap->height = (UINT16)textures[tex]->height;
originalMipmap->format = textureformat;
}
// The system-memory data can be purged now.
Z_ChangeTag(grtex->mipmap.data, PU_HWRCACHE_UNLOCKED);
// If chroma-keyed, create or use a different mipmap for the variant
if (chromakeyed && !textures[tex]->transparency)
{
// Allocate it if it wasn't already
if (!originalMipmap->nextcolormap)
{
GLMipmap_t *newMipmap = calloc(1, sizeof (*grMipmap));
if (newMipmap == NULL)
I_Error("%s: Out of memory", "HWR_GetTexture");
newMipmap->flags = originalMipmap->flags | TF_CHROMAKEYED;
newMipmap->width = originalMipmap->width;
newMipmap->height = originalMipmap->height;
newMipmap->format = originalMipmap->format;
originalMipmap->nextcolormap = newMipmap;
}
// Generate, upload and bind the variant texture instead of the original one
grMipmap = originalMipmap->nextcolormap;
}
if (!grMipmap->data)
HWR_GenerateTexture(tex, grtex, grMipmap);
if (!grMipmap->downloaded)
HWD.pfnSetTexture(grMipmap);
HWR_SetCurrentTexture(grMipmap);
Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
return grtex;
}
static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum)
static void HWR_CacheRawFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum)
{
size_t size = W_LumpLength(flatlumpnum);
UINT16 pflatsize = R_GetFlatSize(size);
// setup the texture info
grMipmap->format = GL_TEXFMT_P_8;
grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
grMipmap->flags = TF_WRAPXY;
grMipmap->width = pflatsize;
grMipmap->height = pflatsize;
......@@ -810,7 +820,7 @@ void HWR_GetRawFlat(lumpnum_t flatlumpnum)
patch = HWR_GetCachedGLPatch(flatlumpnum);
grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap;
if (!grmip->downloaded && !grmip->data)
HWR_CacheFlat(grmip, flatlumpnum);
HWR_CacheRawFlat(grmip, flatlumpnum);
// If hardware does not have the texture, then call pfnSetTexture to upload it
if (!grmip->downloaded)
......@@ -821,40 +831,70 @@ void HWR_GetRawFlat(lumpnum_t flatlumpnum)
Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
}
void HWR_GetLevelFlat(levelflat_t *levelflat)
static void MakeLevelFlatMipmap(GLMipmap_t *grMipmap, INT32 texturenum, UINT16 flags)
{
if (levelflat->type == LEVELFLAT_NONE)
grMipmap->format = GL_TEXFMT_P_8;
grMipmap->flags = flags;
grMipmap->width = (UINT16)textures[texturenum]->width;
grMipmap->height = (UINT16)textures[texturenum]->height;
}
void HWR_GetLevelFlat(levelflat_t *levelflat, boolean chromakeyed)
{
if (levelflat->type == LEVELFLAT_NONE || levelflat->texture_id < 0)
{
HWR_SetCurrentTexture(NULL);
return;
}
INT32 texturenum = texturetranslation[levelflat->texture_id];
if (texturenum <= 0)
{
HWR_SetCurrentTexture(NULL);
return;
}
GLMapTexture_t *grtex = &gl_flats[texturenum];
GLMipmap_t *grMipmap = &grtex->mipmap;
GLMipmap_t *originalMipmap = grMipmap;
if (!originalMipmap->downloaded)
MakeLevelFlatMipmap(originalMipmap, texturenum, TF_WRAPXY);
if (!grMipmap->data && !grMipmap->downloaded)
if (!originalMipmap->data)
{
grMipmap->format = GL_TEXFMT_P_8;
grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
size_t size = originalMipmap->width * originalMipmap->height;
memcpy(Z_Malloc(size, PU_HWRCACHE, &originalMipmap->data), R_GetFlatForTexture(texturenum), size);
}
// If chroma-keyed, create or use a different mipmap for the variant
if (chromakeyed)
{
if (!originalMipmap->data)
{
HWR_SetCurrentTexture(NULL);
return;
}
grMipmap->width = (UINT16)textures[texturenum]->width;
grMipmap->height = (UINT16)textures[texturenum]->height;
// Allocate it if it wasn't already
if (!originalMipmap->nextcolormap)
{
GLMipmap_t *newMipmap = calloc(1, sizeof (*grMipmap));
if (newMipmap == NULL)
I_Error("%s: Out of memory", "HWR_GetLevelFlat");
MakeLevelFlatMipmap(newMipmap, texturenum, TF_WRAPXY | TF_CHROMAKEYED);
originalMipmap->nextcolormap = newMipmap;
}
size_t size = grMipmap->width * grMipmap->height;
memcpy(Z_Malloc(size, PU_HWRCACHE, &grMipmap->data), R_GetFlatForTexture(texturenum), size);
// Upload and bind the variant texture instead of the original one
grMipmap = originalMipmap->nextcolormap;
// Use the original texture's pixel data
// It can just be a pointer to it, since the r_opengl backend deals with the pixels
// that are supposed to be transparent.
grMipmap->data = originalMipmap->data;
}
if (!grMipmap->downloaded)
HWD.pfnSetTexture(&grtex->mipmap);
HWR_SetCurrentTexture(&grtex->mipmap);
HWD.pfnSetTexture(grMipmap);
HWR_SetCurrentTexture(grMipmap);
Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
}
......@@ -997,6 +1037,7 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32
UINT8 *flat;
UINT8 *dest, *src, texel;
RGBA_t col;
RGBA_t *palette = HWR_GetTexturePalette();
// Place the flats data into flat
W_ReadLump(fademasklumpnum, Z_Malloc(W_LumpLength(fademasklumpnum),
......@@ -1014,7 +1055,7 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32
{
// fademask bpp is always 1, and is used just for alpha
texel = src[(posx)>>FRACBITS];
col = V_GetColor(texel);
col = palette[texel];
*dest = col.s.red; // take the red level of the colour and use it for alpha, as fademasks do
dest++;
......@@ -1086,4 +1127,210 @@ void HWR_GetFadeMask(lumpnum_t fademasklumpnum)
Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED);
}
// =================================================
// PALETTE HANDLING
// =================================================
void HWR_SetPalette(RGBA_t *palette)
{
if (HWR_ShouldUsePaletteRendering())
{
// set the palette for palette postprocessing
if (cv_glpalettedepth.value == 16)
{
// crush to 16-bit rgb565, like software currently does in the standard configuration
// Note: Software's screenshots have the 24-bit palette, but the screen gets
// the 16-bit version! For making comparison screenshots either use an external screenshot
// tool or set the palette depth to 24 bits.
RGBA_t crushed_palette[256];
int i;
for (i = 0; i < 256; i++)
{
float fred = (float)(palette[i].s.red >> 3);
float fgreen = (float)(palette[i].s.green >> 2);
float fblue = (float)(palette[i].s.blue >> 3);
crushed_palette[i].s.red = (UINT8)(fred / 31.0f * 255.0f);
crushed_palette[i].s.green = (UINT8)(fgreen / 63.0f * 255.0f);
crushed_palette[i].s.blue = (UINT8)(fblue / 31.0f * 255.0f);
crushed_palette[i].s.alpha = 255;
}
HWD.pfnSetScreenPalette(crushed_palette);
}
else
{
HWD.pfnSetScreenPalette(palette);
}
// this part is responsible for keeping track of the palette OUTSIDE of a level.
if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)))
HWR_SetMapPalette();
}
else
{
// set the palette for the textures
HWD.pfnSetTexturePalette(palette);
// reset mapPalette so next call to HWR_SetMapPalette will update everything correctly
memset(mapPalette, 0, sizeof(mapPalette));
// hardware driver will flush there own cache if cache is non paletized
// now flush data texture cache so 32 bit texture are recomputed
if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA)
{
Z_FreeTag(PU_HWRCACHE);
Z_FreeTag(PU_HWRCACHE_UNLOCKED);
}
}
}
static void HWR_SetPaletteLookup(RGBA_t *palette)
{
int r, g, b;
UINT8 *lut = Z_Malloc(
HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE*sizeof(UINT8),
PU_STATIC, NULL);
#define STEP_SIZE (256/HWR_PALETTE_LUT_SIZE)
for (b = 0; b < HWR_PALETTE_LUT_SIZE; b++)
{
for (g = 0; g < HWR_PALETTE_LUT_SIZE; g++)
{
for (r = 0; r < HWR_PALETTE_LUT_SIZE; r++)
{
lut[b*HWR_PALETTE_LUT_SIZE*HWR_PALETTE_LUT_SIZE+g*HWR_PALETTE_LUT_SIZE+r] =
NearestPaletteColor(r*STEP_SIZE, g*STEP_SIZE, b*STEP_SIZE, palette);
}
}
}
#undef STEP_SIZE
HWD.pfnSetPaletteLookup(lut);
Z_Free(lut);
}
// Updates mapPalette to reflect the loaded level or other game state.
// Textures are flushed if needed.
// Call this function only in palette rendering mode.
void HWR_SetMapPalette(void)
{
RGBA_t RGBA_converted[256];
RGBA_t *palette;
int i;
if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)))
{
// outside of a level, pMasterPalette should have PLAYPAL ready for us
palette = pMasterPalette;
}
else
{
// in a level pMasterPalette might have a flash palette, but we
// want the map's original palette.
lumpnum_t lumpnum = W_GetNumForName(GetPalette());
size_t palsize = W_LumpLength(lumpnum);
UINT8 *RGB_data;
if (palsize < 768) // 256 * 3
I_Error("HWR_SetMapPalette: A programmer assumed palette lumps are at least 768 bytes long, but apparently this was a wrong assumption!\n");
RGB_data = W_CacheLumpNum(lumpnum, PU_CACHE);
// we got the RGB palette now, but we need it in RGBA format.
for (i = 0; i < 256; i++)
{
RGBA_converted[i].s.red = *(RGB_data++);
RGBA_converted[i].s.green = *(RGB_data++);
RGBA_converted[i].s.blue = *(RGB_data++);
RGBA_converted[i].s.alpha = 255;
}
palette = RGBA_converted;
}
// check if the palette has changed from the previous one
if (memcmp(mapPalette, palette, sizeof(mapPalette)))
{
memcpy(mapPalette, palette, sizeof(mapPalette));
// in palette rendering mode, this means that all rgba textures now have wrong colors
// and the lookup table is outdated
HWR_SetPaletteLookup(mapPalette);
HWD.pfnSetTexturePalette(mapPalette);
if (patchformat == GL_TEXFMT_RGBA || textureformat == GL_TEXFMT_RGBA)
{
Z_FreeTag(PU_HWRCACHE);
Z_FreeTag(PU_HWRCACHE_UNLOCKED);
}
}
}
// Creates a hardware lighttable from the supplied lighttable.
// Returns the id of the hw lighttable, usable in FSurfaceInfo.
UINT32 HWR_CreateLightTable(UINT8 *lighttable, RGBA_t *hw_lighttable)
{
UINT32 i;
RGBA_t *palette = HWR_GetTexturePalette();
// To make the palette index -> RGBA mapping easier for the shader,
// the hardware lighttable is composed of RGBA colors instead of palette indices.
for (i = 0; i < 256 * 32; i++)
hw_lighttable[i] = palette[lighttable[i]];
return HWD.pfnCreateLightTable(hw_lighttable);
}
// Updates a hardware lighttable of a given id from the supplied lighttable.
void HWR_UpdateLightTable(UINT32 id, UINT8 *lighttable, RGBA_t *hw_lighttable)
{
UINT32 i;
RGBA_t *palette = HWR_GetTexturePalette();
for (i = 0; i < 256 * 32; i++)
hw_lighttable[i] = palette[lighttable[i]];
HWD.pfnUpdateLightTable(id, hw_lighttable);
}
// get hwr lighttable id for colormap, create it if it doesn't already exist
UINT32 HWR_GetLightTableID(extracolormap_t *colormap)
{
boolean default_colormap = false;
if (!colormap)
{
colormap = R_GetDefaultColormap(); // a place to store the hw lighttable id
// alternatively could just store the id in a global variable if there are issues
default_colormap = true;
}
UINT8 *colormap_pointer;
if (default_colormap)
colormap_pointer = colormaps; // don't actually use the data from the "default colormap"
else
colormap_pointer = colormap->colormap;
// create hw lighttable if there isn't one
if (colormap->gl_lighttable.data == NULL)
{
Z_Malloc(256 * 32 * sizeof(RGBA_t), PU_HWRLIGHTTABLEDATA, &colormap->gl_lighttable.data);
}
// Generate the texture for this light table
if (!colormap->gl_lighttable.id)
{
colormap->gl_lighttable.id = HWR_CreateLightTable(colormap_pointer, colormap->gl_lighttable.data);
}
// Update the texture if it was directly changed by a script
else if (colormap->gl_lighttable.needs_update)
{
HWR_UpdateLightTable(colormap->gl_lighttable.id, colormap_pointer, colormap->gl_lighttable.data);
}
colormap->gl_lighttable.needs_update = false;
return colormap->gl_lighttable.id;
}
// Note: all hardware lighttable ids assigned before this
// call become invalid and must not be used.
void HWR_ClearLightTables(void)
{
Z_FreeTag(PU_HWRLIGHTTABLEDATA);
if (vid.glstate == VID_GL_LIBRARY_LOADED)
HWD.pfnClearLightTables();
}
#endif //HWRENDER
......@@ -320,16 +320,13 @@ void gld_clipper_Clear(void)
#define RMUL (1.6f/1.333333f)
angle_t gld_FrustumAngle(angle_t tiltangle)
angle_t gld_FrustumAngle(float render_fov, angle_t tiltangle)
{
double floatangle;
angle_t a1;
float tilt = (float)fabs(((double)(int)tiltangle) / ANG1);
// NEWCLIP TODO: SRB2CBTODO: make a global render_fov for this function
float render_fov = FIXED_TO_FLOAT(cv_fov.value);
float render_fovratio = (float)BASEVIDWIDTH / (float)BASEVIDHEIGHT; // SRB2CBTODO: NEWCLIPTODO: Is this right?
float render_multiplier = 64.0f / render_fovratio / RMUL;
......
......@@ -17,7 +17,7 @@
boolean gld_clipper_SafeCheckRange(angle_t startAngle, angle_t endAngle);
void gld_clipper_SafeAddClipRange(angle_t startangle, angle_t endangle);
void gld_clipper_Clear(void);
angle_t gld_FrustumAngle(angle_t tiltangle);
angle_t gld_FrustumAngle(float render_fov, angle_t tiltangle);
#ifdef HAVE_SPHEREFRUSTRUM
void gld_FrustrumSetup(void);
boolean gld_SphereInFrustum(float x, float y, float z, float radius);
......