Merge remote-tracking branch 'origin/next' into knuxtweaks

This commit is contained in:
lachwright 2020-07-04 18:53:26 +08:00
commit 6a7565686b
19 changed files with 210 additions and 58 deletions

View file

@ -49,7 +49,8 @@ typedef enum
SF_MULTIABILITY = 1<<13, // Revenge of Final Demo. SF_MULTIABILITY = 1<<13, // Revenge of Final Demo.
SF_NONIGHTSROTATION = 1<<14, // Disable sprite rotation for NiGHTS SF_NONIGHTSROTATION = 1<<14, // Disable sprite rotation for NiGHTS
SF_NONIGHTSSUPER = 1<<15, // Disable super colors for NiGHTS (if you have SF_SUPER) SF_NONIGHTSSUPER = 1<<15, // Disable super colors for NiGHTS (if you have SF_SUPER)
SF_NOSUPERJUMPBOOST = 1<<16, // Disable the jump boost given while super (i.e. Knuckles) SF_NOSUPERSPRITES = 1<<16, // Don't use super sprites while super
SF_NOSUPERJUMPBOOST = 1<<17, // Disable the jump boost given while super (i.e. Knuckles)
// free up to and including 1<<31 // free up to and including 1<<31
} skinflags_t; } skinflags_t;

View file

@ -9506,6 +9506,7 @@ struct {
{"FF_GLOBALANIM",FF_GLOBALANIM}, {"FF_GLOBALANIM",FF_GLOBALANIM},
{"FF_FULLBRIGHT",FF_FULLBRIGHT}, {"FF_FULLBRIGHT",FF_FULLBRIGHT},
{"FF_VERTICALFLIP",FF_VERTICALFLIP}, {"FF_VERTICALFLIP",FF_VERTICALFLIP},
{"FF_HORIZONTALFLIP",FF_HORIZONTALFLIP},
{"FF_PAPERSPRITE",FF_PAPERSPRITE}, {"FF_PAPERSPRITE",FF_PAPERSPRITE},
{"FF_TRANSMASK",FF_TRANSMASK}, {"FF_TRANSMASK",FF_TRANSMASK},
{"FF_TRANSSHIFT",FF_TRANSSHIFT}, {"FF_TRANSSHIFT",FF_TRANSSHIFT},
@ -9655,6 +9656,7 @@ struct {
{"SF_MULTIABILITY",SF_MULTIABILITY}, {"SF_MULTIABILITY",SF_MULTIABILITY},
{"SF_NONIGHTSROTATION",SF_NONIGHTSROTATION}, {"SF_NONIGHTSROTATION",SF_NONIGHTSROTATION},
{"SF_NONIGHTSSUPER",SF_NONIGHTSSUPER}, {"SF_NONIGHTSSUPER",SF_NONIGHTSSUPER},
{"SF_NOSUPERSPRITES",SF_NOSUPERSPRITES},
{"SF_NOSUPERJUMPBOOST",SF_NOSUPERJUMPBOOST}, {"SF_NOSUPERJUMPBOOST",SF_NOSUPERJUMPBOOST},
// Dashmode constants // Dashmode constants

View file

@ -720,14 +720,14 @@ void G_SetNightsRecords(void)
I_Error("Out of memory for replay filepath\n"); I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-last.lmp", gpath); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (FIL_FileExists(lastdemo)) if (FIL_FileExists(lastdemo))
{ {
UINT8 *buf; UINT8 *buf;
size_t len = FIL_ReadFile(lastdemo, &buf); size_t len = FIL_ReadFile(lastdemo, &buf);
snprintf(bestdemo, 255, "%s-time-best.lmp", gpath); snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);;
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo. { // Better time, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))
@ -736,7 +736,7 @@ void G_SetNightsRecords(void)
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
} }
snprintf(bestdemo, 255, "%s-score-best.lmp", gpath); snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)))
{ // Better score, save this demo. { // Better score, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))

View file

@ -50,7 +50,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void);
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development //Hurdler: added for new development
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface); EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT INT32 HWRAPI(GetTextureUsed) (void);

View file

@ -4636,6 +4636,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
unsigned rot; unsigned rot;
UINT16 flip; UINT16 flip;
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
boolean mirrored = thing->mirrored;
boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored);
angle_t ang; angle_t ang;
INT32 heightsec, phs; INT32 heightsec, phs;
@ -4724,6 +4726,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
#endif #endif
ang = R_PointToAngle (thing->x, thing->y) - mobjangle; ang = R_PointToAngle (thing->x, thing->y) - mobjangle;
if (mirrored)
ang = InvAngle(ang);
if (sprframe->rotate == SRF_SINGLE) if (sprframe->rotate == SRF_SINGLE)
{ {
@ -4796,6 +4800,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT)); rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT));
} }
flip = !flip != !hflip;
if (flip) if (flip)
{ {
x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale); x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale);

View file

@ -1242,6 +1242,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
//mdlframe_t *next = NULL; //mdlframe_t *next = NULL;
const boolean papersprite = (spr->mobj->frame & FF_PAPERSPRITE); const boolean papersprite = (spr->mobj->frame & FF_PAPERSPRITE);
const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !(spr->mobj->frame & FF_VERTICALFLIP)); const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !(spr->mobj->frame & FF_VERTICALFLIP));
const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !(spr->mobj->frame & FF_HORIZONTALFLIP));
spritedef_t *sprdef; spritedef_t *sprdef;
spriteframe_t *sprframe; spriteframe_t *sprframe;
spriteinfo_t *sprinfo; spriteinfo_t *sprinfo;
@ -1514,7 +1515,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
#endif #endif
HWD.pfnSetShader(4); // model shader HWD.pfnSetShader(4); // model shader
HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, &Surf); HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf);
} }
return true; return true;

View file

@ -2615,7 +2615,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model)
#define BUFFER_OFFSET(i) ((void*)(i)) #define BUFFER_OFFSET(i) ((void*)(i))
static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface) static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{ {
static GLRGBAFloat poly = {0,0,0,0}; static GLRGBAFloat poly = {0,0,0,0};
static GLRGBAFloat tint = {0,0,0,0}; static GLRGBAFloat tint = {0,0,0,0};
@ -2708,12 +2708,13 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
pglEnable(GL_NORMALIZE); pglEnable(GL_NORMALIZE);
#ifdef USE_FTRANSFORM_MIRROR #ifdef USE_FTRANSFORM_MIRROR
// flipped is if the object is flipped // flipped is if the object is vertically flipped
// hflipped is if the object is horizontally flipped
// pos->flip is if the screen is flipped vertically // pos->flip is if the screen is flipped vertically
// pos->mirror is if the screen is flipped horizontally // pos->mirror is if the screen is flipped horizontally
// XOR all the flips together to figure out what culling to use! // XOR all the flips together to figure out what culling to use!
{ {
boolean reversecull = (flipped ^ pos->flip ^ pos->mirror); boolean reversecull = (flipped ^ hflipped ^ pos->flip ^ pos->mirror);
if (reversecull) if (reversecull)
pglCullFace(GL_FRONT); pglCullFace(GL_FRONT);
else else
@ -2721,7 +2722,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
} }
#else #else
// pos->flip is if the screen is flipped too // pos->flip is if the screen is flipped too
if (flipped != pos->flip) // If either are active, but not both, invert the model's culling if (flipped ^ hflipped ^ pos->flip) // If one or three of these are active, but not two, invert the model's culling
{ {
pglCullFace(GL_FRONT); pglCullFace(GL_FRONT);
} }
@ -2736,6 +2737,8 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
pglTranslatef(pos->x, pos->z, pos->y); pglTranslatef(pos->x, pos->z, pos->y);
if (flipped) if (flipped)
scaley = -scaley; scaley = -scaley;
if (hflipped)
scalez = -scalez;
#ifdef USE_FTRANSFORM_ANGLEZ #ifdef USE_FTRANSFORM_ANGLEZ
pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart
@ -2882,9 +2885,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
// -----------------+ // -----------------+
// HWRAPI DrawModel : Draw a model // HWRAPI DrawModel : Draw a model
// -----------------+ // -----------------+
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, FSurfaceInfo *Surface) EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{ {
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, Surface); DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface);
} }
// -----------------+ // -----------------+

View file

@ -2240,7 +2240,7 @@ void HU_Erase(void)
// IN-LEVEL MULTIPLAYER RANKINGS // IN-LEVEL MULTIPLAYER RANKINGS
//====================================================================== //======================================================================
#define supercheckdef ((players[tab[i].num].powers[pw_super] && players[tab[i].num].mo && (players[tab[i].num].mo->state < &states[S_PLAY_SUPER_TRANS1] || players[tab[i].num].mo->state >= &states[S_PLAY_SUPER_TRANS6])) || (players[tab[i].num].powers[pw_carry] == CR_NIGHTSMODE && skins[players[tab[i].num].skin].flags & SF_SUPER)) #define supercheckdef (!(players[tab[i].num].charflags & SF_NOSUPERSPRITES) && ((players[tab[i].num].powers[pw_super] && players[tab[i].num].mo && (players[tab[i].num].mo->state < &states[S_PLAY_SUPER_TRANS1] || players[tab[i].num].mo->state >= &states[S_PLAY_SUPER_TRANS6])) || (players[tab[i].num].powers[pw_carry] == CR_NIGHTSMODE && skins[players[tab[i].num].skin].flags & SF_SUPER)))
#define greycheckdef (players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD || (G_IsSpecialStage(gamemap) && players[tab[i].num].exiting)) #define greycheckdef (players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD || (G_IsSpecialStage(gamemap) && players[tab[i].num].exiting))
// //
@ -2798,7 +2798,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
if (tab[i].color == 0) if (tab[i].color == 0)
{ {
colormap = colormaps; colormap = colormaps;
if (players[tab[i].num].powers[pw_super]) if (players[tab[i].num].powers[pw_super] && !(players[tab[i].num].charflags & SF_NOSUPERSPRITES))
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, superprefix[players[tab[i].num].skin], 0); V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT/4, 0, superprefix[players[tab[i].num].skin], 0);
else else
{ {

View file

@ -5294,7 +5294,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass 100, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound
MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY|MF_BOUNCE|MF_RUNSPAWNFUNC, // flags MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY|MF_SLIDEME|MF_RUNSPAWNFUNC, // flags
S_NULL // raisestate S_NULL // raisestate
}, },

View file

@ -86,6 +86,7 @@ enum mobj_e {
mobj_cvmem, mobj_cvmem,
mobj_standingslope, mobj_standingslope,
mobj_colorized, mobj_colorized,
mobj_mirrored,
mobj_shadowscale mobj_shadowscale
}; };
@ -152,6 +153,7 @@ static const char *const mobj_opt[] = {
"cvmem", "cvmem",
"standingslope", "standingslope",
"colorized", "colorized",
"mirrored",
"shadowscale", "shadowscale",
NULL}; NULL};
@ -385,6 +387,9 @@ static int mobj_get(lua_State *L)
case mobj_colorized: case mobj_colorized:
lua_pushboolean(L, mo->colorized); lua_pushboolean(L, mo->colorized);
break; break;
case mobj_mirrored:
lua_pushboolean(L, mo->mirrored);
break;
case mobj_shadowscale: case mobj_shadowscale:
lua_pushfixed(L, mo->shadowscale); lua_pushfixed(L, mo->shadowscale);
break; break;
@ -713,6 +718,9 @@ static int mobj_set(lua_State *L)
case mobj_colorized: case mobj_colorized:
mo->colorized = luaL_checkboolean(L, 3); mo->colorized = luaL_checkboolean(L, 3);
break; break;
case mobj_mirrored:
mo->mirrored = luaL_checkboolean(L, 3);
break;
case mobj_shadowscale: case mobj_shadowscale:
mo->shadowscale = luaL_checkfixed(L, 3); mo->shadowscale = luaL_checkfixed(L, 3);
break; break;

View file

@ -759,17 +759,18 @@ static menuitem_t SR_EmblemHintMenu[] =
// Single Player Main // Single Player Main
static menuitem_t SP_MainMenu[] = static menuitem_t SP_MainMenu[] =
{ {
// Note: If changing the positions here, also change them in M_SinglePlayerMenu()
{IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 76}, {IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 76},
{IT_SECRET, NULL, "Record Attack", M_TimeAttack, 84}, {IT_SECRET, NULL, "Record Attack", M_TimeAttack, 84},
{IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 92}, {IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 92},
{IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Marathon Run", M_Marathon, 100}, {IT_SECRET, NULL, "Marathon Run", M_Marathon, 100},
{IT_CALL | IT_STRING, NULL, "Tutorial", M_StartTutorial, 108}, {IT_CALL | IT_STRING, NULL, "Tutorial", M_StartTutorial, 108},
{IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 116} {IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 116}
}; };
enum enum
{ {
sploadgame, spstartgame,
sprecordattack, sprecordattack,
spnightsmode, spnightsmode,
spmarathon, spmarathon,
@ -2276,6 +2277,9 @@ void Nextmap_OnChange(void)
{ {
char *leveltitle; char *leveltitle;
char tabase[256]; char tabase[256];
#ifdef OLDNREPLAYNAME
char tabaseold[256];
#endif
short i; short i;
boolean active; boolean active;
@ -2300,11 +2304,17 @@ void Nextmap_OnChange(void)
SP_NightsAttackMenu[naghost].status = IT_DISABLED; SP_NightsAttackMenu[naghost].status = IT_DISABLED;
// Check if file exists, if not, disable REPLAY option // Check if file exists, if not, disable REPLAY option
sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name);
#ifdef OLDNREPLAYNAME
sprintf(tabaseold,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
#endif
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
SP_NightsReplayMenu[i].status = IT_DISABLED; SP_NightsReplayMenu[i].status = IT_DISABLED;
SP_NightsGuestReplayMenu[i].status = IT_DISABLED; SP_NightsGuestReplayMenu[i].status = IT_DISABLED;
} }
if (FIL_FileExists(va("%s-score-best.lmp", tabase))) { if (FIL_FileExists(va("%s-score-best.lmp", tabase))) {
SP_NightsReplayMenu[0].status = IT_WHITESTRING|IT_CALL; SP_NightsReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL; SP_NightsGuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
@ -2320,16 +2330,37 @@ void Nextmap_OnChange(void)
SP_NightsGuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL; SP_NightsGuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL;
active = true; active = true;
} }
if (FIL_FileExists(va("%s-guest.lmp", tabase))) { if (FIL_FileExists(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)))) {
SP_NightsReplayMenu[3].status = IT_WHITESTRING|IT_CALL; SP_NightsReplayMenu[3].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[3].status = IT_WHITESTRING|IT_CALL; SP_NightsGuestReplayMenu[3].status = IT_WHITESTRING|IT_CALL;
active = true; active = true;
} }
// Old style name compatibility
#ifdef OLDNREPLAYNAME
if (FIL_FileExists(va("%s-score-best.lmp", tabaseold))) {
SP_NightsReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
active = true;
}
if (FIL_FileExists(va("%s-time-best.lmp", tabaseold))) {
SP_NightsReplayMenu[1].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[1].status = IT_WHITESTRING|IT_CALL;
active = true;
}
if (FIL_FileExists(va("%s-last.lmp", tabaseold))) {
SP_NightsReplayMenu[2].status = IT_WHITESTRING|IT_CALL;
SP_NightsGuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL;
active = true;
}
#endif
if (active) { if (active) {
SP_NightsAttackMenu[naguest].status = IT_WHITESTRING|IT_SUBMENU; SP_NightsAttackMenu[naguest].status = IT_WHITESTRING|IT_SUBMENU;
SP_NightsAttackMenu[nareplay].status = IT_WHITESTRING|IT_SUBMENU; SP_NightsAttackMenu[nareplay].status = IT_WHITESTRING|IT_SUBMENU;
SP_NightsAttackMenu[naghost].status = IT_WHITESTRING|IT_SUBMENU; SP_NightsAttackMenu[naghost].status = IT_WHITESTRING|IT_SUBMENU;
} }
else if(itemOn == nareplay) // Reset lastOn so replay isn't still selected when not available. else if(itemOn == nareplay) // Reset lastOn so replay isn't still selected when not available.
{ {
currentMenu->lastOn = itemOn; currentMenu->lastOn = itemOn;
@ -4404,7 +4435,7 @@ static void M_DrawGenericMenu(void)
} }
} }
const char *PlaystyleNames[4] = {"Legacy", "Standard", "Simple", "Old Analog??"}; const char *PlaystyleNames[4] = {"Strafe", "Standard", "Simple", "Old Analog??"};
const char *PlaystyleDesc[4] = { const char *PlaystyleDesc[4] = {
// Legacy // Legacy
"The play style used for\n" "The play style used for\n"
@ -8043,29 +8074,67 @@ static void M_SinglePlayerMenu(INT32 choice)
{ {
(void)choice; (void)choice;
// Reset the item positions, to avoid them sinking farther down every time the menu is opened if one is unavailable
// Note that they're reset, not simply "not moved again", in case mid-game add-ons re-enable an option
SP_MainMenu[spstartgame] .alphaKey = 76;
SP_MainMenu[sprecordattack].alphaKey = 84;
SP_MainMenu[spnightsmode] .alphaKey = 92;
SP_MainMenu[spmarathon] .alphaKey = 100;
//SP_MainMenu[sptutorial] .alphaKey = 108; // Not needed
//SP_MainMenu[spstatistics].alphaKey = 116; // Not needed
levellistmode = LLM_RECORDATTACK; levellistmode = LLM_RECORDATTACK;
if (M_GametypeHasLevels(-1)) if (M_GametypeHasLevels(-1))
SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET; SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
else else // If Record Attack is nonexistent in the current add-on...
SP_MainMenu[sprecordattack].status = IT_NOTHING|IT_DISABLED; {
SP_MainMenu[sprecordattack].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the Record Attack option...
SP_MainMenu[spstartgame].alphaKey += 8; // ...and lower Start Game by 8 pixels to close the gap
}
levellistmode = LLM_NIGHTSATTACK; levellistmode = LLM_NIGHTSATTACK;
if (M_GametypeHasLevels(-1)) if (M_GametypeHasLevels(-1))
SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET; SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
else else // If NiGHTS Mode is nonexistent in the current add-on...
SP_MainMenu[spnightsmode].status = IT_NOTHING|IT_DISABLED; {
SP_MainMenu[spnightsmode].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the NiGHTS Mode option...
// ...and lower the above options' display positions by 8 pixels to close the gap
SP_MainMenu[spstartgame] .alphaKey += 8;
SP_MainMenu[sprecordattack].alphaKey += 8;
}
SP_MainMenu[sptutorial].status = tutorialmap ? IT_CALL|IT_STRING : IT_NOTHING|IT_DISABLED;
// If the FIRST stage immediately leads to the ending, or itself (which gets converted to the title screen in G_DoCompleted for marathonmode only), there's no point in having this option on the menu. You should use Record Attack in that circumstance, although if marathonnext is set this behaviour can be overridden if you make some weird mod that requires multiple playthroughs of the same map in sequence and has some in-level mechanism to break the cycle. // If the FIRST stage immediately leads to the ending, or itself (which gets converted to the title screen in G_DoCompleted for marathonmode only), there's no point in having this option on the menu. You should use Record Attack in that circumstance, although if marathonnext is set this behaviour can be overridden if you make some weird mod that requires multiple playthroughs of the same map in sequence and has some in-level mechanism to break the cycle.
if (!M_SecretUnlocked(SECRET_RECORDATTACK) // also if record attack is locked if (mapheaderinfo[spmarathon_start-1]
|| (mapheaderinfo[spmarathon_start-1]
&& !mapheaderinfo[spmarathon_start-1]->marathonnext && !mapheaderinfo[spmarathon_start-1]->marathonnext
&& (mapheaderinfo[spmarathon_start-1]->nextlevel == spmarathon_start && (mapheaderinfo[spmarathon_start-1]->nextlevel == spmarathon_start
|| mapheaderinfo[spmarathon_start-1]->nextlevel >= 1100))) || mapheaderinfo[spmarathon_start-1]->nextlevel >= 1100))
SP_MainMenu[spmarathon].status = IT_NOTHING|IT_DISABLED; {
else SP_MainMenu[spmarathon].status = IT_NOTHING|IT_DISABLED; // Hide and disable the Marathon Run option...
SP_MainMenu[spmarathon].status = IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED; // ...and lower the above options' display positions by 8 pixels to close the gap
SP_MainMenu[spstartgame] .alphaKey += 8;
SP_MainMenu[sprecordattack].alphaKey += 8;
SP_MainMenu[spnightsmode] .alphaKey += 8;
}
else // Otherwise, if Marathon Run is allowed and Record Attack is unlocked, unlock Marathon Run!
SP_MainMenu[spmarathon].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
if (tutorialmap) // If there's a tutorial available in the current add-on...
SP_MainMenu[sptutorial].status = IT_CALL | IT_STRING; // ...always unlock Tutorial
else // But if there's no tutorial available in the current add-on...
{
SP_MainMenu[sptutorial].status = IT_NOTHING|IT_DISABLED; // ...hide and disable the Tutorial option...
// ...and lower the above options' display positions by 8 pixels to close the gap
SP_MainMenu[spstartgame] .alphaKey += 8;
SP_MainMenu[sprecordattack].alphaKey += 8;
SP_MainMenu[spnightsmode] .alphaKey += 8;
SP_MainMenu[spmarathon] .alphaKey += 8;
}
M_SetupNextMenu(&SP_MainDef); M_SetupNextMenu(&SP_MainDef);
} }
@ -10126,6 +10195,8 @@ static void M_NightsAttack(INT32 choice)
// Player has selected the "START" from the nights attack screen // Player has selected the "START" from the nights attack screen
static void M_ChooseNightsAttack(INT32 choice) static void M_ChooseNightsAttack(INT32 choice)
{ {
char *gpath;
const size_t glen = strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char nameofdemo[256]; char nameofdemo[256];
(void)choice; (void)choice;
emeralds = 0; emeralds = 0;
@ -10136,14 +10207,18 @@ static void M_ChooseNightsAttack(INT32 choice)
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755);
snprintf(nameofdemo, sizeof nameofdemo, "replay"PATHSEP"%s"PATHSEP"%s-last", timeattackfolder, G_BuildMapName(cv_nextmap.value)); if ((gpath = malloc(glen)) == NULL)
I_Error("Out of memory for replay filepath\n");
sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value));
snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1].name);
if (!cv_autorecord.value) if (!cv_autorecord.value)
remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo));
else else
G_RecordDemo(nameofdemo); G_RecordDemo(nameofdemo);
G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), 0, false, false); G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), false, false);
} }
// Player has selected the "START" from the time attack screen // Player has selected the "START" from the time attack screen
@ -10179,6 +10254,7 @@ static void M_ChooseTimeAttack(INT32 choice)
static void M_ReplayTimeAttack(INT32 choice) static void M_ReplayTimeAttack(INT32 choice)
{ {
const char *which; const char *which;
char *demoname;
M_ClearMenus(true); M_ClearMenus(true);
modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows
@ -10220,11 +10296,18 @@ static void M_ReplayTimeAttack(INT32 choice)
which = "last"; which = "last";
break; break;
case 3: // guest case 3: // guest
which = "guest"; G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
break; return;
} }
// srb2/replay/main/map01-score-best.lmp
G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which)); demoname = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which);
#ifdef OLDNREPLAYNAME // Check for old style named NiGHTS replay if a new style replay doesn't exist.
if (!FIL_FileExists(demoname))
demoname = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which);
#endif
G_DoPlayDemo(demoname);
} }
} }
@ -10242,15 +10325,13 @@ static void M_EraseGuest(INT32 choice)
M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING); M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING);
} }
static void M_OverwriteGuest(const char *which, boolean nights) static void M_OverwriteGuest(const char *which)
{ {
char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
UINT8 *buf; UINT8 *buf;
size_t len; size_t len;
if (!nights)
len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which), &buf); len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which), &buf);
else
len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which), &buf);
if (!len) { if (!len) {
return; return;
} }
@ -10271,25 +10352,25 @@ static void M_OverwriteGuest(const char *which, boolean nights)
static void M_OverwriteGuest_Time(INT32 choice) static void M_OverwriteGuest_Time(INT32 choice)
{ {
(void)choice; (void)choice;
M_OverwriteGuest("time-best", currentMenu == &SP_NightsGuestReplayDef); M_OverwriteGuest("time-best");
} }
static void M_OverwriteGuest_Score(INT32 choice) static void M_OverwriteGuest_Score(INT32 choice)
{ {
(void)choice; (void)choice;
M_OverwriteGuest("score-best", currentMenu == &SP_NightsGuestReplayDef); M_OverwriteGuest("score-best");
} }
static void M_OverwriteGuest_Rings(INT32 choice) static void M_OverwriteGuest_Rings(INT32 choice)
{ {
(void)choice; (void)choice;
M_OverwriteGuest("rings-best", false); M_OverwriteGuest("rings-best");
} }
static void M_OverwriteGuest_Last(INT32 choice) static void M_OverwriteGuest_Last(INT32 choice)
{ {
(void)choice; (void)choice;
M_OverwriteGuest("last", currentMenu == &SP_NightsGuestReplayDef); M_OverwriteGuest("last");
} }
static void M_SetGuestReplay(INT32 choice) static void M_SetGuestReplay(INT32 choice)

View file

@ -21,6 +21,9 @@
#include "r_skins.h" // for SKINNAMESIZE #include "r_skins.h" // for SKINNAMESIZE
#include "f_finale.h" // for ttmode_enum #include "f_finale.h" // for ttmode_enum
// Compatibility with old-style named NiGHTS replay files.
#define OLDNREPLAYNAME
// //
// MENUS // MENUS
// //

View file

@ -400,7 +400,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
if (skin) if (skin)
{ {
spr2 = P_GetSkinSprite2(skin, (((player->powers[pw_super]) ? FF_SPR2SUPER : 0)|st->frame) & FF_FRAMEMASK, mobj->player); spr2 = P_GetSkinSprite2(skin, (((player->powers[pw_super] && !(player->charflags & SF_NOSUPERSPRITES)) ? FF_SPR2SUPER : 0)|st->frame) & FF_FRAMEMASK, mobj->player);
numframes = skin->sprites[spr2].numframes; numframes = skin->sprites[spr2].numframes;
} }
else else
@ -9212,10 +9212,11 @@ static void P_DragonbomberThink(mobj_t *mobj)
mobj->angle += DRAGONTURNSPEED; mobj->angle += DRAGONTURNSPEED;
else else
{ {
boolean flip = mobj->spawnpoint->options & MTF_OBJECTFLIP;
fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale); fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale);
fixed_t x = mobj->spawnpoint->x << FRACBITS; fixed_t x = mobj->spawnpoint->x << FRACBITS;
fixed_t y = mobj->spawnpoint->y << FRACBITS; fixed_t y = mobj->spawnpoint->y << FRACBITS;
fixed_t z = mobj->spawnpoint->z << FRACBITS; fixed_t z = (flip ? P_GetSectorCeilingZAt : P_GetSectorFloorZAt)(R_PointInSubsector(x, y)->sector, x, y) + (flip ? -1 : 1)*(mobj->spawnpoint->z << FRACBITS);
angle_t diff = R_PointToAngle2(mobj->x, mobj->y, x, y) - mobj->angle; angle_t diff = R_PointToAngle2(mobj->x, mobj->y, x, y) - mobj->angle;
if (diff > ANGLE_180) if (diff > ANGLE_180)
mobj->angle -= DRAGONTURNSPEED; mobj->angle -= DRAGONTURNSPEED;

View file

@ -373,6 +373,7 @@ typedef struct mobj_s
struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?)
boolean colorized; // Whether the mobj uses the rainbow colormap boolean colorized; // Whether the mobj uses the rainbow colormap
boolean mirrored; // The object's rotations will be mirrored left to right, e.g., see frame AL from the right and AR from the left
fixed_t shadowscale; // If this object casts a shadow, and the size relative to radius fixed_t shadowscale; // If this object casts a shadow, and the size relative to radius
// WARNING: New fields must be added separately to savegame and Lua. // WARNING: New fields must be added separately to savegame and Lua.

View file

@ -64,8 +64,10 @@
#define FF_FULLBRIGHT 0x00100000 #define FF_FULLBRIGHT 0x00100000
/// \brief Frame flags: Flip sprite vertically (relative to what it should be for its gravity) /// \brief Frame flags: Flip sprite vertically (relative to what it should be for its gravity)
#define FF_VERTICALFLIP 0x00200000 #define FF_VERTICALFLIP 0x00200000
/// \brief Frame flags: Flip sprite horizontally
#define FF_HORIZONTALFLIP 0x00400000
/// \brief Frame flags: Thin, paper-like sprite (for collision equivalent, see MF_PAPERCOLLISION) /// \brief Frame flags: Thin, paper-like sprite (for collision equivalent, see MF_PAPERCOLLISION)
#define FF_PAPERSPRITE 0x00400000 #define FF_PAPERSPRITE 0x00800000
/// \brief Frame flags - Animate: Simple stateless animation /// \brief Frame flags - Animate: Simple stateless animation
#define FF_ANIMATE 0x01000000 #define FF_ANIMATE 0x01000000

View file

@ -1294,8 +1294,9 @@ typedef enum
MD2_CEILINGROVER = 1<<10, MD2_CEILINGROVER = 1<<10,
MD2_SLOPE = 1<<11, MD2_SLOPE = 1<<11,
MD2_COLORIZED = 1<<12, MD2_COLORIZED = 1<<12,
MD2_ROLLANGLE = 1<<13, MD2_MIRRORED = 1<<13,
MD2_SHADOWSCALE = 1<<14, MD2_ROLLANGLE = 1<<14,
MD2_SHADOWSCALE = 1<<15,
} mobj_diff2_t; } mobj_diff2_t;
typedef enum typedef enum
@ -1500,6 +1501,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
diff2 |= MD2_SLOPE; diff2 |= MD2_SLOPE;
if (mobj->colorized) if (mobj->colorized)
diff2 |= MD2_COLORIZED; diff2 |= MD2_COLORIZED;
if (mobj->mirrored)
diff2 |= MD2_MIRRORED;
if (mobj->rollangle) if (mobj->rollangle)
diff2 |= MD2_ROLLANGLE; diff2 |= MD2_ROLLANGLE;
if (mobj->shadowscale) if (mobj->shadowscale)
@ -1638,6 +1641,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
WRITEUINT16(save_p, mobj->standingslope->id); WRITEUINT16(save_p, mobj->standingslope->id);
if (diff2 & MD2_COLORIZED) if (diff2 & MD2_COLORIZED)
WRITEUINT8(save_p, mobj->colorized); WRITEUINT8(save_p, mobj->colorized);
if (diff2 & MD2_MIRRORED)
WRITEUINT8(save_p, mobj->mirrored);
if (diff2 & MD2_ROLLANGLE) if (diff2 & MD2_ROLLANGLE)
WRITEANGLE(save_p, mobj->rollangle); WRITEANGLE(save_p, mobj->rollangle);
if (diff2 & MD2_SHADOWSCALE) if (diff2 & MD2_SHADOWSCALE)
@ -2641,6 +2646,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
mobj->standingslope = P_SlopeById(READUINT16(save_p)); mobj->standingslope = P_SlopeById(READUINT16(save_p));
if (diff2 & MD2_COLORIZED) if (diff2 & MD2_COLORIZED)
mobj->colorized = READUINT8(save_p); mobj->colorized = READUINT8(save_p);
if (diff2 & MD2_MIRRORED)
mobj->mirrored = READUINT8(save_p);
if (diff2 & MD2_ROLLANGLE) if (diff2 & MD2_ROLLANGLE)
mobj->rollangle = READANGLE(save_p); mobj->rollangle = READANGLE(save_p);
if (diff2 & MD2_SHADOWSCALE) if (diff2 & MD2_SHADOWSCALE)

View file

@ -3157,6 +3157,7 @@ static void P_LoadNightsGhosts(void)
{ {
const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath = malloc(glen); char *gpath = malloc(glen);
INT32 i;
if (!gpath) if (!gpath)
return; return;
@ -3164,16 +3165,43 @@ static void P_LoadNightsGhosts(void)
sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
// Best Score ghost // Best Score ghost
if (cv_ghost_bestscore.value && FIL_FileExists(va("%s-score-best.lmp", gpath))) if (cv_ghost_bestscore.value)
G_AddGhost(va("%s-score-best.lmp", gpath)); {
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_bestscore.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-score-best.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-score-best.lmp", gpath, skins[i].name));
}
}
// Best Time ghost // Best Time ghost
if (cv_ghost_besttime.value && FIL_FileExists(va("%s-time-best.lmp", gpath))) if (cv_ghost_besttime.value)
G_AddGhost(va("%s-time-best.lmp", gpath)); {
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name));
}
}
// Last ghost // Last ghost
if (cv_ghost_last.value && FIL_FileExists(va("%s-last.lmp", gpath))) if (cv_ghost_last.value)
G_AddGhost(va("%s-last.lmp", gpath)); {
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-last.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-last.lmp", gpath, skins[i].name));
}
}
// Guest ghost // Guest ghost
if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath))) if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath)))

View file

@ -1367,6 +1367,8 @@ static void R_ProjectSprite(mobj_t *thing)
size_t frame, rot; size_t frame, rot;
UINT16 flip; UINT16 flip;
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
boolean mirrored = thing->mirrored;
boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored);
INT32 lindex; INT32 lindex;
@ -1477,7 +1479,11 @@ static void R_ProjectSprite(mobj_t *thing)
#endif #endif
if (sprframe->rotate != SRF_SINGLE || papersprite) if (sprframe->rotate != SRF_SINGLE || papersprite)
{
ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle); ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle);
if (mirrored)
ang = InvAngle(ang);
}
if (sprframe->rotate == SRF_SINGLE) if (sprframe->rotate == SRF_SINGLE)
{ {
@ -1537,6 +1543,8 @@ static void R_ProjectSprite(mobj_t *thing)
} }
#endif #endif
flip = !flip != !hflip;
// calculate edges of the shape // calculate edges of the shape
if (flip) if (flip)
offset = spr_offset - spr_width; offset = spr_offset - spr_width;

View file

@ -821,7 +821,7 @@ static void ST_drawLivesArea(void)
// skincolor face/super // skincolor face/super
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE); UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE);
patch_t *face = faceprefix[stplyr->skin]; patch_t *face = faceprefix[stplyr->skin];
if (stplyr->powers[pw_super]) if (stplyr->powers[pw_super] && !(stplyr->charflags & SF_NOSUPERSPRITES))
face = superprefix[stplyr->skin]; face = superprefix[stplyr->skin];
V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, V_DrawSmallMappedPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y,
hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, face, colormap); hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, face, colormap);